* configure.ac (AC_CHECK_FUNCS): Add check for setsid.
[deliverable/binutils-gdb.git] / gdb / solib-svr4.c
index 63918277b90693bf18f79c3ecd33bf1e1e9466f1..d4d321339bbc5602b65f33a519238f56d6eb7cf5 100644 (file)
@@ -1,13 +1,13 @@
 /* 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 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 +16,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 <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 
 #include "bfd-target.h"
 #include "elf-bfd.h"
 #include "exec.h"
+#include "auxv.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
@@ -108,6 +103,40 @@ 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
@@ -354,7 +383,7 @@ 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, *buf;
+  gdb_byte *bufend, *bufstart, *buf;
   Elf32_External_Dyn *x_dynp_32;
   Elf64_External_Dyn *x_dynp_64;
   struct bfd_section *sect;
@@ -371,16 +400,13 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr)
     return 0;
   dyn_addr = bfd_section_vma (abfd, sect);
 
-  /* Read in .dynamic section, silently ignore errors.  */
+  /* Read in .dynamic from the BFD.  We will get the actual value
+     from memory later.  */
   sect_size = bfd_section_size (abfd, sect);
-  buf = alloca (sect_size);
-  if (target_read_memory (dyn_addr, buf, sect_size))
-    {
-      /* If target_read_memory fails, try reading the BFD file.  */
-      if (!bfd_get_section_contents (abfd, sect,
-                                    buf, 0, sect_size))
-       return 0;
-    }
+  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)
@@ -395,7 +421,7 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr)
        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
+    else
       {
        x_dynp_64 = (Elf64_External_Dyn *) buf;
        dyn_tag = bfd_h_get_64 (abfd, (bfd_byte *) x_dynp_64->d_tag);
@@ -405,9 +431,20 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr)
        return 0;
      if (dyn_tag == dyntag)
        {
+        /* If requested, try to read the runtime value of this .dynamic
+           entry.  */
         if (ptr)
-          *ptr = dyn_ptr;
-         return 1;
+          {
+            gdb_byte ptr_buf[8];
+            CORE_ADDR ptr_addr;
+
+            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);
+            *ptr = dyn_ptr;
+          }
+        return 1;
        }
   }
 
@@ -445,11 +482,9 @@ elf_locate_base (void)
   struct minimal_symbol *msymbol;
   CORE_ADDR dyn_ptr;
 
-  /* Find DT_DEBUG.  */
-  if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr))
-    return dyn_ptr;
-
-  /* Find DT_MIPS_RLD_MAP.  */
+  /* 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))
     {
       gdb_byte *pbuf;
@@ -462,6 +497,10 @@ elf_locate_base (void)
       return extract_typed_address (pbuf, builtin_type_void_data_ptr);
     }
 
+  /* Find DT_DEBUG.  */
+  if (scan_dyntag (DT_DEBUG, exec_bfd, &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);
@@ -543,6 +582,17 @@ solib_svr4_r_map (void)
                                    builtin_type_void_data_ptr);
 }
 
+/* Find r_brk from the inferior's debug base.  */
+
+static CORE_ADDR
+solib_svr4_r_brk (void)
+{
+  struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
+
+  return read_memory_typed_address (debug_base + lmo->r_brk_offset,
+                                   builtin_type_void_data_ptr);
+}
+
 /* Find the link map for the dynamic linker (if it is not in the
    normal list of loaded shared objects).  */
 
@@ -601,7 +651,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.  */
@@ -696,17 +748,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.  */
@@ -795,7 +844,7 @@ svr4_fetch_objfile_link_map (struct objfile *objfile)
 {
   CORE_ADDR lm;
 
-  if ((debug_base = locate_base ()) == 0)
+  if (locate_base () == 0)
     return 0;   /* failed somehow... */
 
   /* Position ourselves on the first link map.  */
@@ -960,6 +1009,7 @@ enable_break (void)
   struct minimal_symbol *msymbol;
   char **bkpt_namep;
   asection *interp_sect;
+  CORE_ADDR sym_addr;
 
   /* First, remove all the solib event breakpoints.  Their addresses
      may have changed since the last time we ran the program.  */
@@ -968,6 +1018,59 @@ enable_break (void)
   interp_text_sect_low = interp_text_sect_high = 0;
   interp_plt_sect_low = interp_plt_sect_high = 0;
 
+  /* If we already have a shared library list in the target, and
+     r_debug contains r_brk, set the breakpoint there - this should
+     mean r_brk has already been relocated.  Assume the dynamic linker
+     is the object containing r_brk.  */
+
+  solib_add (NULL, 0, &current_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
+       (current_gdbarch, gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+                                                             sym_addr,
+                                                             &current_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 .interp section; if not found, warn the user and drop
      into the old breakpoint at symbol code.  */
   interp_sect = bfd_get_section_by_name (exec_bfd, ".interp");
@@ -977,15 +1080,16 @@ enable_break (void)
       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;
 
       /* Read the contents of the .interp section into a local buffer;
          the contents specify the dynamic linker this program uses.  */
+      sym_addr = 0;
       interp_sect_size = bfd_section_size (exec_bfd, interp_sect);
       buf = alloca (interp_sect_size);
       bfd_get_section_contents (exec_bfd, interp_sect,
@@ -1000,11 +1104,6 @@ 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);
@@ -1027,26 +1126,38 @@ 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, &current_target, auto_solib_add);
       so = master_so_list ();
       while (so)
        {
-         if (strcmp (buf, so->so_original_name) == 0)
+         if (svr4_same_1 (buf, 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 (&current_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_offset_p = 1;
          debug_loader_offset = load_addr;
@@ -1350,7 +1461,7 @@ svr4_solib_create_inferior_hook (void)
   do
     {
       target_resume (pid_to_ptid (-1), 0, stop_signal);
-      wait_for_inferior ();
+      wait_for_inferior (0);
     }
   while (stop_signal != TARGET_SIGNAL_TRAP);
   stop_soon = NO_STOP_QUIETLY;
@@ -1430,12 +1541,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,
@@ -1444,6 +1555,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
@@ -1488,6 +1601,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.  */
@@ -1518,6 +1632,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.  */
@@ -1549,7 +1664,7 @@ elf_lookup_lib_symbol (const struct objfile *objfile,
      || scan_dyntag (DT_SYMBOLIC, objfile->obfd, NULL) != 1)
     return NULL;
 
-  return  lookup_global_symbol_from_objfile
+  return lookup_global_symbol_from_objfile
                (objfile, name, linkage_name, domain, symtab);
 }
 
@@ -1569,7 +1684,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;
 }
This page took 0.029316 seconds and 4 git commands to generate.