* gdbthread.h (struct thread_info): Add comments around
[deliverable/binutils-gdb.git] / gdb / solib-svr4.c
index 70e880266600adacaa221350bc6a6a8442cd09d7..fc6bf6fc4c73c41e2befa4e06f25ef1d2ad768e0 100644 (file)
@@ -42,6 +42,7 @@
 #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);
@@ -85,20 +86,13 @@ static char *solib_break_names[] =
   NULL
 };
 
-#define BKPT_AT_SYMBOL 1
-
-#if defined (BKPT_AT_SYMBOL)
 static char *bkpt_names[] =
 {
-#ifdef SOLIB_BKPT_NAME
-  SOLIB_BKPT_NAME,             /* Prefer configured name if it exists. */
-#endif
   "_start",
   "__start",
   "main",
   NULL
 };
-#endif
 
 static char *main_name_list[] =
 {
@@ -380,6 +374,137 @@ bfd_lookup_symbol (bfd *abfd, char *symname)
   return symaddr;
 }
 
+
+/* Read program header TYPE from inferior memory.  The header is found
+   by scanning the OS auxillary vector.
+
+   Return a pointer to allocated memory holding the program header contents,
+   or NULL on failure.  If sucessful, and unless P_SECT_SIZE is NULL, the
+   size of those contents is returned to P_SECT_SIZE.  Likewise, the target
+   architecture size (32-bit or 64-bit) is returned to P_ARCH_SIZE.  */
+
+static gdb_byte *
+read_program_header (int type, int *p_sect_size, int *p_arch_size)
+{
+  CORE_ADDR at_phdr, at_phent, at_phnum;
+  int arch_size, sect_size;
+  CORE_ADDR sect_addr;
+  gdb_byte *buf;
+
+  /* Get required auxv elements from target.  */
+  if (target_auxv_search (&current_target, AT_PHDR, &at_phdr) <= 0)
+    return 0;
+  if (target_auxv_search (&current_target, AT_PHENT, &at_phent) <= 0)
+    return 0;
+  if (target_auxv_search (&current_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.  */
 
@@ -457,6 +582,59 @@ scan_dyntag (int dyntag, bfd *abfd, CORE_ADDR *ptr)
   return 0;
 }
 
+/* Scan for DYNTAG in .dynamic section of the target's main executable,
+   found by consulting the OS auxillary vector.  If DYNTAG is found 1 is
+   returned and the corresponding PTR is set.  */
+
+static int
+scan_dyntag_auxv (int dyntag, CORE_ADDR *ptr)
+{
+  int sect_size, arch_size, step;
+  long dyn_tag;
+  CORE_ADDR dyn_ptr;
+  gdb_byte *bufend, *bufstart, *buf;
+
+  /* Read in .dynamic section.  */
+  buf = bufstart = read_program_header (PT_DYNAMIC, &sect_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;
+}
+
 
 /*
 
@@ -491,7 +669,8 @@ elf_locate_base (void)
   /* Look for DT_MIPS_RLD_MAP first.  MIPS executables use this
      instead of DT_DEBUG, although they sometimes contain an unused
      DT_DEBUG.  */
-  if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr))
+  if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr)
+      || scan_dyntag_auxv (DT_MIPS_RLD_MAP, &dyn_ptr))
     {
       gdb_byte *pbuf;
       int pbuf_size = TYPE_LENGTH (builtin_type_void_data_ptr);
@@ -504,7 +683,8 @@ elf_locate_base (void)
     }
 
   /* Find DT_DEBUG.  */
-  if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr))
+  if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr)
+      || scan_dyntag_auxv (DT_DEBUG, &dyn_ptr))
     return dyn_ptr;
 
   /* This may be a static executable.  Look for the symbol
@@ -916,7 +1096,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);
 }
@@ -967,11 +1147,10 @@ exec_entry_point (struct bfd *abfd, struct target_ops *targ)
 static int
 enable_break (void)
 {
-#ifdef BKPT_AT_SYMBOL
-
   struct minimal_symbol *msymbol;
   char **bkpt_namep;
   asection *interp_sect;
+  gdb_byte *interp_name;
   CORE_ADDR sym_addr;
 
   /* First, remove all the solib event breakpoints.  Their addresses
@@ -996,7 +1175,7 @@ enable_break (void)
       struct obj_section *os;
 
       sym_addr = gdbarch_addr_bits_remove
-       (current_gdbarch, gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+       (target_gdbarch, gdbarch_convert_from_func_ptr_addr (target_gdbarch,
                                                              sym_addr,
                                                              &current_target));
 
@@ -1034,29 +1213,20 @@ enable_break (void)
        }
     }
 
-  /* Find the .interp section; if not found, warn the user and drop
+  /* 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;
+      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.  */
       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,
-                               buf, 0, interp_sect_size);
 
       /* Now we need to figure out where the dynamic linker was
          loaded so that we can load its symbols and place a breakpoint
@@ -1067,21 +1237,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.  */
@@ -1092,7 +1254,7 @@ enable_break (void)
       so = master_so_list ();
       while (so)
        {
-         if (svr4_same_1 (buf, so->so_original_name))
+         if (svr4_same_1 (interp_name, so->so_original_name))
            {
              load_addr_found = 1;
              loader_found_in_list = 1;
@@ -1121,7 +1283,7 @@ enable_break (void)
 
       if (!loader_found_in_list)
        {
-         debug_loader_name = xstrdup (buf);
+         debug_loader_name = xstrdup (interp_name);
          debug_loader_offset_p = 1;
          debug_loader_offset = load_addr;
          solib_add (NULL, 0, &current_target, auto_solib_add);
@@ -1158,7 +1320,7 @@ enable_break (void)
        /* Convert 'sym_addr' from a function pointer to an address.
           Because we pass tmp_bfd_target instead of the current
           target, this will always produce an unrelocated value.  */
-       sym_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+       sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch,
                                                       sym_addr,
                                                       tmp_bfd_target);
 
@@ -1169,13 +1331,14 @@ enable_break (void)
       if (sym_addr != 0)
        {
          create_solib_event_breakpoint (load_addr + sym_addr);
+         xfree (interp_name);
          return 1;
        }
 
       /* For whatever reason we couldn't set a breakpoint in the dynamic
          linker.  Warn and drop into the old code.  */
     bkpt_at_symbol:
-      xfree (tmp_pathname);
+      xfree (interp_name);
       warning (_("Unable to find dynamic linker breakpoint function.\n"
                "GDB will be unable to debug shared library initializers\n"
                "and track explicitly loaded dynamic code."));
@@ -1203,8 +1366,6 @@ enable_break (void)
          return 1;
        }
     }
-#endif /* BKPT_AT_SYMBOL */
-
   return 0;
 }
 
@@ -1466,12 +1627,12 @@ svr4_free_so (struct so_list *so)
 static CORE_ADDR
 svr4_truncate_ptr (CORE_ADDR addr)
 {
-  if (gdbarch_ptr_bit (current_gdbarch) == sizeof (CORE_ADDR) * 8)
+  if (gdbarch_ptr_bit (target_gdbarch) == sizeof (CORE_ADDR) * 8)
     /* We don't need to truncate anything, and the bit twiddling below
        will fail due to overflow problems.  */
     return addr;
   else
-    return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (current_gdbarch)) - 1);
+    return addr & (((CORE_ADDR) 1 << gdbarch_ptr_bit (target_gdbarch)) - 1);
 }
 
 
@@ -1529,7 +1690,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 ();
@@ -1540,7 +1701,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);
 }
 \f
This page took 0.028249 seconds and 4 git commands to generate.