X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fsolib-svr4.c;h=07e4f76a54a99aed4835571831ad7801d85ce226;hb=a6d9a66e2318b2002461996aeb5d4f18a0a9d3d6;hp=caadb4a26d616aaee3f29eed0a0f4662bd32d11d;hpb=e4cd0d6a2669159e399359ff2cb59dd93668f056;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index caadb4a26d..07e4f76a54 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -1,14 +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 + Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, + 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, @@ -17,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" @@ -34,6 +32,9 @@ #include "gdbcore.h" #include "target.h" #include "inferior.h" +#include "regcache.h" +#include "gdbthread.h" +#include "observer.h" #include "gdb_assert.h" @@ -42,15 +43,14 @@ #include "solib-svr4.h" #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 @@ -59,6 +59,16 @@ struct lm_info rather than void *, so that we may use byte offsets to find the various fields without the need for a cast. */ gdb_byte *lm; + + /* Amount by which addresses in the binary should be relocated to + match the inferior. This could most often be taken directly + from lm, but when prelinking is involved and the prelink base + 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 @@ -77,33 +87,16 @@ static char *solib_break_names[] = "rtld_db_dlactivity", "_rtld_debug_state", - /* On the 64-bit PowerPC, the linker symbol with the same name as - the C function points to a function descriptor, not to the entry - point. The linker symbol whose name is the C function name - prefixed with a '.' points to the function's entry point. So - when we look through this table, we ignore symbols that point - into the data section (thus skipping the descriptor's symbol), - and eventually try this one, giving us the real entry point - address. */ - "._dl_debug_state", - 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[] = { @@ -111,68 +104,264 @@ static char *main_name_list[] = NULL }; -/* Macro to extract an address from a solib structure. When GDB is - configured for some 32-bit targets (e.g. Solaris 2.7 sparc), BFD is - configured to handle 64-bit targets, so CORE_ADDR is 64 bits. We - have to extract only the significant bits of addresses to get the - right address when accessing the core file BFD. +/* Return non-zero if GDB_SO_NAME and INFERIOR_SO_NAME represent + the same shared library. */ - Assume that the address is unsigned. */ +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; -#define SOLIB_EXTRACT_ADDRESS(MEMBER) \ - extract_unsigned_integer (&(MEMBER), sizeof (MEMBER)) + return 0; +} -/* local data declarations */ +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 (struct so_list *so) +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, + ptr_type); +} + +static int +HAS_LM_DYNAMIC_FROM_LINK_MAP (void) +{ + struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + + return lmo->l_ld_offset >= 0; +} + +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, + ptr_type); +} + +static CORE_ADDR +LM_ADDR_CHECK (struct so_list *so, bfd *abfd) +{ + if (so->lm_info->l_addr == (CORE_ADDR)-1) + { + struct bfd_section *dyninfo_sect; + CORE_ADDR l_addr, l_dynaddr, dynaddr, align = 0x1000; + + l_addr = LM_ADDR_FROM_LINK_MAP (so); + + if (! abfd || ! HAS_LM_DYNAMIC_FROM_LINK_MAP ()) + goto set_addr; + + l_dynaddr = LM_DYNAMIC_FROM_LINK_MAP (so); + + dyninfo_sect = bfd_get_section_by_name (abfd, ".dynamic"); + if (dyninfo_sect == NULL) + goto set_addr; + + dynaddr = bfd_section_vma (abfd, dyninfo_sect); + + if (dynaddr + l_addr != l_dynaddr) + { + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + Elf_Internal_Ehdr *ehdr = elf_tdata (abfd)->elf_header; + Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr; + int i; - return (CORE_ADDR) extract_signed_integer (so->lm_info->lm + lmo->l_addr_offset, - lmo->l_addr_size); + align = 1; + + for (i = 0; i < ehdr->e_phnum; i++) + if (phdr[i].p_type == PT_LOAD && phdr[i].p_align > align) + align = phdr[i].p_align; + } + + /* Turn it into a mask. */ + align--; + + /* If the changes match the alignment requirements, we + assume we're using a core file that was generated by the + same binary, just prelinked with a different base offset. + If it doesn't match, we may have a different binary, the + same binary with the dynamic table loaded at an unrelated + location, or anything, really. To avoid regressions, + don't adjust the base offset in the latter case, although + odds are that, if things really changed, debugging won't + quite work. */ + if ((l_addr & align) == ((l_dynaddr - dynaddr) & align)) + { + l_addr = l_dynaddr - dynaddr; + + warning (_(".dynamic section for \"%s\" " + "is not at the expected address"), so->so_name); + warning (_("difference appears to be caused by prelink, " + "adjusting expectations")); + } + else + warning (_(".dynamic section for \"%s\" " + "is not at the expected address " + "(wrong library or version mismatch?)"), so->so_name); + } + + set_addr: + so->lm_info->l_addr = l_addr; + } + + return so->lm_info->l_addr; } 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; - /* Assume that the address is unsigned. */ - return extract_unsigned_integer (so->lm_info->lm + lmo->l_next_offset, - lmo->l_next_size); + return extract_typed_address (so->lm_info->lm + lmo->l_next_offset, + 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; - /* Assume that the address is unsigned. */ - return extract_unsigned_integer (so->lm_info->lm + lmo->l_name_offset, - lmo->l_name_size); + return extract_typed_address (so->lm_info->lm + lmo->l_name_offset, + 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. */ + if (exec_bfd && bfd_get_section_by_name (exec_bfd, ".dynamic") == NULL) + return 0; + + return extract_typed_address (so->lm_info->lm + lmo->l_prev_offset, + ptr_type) == 0; +} + +/* Per-inferior SVR4 specific data. */ + +struct svr4_info +{ + int pid; + + CORE_ADDR debug_base; /* Base of dynamic linker structures */ + + /* Validity flag for debug_loader_offset. */ + int debug_loader_offset_p; + + /* Load address for the dynamic linker, inferred. */ + CORE_ADDR debug_loader_offset; + + /* Name of the dynamic linker, valid if debug_loader_offset_p. */ + char *debug_loader_name; + + /* Load map address for the main executable. */ + CORE_ADDR main_lm_addr; +}; + +/* List of known processes using solib-svr4 shared libraries, storing + the required bookkeeping for each. */ + +typedef struct svr4_info *svr4_info_p; +DEF_VEC_P(svr4_info_p); +VEC(svr4_info_p) *svr4_info = NULL; + +/* Get svr4 data for inferior PID (target id). If none is found yet, + add it now. This function always returns a valid object. */ + +struct svr4_info * +get_svr4_info (int pid) +{ + int ix; + struct svr4_info *it; + + gdb_assert (pid != 0); + + for (ix = 0; VEC_iterate (svr4_info_p, svr4_info, ix, it); ++ix) + { + if (it->pid == pid) + return it; + } + + it = XZALLOC (struct svr4_info); + it->pid = pid; + + VEC_safe_push (svr4_info_p, svr4_info, it); + + return it; +} + +/* Get rid of any svr4 related bookkeeping for inferior PID (target + id). */ - /* Assume that the address is unsigned. */ - return extract_unsigned_integer (so->lm_info->lm + lmo->l_prev_offset, - lmo->l_prev_size) == 0; +static void +remove_svr4_info (int pid) +{ + int ix; + struct svr4_info *it; + + for (ix = 0; VEC_iterate (svr4_info_p, svr4_info, ix, it); ++ix) + { + if (it->pid == pid) + { + VEC_unordered_remove (svr4_info_p, svr4_info, ix); + return; + } + } } -static CORE_ADDR debug_base; /* Base of dynamic linker structures */ -static CORE_ADDR breakpoint_addr; /* Address where end bkpt is set */ +/* This is an "inferior_exit" observer. Inferior PID (target id) is + being removed from the inferior list, because it exited, was + killed, detached, or we just dropped the connection to the debug + interface --- discard any solib-svr4 related bookkeeping for this + inferior. */ + +static void +solib_svr4_inferior_exit (int pid) +{ + remove_svr4_info (pid); +} /* Local function prototypes */ static int match_main (char *); -static CORE_ADDR bfd_lookup_symbol (bfd *, char *, flagword); +static CORE_ADDR bfd_lookup_symbol (bfd *, char *); /* @@ -182,24 +371,25 @@ static CORE_ADDR bfd_lookup_symbol (bfd *, char *, flagword); SYNOPSIS - CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) + CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname) DESCRIPTION An expensive way to lookup the value of a single symbol for bfd's that are only temporary anyway. This is used by the shared library support to find the address of the debugger - interface structures in the shared library. + notification routine in the shared library. - If SECT_FLAGS is non-zero, only match symbols in sections whose - flags include all those in SECT_FLAGS. + The returned symbol may be in a code or data section; functions + will normally be in a code section, but may be in a data section + if this architecture uses function descriptors. Note that 0 is specifically allowed as an error return (no such symbol). */ static CORE_ADDR -bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) +bfd_lookup_symbol (bfd *abfd, char *symname) { long storage_needed; asymbol *sym; @@ -221,9 +411,9 @@ bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) { sym = *symbol_table++; if (strcmp (sym->name, symname) == 0 - && (sym->section->flags & sect_flags) == sect_flags) + && (sym->section->flags & (SEC_CODE | SEC_DATA)) != 0) { - /* Bfd symbols are section relative. */ + /* BFD symbols are section relative. */ symaddr = sym->value + sym->section->vma; break; } @@ -250,9 +440,9 @@ bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) sym = *symbol_table++; if (strcmp (sym->name, symname) == 0 - && (sym->section->flags & sect_flags) == sect_flags) + && (sym->section->flags & (SEC_CODE | SEC_DATA)) != 0) { - /* Bfd symbols are section relative. */ + /* BFD symbols are section relative. */ symaddr = sym->value + sym->section->vma; break; } @@ -263,6 +453,273 @@ bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) 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. */ + +static int +scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr) +{ + int arch_size, step, sect_size; + long dyn_tag; + CORE_ADDR dyn_ptr, dyn_addr; + gdb_byte *bufend, *bufstart, *buf; + Elf32_External_Dyn *x_dynp_32; + Elf64_External_Dyn *x_dynp_64; + struct bfd_section *sect; + + if (abfd == NULL) + return 0; + + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + return 0; + + arch_size = bfd_get_arch_size (abfd); + if (arch_size == -1) + return 0; + + /* Find the start address of the .dynamic section. */ + sect = bfd_get_section_by_name (abfd, ".dynamic"); + if (sect == NULL) + return 0; + dyn_addr = bfd_section_vma (abfd, sect); + + /* Read in .dynamic from the BFD. We will get the actual value + from memory later. */ + sect_size = bfd_section_size (abfd, sect); + buf = bufstart = alloca (sect_size); + if (!bfd_get_section_contents (abfd, sect, + buf, 0, sect_size)) + 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) + { + x_dynp_32 = (Elf32_External_Dyn *) buf; + dyn_tag = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp_32->d_tag); + dyn_ptr = bfd_h_get_32 (abfd, (bfd_byte *) x_dynp_32->d_un.d_ptr); + } + else + { + x_dynp_64 = (Elf64_External_Dyn *) buf; + dyn_tag = bfd_h_get_64 (abfd, (bfd_byte *) x_dynp_64->d_tag); + dyn_ptr = bfd_h_get_64 (abfd, (bfd_byte *) x_dynp_64->d_un.d_ptr); + } + if (dyn_tag == DT_NULL) + return 0; + if (dyn_tag == dyntag) + { + /* If requested, try to read the runtime value of this .dynamic + 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, ptr_type); + *ptr = dyn_ptr; + } + return 1; + } + } + + 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; +} + + /* LOCAL FUNCTION @@ -290,104 +747,37 @@ bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags) static CORE_ADDR elf_locate_base (void) { - struct bfd_section *dyninfo_sect; - int dyninfo_sect_size; - CORE_ADDR dyninfo_addr; - gdb_byte *buf; - gdb_byte *bufend; - int arch_size; - - /* Find the start address of the .dynamic section. */ - dyninfo_sect = bfd_get_section_by_name (exec_bfd, ".dynamic"); - if (dyninfo_sect == NULL) - return 0; - dyninfo_addr = bfd_section_vma (exec_bfd, dyninfo_sect); - - /* Read in .dynamic section, silently ignore errors. */ - dyninfo_sect_size = bfd_section_size (exec_bfd, dyninfo_sect); - buf = alloca (dyninfo_sect_size); - if (target_read_memory (dyninfo_addr, buf, dyninfo_sect_size)) - return 0; - - /* Find the DT_DEBUG entry in the the .dynamic section. - For mips elf we look for DT_MIPS_RLD_MAP, mips elf apparently has - no DT_DEBUG entries. */ - - arch_size = bfd_get_arch_size (exec_bfd); - if (arch_size == -1) /* failure */ - return 0; - - if (arch_size == 32) - { /* 32-bit elf */ - for (bufend = buf + dyninfo_sect_size; - buf < bufend; - buf += sizeof (Elf32_External_Dyn)) - { - Elf32_External_Dyn *x_dynp = (Elf32_External_Dyn *) buf; - long dyn_tag; - CORE_ADDR dyn_ptr; + struct minimal_symbol *msymbol; + CORE_ADDR dyn_ptr; - dyn_tag = bfd_h_get_32 (exec_bfd, (bfd_byte *) x_dynp->d_tag); - if (dyn_tag == DT_NULL) - break; - else if (dyn_tag == DT_DEBUG) - { - dyn_ptr = bfd_h_get_32 (exec_bfd, - (bfd_byte *) x_dynp->d_un.d_ptr); - return dyn_ptr; - } - else if (dyn_tag == DT_MIPS_RLD_MAP) - { - gdb_byte *pbuf; - int pbuf_size = TARGET_PTR_BIT / HOST_CHAR_BIT; - - pbuf = alloca (pbuf_size); - /* DT_MIPS_RLD_MAP contains a pointer to the address - of the dynamic link structure. */ - dyn_ptr = bfd_h_get_32 (exec_bfd, - (bfd_byte *) x_dynp->d_un.d_ptr); - if (target_read_memory (dyn_ptr, pbuf, pbuf_size)) - return 0; - return extract_unsigned_integer (pbuf, pbuf_size); - } - } - } - else /* 64-bit elf */ + /* 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) + || scan_dyntag_auxv (DT_MIPS_RLD_MAP, &dyn_ptr)) { - for (bufend = buf + dyninfo_sect_size; - buf < bufend; - buf += sizeof (Elf64_External_Dyn)) - { - Elf64_External_Dyn *x_dynp = (Elf64_External_Dyn *) buf; - long dyn_tag; - CORE_ADDR dyn_ptr; - - dyn_tag = bfd_h_get_64 (exec_bfd, (bfd_byte *) x_dynp->d_tag); - if (dyn_tag == DT_NULL) - break; - else if (dyn_tag == DT_DEBUG) - { - dyn_ptr = bfd_h_get_64 (exec_bfd, - (bfd_byte *) x_dynp->d_un.d_ptr); - return dyn_ptr; - } - else if (dyn_tag == DT_MIPS_RLD_MAP) - { - gdb_byte *pbuf; - int pbuf_size = TARGET_PTR_BIT / HOST_CHAR_BIT; - - pbuf = alloca (pbuf_size); - /* DT_MIPS_RLD_MAP contains a pointer to the address - of the dynamic link structure. */ - dyn_ptr = bfd_h_get_64 (exec_bfd, - (bfd_byte *) x_dynp->d_un.d_ptr); - if (target_read_memory (dyn_ptr, pbuf, pbuf_size)) - return 0; - return extract_unsigned_integer (pbuf, pbuf_size); - } - } + struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; + gdb_byte *pbuf; + 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, ptr_type); } + /* Find DT_DEBUG. */ + 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 + conventionally named _r_debug, as a last resort. */ + msymbol = lookup_minimal_symbol ("_r_debug", NULL, symfile_objfile); + if (msymbol != NULL) + return SYMBOL_VALUE_ADDRESS (msymbol); + /* DT_DEBUG entry not found. */ return 0; } @@ -400,7 +790,7 @@ elf_locate_base (void) SYNOPSIS - CORE_ADDR locate_base (void) + CORE_ADDR locate_base (struct svr4_info *) DESCRIPTION @@ -430,7 +820,7 @@ elf_locate_base (void) */ static CORE_ADDR -locate_base (void) +locate_base (struct svr4_info *info) { /* Check to see if we have a currently valid address, and if so, avoid doing all this work again and just return the cached address. If @@ -438,13 +828,9 @@ locate_base (void) section for ELF executables. There's no point in doing any of this though if we don't have some link map offsets to work with. */ - if (debug_base == 0 && svr4_have_link_map_offsets ()) - { - if (exec_bfd != NULL - && bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour) - debug_base = elf_locate_base (); - } - return (debug_base); + if (info->debug_base == 0 && svr4_have_link_map_offsets ()) + info->debug_base = elf_locate_base (); + return info->debug_base; } /* Find the first element in the inferior's dynamic link map, and @@ -455,32 +841,47 @@ locate_base (void) RT_CONSISTENT. */ static CORE_ADDR -solib_svr4_r_map (void) +solib_svr4_r_map (struct svr4_info *info) { 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 (info->debug_base + lmo->r_map_offset, + ptr_type); +} + +/* Find r_brk from the inferior's debug base. */ + +static CORE_ADDR +solib_svr4_r_brk (struct svr4_info *info) +{ + 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 (info->debug_base + lmo->r_brk_offset, + ptr_type); } /* Find the link map for the dynamic linker (if it is not in the normal list of loaded shared objects). */ static CORE_ADDR -solib_svr4_r_ldsomap (void) +solib_svr4_r_ldsomap (struct svr4_info *info) { 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 the r_ldsomap member. */ - version = read_memory_unsigned_integer (debug_base + lmo->r_version_offset, - lmo->r_version_size); + version + = read_memory_unsigned_integer (info->debug_base + lmo->r_version_offset, + lmo->r_version_size); if (version < 2 || lmo->r_ldsomap_offset == -1) return 0; - return read_memory_typed_address (debug_base + lmo->r_ldsomap_offset, - builtin_type_void_data_ptr); + return read_memory_typed_address (info->debug_base + lmo->r_ldsomap_offset, + ptr_type); } /* @@ -513,27 +914,31 @@ 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 (); - gdb_byte *l_name_buf = xmalloc (lmo->l_name_size); + 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); + struct svr4_info *info = get_svr4_info (PIDGET (inferior_ptid)); if (symfile_objfile) - if (!query ("Attempt to reload symbols from process? ")) + 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. */ + info->debug_base = 0; + if (locate_base (info) == 0) return 0; /* failed somehow... */ /* First link map member should be the executable. */ - lm = solib_svr4_r_map (); + lm = solib_svr4_r_map (info); if (lm == 0) return 0; /* failed somehow... */ /* Read address of name from target memory to GDB. */ - read_memory (lm + lmo->l_name_offset, l_name_buf, lmo->l_name_size); + read_memory (lm + lmo->l_name_offset, l_name_buf, l_name_size); - /* Convert the address to host format. Assume that the address is - unsigned. */ - l_name = extract_unsigned_integer (l_name_buf, lmo->l_name_size); + /* Convert the address to host format. */ + l_name = extract_typed_address (l_name_buf, ptr_type); /* Free l_name_buf. */ do_cleanups (cleanups); @@ -543,6 +948,7 @@ open_symbol_file_object (void *from_ttyp) /* Now fetch the filename from target memory. */ target_read_string (l_name, &filename, SO_NAME_MAX_PATH_SIZE - 1, &errcode); + make_cleanup (xfree, filename); if (errcode) { @@ -551,13 +957,48 @@ open_symbol_file_object (void *from_ttyp) return 0; } - make_cleanup (xfree, filename); /* Have a pathname: read the symbol file. */ symbol_file_add_main (filename, from_tty); return 1; } +/* If no shared library information is available from the dynamic + linker, build a fallback list from other sources. */ + +static struct so_list * +svr4_default_sos (void) +{ + struct inferior *inf = current_inferior (); + struct svr4_info *info = get_svr4_info (inf->pid); + + struct so_list *head = NULL; + struct so_list **link_ptr = &head; + + if (info->debug_loader_offset_p) + { + struct so_list *new = XZALLOC (struct so_list); + + new->lm_info = xmalloc (sizeof (struct lm_info)); + + /* Nothing will ever check the cached copy of the link + map if we set l_addr. */ + new->lm_info->l_addr = info->debug_loader_offset; + new->lm_info->lm_addr = 0; + new->lm_info->lm = NULL; + + strncpy (new->so_name, info->debug_loader_name, + SO_NAME_MAX_PATH_SIZE - 1); + new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; + strcpy (new->so_original_name, new->so_name); + + *link_ptr = new; + link_ptr = &new->next; + } + + return head; +} + /* LOCAL FUNCTION current_sos -- build a list of currently loaded shared objects @@ -584,22 +1025,28 @@ svr4_current_sos (void) struct so_list *head = 0; struct so_list **link_ptr = &head; CORE_ADDR ldsomap = 0; + struct inferior *inf; + struct svr4_info *info; - /* Make sure we've looked up the inferior's dynamic linker's base - structure. */ - if (! debug_base) - { - debug_base = locate_base (); + if (ptid_equal (inferior_ptid, null_ptid)) + return NULL; - /* If we can't find the dynamic linker's base structure, this - must not be a dynamically linked executable. Hmm. */ - if (! debug_base) - return 0; - } + inf = current_inferior (); + info = get_svr4_info (inf->pid); + + /* Always locate the debug struct, in case it has moved. */ + info->debug_base = 0; + locate_base (info); + + /* If we can't find the dynamic linker's base structure, this + must not be a dynamically linked executable. Hmm. */ + if (! info->debug_base) + return svr4_default_sos (); /* Walk the inferior's link map list, and build our list of `struct so_list' nodes. */ - lm = solib_svr4_r_map (); + lm = solib_svr4_r_map (info); + while (lm) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); @@ -609,6 +1056,8 @@ svr4_current_sos (void) new->lm_info = xmalloc (sizeof (struct lm_info)); 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); @@ -622,7 +1071,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); + { + info->main_lm_addr = new->lm_info->lm_addr; + free_so (new); + } else { int errcode; @@ -638,9 +1090,9 @@ svr4_current_sos (void) { strncpy (new->so_name, buffer, SO_NAME_MAX_PATH_SIZE - 1); new->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; - xfree (buffer); strcpy (new->so_original_name, new->so_name); } + xfree (buffer); /* If this entry has no name, or its name matches the name for the main executable, don't include it in the list. */ @@ -660,81 +1112,40 @@ svr4_current_sos (void) symbol information for the dynamic linker is quite crucial for skipping dynamic linker resolver code. */ if (lm == 0 && ldsomap == 0) - lm = ldsomap = solib_svr4_r_ldsomap (); + lm = ldsomap = solib_svr4_r_ldsomap (info); discard_cleanups (old_chain); } + if (head == NULL) + return svr4_default_sos (); + 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; + struct svr4_info *info = get_svr4_info (PIDGET (inferior_ptid)); - if ((debug_base = locate_base ()) == 0) - return 0; /* failed somehow... */ + /* Cause svr4_current_sos() to be run if it hasn't been already. */ + if (info->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; - gdb_byte *l_name_buf = xmalloc (lmo->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, lmo->l_name_size); - - /* Extract this object's name. Assume that the address is - unsigned. */ - name_address = extract_unsigned_integer (l_name_buf, lmo->l_name_size); - 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. Assume that the - address is unsigned. */ - lm = extract_unsigned_integer (objfile_lm_info.lm + lmo->l_next_offset, - lmo->l_next_size); - do_cleanups (old_chain); - } + /* svr4_current_sos() will set main_lm_addr for the main executable. */ + if (objfile == symfile_objfile) + return info->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; } @@ -763,7 +1174,7 @@ static CORE_ADDR interp_text_sect_high; static CORE_ADDR interp_plt_sect_low; static CORE_ADDR interp_plt_sect_high; -static int +int svr4_in_dynsym_resolve_code (CORE_ADDR pc) { return ((pc >= interp_text_sect_low && pc < interp_text_sect_high) @@ -785,7 +1196,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); } @@ -834,15 +1245,14 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ) */ static int -enable_break (void) +enable_break (struct svr4_info *info) { - int success = 0; - -#ifdef BKPT_AT_SYMBOL - struct minimal_symbol *msymbol; char **bkpt_namep; asection *interp_sect; + gdb_byte *interp_name; + CORE_ADDR sym_addr; + struct inferior *inf = current_inferior (); /* First, remove all the solib event breakpoints. Their addresses may have changed since the last time we ran the program. */ @@ -851,28 +1261,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 (info->debug_base && solib_svr4_r_map (info) != 0) + sym_addr = solib_svr4_r_brk (info); + + 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 (target_gdbarch, 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 @@ -883,21 +1338,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. */ - 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. */ @@ -905,25 +1352,47 @@ 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, NULL, 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; - load_addr = LM_ADDR (so); + 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)); + { + struct regcache *regcache + = get_thread_arch_regcache (inferior_ptid, target_gdbarch); + load_addr = (regcache_read_pc (regcache) + - exec_entry_point (tmp_bfd, tmp_bfd_target)); + } + + if (!loader_found_in_list) + { + info->debug_loader_name = xstrdup (interp_name); + info->debug_loader_offset_p = 1; + info->debug_loader_offset = load_addr; + solib_add (NULL, 0, ¤t_target, auto_solib_add); + } /* Record the relocated start and end address of the dynamic linker text and plt section for svr4_in_dynsym_resolve_code. */ @@ -947,56 +1416,64 @@ enable_break (void) /* Now try to set a breakpoint in the dynamic linker. */ for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++) { - /* On ABI's that use function descriptors, there are usually - two linker symbols associated with each C function: one - pointing at the actual entry point of the machine code, - and one pointing at the function's descriptor. The - latter symbol has the same name as the C function. - - What we're looking for here is the machine code entry - point, so we are only interested in symbols in code - sections. */ - sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep, SEC_CODE); + sym_addr = bfd_lookup_symbol (tmp_bfd, *bkpt_namep); if (sym_addr != 0) break; } + if (sym_addr != 0) + /* 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 (target_gdbarch, + sym_addr, + tmp_bfd_target); + /* We're done with both the temporary bfd and target. Remember, closing the target closes the underlying bfd. */ target_close (tmp_bfd_target, 0); if (sym_addr != 0) { - create_solib_event_breakpoint (load_addr + sym_addr); + create_solib_event_breakpoint (target_gdbarch, 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: - warning (_("Unable to find dynamic linker breakpoint function.\nGDB will be unable to debug shared library initializers\nand track explicitly loaded dynamic code.")); + 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.")); } - /* Scan through the list of symbols, trying to look up the symbol and - set a breakpoint there. Terminate loop when we/if we succeed. */ + /* Scan through the lists of symbols, trying to look up the symbol and + set a breakpoint there. Terminate loop when we/if we succeed. */ - breakpoint_addr = 0; - for (bkpt_namep = bkpt_names; *bkpt_namep != NULL; bkpt_namep++) + for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++) { msymbol = lookup_minimal_symbol (*bkpt_namep, NULL, symfile_objfile); if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) { - create_solib_event_breakpoint (SYMBOL_VALUE_ADDRESS (msymbol)); + create_solib_event_breakpoint (target_gdbarch, + SYMBOL_VALUE_ADDRESS (msymbol)); return 1; } } - /* Nothing good happened. */ - success = 0; - -#endif /* BKPT_AT_SYMBOL */ - - return (success); + for (bkpt_namep = bkpt_names; *bkpt_namep != NULL; bkpt_namep++) + { + msymbol = lookup_minimal_symbol (*bkpt_namep, NULL, symfile_objfile); + if ((msymbol != NULL) && (SYMBOL_VALUE_ADDRESS (msymbol) != 0)) + { + create_solib_event_breakpoint (target_gdbarch, + SYMBOL_VALUE_ADDRESS (msymbol)); + return 1; + } + } + return 0; } /* @@ -1043,7 +1520,9 @@ static void svr4_relocate_main_executable (void) { asection *interp_sect; - CORE_ADDR pc = read_pc (); + struct regcache *regcache + = get_thread_arch_regcache (inferior_ptid, target_gdbarch); + CORE_ADDR pc = regcache_read_pc (regcache); /* Decide if the objfile needs to be relocated. As indicated above, we will only be here when execution is stopped at the beginning @@ -1190,21 +1669,20 @@ svr4_relocate_main_executable (void) static void svr4_solib_create_inferior_hook (void) { + struct inferior *inf; + struct thread_info *tp; + struct svr4_info *info; + + info = get_svr4_info (PIDGET (inferior_ptid)); + /* Relocate the main executable if necessary. */ svr4_relocate_main_executable (); if (!svr4_have_link_map_offsets ()) - { - warning (_("no shared library support for this OS / ABI")); - return; + return; - } - - if (!enable_break ()) - { - warning (_("shared library handler failed to enable breakpoint")); - return; - } + if (!enable_break (info)) + return; #if defined(_SCO_DS) /* SCO needs the loop below, other systems should be using the @@ -1216,23 +1694,26 @@ 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) */ } static void svr4_clear_solib (void) { - debug_base = 0; + remove_svr4_info (PIDGET (inferior_ptid)); } static void @@ -1254,26 +1735,28 @@ svr4_free_so (struct so_list *so) natural pointer/address correspondence. (For example, on the MIPS, converting a 32-bit pointer to a 64-bit CORE_ADDR requires you to sign-extend the value. There, simply truncating the bits above - TARGET_PTR_BIT, as we do below, is no good.) This should probably + gdbarch_ptr_bit, as we do below, is no good.) This should probably be a new gdbarch method or something. */ static CORE_ADDR svr4_truncate_ptr (CORE_ADDR addr) { - if (TARGET_PTR_BIT == 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 << TARGET_PTR_BIT) - 1); + return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (target_gdbarch)) - 1); } static void svr4_relocate_section_addresses (struct so_list *so, - struct section_table *sec) + struct target_section *sec) { - sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR (so)); - sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR (so)); + sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR_CHECK (so, + sec->bfd)); + sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR_CHECK (so, + sec->bfd)); } @@ -1296,12 +1779,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, @@ -1310,6 +1793,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 @@ -1318,7 +1803,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 (); @@ -1329,7 +1814,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); } @@ -1354,18 +1839,16 @@ 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. */ lmo.link_map_size = 20; lmo.l_addr_offset = 0; - lmo.l_addr_size = 4; lmo.l_name_offset = 4; - lmo.l_name_size = 4; + lmo.l_ld_offset = 8; lmo.l_next_offset = 12; - lmo.l_next_size = 4; lmo.l_prev_offset = 16; - lmo.l_prev_size = 4; } return lmp; @@ -1387,25 +1870,41 @@ 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. */ lmo.link_map_size = 40; lmo.l_addr_offset = 0; - lmo.l_addr_size = 8; lmo.l_name_offset = 8; - lmo.l_name_size = 8; + lmo.l_ld_offset = 16; lmo.l_next_offset = 24; - lmo.l_next_size = 8; lmo.l_prev_offset = 32; - lmo.l_prev_size = 8; } return lmp; } -static struct target_so_ops svr4_so_ops; +struct target_so_ops svr4_so_ops; + +/* Lookup global symbol for ELF DSOs linked with -Bsymbolic. Those DSOs have a + different rule for symbol lookup. The lookup begins here in the DSO, not in + the main executable. */ + +static struct symbol * +elf_lookup_lib_symbol (const struct objfile *objfile, + const char *name, + const char *linkage_name, + 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); +} extern initialize_file_ftype _initialize_svr4_solib; /* -Wmissing-prototypes */ @@ -1422,7 +1921,8 @@ _initialize_svr4_solib (void) svr4_so_ops.current_sos = svr4_current_sos; 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; + svr4_so_ops.same = svr4_same; - /* FIXME: Don't do this here. *_gdbarch_init() should set so_ops. */ - current_target_so_ops = &svr4_so_ops; + observer_attach_inferior_exit (solib_svr4_inferior_exit); }