Description: cleanups needed to support "gcore" command when target has GNU_RELRO sections. Bug: http://sourceware.org/bugzilla/show_bug.cgi?id=11804 Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gdb/+bug/680588 Origin: http://sourceware.org/ml/gdb-patches/2010-08/msg00554.html Author: Jan Kratochvil Updated for gdb 7.4-2012.02 by Steve Beattie gdb/ 2010-09-22 Jan Kratochvil Fix gcore writer for -Wl,-z,relro. * defs.h (find_memory_region_ftype): New parameter `modified'. New comment. * fbsd-nat.c (fbsd_find_memory_regions): Pass -1 to func. * gcore.c (gcore_create_callback): New parameter `modified'. Consider segment as unmodified only if also MODIFIED is 0. Set SEC_READONLY just according to WRITE. (objfile_find_memory_regions): Pass new values for the `modified' parameter. * gnu-nat.c (gnu_find_memory_regions): Pass -1 for the `modified' parameter. * linux-nat.c (read_mapping): New parameters mapfilename and modified. (linux_nat_find_memory_regions): New variable `modified'. Try "/proc/%d/smaps" first. Pass `&modified' and `mapsfilename' to read_mapping. Call func with MODIFIED. (linux_nat_info_proc_cmd): Pass `fname1' and NULL to read_mapping. * procfs.c (find_memory_regions_callback): Pass -1 for the `modified' parameter. gdb/testsuite/ 2010-09-22 Jan Kratochvil Fix gcore writer for -Wl,-z,relro. * gdb.base/gcore-relro.exp: New file. * gdb.base/gcore-relro-main.c: New file. * gdb.base/gcore-relro-lib.c: New file. --- gdb/defs.h | 3 - gdb/fbsd-nat.c | 2 gdb/gcore.c | 17 ++++-- gdb/gnu-nat.c | 4 - gdb/linux-tdep.c | 57 ++++++++++++++++++++- gdb/procfs.c | 2 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 | 80 ++++++++++++++++++++++++++++++ 9 files changed, 197 insertions(+), 14 deletions(-) Index: 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 Index: 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); Index: b/gdb/gcore.c =================================================================== --- a/gdb/gcore.c +++ b/gdb/gcore.c @@ -379,8 +379,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; @@ -389,7 +389,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) { @@ -400,7 +400,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. */ @@ -432,10 +432,12 @@ gcore_create_callback (CORE_ADDR vaddr, } } - keep: - flags |= SEC_READONLY; + keep:; } + if (write == 0) + flags |= SEC_READONLY; + if (exec) flags |= SEC_CODE; else @@ -485,6 +487,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; @@ -497,6 +500,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. */ @@ -505,6 +509,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; Index: 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; } Index: b/gdb/procfs.c =================================================================== --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -5279,7 +5279,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 Index: b/gdb/testsuite/gdb.base/gcore-relro-lib.c =================================================================== --- /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) +{ +} Index: b/gdb/testsuite/gdb.base/gcore-relro-main.c =================================================================== --- /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; +} Index: b/gdb/testsuite/gdb.base/gcore-relro.exp =================================================================== --- /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" Index: b/gdb/linux-tdep.c =================================================================== --- a/gdb/linux-tdep.c +++ b/gdb/linux-tdep.c @@ -245,6 +245,33 @@ read_mapping (const char *line, *filename = p; } +/* Service function for proc smaps detail lines */ + +static int +read_smaps_line (const char *line) +{ + int got; + char keyword[64 + 1]; + unsigned long number; + + if (strncmp (line, "Shared_Dirty:", sizeof ("Shared_Dirty:")) != 0 + && strncmp (line, "Private_Dirty:", sizeof ("Private_Dirty:")) != 0 + && strncmp (line, "Swap:", sizeof ("Swap:") != 0)) + return 0; + + got = sscanf (line, "%64s%lu", keyword, &number); + if (got != 2) + { + warning (_("Failed to parse smaps line '%s'"), line); + return -1; + } + + if (number != 0) + return 1; + + return 0; +} + /* Implement the "info proc" command. */ static void @@ -538,20 +565,29 @@ linux_find_memory_regions (struct gdbarc { char filename[100]; gdb_byte *data; + int have_smaps = 1; /* We need to know the real target PID to access /proc. */ if (current_inferior ()->fake_pid_p) 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) + { + have_smaps = 0; + 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; @@ -567,7 +603,22 @@ linux_find_memory_regions (struct gdbarc exec = (memchr (permissions, 'x', permissions_len) != 0); /* Invoke the callback function to create the corefile segment. */ - func (addr, endaddr - addr, read, write, exec, obfd); + if (have_smaps) + { + int modified = 0; + for (line = strtok (NULL, "\n"); line && line[0] >= 'A' && line[0] <= 'Z'; line = strtok (NULL, "\n")) + { + if (modified == 0) + modified = read_smaps_line (line); + } + + func (addr, endaddr - addr, read, write, exec, modified, obfd); + } + else + { + func (addr, endaddr - addr, read, write, exec, -1, obfd); + line = strtok (NULL, "\n"); + } } do_cleanups (cleanup);