From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 4286 invoked by alias); 8 Feb 2008 19:11:35 -0000 Received: (qmail 4277 invoked by uid 22791); 8 Feb 2008 19:11:34 -0000 X-Spam-Check-By: sourceware.org Received: from NaN.false.org (HELO nan.false.org) (208.75.86.248) by sourceware.org (qpsmtpd/0.31) with ESMTP; Fri, 08 Feb 2008 19:11:15 +0000 Received: from nan.false.org (localhost [127.0.0.1]) by nan.false.org (Postfix) with ESMTP id 231C198300; Fri, 8 Feb 2008 19:11:14 +0000 (GMT) Received: from caradoc.them.org (22.svnf5.xdsl.nauticom.net [209.195.183.55]) by nan.false.org (Postfix) with ESMTP id 8AE3C9810C; Fri, 8 Feb 2008 19:11:13 +0000 (GMT) Received: from drow by caradoc.them.org with local (Exim 4.68) (envelope-from ) id 1JNYcx-00089j-Mg; Fri, 08 Feb 2008 14:11:11 -0500 Date: Fri, 08 Feb 2008 19:11:00 -0000 From: Daniel Jacobowitz To: gdb-patches@sourceware.org Cc: Kevin Buettner Subject: [rfa/solib] Always reload DT_DEBUG, trust r_brk Message-ID: <20080208191111.GA30569@caradoc.them.org> Mail-Followup-To: gdb-patches@sourceware.org, Kevin Buettner MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.17 (2007-12-11) 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: 2008-02/txt/msg00156.txt.bz2 This patch makes two changes to SVR4 shared library support. They are motivated by a custom dynamic linker I've been working with for the last few weeks. It is an intermediate stage between the kernel ELF loader and the C library's normal runtime loader, which adjusts a couple of things in the new binary before it starts. I have made it as transparent to the debugger as possible, but there are still a few quirks that seem impossible to eliminate (they bump up against the userspace/kernelspace security boundary). First, instead of reading the location of _r_debug from the DT_DEBUG dynamic tag once, do so each time we reload the shared libraries list. This has minimal cost, since we're already going to reload r_map and the entire set of link maps. I use this to set an early map which includes the first stage loader, making it easy to debug. Also, if r_brk is already set in the r_debug struct, do not bother searching for it by name in ld.so. Trust r_debug to be correct, and assume that the dynamic loader (for lazy-resolution-stub-skipping purposes) is the object containing *_r_debug.r_brk. This lets us, when the custom dynamic linker is in use, be independent of the name of ld.so and its symbols. By the way, that's one step towards never depending on symbols for ld.so, but the last step isn't obvious. We would have to support both relocated and unrelocated _r_debug contents (not hard); glibc would have to initialize _r_debug with the address of _dl_debug_state (not hard); but we'd also have to be able to find _r_debug before ld.so has had a chance to fill in DT_DEBUG in the application. I don't know how Solaris handles that. I've tested these changes on x86_64-linux and other platforms, both with and without the custom dynamic linker. They have no effect without it. Do they seem generally reasonable? OK to commit? -- Daniel Jacobowitz CodeSourcery 2008-02-08 Daniel Jacobowitz * mipsnbsd-tdep.c (mipsnbsd_ilp32_fetch_link_map_offsets): Set r_brk_offset. (mipsnbsd_lp64_fetch_link_map_offsets): Likewise. * solib-svr4.c (solib_svr4_r_brk): New. (open_symbol_file_object, svr4_current_sos): Always check the debug base. (svr4_fetch_objfile_link_map): Do not set debug_base. (enable_break): Use r_brk if it is set. (svr4_ilp32_fetch_link_map_offsets): Set r_brk_offset. (svr4_lp64_fetch_link_map_offsets): Likewise. * solib-svr4.h (struct link_map_offsets): Add r_brk_offset. Index: mipsnbsd-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/mipsnbsd-tdep.c,v retrieving revision 1.33 diff -u -p -r1.33 mipsnbsd-tdep.c --- mipsnbsd-tdep.c 1 Jan 2008 22:53:12 -0000 1.33 +++ mipsnbsd-tdep.c 8 Feb 2008 18:37:08 -0000 @@ -341,6 +341,7 @@ mipsnbsd_ilp32_fetch_link_map_offsets (v lmo.r_version_offset = 0; lmo.r_version_size = 4; lmo.r_map_offset = 4; + lmo.r_brk_offset = 8; lmo.r_ldsomap_offset = -1; /* Everything we need is in the first 24 bytes. */ @@ -368,6 +369,7 @@ mipsnbsd_lp64_fetch_link_map_offsets (vo lmo.r_version_offset = 0; lmo.r_version_size = 4; lmo.r_map_offset = 8; + lmo.r_brk_offset = 16; lmo.r_ldsomap_offset = -1; /* Everything we need is in the first 40 bytes. */ Index: solib-svr4.c =================================================================== RCS file: /cvs/src/src/gdb/solib-svr4.c,v retrieving revision 1.82 diff -u -p -r1.82 solib-svr4.c --- solib-svr4.c 29 Jan 2008 21:11:24 -0000 1.82 +++ solib-svr4.c 8 Feb 2008 18:37:08 -0000 @@ -548,6 +548,17 @@ solib_svr4_r_map (void) builtin_type_void_data_ptr); } +/* Find r_brk from the inferior's debug base. */ + +static CORE_ADDR +solib_svr4_r_brk (void) +{ + struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + + return read_memory_typed_address (debug_base + lmo->r_brk_offset, + builtin_type_void_data_ptr); +} + /* Find the link map for the dynamic linker (if it is not in the normal list of loaded shared objects). */ @@ -606,7 +617,9 @@ open_symbol_file_object (void *from_ttyp if (!query ("Attempt to reload symbols from process? ")) return 0; - if ((debug_base = locate_base ()) == 0) + /* Always locate the debug struct, in case it has moved. */ + debug_base = 0; + if (locate_base () == 0) return 0; /* failed somehow... */ /* First link map member should be the executable. */ @@ -701,17 +714,14 @@ svr4_current_sos (void) struct so_list **link_ptr = &head; CORE_ADDR ldsomap = 0; - /* Make sure we've looked up the inferior's dynamic linker's base - structure. */ - if (! debug_base) - { - debug_base = locate_base (); + /* Always locate the debug struct, in case it has moved. */ + debug_base = 0; + locate_base (); - /* If we can't find the dynamic linker's base structure, this - must not be a dynamically linked executable. Hmm. */ - if (! debug_base) - return svr4_default_sos (); - } + /* If we can't find the dynamic linker's base structure, this + must not be a dynamically linked executable. Hmm. */ + if (! debug_base) + return svr4_default_sos (); /* Walk the inferior's link map list, and build our list of `struct so_list' nodes. */ @@ -800,7 +810,7 @@ svr4_fetch_objfile_link_map (struct objf { CORE_ADDR lm; - if ((debug_base = locate_base ()) == 0) + if (locate_base () == 0) return 0; /* failed somehow... */ /* Position ourselves on the first link map. */ @@ -965,6 +975,7 @@ enable_break (void) struct minimal_symbol *msymbol; char **bkpt_namep; asection *interp_sect; + CORE_ADDR sym_addr; /* First, remove all the solib event breakpoints. Their addresses may have changed since the last time we ran the program. */ @@ -973,6 +984,54 @@ enable_break (void) interp_text_sect_low = interp_text_sect_high = 0; interp_plt_sect_low = interp_plt_sect_high = 0; + /* If we already have a shared library list in the target, and + r_debug contains r_brk, set the breakpoint there - this should + mean r_brk has already been relocated. Assume the dynamic linker + is the object containing r_brk. */ + + solib_add (NULL, 0, ¤t_target, auto_solib_add); + sym_addr = 0; + if (debug_base && solib_svr4_r_map () != 0) + sym_addr = solib_svr4_r_brk (); + + if (sym_addr != 0) + { + struct obj_section *os; + + os = find_pc_section (sym_addr); + if (os != NULL) + { + /* Record the relocated start and end address of the dynamic linker + text and plt section for svr4_in_dynsym_resolve_code. */ + bfd *tmp_bfd; + CORE_ADDR load_addr; + + tmp_bfd = os->objfile->obfd; + load_addr = ANOFFSET (os->objfile->section_offsets, + os->objfile->sect_index_text); + + interp_sect = bfd_get_section_by_name (tmp_bfd, ".text"); + if (interp_sect) + { + interp_text_sect_low = + bfd_section_vma (tmp_bfd, interp_sect) + load_addr; + interp_text_sect_high = + interp_text_sect_low + bfd_section_size (tmp_bfd, interp_sect); + } + interp_sect = bfd_get_section_by_name (tmp_bfd, ".plt"); + if (interp_sect) + { + interp_plt_sect_low = + bfd_section_vma (tmp_bfd, interp_sect) + load_addr; + interp_plt_sect_high = + interp_plt_sect_low + bfd_section_size (tmp_bfd, interp_sect); + } + + create_solib_event_breakpoint (sym_addr); + return 1; + } + } + /* Find the .interp section; if not found, warn the user and drop into the old breakpoint at symbol code. */ interp_sect = bfd_get_section_by_name (exec_bfd, ".interp"); @@ -988,10 +1047,10 @@ enable_break (void) struct target_ops *tmp_bfd_target; int tmp_fd = -1; char *tmp_pathname = NULL; - CORE_ADDR sym_addr = 0; /* Read the contents of the .interp section into a local buffer; the contents specify the dynamic linker this program uses. */ + sym_addr = 0; interp_sect_size = bfd_section_size (exec_bfd, interp_sect); buf = alloca (interp_sect_size); bfd_get_section_contents (exec_bfd, interp_sect, @@ -1028,7 +1087,6 @@ enable_break (void) /* On a running target, we can get the dynamic linker's base address from the shared library table. */ - solib_add (NULL, 0, ¤t_target, auto_solib_add); so = master_so_list (); while (so) { @@ -1504,6 +1562,7 @@ svr4_ilp32_fetch_link_map_offsets (void) lmo.r_version_offset = 0; lmo.r_version_size = 4; lmo.r_map_offset = 4; + lmo.r_brk_offset = 8; lmo.r_ldsomap_offset = 20; /* Everything we need is in the first 20 bytes. */ @@ -1534,6 +1593,7 @@ svr4_lp64_fetch_link_map_offsets (void) lmo.r_version_offset = 0; lmo.r_version_size = 4; lmo.r_map_offset = 8; + lmo.r_brk_offset = 16; lmo.r_ldsomap_offset = 40; /* Everything we need is in the first 40 bytes. */ Index: solib-svr4.h =================================================================== RCS file: /cvs/src/src/gdb/solib-svr4.h,v retrieving revision 1.18 diff -u -p -r1.18 solib-svr4.h --- solib-svr4.h 1 Jan 2008 22:53:13 -0000 1.18 +++ solib-svr4.h 8 Feb 2008 18:37:08 -0000 @@ -37,6 +37,9 @@ struct link_map_offsets /* Offset of r_debug.r_map. */ int r_map_offset; + /* Offset of r_debug.r_brk. */ + int r_brk_offset; + /* Offset of r_debug.r_ldsomap. */ int r_ldsomap_offset;