X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fsolib-svr4.c;h=b437cee3cbf099f3f4bf83a50536b55f23cd4427;hb=0fb0cc7590113e9b459dfcc48dc71c9d419d9580;hp=d6b075badcf3e30059ab79f872c526e78c1dbab2;hpb=65728c26984bf8b45c0f473d96443186b5c4ebab;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index d6b075badc..b437cee3cb 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -1,13 +1,14 @@ /* Handle SVR4 shared libraries for GDB, the GNU Debugger. Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, - 2001, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 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 2 of the License, or + 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, @@ -16,9 +17,7 @@ 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include "defs.h" @@ -33,6 +32,7 @@ #include "gdbcore.h" #include "target.h" #include "inferior.h" +#include "gdbthread.h" #include "gdb_assert.h" @@ -43,14 +43,12 @@ #include "bfd-target.h" #include "elf-bfd.h" #include "exec.h" +#include "auxv.h" +#include "exceptions.h" static struct link_map_offsets *svr4_fetch_link_map_offsets (void); static int svr4_have_link_map_offsets (void); -/* This hook is set to a function that provides native link map - offsets if the code in solib-legacy.c is linked in. */ -struct link_map_offsets *(*legacy_svr4_fetch_link_map_offsets_hook) (void); - /* Link map info to include in an allocated so_list entry */ struct lm_info @@ -66,6 +64,9 @@ struct lm_info address changes, we may need a different offset, we want to warn about the difference and compute it only once. */ CORE_ADDR l_addr; + + /* The target location of lm. */ + CORE_ADDR lm_addr; }; /* On SVR4 systems, a list of symbols in the dynamic linker where @@ -87,20 +88,13 @@ static char *solib_break_names[] = NULL }; -#define BKPT_AT_SYMBOL 1 - -#if defined (BKPT_AT_SYMBOL) static char *bkpt_names[] = { -#ifdef SOLIB_BKPT_NAME - SOLIB_BKPT_NAME, /* Prefer configured name if it exists. */ -#endif "_start", "__start", "main", NULL }; -#endif static char *main_name_list[] = { @@ -108,15 +102,50 @@ static char *main_name_list[] = NULL }; +/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent + the same shared library. */ + +static int +svr4_same_1 (const char *gdb_so_name, const char *inferior_so_name) +{ + if (strcmp (gdb_so_name, inferior_so_name) == 0) + return 1; + + /* On Solaris, when starting inferior we think that dynamic linker is + /usr/lib/ld.so.1, but later on, the table of loaded shared libraries + contains /lib/ld.so.1. Sometimes one file is a link to another, but + sometimes they have identical content, but are not linked to each + other. We don't restrict this check for Solaris, but the chances + of running into this situation elsewhere are very low. */ + if (strcmp (gdb_so_name, "/usr/lib/ld.so.1") == 0 + && strcmp (inferior_so_name, "/lib/ld.so.1") == 0) + return 1; + + /* Similarly, we observed the same issue with sparc64, but with + different locations. */ + if (strcmp (gdb_so_name, "/usr/lib/sparcv9/ld.so.1") == 0 + && strcmp (inferior_so_name, "/lib/sparcv9/ld.so.1") == 0) + return 1; + + return 0; +} + +static int +svr4_same (struct so_list *gdb, struct so_list *inferior) +{ + return (svr4_same_1 (gdb->so_original_name, inferior->so_original_name)); +} + /* link map access functions */ static CORE_ADDR LM_ADDR_FROM_LINK_MAP (struct so_list *so) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; return extract_typed_address (so->lm_info->lm + lmo->l_addr_offset, - builtin_type_void_data_ptr); + ptr_type); } static int @@ -131,9 +160,10 @@ static CORE_ADDR LM_DYNAMIC_FROM_LINK_MAP (struct so_list *so) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; return extract_typed_address (so->lm_info->lm + lmo->l_ld_offset, - builtin_type_void_data_ptr); + ptr_type); } static CORE_ADDR @@ -210,24 +240,27 @@ static CORE_ADDR LM_NEXT (struct so_list *so) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; return extract_typed_address (so->lm_info->lm + lmo->l_next_offset, - builtin_type_void_data_ptr); + ptr_type); } static CORE_ADDR LM_NAME (struct so_list *so) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; return extract_typed_address (so->lm_info->lm + lmo->l_name_offset, - builtin_type_void_data_ptr); + ptr_type); } static int IGNORE_FIRST_LINK_MAP_ENTRY (struct so_list *so) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; /* Assume that everything is a library if the dynamic loader was loaded late by a static executable. */ @@ -235,7 +268,7 @@ IGNORE_FIRST_LINK_MAP_ENTRY (struct so_list *so) return 0; return extract_typed_address (so->lm_info->lm + lmo->l_prev_offset, - builtin_type_void_data_ptr) == 0; + ptr_type) == 0; } static CORE_ADDR debug_base; /* Base of dynamic linker structures */ @@ -249,6 +282,9 @@ static CORE_ADDR debug_loader_offset; /* Name of the dynamic linker, valid if debug_loader_offset_p. */ static char *debug_loader_name; +/* Load map address for the main executable. */ +static CORE_ADDR main_lm_addr; + /* Local function prototypes */ static int match_main (char *); @@ -345,6 +381,137 @@ bfd_lookup_symbol (bfd *abfd, char *symname) return symaddr; } + +/* Read program header TYPE from inferior memory. The header is found + by scanning the OS auxillary vector. + + Return a pointer to allocated memory holding the program header contents, + or NULL on failure. If sucessful, and unless P_SECT_SIZE is NULL, the + size of those contents is returned to P_SECT_SIZE. Likewise, the target + architecture size (32-bit or 64-bit) is returned to P_ARCH_SIZE. */ + +static gdb_byte * +read_program_header (int type, int *p_sect_size, int *p_arch_size) +{ + CORE_ADDR at_phdr, at_phent, at_phnum; + int arch_size, sect_size; + CORE_ADDR sect_addr; + gdb_byte *buf; + + /* Get required auxv elements from target. */ + if (target_auxv_search (¤t_target, AT_PHDR, &at_phdr) <= 0) + return 0; + if (target_auxv_search (¤t_target, AT_PHENT, &at_phent) <= 0) + return 0; + if (target_auxv_search (¤t_target, AT_PHNUM, &at_phnum) <= 0) + return 0; + if (!at_phdr || !at_phnum) + return 0; + + /* Determine ELF architecture type. */ + if (at_phent == sizeof (Elf32_External_Phdr)) + arch_size = 32; + else if (at_phent == sizeof (Elf64_External_Phdr)) + arch_size = 64; + else + return 0; + + /* Find .dynamic section via the PT_DYNAMIC PHDR. */ + if (arch_size == 32) + { + Elf32_External_Phdr phdr; + int i; + + /* Search for requested PHDR. */ + for (i = 0; i < at_phnum; i++) + { + if (target_read_memory (at_phdr + i * sizeof (phdr), + (gdb_byte *)&phdr, sizeof (phdr))) + return 0; + + if (extract_unsigned_integer ((gdb_byte *)phdr.p_type, 4) == type) + break; + } + + if (i == at_phnum) + return 0; + + /* Retrieve address and size. */ + sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr, 4); + sect_size = extract_unsigned_integer ((gdb_byte *)phdr.p_memsz, 4); + } + else + { + Elf64_External_Phdr phdr; + int i; + + /* Search for requested PHDR. */ + for (i = 0; i < at_phnum; i++) + { + if (target_read_memory (at_phdr + i * sizeof (phdr), + (gdb_byte *)&phdr, sizeof (phdr))) + return 0; + + if (extract_unsigned_integer ((gdb_byte *)phdr.p_type, 4) == type) + break; + } + + if (i == at_phnum) + return 0; + + /* Retrieve address and size. */ + sect_addr = extract_unsigned_integer ((gdb_byte *)phdr.p_vaddr, 8); + sect_size = extract_unsigned_integer ((gdb_byte *)phdr.p_memsz, 8); + } + + /* Read in requested program header. */ + buf = xmalloc (sect_size); + if (target_read_memory (sect_addr, buf, sect_size)) + { + xfree (buf); + return NULL; + } + + if (p_arch_size) + *p_arch_size = arch_size; + if (p_sect_size) + *p_sect_size = sect_size; + + return buf; +} + + +/* Return program interpreter string. */ +static gdb_byte * +find_program_interpreter (void) +{ + gdb_byte *buf = NULL; + + /* If we have an exec_bfd, use its section table. */ + if (exec_bfd + && bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour) + { + struct bfd_section *interp_sect; + + interp_sect = bfd_get_section_by_name (exec_bfd, ".interp"); + if (interp_sect != NULL) + { + CORE_ADDR sect_addr = bfd_section_vma (exec_bfd, interp_sect); + int sect_size = bfd_section_size (exec_bfd, interp_sect); + + buf = xmalloc (sect_size); + bfd_get_section_contents (exec_bfd, interp_sect, buf, 0, sect_size); + } + } + + /* If we didn't find it, use the target auxillary vector. */ + if (!buf) + buf = read_program_header (PT_INTERP, NULL, NULL); + + return buf; +} + + /* Scan for DYNTAG in .dynamic section of ABFD. If DYNTAG is found 1 is returned and the corresponding PTR is set. */ @@ -406,13 +573,14 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr) entry. */ if (ptr) { + struct type *ptr_type; gdb_byte ptr_buf[8]; CORE_ADDR ptr_addr; + ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; ptr_addr = dyn_addr + (buf - bufstart) + arch_size / 8; if (target_read_memory (ptr_addr, ptr_buf, arch_size / 8) == 0) - dyn_ptr = extract_typed_address (ptr_buf, - builtin_type_void_data_ptr); + dyn_ptr = extract_typed_address (ptr_buf, ptr_type); *ptr = dyn_ptr; } return 1; @@ -422,6 +590,59 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr) return 0; } +/* Scan for DYNTAG in .dynamic section of the target's main executable, + found by consulting the OS auxillary vector. If DYNTAG is found 1 is + returned and the corresponding PTR is set. */ + +static int +scan_dyntag_auxv (int dyntag, CORE_ADDR *ptr) +{ + int sect_size, arch_size, step; + long dyn_tag; + CORE_ADDR dyn_ptr; + gdb_byte *bufend, *bufstart, *buf; + + /* Read in .dynamic section. */ + buf = bufstart = read_program_header (PT_DYNAMIC, §_size, &arch_size); + if (!buf) + return 0; + + /* Iterate over BUF and scan for DYNTAG. If found, set PTR and return. */ + step = (arch_size == 32) ? sizeof (Elf32_External_Dyn) + : sizeof (Elf64_External_Dyn); + for (bufend = buf + sect_size; + buf < bufend; + buf += step) + { + if (arch_size == 32) + { + Elf32_External_Dyn *dynp = (Elf32_External_Dyn *) buf; + dyn_tag = extract_unsigned_integer ((gdb_byte *) dynp->d_tag, 4); + dyn_ptr = extract_unsigned_integer ((gdb_byte *) dynp->d_un.d_ptr, 4); + } + else + { + Elf64_External_Dyn *dynp = (Elf64_External_Dyn *) buf; + dyn_tag = extract_unsigned_integer ((gdb_byte *) dynp->d_tag, 8); + dyn_ptr = extract_unsigned_integer ((gdb_byte *) dynp->d_un.d_ptr, 8); + } + if (dyn_tag == DT_NULL) + break; + + if (dyn_tag == dyntag) + { + if (ptr) + *ptr = dyn_ptr; + + xfree (bufstart); + return 1; + } + } + + xfree (bufstart); + return 0; +} + /* @@ -456,20 +677,23 @@ elf_locate_base (void) /* Look for DT_MIPS_RLD_MAP first. MIPS executables use this instead of DT_DEBUG, although they sometimes contain an unused DT_DEBUG. */ - if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr)) + if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr) + || scan_dyntag_auxv (DT_MIPS_RLD_MAP, &dyn_ptr)) { + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; gdb_byte *pbuf; - int pbuf_size = TYPE_LENGTH (builtin_type_void_data_ptr); + int pbuf_size = TYPE_LENGTH (ptr_type); pbuf = alloca (pbuf_size); /* DT_MIPS_RLD_MAP contains a pointer to the address of the dynamic link structure. */ if (target_read_memory (dyn_ptr, pbuf, pbuf_size)) return 0; - return extract_typed_address (pbuf, builtin_type_void_data_ptr); + return extract_typed_address (pbuf, ptr_type); } /* Find DT_DEBUG. */ - if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr)) + if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr) + || scan_dyntag_auxv (DT_DEBUG, &dyn_ptr)) return dyn_ptr; /* This may be a static executable. Look for the symbol @@ -548,9 +772,20 @@ static CORE_ADDR solib_svr4_r_map (void) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; - return read_memory_typed_address (debug_base + lmo->r_map_offset, - builtin_type_void_data_ptr); + return read_memory_typed_address (debug_base + lmo->r_map_offset, ptr_type); +} + +/* 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 (); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + + return read_memory_typed_address (debug_base + lmo->r_brk_offset, ptr_type); } /* Find the link map for the dynamic linker (if it is not in the @@ -560,6 +795,7 @@ static CORE_ADDR solib_svr4_r_ldsomap (void) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; ULONGEST version; /* Check version, and return zero if `struct r_debug' doesn't have @@ -570,7 +806,7 @@ solib_svr4_r_ldsomap (void) return 0; return read_memory_typed_address (debug_base + lmo->r_ldsomap_offset, - builtin_type_void_data_ptr); + ptr_type); } /* @@ -603,7 +839,8 @@ open_symbol_file_object (void *from_ttyp) int errcode; int from_tty = *(int *)from_ttyp; struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); - int l_name_size = TYPE_LENGTH (builtin_type_void_data_ptr); + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + int l_name_size = TYPE_LENGTH (ptr_type); gdb_byte *l_name_buf = xmalloc (l_name_size); struct cleanup *cleanups = make_cleanup (xfree, l_name_buf); @@ -611,7 +848,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. */ @@ -623,7 +862,7 @@ open_symbol_file_object (void *from_ttyp) read_memory (lm + lmo->l_name_offset, l_name_buf, l_name_size); /* Convert the address to host format. */ - l_name = extract_typed_address (l_name_buf, builtin_type_void_data_ptr); + l_name = extract_typed_address (l_name_buf, ptr_type); /* Free l_name_buf. */ do_cleanups (cleanups); @@ -666,6 +905,7 @@ svr4_default_sos (void) /* Nothing will ever check the cached copy of the link map if we set l_addr. */ new->lm_info->l_addr = debug_loader_offset; + new->lm_info->lm_addr = 0; new->lm_info->lm = NULL; strncpy (new->so_name, debug_loader_name, SO_NAME_MAX_PATH_SIZE - 1); @@ -706,17 +946,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. */ @@ -732,6 +969,7 @@ svr4_current_sos (void) make_cleanup (xfree, new->lm_info); new->lm_info->l_addr = (CORE_ADDR)-1; + new->lm_info->lm_addr = lm; new->lm_info->lm = xzalloc (lmo->link_map_size); make_cleanup (xfree, new->lm_info->lm); @@ -745,7 +983,10 @@ svr4_current_sos (void) does have a name, so we can no longer use a missing name to decide when to ignore it. */ if (IGNORE_FIRST_LINK_MAP_ENTRY (new) && ldsomap == 0) - free_so (new); + { + main_lm_addr = new->lm_info->lm_addr; + free_so (new); + } else { int errcode; @@ -794,76 +1035,28 @@ svr4_current_sos (void) return head; } -/* Get the address of the link_map for a given OBJFILE. Loop through - the link maps, and return the address of the one corresponding to - the given objfile. Note that this function takes into account that - objfile can be the main executable, not just a shared library. The - main executable has always an empty name field in the linkmap. */ +/* Get the address of the link_map for a given OBJFILE. */ CORE_ADDR svr4_fetch_objfile_link_map (struct objfile *objfile) { - CORE_ADDR lm; + struct so_list *so; - if ((debug_base = locate_base ()) == 0) - return 0; /* failed somehow... */ + /* Cause svr4_current_sos() to be run if it hasn't been already. */ + if (main_lm_addr == 0) + solib_add (NULL, 0, ¤t_target, auto_solib_add); - /* Position ourselves on the first link map. */ - lm = solib_svr4_r_map (); - while (lm) - { - /* Get info on the layout of the r_debug and link_map structures. */ - struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); - int errcode; - char *buffer; - struct lm_info objfile_lm_info; - struct cleanup *old_chain; - CORE_ADDR name_address; - int l_name_size = TYPE_LENGTH (builtin_type_void_data_ptr); - gdb_byte *l_name_buf = xmalloc (l_name_size); - old_chain = make_cleanup (xfree, l_name_buf); - - /* Set up the buffer to contain the portion of the link_map - structure that gdb cares about. Note that this is not the - whole link_map structure. */ - objfile_lm_info.lm = xzalloc (lmo->link_map_size); - make_cleanup (xfree, objfile_lm_info.lm); - - /* Read the link map into our internal structure. */ - read_memory (lm, objfile_lm_info.lm, lmo->link_map_size); - - /* Read address of name from target memory to GDB. */ - read_memory (lm + lmo->l_name_offset, l_name_buf, l_name_size); - - /* Extract this object's name. */ - name_address = extract_typed_address (l_name_buf, - builtin_type_void_data_ptr); - target_read_string (name_address, &buffer, - SO_NAME_MAX_PATH_SIZE - 1, &errcode); - make_cleanup (xfree, buffer); - if (errcode != 0) - warning (_("Can't read pathname for load map: %s."), - safe_strerror (errcode)); - else - { - /* Is this the linkmap for the file we want? */ - /* If the file is not a shared library and has no name, - we are sure it is the main executable, so we return that. */ - - if (buffer - && ((strcmp (buffer, objfile->name) == 0) - || (!(objfile->flags & OBJF_SHARED) - && (strcmp (buffer, "") == 0)))) - { - do_cleanups (old_chain); - return lm; - } - } - /* Not the file we wanted, continue checking. */ - lm = extract_typed_address (objfile_lm_info.lm + lmo->l_next_offset, - builtin_type_void_data_ptr); - do_cleanups (old_chain); - } + /* svr4_current_sos() will set main_lm_addr for the main executable. */ + if (objfile == symfile_objfile) + return main_lm_addr; + + /* The other link map addresses may be found by examining the list + of shared libraries. */ + for (so = master_so_list (); so; so = so->next) + if (so->objfile == objfile) + return so->lm_info->lm_addr; + + /* Not found! */ return 0; } @@ -914,7 +1107,7 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ) gdbarch_convert_from_func_ptr_addr(). The method gdbarch_convert_from_func_ptr_addr() is the merely the identify function for targets which don't use function descriptors. */ - return gdbarch_convert_from_func_ptr_addr (current_gdbarch, + return gdbarch_convert_from_func_ptr_addr (target_gdbarch, bfd_get_start_address (abfd), targ); } @@ -965,11 +1158,11 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ) static int enable_break (void) { -#ifdef BKPT_AT_SYMBOL - struct minimal_symbol *msymbol; char **bkpt_namep; asection *interp_sect; + gdb_byte *interp_name; + CORE_ADDR sym_addr; /* First, remove all the solib event breakpoints. Their addresses may have changed since the last time we ran the program. */ @@ -978,28 +1171,73 @@ enable_break (void) interp_text_sect_low = interp_text_sect_high = 0; interp_plt_sect_low = interp_plt_sect_high = 0; - /* Find the .interp section; if not found, warn the user and drop + /* 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; + + sym_addr = gdbarch_addr_bits_remove + (target_gdbarch, gdbarch_convert_from_func_ptr_addr (target_gdbarch, + sym_addr, + ¤t_target)); + + 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 program interpreter; 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"); - if (interp_sect) + interp_name = find_program_interpreter (); + if (interp_name) { - unsigned int interp_sect_size; - char *buf; CORE_ADDR load_addr = 0; int load_addr_found = 0; + int loader_found_in_list = 0; struct so_list *so; bfd *tmp_bfd = NULL; struct target_ops *tmp_bfd_target; - int tmp_fd = -1; - char *tmp_pathname = NULL; - CORE_ADDR sym_addr = 0; + volatile struct gdb_exception ex; - /* Read the contents of the .interp section into a local buffer; - the contents specify the dynamic linker this program uses. */ - interp_sect_size = bfd_section_size (exec_bfd, interp_sect); - buf = alloca (interp_sect_size); - bfd_get_section_contents (exec_bfd, interp_sect, - buf, 0, interp_sect_size); + sym_addr = 0; /* Now we need to figure out where the dynamic linker was loaded so that we can load its symbols and place a breakpoint @@ -1010,26 +1248,13 @@ enable_break (void) be trivial on GNU/Linux). Therefore, we have to try an alternate mechanism to find the dynamic linker's base address. */ - /* TODO drow/2006-09-12: This is somewhat fragile, because it - relies on read_pc. On both Solaris and GNU/Linux we can use - the AT_BASE auxilliary entry, which GDB now knows how to - access, to find the base address. */ - - tmp_fd = solib_open (buf, &tmp_pathname); - if (tmp_fd >= 0) - tmp_bfd = bfd_fopen (tmp_pathname, gnutarget, FOPEN_RB, tmp_fd); - + TRY_CATCH (ex, RETURN_MASK_ALL) + { + tmp_bfd = solib_bfd_open (interp_name); + } if (tmp_bfd == NULL) goto bkpt_at_symbol; - /* Make sure the dynamic linker's really a useful object. */ - if (!bfd_check_format (tmp_bfd, bfd_object)) - { - warning (_("Unable to grok dynamic linker %s as an object file"), buf); - bfd_close (tmp_bfd); - goto bkpt_at_symbol; - } - /* Now convert the TMP_BFD into a target. That way target, as well as BFD operations can be used. Note that closing the target will also close the underlying bfd. */ @@ -1037,27 +1262,39 @@ 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) { - if (strcmp (buf, so->so_original_name) == 0) + if (svr4_same_1 (interp_name, so->so_original_name)) { load_addr_found = 1; + loader_found_in_list = 1; load_addr = LM_ADDR_CHECK (so, tmp_bfd); break; } so = so->next; } + /* If we were not able to find the base address of the loader + from our so_list, then try using the AT_BASE auxilliary entry. */ + if (!load_addr_found) + if (target_auxv_search (¤t_target, AT_BASE, &load_addr) > 0) + load_addr_found = 1; + /* Otherwise we find the dynamic linker's base address by examining the current pc (which should point at the entry point for the - dynamic linker) and subtracting the offset of the entry point. */ + dynamic linker) and subtracting the offset of the entry point. + + This is more fragile than the previous approaches, but is a good + fallback method because it has actually been working well in + most cases. */ if (!load_addr_found) + load_addr = (read_pc () + - exec_entry_point (tmp_bfd, tmp_bfd_target)); + + if (!loader_found_in_list) { - load_addr = (read_pc () - - exec_entry_point (tmp_bfd, tmp_bfd_target)); - debug_loader_name = xstrdup (buf); + debug_loader_name = xstrdup (interp_name); debug_loader_offset_p = 1; debug_loader_offset = load_addr; solib_add (NULL, 0, ¤t_target, auto_solib_add); @@ -1094,7 +1331,7 @@ enable_break (void) /* Convert 'sym_addr' from a function pointer to an address. Because we pass tmp_bfd_target instead of the current target, this will always produce an unrelocated value. */ - sym_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch, + sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch, sym_addr, tmp_bfd_target); @@ -1105,13 +1342,14 @@ enable_break (void) if (sym_addr != 0) { create_solib_event_breakpoint (load_addr + sym_addr); + xfree (interp_name); return 1; } /* For whatever reason we couldn't set a breakpoint in the dynamic linker. Warn and drop into the old code. */ bkpt_at_symbol: - xfree (tmp_pathname); + xfree (interp_name); warning (_("Unable to find dynamic linker breakpoint function.\n" "GDB will be unable to debug shared library initializers\n" "and track explicitly loaded dynamic code.")); @@ -1139,8 +1377,6 @@ enable_break (void) return 1; } } -#endif /* BKPT_AT_SYMBOL */ - return 0; } @@ -1335,6 +1571,9 @@ svr4_relocate_main_executable (void) static void svr4_solib_create_inferior_hook (void) { + struct inferior *inf; + struct thread_info *tp; + /* Relocate the main executable if necessary. */ svr4_relocate_main_executable (); @@ -1354,16 +1593,19 @@ svr4_solib_create_inferior_hook (void) can go groveling around in the dynamic linker structures to find out what we need to know about them. */ + inf = current_inferior (); + tp = inferior_thread (); + clear_proceed_status (); - stop_soon = STOP_QUIETLY; - stop_signal = TARGET_SIGNAL_0; + inf->stop_soon = STOP_QUIETLY; + tp->stop_signal = TARGET_SIGNAL_0; do { - target_resume (pid_to_ptid (-1), 0, stop_signal); - wait_for_inferior (); + target_resume (pid_to_ptid (-1), 0, tp->stop_signal); + wait_for_inferior (0); } - while (stop_signal != TARGET_SIGNAL_TRAP); - stop_soon = NO_STOP_QUIETLY; + while (tp->stop_signal != TARGET_SIGNAL_TRAP); + inf->stop_soon = NO_STOP_QUIETLY; #endif /* defined(_SCO_DS) */ } @@ -1375,6 +1617,7 @@ svr4_clear_solib (void) debug_loader_offset = 0; xfree (debug_loader_name); debug_loader_name = NULL; + main_lm_addr = 0; } static void @@ -1401,12 +1644,12 @@ svr4_free_so (struct so_list *so) static CORE_ADDR svr4_truncate_ptr (CORE_ADDR addr) { - if (gdbarch_ptr_bit (current_gdbarch) == sizeof (CORE_ADDR) * 8) + if (gdbarch_ptr_bit (target_gdbarch) == sizeof (CORE_ADDR) * 8) /* We don't need to truncate anything, and the bit twiddling below will fail due to overflow problems. */ return addr; else - return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (current_gdbarch)) - 1); + return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (target_gdbarch)) - 1); } @@ -1440,12 +1683,12 @@ solib_svr4_init (struct obstack *obstack) struct solib_svr4_ops *ops; ops = OBSTACK_ZALLOC (obstack, struct solib_svr4_ops); - ops->fetch_link_map_offsets = legacy_svr4_fetch_link_map_offsets_hook; + ops->fetch_link_map_offsets = NULL; return ops; } /* Set the architecture-specific `struct link_map_offsets' fetcher for - GDBARCH to FLMO. */ + GDBARCH to FLMO. Also, install SVR4 solib_ops into GDBARCH. */ void set_solib_svr4_fetch_link_map_offsets (struct gdbarch *gdbarch, @@ -1454,6 +1697,8 @@ set_solib_svr4_fetch_link_map_offsets (struct gdbarch *gdbarch, struct solib_svr4_ops *ops = gdbarch_data (gdbarch, solib_svr4_data); ops->fetch_link_map_offsets = flmo; + + set_solib_ops (gdbarch, &svr4_so_ops); } /* Fetch a link_map_offsets structure using the architecture-specific @@ -1462,7 +1707,7 @@ set_solib_svr4_fetch_link_map_offsets (struct gdbarch *gdbarch, static struct link_map_offsets * svr4_fetch_link_map_offsets (void) { - struct solib_svr4_ops *ops = gdbarch_data (current_gdbarch, solib_svr4_data); + struct solib_svr4_ops *ops = gdbarch_data (target_gdbarch, solib_svr4_data); gdb_assert (ops->fetch_link_map_offsets); return ops->fetch_link_map_offsets (); @@ -1473,7 +1718,7 @@ svr4_fetch_link_map_offsets (void) static int svr4_have_link_map_offsets (void) { - struct solib_svr4_ops *ops = gdbarch_data (current_gdbarch, solib_svr4_data); + struct solib_svr4_ops *ops = gdbarch_data (target_gdbarch, solib_svr4_data); return (ops->fetch_link_map_offsets != NULL); } @@ -1498,6 +1743,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. */ @@ -1528,6 +1774,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. */ @@ -1553,14 +1800,14 @@ static struct symbol * elf_lookup_lib_symbol (const struct objfile *objfile, const char *name, const char *linkage_name, - const domain_enum domain, struct symtab **symtab) + const domain_enum domain) { if (objfile->obfd == NULL || scan_dyntag (DT_SYMBOLIC, objfile->obfd, NULL) != 1) return NULL; return lookup_global_symbol_from_objfile - (objfile, name, linkage_name, domain, symtab); + (objfile, name, linkage_name, domain); } extern initialize_file_ftype _initialize_svr4_solib; /* -Wmissing-prototypes */ @@ -1579,7 +1826,5 @@ _initialize_svr4_solib (void) svr4_so_ops.open_symbol_file_object = open_symbol_file_object; svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code; svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol; - - /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ - current_target_so_ops = &svr4_so_ops; + svr4_so_ops.same = svr4_same; }