2003-10-19 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / solib-svr4.c
index 987e776df3ad392c2887d2275198d31439e6da04..7fda5e4e0202b1a6289441251ec1f4131ebf7cee 100644 (file)
@@ -43,6 +43,7 @@
 
 static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
 static struct link_map_offsets *legacy_fetch_link_map_offsets (void);
+static int svr4_have_link_map_offsets (void);
 
 /* fetch_link_map_offsets_gdbarch_data is a handle used to obtain the
    architecture specific link map offsets fetching function.  */
@@ -80,6 +81,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
 };
 
@@ -92,6 +104,7 @@ static char *bkpt_names[] =
   SOLIB_BKPT_NAME,             /* Prefer configured name if it exists. */
 #endif
   "_start",
+  "__start",
   "main",
   NULL
 };
@@ -103,14 +116,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 */
 
@@ -130,7 +145,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
@@ -138,7 +155,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
@@ -146,8 +165,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 */
@@ -157,7 +177,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);
 
 /*
 
@@ -167,7 +187,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
 
@@ -176,12 +196,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;
@@ -196,13 +219,14 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
   if (storage_needed > 0)
     {
       symbol_table = (asymbol **) xmalloc (storage_needed);
-      back_to = make_cleanup (xfree, (PTR) symbol_table);
+      back_to = make_cleanup (xfree, symbol_table);
       number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
 
       for (i = 0; i < number_of_symbols; i++)
        {
          sym = *symbol_table++;
-         if (STREQ (sym->name, symname))
+         if (STREQ (sym->name, symname)
+              && (sym->section->flags & sect_flags) == sect_flags)
            {
              /* Bfd symbols are section relative. */
              symaddr = sym->value + sym->section->vma;
@@ -223,13 +247,15 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
   if (storage_needed > 0)
     {
       symbol_table = (asymbol **) xmalloc (storage_needed);
-      back_to = make_cleanup (xfree, (PTR) symbol_table);
+      back_to = make_cleanup (xfree, symbol_table);
       number_of_symbols = bfd_canonicalize_dynamic_symtab (abfd, symbol_table);
 
       for (i = 0; i < number_of_symbols; i++)
        {
          sym = *symbol_table++;
-         if (STREQ (sym->name, symname))
+
+         if (STREQ (sym->name, symname)
+              && (sym->section->flags & sect_flags) == sect_flags)
            {
              /* Bfd symbols are section relative. */
              symaddr = sym->value + sym->section->vma;
@@ -335,7 +361,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;
@@ -445,15 +471,16 @@ elf_locate_base (void)
          else if (dyn_tag == DT_MIPS_RLD_MAP)
            {
              char *pbuf;
+             int pbuf_size = TARGET_PTR_BIT / HOST_CHAR_BIT;
 
-             pbuf = alloca (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, sizeof (pbuf)))
+             if (target_read_memory (dyn_ptr, pbuf, pbuf_size))
                return 0;
-             return extract_unsigned_integer (pbuf, sizeof (pbuf));
+             return extract_unsigned_integer (pbuf, pbuf_size);
            }
        }
     }
@@ -476,6 +503,20 @@ elf_locate_base (void)
                                      (bfd_byte *) x_dynp->d_un.d_ptr);
              return dyn_ptr;
            }
+         else if (dyn_tag == DT_MIPS_RLD_MAP)
+           {
+             char *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);
+           }
        }
     }
 
@@ -526,9 +567,10 @@ locate_base (void)
   /* 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
      we have no cached address, try to locate it in the dynamic info
-     section for ELF executables.  */
+     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)
+  if (debug_base == 0 && svr4_have_link_map_offsets ())
     {
       if (exec_bfd != NULL
          && bfd_get_flavour (exec_bfd) == bfd_target_elf_flavour)
@@ -569,7 +611,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
@@ -627,8 +670,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);
@@ -761,6 +805,78 @@ 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.  */
+
+CORE_ADDR
+svr4_fetch_objfile_link_map (struct objfile *objfile)
+{
+  CORE_ADDR lm;
+
+  if ((debug_base = locate_base ()) == 0)
+    return 0;   /* failed somehow... */
+
+  /* Position ourselves on the first link map.  */
+  lm = first_link_map_member ();  
+  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;
+      char *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 = xmalloc (lmo->link_map_size);
+      make_cleanup (xfree, objfile_lm_info.lm);
+      memset (objfile_lm_info.lm, 0, lmo->link_map_size);
+
+      /* 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 ("svr4_fetch_objfile_link_map: Can't read pathname for load map: %s\n",
+                  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);
+    }
+  return 0;
+}
 
 /* On some systems, the only way to recognize the link map entry for
    the main executable file is by looking at its name.  Return
@@ -950,7 +1066,16 @@ 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;
        }
@@ -1110,8 +1235,8 @@ svr4_relocate_main_executable (void)
       displacement = pc - bfd_get_start_address (exec_bfd);
       changed = 0;
 
-      new_offsets = xcalloc (sizeof (struct section_offsets),
-                            symfile_objfile->num_sections);
+      new_offsets = xcalloc (symfile_objfile->num_sections,
+                            sizeof (struct section_offsets));
       old_chain = make_cleanup (xfree, new_offsets);
 
       for (i = 0; i < symfile_objfile->num_sections; i++)
@@ -1186,6 +1311,13 @@ svr4_solib_create_inferior_hook (void)
   /* 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;
+
+    }
+
   if (!enable_break ())
     {
       warning ("shared library handler failed to enable breakpoint");
@@ -1203,7 +1335,7 @@ svr4_solib_create_inferior_hook (void)
      out what we need to know about them. */
 
   clear_proceed_status ();
-  stop_soon_quietly = 1;
+  stop_soon = STOP_QUIETLY;
   stop_signal = TARGET_SIGNAL_0;
   do
     {
@@ -1211,7 +1343,7 @@ svr4_solib_create_inferior_hook (void)
       wait_for_inferior ();
     }
   while (stop_signal != TARGET_SIGNAL_TRAP);
-  stop_soon_quietly = 0;
+  stop_soon = NO_STOP_QUIETLY;
 #endif /* defined(_SCO_DS) */
 }
 
@@ -1228,14 +1360,41 @@ svr4_free_so (struct so_list *so)
   xfree (so->lm_info);
 }
 
+
+/* Clear any bits of ADDR that wouldn't fit in a target-format
+   data pointer.  "Data pointer" here refers to whatever sort of
+   address the dynamic linker uses to manage its sections.  At the
+   moment, we don't support shared libraries on any processors where
+   code and data pointers are different sizes.
+
+   This isn't really the right solution.  What we really need here is
+   a way to do arithmetic on CORE_ADDR values that respects the
+   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
+   be a new gdbarch method or something.  */
+static CORE_ADDR
+svr4_truncate_ptr (CORE_ADDR addr)
+{
+  if (TARGET_PTR_BIT == 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);
+}
+
+
 static void
 svr4_relocate_section_addresses (struct so_list *so,
                                  struct section_table *sec)
 {
-  sec->addr += LM_ADDR (so);
-  sec->endaddr += LM_ADDR (so);
+  sec->addr    = svr4_truncate_ptr (sec->addr    + LM_ADDR (so));
+  sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR (so));
 }
 
+
 /* Fetch a link_map_offsets structure for native targets using struct
    definitions from link.h.  See solib-legacy.c for the function
    which does the actual work.
@@ -1265,7 +1424,7 @@ static struct link_map_offsets *
 svr4_fetch_link_map_offsets (void)
 {
   struct link_map_offsets *(*flmo)(void) =
-    gdbarch_data (fetch_link_map_offsets_gdbarch_data);
+    gdbarch_data (current_gdbarch, fetch_link_map_offsets_gdbarch_data);
 
   if (flmo == NULL)
     {
@@ -1278,6 +1437,20 @@ svr4_fetch_link_map_offsets (void)
     return (flmo ());
 }
 
+/* Return 1 if a link map offset fetcher has been defined, 0 otherwise.  */
+static int
+svr4_have_link_map_offsets (void)
+{
+  struct link_map_offsets *(*flmo)(void) =
+    gdbarch_data (current_gdbarch, fetch_link_map_offsets_gdbarch_data);
+  if (flmo == NULL
+      || (flmo == legacy_fetch_link_map_offsets 
+          && legacy_svr4_fetch_link_map_offsets_hook == NULL))
+    return 0;
+  else
+    return 1;
+}
+
 /* set_solib_svr4_fetch_link_map_offsets() is intended to be called by
    a <arch>_gdbarch_init() function.  It is used to establish an
    architecture specific link_map_offsets fetcher for the architecture
@@ -1290,33 +1463,31 @@ set_solib_svr4_fetch_link_map_offsets (struct gdbarch *gdbarch,
   set_gdbarch_data (gdbarch, fetch_link_map_offsets_gdbarch_data, flmo);
 }
 
-/* Initialize the architecture specific link_map_offsets fetcher. 
-   This is called after <arch>_gdbarch_init() has set up its struct
-   gdbarch for the new architecture, so care must be taken to use the
-   value set by set_solib_svr4_fetch_link_map_offsets(), above.  We
-   do, however, attempt to provide a reasonable alternative (for
-   native targets anyway) if the <arch>_gdbarch_init() fails to call
+/* Initialize the architecture-specific link_map_offsets fetcher.
+   This is called after <arch>_gdbarch_init() has set up its `struct
+   gdbarch' for the new architecture, and is only called if the
+   link_map_offsets fetcher isn't already initialized (which is
+   usually done by calling set_solib_svr4_fetch_link_map_offsets()
+   above in <arch>_gdbarch_init()).  Therefore we attempt to provide a
+   reasonable alternative (for native targets anyway) if the
+   <arch>_gdbarch_init() fails to call
    set_solib_svr4_fetch_link_map_offsets().  */
 
 static void *
 init_fetch_link_map_offsets (struct gdbarch *gdbarch)
 {
-  struct link_map_offsets *(*flmo) =
-    gdbarch_data (fetch_link_map_offsets_gdbarch_data);
-
-  if (flmo == NULL)
-    return legacy_fetch_link_map_offsets;
-  else
-    return flmo;
+  return legacy_fetch_link_map_offsets;
 }
 
 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.044607 seconds and 4 git commands to generate.