From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18881 invoked by alias); 30 Aug 2010 09:15:39 -0000 Received: (qmail 18860 invoked by uid 22791); 30 Aug 2010 09:15:35 -0000 X-SWARE-Spam-Status: No, hits=-6.0 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_BJ,T_FRT_PROFILE2,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 30 Aug 2010 09:15:26 +0000 Received: from int-mx02.intmail.prod.int.phx2.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o7U9FOnb022050 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Mon, 30 Aug 2010 05:15:25 -0400 Received: from host1.dyn.jankratochvil.net (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx02.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o7U9FMqt002075 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 30 Aug 2010 05:15:24 -0400 Received: from host1.dyn.jankratochvil.net (localhost [127.0.0.1]) by host1.dyn.jankratochvil.net (8.14.4/8.14.4) with ESMTP id o7U9FMAM024717 for ; Mon, 30 Aug 2010 11:15:22 +0200 Received: (from jkratoch@localhost) by host1.dyn.jankratochvil.net (8.14.4/8.14.4/Submit) id o7U9FLrP024716 for gdb-patches@sourceware.org; Mon, 30 Aug 2010 11:15:21 +0200 Date: Mon, 30 Aug 2010 09:15:00 -0000 From: Jan Kratochvil To: gdb-patches@sourceware.org Subject: [patch] Fix gcore writer for -Wl,-z,relro (PR corefiles/11804) Message-ID: <20100830091521.GB25961@host1.dyn.jankratochvil.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.20 (2009-12-10) X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-08/txt/msg00499.txt.bz2 Hi, currently for -Wl,-z,relro executables GDB will not dump the DYNAMIC segment into the core file, failing to read shared library list later. (gdb) info sharedlibrary >From To Syms Read Shared Object Library 0x00007ffff7dddb20 0x00007ffff7df5c74 Yes /lib64/ld-linux-x86-64.so.2 This is just the fallback, GDB considers the executable uninitialized with DT_DEBUG value zero. Linux kernel dumps it correctly, respecting if the page got ever modified since being read from the disk, even if it is not (no longer) writable. No regressions on {x86_64,x86_64-m32,i686}-fedora14snapshot-linux-gnu. The "Shared_Dirty:" / "Private_Dirty:" / "Swap:" rule has been suggested by Roland McGrath and confirmed by Larry Woodman. This patch depends on: [patch] Code cleanup: Make function typedef for find memory region http://sourceware.org/ml/gdb-patches/2010-08/msg00498.html Thanks, Jan gdb/ 2010-08-30 Jan Kratochvil Fix gcore writer for -Wl,-z,relro. * defs.h (find_memory_region_t): 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. (linux_nat_find_memory_regions): New variable `modified'. Try "/proc/%d/smaps" first. Pass `&modified' to read_mapping. Call func with MODIFIED. (linux_nat_info_proc_cmd): Pass NULL to read_mapping. * procfs.c (find_memory_regions_callback): Pass -1 for the `modified' parameter. gdb/testsuite/ 2010-08-30 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. --- a/gdb/defs.h +++ b/gdb/defs.h @@ -634,9 +634,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_t) (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 (int (*func) (find_memory_region_t, --- a/gdb/fbsd-nat.c +++ b/gdb/fbsd-nat.c @@ -133,7 +133,7 @@ fbsd_find_memory_regions (find_memory_region_t 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); --- a/gdb/gcore.c +++ b/gdb/gcore.c @@ -378,8 +378,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; @@ -388,7 +388,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) { @@ -399,7 +399,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. */ @@ -432,10 +432,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 @@ -485,6 +487,7 @@ objfile_find_memory_regions (find_memory_region_t 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; @@ -497,6 +500,7 @@ objfile_find_memory_regions (find_memory_region_t 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. */ @@ -505,6 +509,7 @@ objfile_find_memory_regions (find_memory_region_t 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; --- a/gdb/gnu-nat.c +++ b/gdb/gnu-nat.c @@ -2544,7 +2544,7 @@ gnu_find_memory_regions (find_memory_region_t 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; @@ -2557,7 +2557,7 @@ gnu_find_memory_regions (find_memory_region_t func, void *data) last_protection & VM_PROT_READ, last_protection & VM_PROT_WRITE, last_protection & VM_PROT_EXECUTE, - data); + -1, data); return 0; } --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -4079,7 +4079,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); @@ -4097,6 +4097,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); } @@ -4111,13 +4145,17 @@ linux_nat_find_memory_regions (find_memory_region_t func, void *obfd) 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) @@ -4126,7 +4164,7 @@ linux_nat_find_memory_regions (find_memory_region_t func, void *obfd) /* 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; @@ -4149,7 +4187,7 @@ linux_nat_find_memory_regions (find_memory_region_t func, void *obfd) /* 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; @@ -4612,7 +4650,8 @@ linux_nat_info_proc_cmd (char *args, int from_tty) } while (read_mapping (procfile, &addr, &endaddr, &permissions[0], - &offset, &device[0], &inode, &filename[0])) + &offset, &device[0], &inode, &filename[0], + NULL)) { size = endaddr - addr; --- a/gdb/procfs.c +++ b/gdb/procfs.c @@ -5285,7 +5285,7 @@ find_memory_regions_callback (struct prmap *map, find_memory_region_t func, (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 --- /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) +{ +} --- /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; +} --- /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"