From 4f69f4c267a21e787685116945fb40729a7297a5 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Tue, 7 Aug 2012 13:26:33 +0000 Subject: [PATCH] gdb/ PR 11804 * defs.h (find_memory_region_ftype): New comment. New arg modified. * fbsd-nat.c (fbsd_find_memory_regions): Add the passed modified value. * gcore.c (gcore_create_callback): New function comment. Add modified parameter. Only write modified regions. Set SEC_READONLY exactly according to MODIFIED. (objfile_find_memory_regions): Ignore separate debug info files. Ass the passed modified value to FUNC. * gnu-nat.c (gnu_find_memory_regions): Add the passed modified value. * linux-tdep.c (linux_find_memory_regions): Try to reads smaps file first. New variables modified and has_anonymous. Parse the lines of smaps file. Add the passed MODIFIED value to FUNC. * procfs.c (find_memory_regions_callback): Add the passed modified value. gdb/testsuite/ PR 11804 * gdb.base/gcore-relro.exp: New file. * gdb.base/gcore-relro-main.c: New file. * gdb.base/gcore-relro-lib.c: New file. --- gdb/ChangeLog | 18 +++++++ gdb/defs.h | 7 ++- gdb/fbsd-nat.c | 5 +- gdb/gcore.c | 24 +++++++--- gdb/gnu-nat.c | 2 + gdb/linux-tdep.c | 42 +++++++++++++++-- gdb/procfs.c | 1 + gdb/testsuite/ChangeLog | 8 ++++ gdb/testsuite/gdb.base/gcore-relro-lib.c | 21 +++++++++ gdb/testsuite/gdb.base/gcore-relro-main.c | 25 ++++++++++ gdb/testsuite/gdb.base/gcore-relro.exp | 78 +++++++++++++++++++++++++++++++ 11 files changed, 219 insertions(+), 12 deletions(-) create mode 100644 gdb/testsuite/gdb.base/gcore-relro-lib.c create mode 100644 gdb/testsuite/gdb.base/gcore-relro-main.c create mode 100644 gdb/testsuite/gdb.base/gcore-relro.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c300886..55ed8dd 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,21 @@ +2012-08-07 Jan Kratochvil + Jean-Marc Saffroy + + PR 11804 + * defs.h (find_memory_region_ftype): New comment. New arg modified. + * fbsd-nat.c (fbsd_find_memory_regions): Add the passed modified value. + * gcore.c (gcore_create_callback): New function comment. Add modified + parameter. Only write modified regions. Set SEC_READONLY exactly + according to MODIFIED. + (objfile_find_memory_regions): Ignore separate debug info files. Ass + the passed modified value to FUNC. + * gnu-nat.c (gnu_find_memory_regions): Add the passed modified value. + * linux-tdep.c (linux_find_memory_regions): Try to reads smaps file + first. New variables modified and has_anonymous. Parse the lines of + smaps file. Add the passed MODIFIED value to FUNC. + * procfs.c (find_memory_regions_callback): Add the passed modified + value. + 2012-08-06 Tom Tromey * dwarf2-frame.c (clear_pointer_cleanup): New function. diff --git a/gdb/defs.h b/gdb/defs.h index 7be99a2..de34740 100644 --- a/gdb/defs.h +++ b/gdb/defs.h @@ -362,9 +362,14 @@ extern void init_source_path (void); /* From exec.c */ +/* Process memory area starting at ADDR with length SIZE. Area is readable iff + READ is non-zero, writable if WRITE is non-zero, executable if EXEC is + non-zero. Area is possibly changed against its original file based copy if + MODIFIED is non-zero. DATA is passed without changes from a caller. */ + 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..4a8a509 100644 --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -131,8 +131,9 @@ fbsd_find_memory_regions (find_memory_region_ftype func, void *obfd) exec ? 'x' : '-'); } - /* Invoke the callback function to create the corefile segment. */ - func (start, size, read, write, exec, obfd); + /* Invoke the callback function to create the corefile segment. + Pass MODIFIED as true, we do not know the real modification state. */ + func (start, size, read, write, exec, 1, obfd); } do_cleanups (cleanup); diff --git a/gdb/gcore.c b/gdb/gcore.c index a45e787..3c8e2f4 100644 --- a/gdb/gcore.c +++ b/gdb/gcore.c @@ -379,9 +379,12 @@ make_output_phdrs (bfd *obfd, asection *osec, void *ignored) bfd_record_phdr (obfd, p_type, 1, p_flags, 0, 0, 0, 0, 1, &osec); } +/* find_memory_region_ftype implementation. DATA is 'bfd *' for the core file + GDB is creating. */ + 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 +393,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 +404,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 +436,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 +482,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 +495,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, pass it as true. */ obfd); if (ret != 0) return ret; @@ -498,6 +508,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 +517,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..5a653cf 100644 --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -2558,6 +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, + 1, /* MODIFIED is unknown, pass it as true. */ data); last_region_address = region_address; last_region_end = region_address += region_length; @@ -2571,6 +2572,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, + 1, /* MODIFIED is unknown, pass it as true. */ data); return 0; diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c index b6f2efb..65f5f97 100644 --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -547,19 +547,28 @@ 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 == NULL) + { + /* Older Linux kernels did not support /proc/PID/smaps. */ + 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 +578,35 @@ 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; + } + + /* Older Linux kernels did not support the "Anonymous:" counter. + If it is missing, we can't be sure - dump all the pages. */ + if (!has_anonymous) + 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..ee2b123 100644 --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -5074,6 +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, + 1, /* MODIFIED is unknown, pass it as true. */ data); } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d0b0f35..0b01846 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,4 +1,12 @@ 2012-08-07 Jan Kratochvil + Jean-Marc Saffroy + + PR 11804 + * gdb.base/gcore-relro.exp: New file. + * gdb.base/gcore-relro-main.c: New file. + * gdb.base/gcore-relro-lib.c: New file. + +2012-08-07 Jan Kratochvil Do not false FAIL with old GCCs. * gdb.base/watchpoint.exp (self-delete local watch) <$no_hw>: XFAIL for 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..5b8d6c7 --- /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] { + 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" -- 2.7.4