diff --git a/gdb/defs.h b/gdb/defs.h --- a/gdb/defs.h +++ b/gdb/defs.h @@ -672,9 +672,10 @@ extern void init_source_path (void); /* From exec.c */ +/* MODIFIED has value -1 for unknown, 0 for not modified, 1 for modified. */ typedef int (*find_memory_region_ftype) (CORE_ADDR addr, unsigned long size, int read, int write, int exec, - void *data); + int modified, void *data); /* Take over the 'find_mapped_memory' vector from exec.c. */ extern void exec_set_find_memory_regions diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -132,7 +132,7 @@ fbsd_find_memory_regions (find_memory_re } /* Invoke the callback function to create the corefile segment. */ - func (start, size, read, write, exec, obfd); + func (start, size, read, write, exec, -1, obfd); } do_cleanups (cleanup); diff --git a/gdb/gcore.c b/gdb/gcore.c --- a/gdb/gcore.c +++ b/gdb/gcore.c @@ -377,8 +377,8 @@ make_output_phdrs (bfd *obfd, asection * } static int -gcore_create_callback (CORE_ADDR vaddr, unsigned long size, - int read, int write, int exec, void *data) +gcore_create_callback (CORE_ADDR vaddr, unsigned long size, int read, + int write, int exec, int modified, void *data) { bfd *obfd = data; asection *osec; @@ -387,7 +387,7 @@ gcore_create_callback (CORE_ADDR vaddr, /* If the memory segment has no permissions set, ignore it, otherwise when we later try to access it for read/write, we'll get an error or jam the kernel. */ - if (read == 0 && write == 0 && exec == 0) + if (read == 0 && write == 0 && exec == 0 && modified == 0) { if (info_verbose) { @@ -398,7 +398,7 @@ gcore_create_callback (CORE_ADDR vaddr, return 0; } - if (write == 0 && !solib_keep_data_in_core (vaddr, size)) + if (write == 0 && modified == 0 && !solib_keep_data_in_core (vaddr, size)) { /* See if this region of memory lies inside a known file on disk. If so, we can avoid copying its contents by clearing SEC_LOAD. */ @@ -430,10 +430,12 @@ gcore_create_callback (CORE_ADDR vaddr, } } - keep: - flags |= SEC_READONLY; + keep:; } + if (write == 0) + flags |= SEC_READONLY; + if (exec) flags |= SEC_CODE; else @@ -483,6 +485,7 @@ objfile_find_memory_regions (find_memory 1, /* All sections will be readable. */ (flags & SEC_READONLY) == 0, /* Writable. */ (flags & SEC_CODE) != 0, /* Executable. */ + -1, /* Modified is unknown. */ obfd); if (ret != 0) return ret; @@ -495,6 +498,7 @@ objfile_find_memory_regions (find_memory 1, /* Stack section will be readable. */ 1, /* Stack section will be writable. */ 0, /* Stack section will not be executable. */ + 1, /* Stack section will be modified. */ obfd); /* Make a heap segment. */ @@ -503,6 +507,7 @@ objfile_find_memory_regions (find_memory 1, /* Heap section will be readable. */ 1, /* Heap section will be writable. */ 0, /* Heap section will not be executable. */ + 1, /* Heap section will be modified. */ obfd); return 0; diff --git a/gdb/gnu-nat.c b/gdb/gnu-nat.c --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -2558,7 +2558,7 @@ gnu_find_memory_regions (find_memory_reg last_protection & VM_PROT_READ, last_protection & VM_PROT_WRITE, last_protection & VM_PROT_EXECUTE, - data); + -1, data); last_region_address = region_address; last_region_end = region_address += region_length; last_protection = protection; @@ -2571,7 +2571,7 @@ gnu_find_memory_regions (find_memory_reg last_protection & VM_PROT_READ, last_protection & VM_PROT_WRITE, last_protection & VM_PROT_EXECUTE, - data); + -1, data); return 0; } diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -4352,7 +4352,7 @@ read_mapping (FILE *mapfile, long long *endaddr, char *permissions, long long *offset, - char *device, long long *inode, char *filename) + char *device, long long *inode, char *filename, int *modified) { int ret = fscanf (mapfile, "%llx-%llx %s %llx %s %llx", addr, endaddr, permissions, offset, device, inode); @@ -4370,6 +4370,40 @@ read_mapping (FILE *mapfile, ret += fscanf (mapfile, "%[^\n]\n", filename); } + if (modified != NULL) + { + *modified = -1; + for (;;) + { + int ch; + char keyword[64 + 1]; + unsigned long number; + + ch = fgetc (mapfile); + if (ch != EOF) + ungetc (ch, mapfile); + if (ch < 'A' || ch > 'Z') + break; + if (fscanf (mapfile, "%64s%lu kB\n", keyword, &number) != 2) + { + warning (_("Error parsing /proc/PID/{s,}maps file")); + do + ch = fgetc (mapfile); + while (ch != EOF && ch != '\n'); + break; + } + if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0 + || strcmp (keyword, "Private_Dirty:") == 0 + || strcmp (keyword, "Swap:") == 0)) + *modified = 1; + else if (*modified == -1) + { + /* Valid line proves an smaps file is being read in. */ + *modified = 0; + } + } + } + return (ret != 0 && ret != EOF); } @@ -4384,13 +4418,17 @@ linux_nat_find_memory_regions (find_memo FILE *mapsfile; long long addr, endaddr, size, offset, inode; char permissions[8], device[8], filename[MAXPATHLEN]; - int read, write, exec; + int read, write, exec, modified; struct cleanup *cleanup; /* Compose the filename for the /proc memory map, and open it. */ - sprintf (mapsfilename, "/proc/%d/maps", pid); + sprintf (mapsfilename, "/proc/%d/smaps", pid); if ((mapsfile = fopen (mapsfilename, "r")) == NULL) - error (_("Could not open %s."), mapsfilename); + { + sprintf (mapsfilename, "/proc/%d/maps", pid); + if ((mapsfile = fopen (mapsfilename, "r")) == NULL) + error (_("Could not open %s."), mapsfilename); + } cleanup = make_cleanup_fclose (mapsfile); if (info_verbose) @@ -4399,7 +4437,7 @@ linux_nat_find_memory_regions (find_memo /* Now iterate until end-of-file. */ while (read_mapping (mapsfile, &addr, &endaddr, &permissions[0], - &offset, &device[0], &inode, &filename[0])) + &offset, &device[0], &inode, &filename[0], &modified)) { size = endaddr - addr; @@ -4422,7 +4460,7 @@ linux_nat_find_memory_regions (find_memo /* Invoke the callback function to create the corefile segment. */ - func (addr, size, read, write, exec, obfd); + func (addr, size, read, write, exec, modified, obfd); } do_cleanups (cleanup); return 0; @@ -4871,7 +4909,8 @@ linux_nat_info_proc_cmd_1 (char *args, e } while (read_mapping (procfile, &addr, &endaddr, &permissions[0], - &offset, &device[0], &inode, &filename[0])) + &offset, &device[0], &inode, &filename[0], + NULL)) { size = endaddr - addr; diff --git a/gdb/procfs.c b/gdb/procfs.c --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -5275,7 +5275,7 @@ find_memory_regions_callback (struct prm (map->pr_mflags & MA_READ) != 0, (map->pr_mflags & MA_WRITE) != 0, (map->pr_mflags & MA_EXEC) != 0, - data); + -1, data); } /* External interface. Calls a callback function once for each diff --git a/gdb/testsuite/gdb.base/gcore-relro-lib.c b/gdb/testsuite/gdb.base/gcore-relro-lib.c new file mode 100644 --- /dev/null +++ b/gdb/testsuite/gdb.base/gcore-relro-lib.c @@ -0,0 +1,21 @@ +/* Copyright 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +void +lib (void) +{ +} diff --git a/gdb/testsuite/gdb.base/gcore-relro-main.c b/gdb/testsuite/gdb.base/gcore-relro-main.c new file mode 100644 --- /dev/null +++ b/gdb/testsuite/gdb.base/gcore-relro-main.c @@ -0,0 +1,25 @@ +/* Copyright 2010 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +extern void lib (void); + +int +main (void) +{ + lib (); + return 0; +} diff --git a/gdb/testsuite/gdb.base/gcore-relro.exp b/gdb/testsuite/gdb.base/gcore-relro.exp new file mode 100644 --- /dev/null +++ b/gdb/testsuite/gdb.base/gcore-relro.exp @@ -0,0 +1,80 @@ +# Copyright 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +if {[skip_shlib_tests]} { + return 0 +} + +set testfile "gcore-relro" +set srcmainfile ${testfile}-main.c +set srclibfile ${testfile}-lib.c +set libfile ${objdir}/${subdir}/${testfile}-lib.so +set objfile ${objdir}/${subdir}/${testfile}-main.o +set executable ${testfile}-main +set binfile ${objdir}/${subdir}/${executable} +set gcorefile ${objdir}/${subdir}/${executable}.gcore + +if { [gdb_compile_shlib ${srcdir}/${subdir}/${srclibfile} ${libfile} {debug}] != "" + || [gdb_compile ${srcdir}/${subdir}/${srcmainfile} ${objfile} object {debug}] != "" } { + untested ${testfile}.exp + return -1 +} +set opts [list debug shlib=${libfile} additional_flags=-Wl,-z,relro] +if { [gdb_compile ${objfile} ${binfile} executable $opts] != "" } { + unsupported "-Wl,-z,relro compilation failed" + return -1 +} + +clean_restart $executable +gdb_load_shlibs $libfile + +# Does this gdb support gcore? +set test "help gcore" +gdb_test_multiple $test $test { + -re "Undefined command: .gcore.*\r\n$gdb_prompt $" { + # gcore command not supported -- nothing to test here. + unsupported "gdb does not support gcore on this target" + return -1; + } + -re "Save a core file .*\r\n$gdb_prompt $" { + pass $test + } +} + +if { ![runto lib] } then { + return -1 +} + +set escapedfilename [string_to_regexp ${gcorefile}] + +set test "save a corefile" +gdb_test_multiple "gcore ${gcorefile}" $test { + -re "Saved corefile ${escapedfilename}\r\n$gdb_prompt $" { + pass $test + } + -re "Can't create a corefile\r\n$gdb_prompt $" { + unsupported $test + return -1 + } +} + +# Now restart gdb and load the corefile. + +clean_restart $executable +gdb_load_shlibs $libfile + +gdb_test "core ${gcorefile}" "Core was generated by .*" "re-load generated corefile" + +gdb_test "frame" "#0 \[^\r\n\]* lib .*" "library got loaded"