* solist.h (master_so_list): New function.
[deliverable/binutils-gdb.git] / gdb / solib-svr4.c
index 6c4c10ae0139d8fc4c8d8419f7e92ae195c977fc..020a55c284445aff4f0565baa1b2a2bde323607f 100644 (file)
@@ -1,6 +1,7 @@
 /* Handle SVR4 shared libraries for GDB, the GNU Debugger.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000,
-   2001
+
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999,
+   2000, 2001, 2003, 2004
    Free Software Foundation, Inc.
 
    This file is part of GDB.
@@ -37,6 +38,9 @@
 #include "solist.h"
 #include "solib-svr4.h"
 
+#include "bfd-target.h"
+#include "exec.h"
+
 #ifndef SVR4_FETCH_LINK_MAP_OFFSETS
 #define SVR4_FETCH_LINK_MAP_OFFSETS() svr4_fetch_link_map_offsets ()
 #endif
@@ -81,6 +85,17 @@ static char *solib_break_names[] =
   "_dl_debug_state",
   "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
 };
 
@@ -105,14 +120,16 @@ 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.  */
+/* 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.
+
+   Assume that the address is unsigned.  */
 
 #define SOLIB_EXTRACT_ADDRESS(MEMBER) \
-       extract_address (&(MEMBER), sizeof (MEMBER))
+       extract_unsigned_integer (&(MEMBER), sizeof (MEMBER))
 
 /* local data declarations */
 
@@ -132,7 +149,9 @@ LM_NEXT (struct so_list *so)
 {
   struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
 
-  return extract_address (so->lm_info->lm + lmo->l_next_offset, lmo->l_next_size);
+  /* Assume that the address is unsigned.  */
+  return extract_unsigned_integer (so->lm_info->lm + lmo->l_next_offset,
+                                  lmo->l_next_size);
 }
 
 static CORE_ADDR
@@ -140,7 +159,9 @@ LM_NAME (struct so_list *so)
 {
   struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
 
-  return extract_address (so->lm_info->lm + lmo->l_name_offset, lmo->l_name_size);
+  /* Assume that the address is unsigned.  */
+  return extract_unsigned_integer (so->lm_info->lm + lmo->l_name_offset,
+                                  lmo->l_name_size);
 }
 
 static int
@@ -148,8 +169,9 @@ IGNORE_FIRST_LINK_MAP_ENTRY (struct so_list *so)
 {
   struct link_map_offsets *lmo = SVR4_FETCH_LINK_MAP_OFFSETS ();
 
-  return extract_address (so->lm_info->lm + lmo->l_prev_offset,
-                          lmo->l_prev_size) == 0;
+  /* Assume that the address is unsigned.  */
+  return extract_unsigned_integer (so->lm_info->lm + lmo->l_prev_offset,
+                                  lmo->l_prev_size) == 0;
 }
 
 static CORE_ADDR debug_base;   /* Base of dynamic linker structures */
@@ -159,7 +181,7 @@ static CORE_ADDR breakpoint_addr;   /* Address where end bkpt is set */
 
 static int match_main (char *);
 
-static CORE_ADDR bfd_lookup_symbol (bfd *, char *);
+static CORE_ADDR bfd_lookup_symbol (bfd *, char *, flagword);
 
 /*
 
@@ -169,7 +191,7 @@ static CORE_ADDR bfd_lookup_symbol (bfd *, char *);
 
    SYNOPSIS
 
-   CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname)
+   CORE_ADDR bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags)
 
    DESCRIPTION
 
@@ -178,12 +200,15 @@ static CORE_ADDR bfd_lookup_symbol (bfd *, char *);
    shared library support to find the address of the debugger
    interface structures in the shared library.
 
+   If SECT_FLAGS is non-zero, only match symbols in sections whose
+   flags include all those in SECT_FLAGS.
+
    Note that 0 is specifically allowed as an error return (no
    such symbol).
  */
 
 static CORE_ADDR
-bfd_lookup_symbol (bfd *abfd, char *symname)
+bfd_lookup_symbol (bfd *abfd, char *symname, flagword sect_flags)
 {
   long storage_needed;
   asymbol *sym;
@@ -204,7 +229,8 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
       for (i = 0; i < number_of_symbols; i++)
        {
          sym = *symbol_table++;
-         if (STREQ (sym->name, symname))
+         if (strcmp (sym->name, symname) == 0
+              && (sym->section->flags & sect_flags) == sect_flags)
            {
              /* Bfd symbols are section relative. */
              symaddr = sym->value + sym->section->vma;
@@ -231,7 +257,9 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
       for (i = 0; i < number_of_symbols; i++)
        {
          sym = *symbol_table++;
-         if (STREQ (sym->name, symname))
+
+         if (strcmp (sym->name, symname) == 0
+              && (sym->section->flags & sect_flags) == sect_flags)
            {
              /* Bfd symbols are section relative. */
              symaddr = sym->value + sym->section->vma;
@@ -337,7 +365,7 @@ look_for_base (int fd, CORE_ADDR baseaddr)
 
   for (symbolp = debug_base_symbols; *symbolp != NULL; symbolp++)
     {
-      address = bfd_lookup_symbol (interp_bfd, *symbolp);
+      address = bfd_lookup_symbol (interp_bfd, *symbolp, 0);
       if (address != 0)
        {
          break;
@@ -398,7 +426,7 @@ look_for_base (int fd, CORE_ADDR baseaddr)
 static CORE_ADDR
 elf_locate_base (void)
 {
-  sec_ptr dyninfo_sect;
+  struct bfd_section *dyninfo_sect;
   int dyninfo_sect_size;
   CORE_ADDR dyninfo_addr;
   char *buf;
@@ -587,7 +615,8 @@ first_link_map_member (void)
 
   read_memory (debug_base + lmo->r_map_offset, r_map_buf, lmo->r_map_size);
 
-  lm = extract_address (r_map_buf, lmo->r_map_size);
+  /* Assume that the address is unsigned.  */
+  lm = extract_unsigned_integer (r_map_buf, lmo->r_map_size);
 
   /* FIXME:  Perhaps we should validate the info somehow, perhaps by
      checking r_version for a known version number, or r_state for
@@ -645,8 +674,9 @@ open_symbol_file_object (void *from_ttyp)
   /* Read address of name from target memory to GDB.  */
   read_memory (lm + lmo->l_name_offset, l_name_buf, lmo->l_name_size);
 
-  /* Convert the address to host format.  */
-  l_name = extract_address (l_name_buf, lmo->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);
 
   /* Free l_name_buf.  */
   do_cleanups (cleanups);
@@ -820,9 +850,9 @@ svr4_fetch_objfile_link_map (struct objfile *objfile)
       /* 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.  */
-      name_address = extract_address (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);
@@ -843,9 +873,10 @@ svr4_fetch_objfile_link_map (struct objfile *objfile)
              return lm;
            }
        }
-      /* Not the file we wanted, continue checking.  */
-      lm = extract_address (objfile_lm_info.lm + lmo->l_next_offset,
-                           lmo->l_next_size);
+      /* 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);
     }
   return 0;
@@ -884,6 +915,24 @@ svr4_in_dynsym_resolve_code (CORE_ADDR pc)
          || in_plt_section (pc, NULL));
 }
 
+/* Given an executable's ABFD and target, compute the entry-point
+   address.  */
+
+static CORE_ADDR
+exec_entry_point (struct bfd *abfd, struct target_ops *targ)
+{
+  /* KevinB wrote ... for most targets, the address returned by
+     bfd_get_start_address() is the entry point for the start
+     function.  But, for some targets, bfd_get_start_address() returns
+     the address of a function descriptor from which the entry point
+     address may be extracted.  This address is extracted by
+     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,
+                                            bfd_get_start_address (abfd),
+                                            targ);
+}
 
 /*
 
@@ -955,8 +1004,9 @@ enable_break (void)
       char *buf;
       CORE_ADDR load_addr = 0;
       int load_addr_found = 0;
-      struct so_list *inferior_sos;
+      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;
@@ -992,30 +1042,32 @@ enable_break (void)
          goto bkpt_at_symbol;
        }
 
-      /* If the entry in _DYNAMIC for the dynamic linker has already
-         been filled in, we can read its base address from there. */
-      inferior_sos = svr4_current_sos ();
-      if (inferior_sos)
-       {
-         /* Connected to a running target.  Update our shared library table. */
-         solib_add (NULL, 0, NULL, auto_solib_add);
-       }
-      while (inferior_sos)
+      /* 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.  */
+      tmp_bfd_target = target_bfd_reopen (tmp_bfd);
+
+      /* 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, inferior_sos->so_original_name) == 0)
+         if (strcmp (buf, so->so_original_name) == 0)
            {
              load_addr_found = 1;
-             load_addr = LM_ADDR (inferior_sos);
+             load_addr = LM_ADDR (so);
              break;
            }
-         inferior_sos = inferior_sos->next;
+         so = so->next;
        }
 
       /* 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.  */
       if (!load_addr_found)
-       load_addr = read_pc () - tmp_bfd->start_address;
+       load_addr = (read_pc ()
+                    - exec_entry_point (tmp_bfd, tmp_bfd_target));
 
       /* Record the relocated start and end address of the dynamic linker
          text and plt section for svr4_in_dynsym_resolve_code.  */
@@ -1039,13 +1091,23 @@ enable_break (void)
       /* Now try to set a breakpoint in the dynamic linker.  */
       for (bkpt_namep = solib_break_names; *bkpt_namep != NULL; bkpt_namep++)
        {
-         sym_addr = bfd_lookup_symbol (tmp_bfd, *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);
          if (sym_addr != 0)
            break;
        }
 
-      /* We're done with the temporary bfd.  */
-      bfd_close (tmp_bfd);
+      /* 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)
        {
@@ -1164,7 +1226,7 @@ svr4_relocate_main_executable (void)
   interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
   if (interp_sect == NULL 
       && (bfd_get_file_flags (exec_bfd) & DYNAMIC) != 0
-      && bfd_get_start_address (exec_bfd) != pc)
+      && (exec_entry_point (exec_bfd, &exec_ops) != pc))
     {
       struct cleanup *old_chain;
       struct section_offsets *new_offsets;
@@ -1196,7 +1258,7 @@ svr4_relocate_main_executable (void)
         The same language also appears in Edition 4.0 of the System V
         ABI and is left unspecified in some of the earlier editions.  */
 
-      displacement = pc - bfd_get_start_address (exec_bfd);
+      displacement = pc - exec_entry_point (exec_bfd, &exec_ops);
       changed = 0;
 
       new_offsets = xcalloc (symfile_objfile->num_sections,
@@ -1443,13 +1505,86 @@ init_fetch_link_map_offsets (struct gdbarch *gdbarch)
   return legacy_fetch_link_map_offsets;
 }
 
+/* Most OS'es that have SVR4-style ELF dynamic libraries define a
+   `struct r_debug' and a `struct link_map' that are binary compatible
+   with the origional SVR4 implementation.  */
+
+/* Fetch (and possibly build) an appropriate `struct link_map_offsets'
+   for an ILP32 SVR4 system.  */
+  
+struct link_map_offsets *
+svr4_ilp32_fetch_link_map_offsets (void)
+{
+  static struct link_map_offsets lmo;
+  static struct link_map_offsets *lmp = NULL;
+
+  if (lmp == NULL)
+    {
+      lmp = &lmo;
+
+      /* Everything we need is in the first 8 bytes.  */
+      lmo.r_debug_size = 8;
+      lmo.r_map_offset = 4;
+      lmo.r_map_size   = 4;
+
+      /* 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_next_offset = 12;
+      lmo.l_next_size   = 4;
+      lmo.l_prev_offset = 16;
+      lmo.l_prev_size   = 4;
+    }
+
+  return lmp;
+}
+
+/* Fetch (and possibly build) an appropriate `struct link_map_offsets'
+   for an LP64 SVR4 system.  */
+  
+struct link_map_offsets *
+svr4_lp64_fetch_link_map_offsets (void)
+{
+  static struct link_map_offsets lmo;
+  static struct link_map_offsets *lmp = NULL;
+
+  if (lmp == NULL)
+    {
+      lmp = &lmo;
+
+      /* Everything we need is in the first 16 bytes.  */
+      lmo.r_debug_size = 16;
+      lmo.r_map_offset = 8;
+      lmo.r_map_size   = 8;
+
+      /* 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_next_offset = 24;
+      lmo.l_next_size   = 8;
+      lmo.l_prev_offset = 32;
+      lmo.l_prev_size   = 8;
+    }
+
+  return lmp;
+}
+\f
+
 static struct target_so_ops svr4_so_ops;
 
+extern initialize_file_ftype _initialize_svr4_solib; /* -Wmissing-prototypes */
+
 void
 _initialize_svr4_solib (void)
 {
   fetch_link_map_offsets_gdbarch_data =
-    register_gdbarch_data (init_fetch_link_map_offsets, 0);
+    register_gdbarch_data (init_fetch_link_map_offsets);
 
   svr4_so_ops.relocate_section_addresses = svr4_relocate_section_addresses;
   svr4_so_ops.free_so = svr4_free_so;
This page took 0.036015 seconds and 4 git commands to generate.