diff --git a/gdb/defs.h b/gdb/defs.h index 7be99a2..feb3106 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -362,9 +362,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 index b3e4fab..5db0f5d 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -132,7 +132,7 @@ fbsd_find_memory_regions (find_memory_region_ftype func, void *obfd) } /* 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 index a45e787..a9dd2ba 100644 --- a/gdb/gcore.c +++ b/gdb/gcore.c @@ -380,8 +380,8 @@ make_output_phdrs (bfd *obfd, asection *osec, void *ignored) } 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; @@ -390,7 +390,7 @@ gcore_create_callback (CORE_ADDR vaddr, unsigned long size, /* 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) { @@ -401,7 +401,7 @@ gcore_create_callback (CORE_ADDR vaddr, unsigned long size, 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. */ @@ -433,10 +433,12 @@ gcore_create_callback (CORE_ADDR vaddr, unsigned long size, } } - keep: - flags |= SEC_READONLY; + keep:; } + if (write == 0) + flags |= SEC_READONLY; + if (exec) flags |= SEC_CODE; else @@ -477,6 +479,10 @@ objfile_find_memory_regions (find_memory_region_ftype func, void *obfd) asection *isec = objsec->the_bfd_section; flagword flags = bfd_get_section_flags (ibfd, isec); + /* Separate debug info files are irrelevant for gcore. */ + if (objfile->separate_debug_objfile_backlink != NULL) + continue; + if ((flags & SEC_ALLOC) || (flags & SEC_LOAD)) { int size = bfd_section_size (ibfd, isec); @@ -486,6 +492,7 @@ objfile_find_memory_regions (find_memory_region_ftype func, void *obfd) 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; @@ -498,6 +505,7 @@ objfile_find_memory_regions (find_memory_region_ftype func, void *obfd) 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. */ @@ -506,6 +514,7 @@ objfile_find_memory_regions (find_memory_region_ftype func, void *obfd) 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 index 0c45f20..046e32a 100644 --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -2558,7 +2558,7 @@ gnu_find_memory_regions (find_memory_region_ftype func, void *data) 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_region_ftype func, void *data) 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-tdep.c b/gdb/linux-tdep.c index b6f2efb..4a36fe4 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -547,19 +547,27 @@ linux_find_memory_regions (struct gdbarch *gdbarch, return 1; xsnprintf (filename, sizeof filename, - "/proc/%d/maps", current_inferior ()->pid); + "/proc/%d/smaps", current_inferior ()->pid); data = target_fileio_read_stralloc (filename); + if (! data) + { + xsnprintf (filename, sizeof filename, + "/proc/%d/maps", current_inferior ()->pid); + data = target_fileio_read_stralloc (filename); + } if (data) { struct cleanup *cleanup = make_cleanup (xfree, data); char *line; - for (line = strtok (data, "\n"); line; line = strtok (NULL, "\n")) + line = strtok (data, "\n"); + while (line) { ULONGEST addr, endaddr, offset, inode; const char *permissions, *device, *filename; size_t permissions_len, device_len; int read, write, exec; + int modified = 0, has_anonymous = 0; read_mapping (line, &addr, &endaddr, &permissions, &permissions_len, &offset, &device, &device_len, &inode, &filename); @@ -569,8 +577,34 @@ linux_find_memory_regions (struct gdbarch *gdbarch, write = (memchr (permissions, 'w', permissions_len) != 0); exec = (memchr (permissions, 'x', permissions_len) != 0); + /* Try to detect if region was modified by parsing smaps counters. */ + for (line = strtok (NULL, "\n"); + line && line[0] >= 'A' && line[0] <= 'Z'; + line = strtok (NULL, "\n")) + { + char keyword[64 + 1]; + unsigned long number; + + if (sscanf(line, "%64s%lu kB\n", keyword, &number) != 2) + { + warning (_("Error parsing {s,}maps file '%s'"), filename); + break; + } + if (strcmp(keyword, "Anonymous:") == 0) + has_anonymous = 1; + if (number != 0 && (strcmp (keyword, "Shared_Dirty:") == 0 + || strcmp (keyword, "Private_Dirty:") == 0 + || strcmp (keyword, "Swap:") == 0 + || strcmp (keyword, "Anonymous:") == 0)) + modified = 1; + } + + /* When "Anonymous:" is missing, we can't be sure. */ + if (! has_anonymous && modified == 0) + modified = -1; + /* Invoke the callback function to create the corefile segment. */ - func (addr, endaddr - addr, read, write, exec, obfd); + func (addr, endaddr - addr, read, write, exec, modified, obfd); } do_cleanups (cleanup); diff --git a/gdb/procfs.c b/gdb/procfs.c index 4409e5b..79f22de 100644 --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -5074,7 +5074,7 @@ find_memory_regions_callback (struct prmap *map, (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 index 0000000..d74b690 --- /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 index 0000000..46b9dfe --- /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 index 0000000..ace80e4 --- /dev/null +++ b/gdb/testsuite/gdb.base/gcore-relro.exp @@ -0,0 +1,78 @@ +# Copyright 2012 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 +} + +standard_testfile gcore-relro-main.c +set libfile gcore-relro-lib +set srcfile_lib ${libfile}.c +set binfile_lib [standard_output_file ${libfile}.so] +set gcorefile ${binfile}.gcore +set objfile [standard_output_file ${testfile}.o] + + if { [gdb_compile_shlib ${srcdir}/${subdir}/${srcfile_lib} ${binfile_lib} {debug}] != "" + || [gdb_compile ${srcdir}/${subdir}/${srcfile} ${objfile} object {debug}] != "" } { + untested ${testfile}.exp + return -1 + } + set opts [list debug shlib=${binfile_lib} additional_flags=-Wl,-z,relro] + if { [gdb_compile ${objfile} ${binfile} executable $opts] != "" } { + unsupported "-Wl,-z,relro compilation failed" + return -1 + } + +clean_restart ${binfile} +gdb_load_shlibs ${binfile_lib} + +# 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 ${binfile} +gdb_load_shlibs ${binfile_lib} + +gdb_test "core ${gcorefile}" "Core was generated by .*" "re-load generated corefile" + +gdb_test "frame" "#0 \[^\r\n\]* lib .*" "library got loaded"