Add support for DT_MIPS_RLD_MAP_REL.
authorMatthew Fortune <matthew.fortune@imgtec.com>
Thu, 11 Jun 2015 09:37:31 +0000 (10:37 +0100)
committerMatthew Fortune <matthew.fortune@imgtec.com>
Fri, 14 Aug 2015 12:11:21 +0000 (13:11 +0100)
This tag allows debugging of MIPS position independent executables
and provides access to shared library information.

gdb/gdbserver/

* linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP_REL.

gdb/

* solib-svr4.c (read_program_header): Add base_addr argument to
report the runtime address of the segment.
(find_program_interpreter): Update read_program_header call to pass
a NULL pointer for the new argument.
(scan_dyntag): Add ptr_addr argument to report the runtime address
of the tag payload.
(scan_dyntag_auxv): Likewise and use thew new base_addr argument of
read_program_header to get the base address of the dynamic segment.
(elf_locate_base): Update uses of scan_dyntag, scan_dyntag_auxv and
read_program_header.
(elf_locate_base): Scan for and handle DT_MIPS_RLD_MAP_REL.

gdb/ChangeLog
gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/solib-svr4.c

index 3354358a9b3354e2495c1b7e6e67735b088ddef2..be3248e3a1e4bdd41159f382c5fb8e19986b21b6 100644 (file)
@@ -1,3 +1,17 @@
+2015-08-14  Matthew Fortune  <matthew.fortune@imgtec.com>
+
+       * solib-svr4.c (read_program_header): Add base_addr argument to
+       report the runtime address of the segment.
+       (find_program_interpreter): Update read_program_header call to pass
+       a NULL pointer for the new argument.
+       (scan_dyntag): Add ptr_addr argument to report the runtime address
+       of the tag payload.
+       (scan_dyntag_auxv): Likewise and use thew new base_addr argument of
+       read_program_header to get the base address of the dynamic segment.
+       (elf_locate_base): Update uses of scan_dyntag, scan_dyntag_auxv and
+       read_program_header.
+       (elf_locate_base): Scan for and handle DT_MIPS_RLD_MAP_REL.
+
 2015-08-14  Matthew Fortune  <matthew.fortune@imgtec.com>
 
        * MAINTAINERS (Write After Approval): Add Matthew Fortune.
index 4f64e43cbcbfac14dfd6b3438e1557fc47221727..7f52fb8f9fc5e1954306c12bacf61cab6086815b 100644 (file)
@@ -1,3 +1,7 @@
+2015-08-14  Matthew Fortune  <matthew.fortune@imgtec.com>
+
+       * linux-low.c (get_r_debug): Handle DT_MIPS_RLD_MAP_REL.
+
 2015-08-06  Pedro Alves  <palves@redhat.com>
 
        * tracepoint.c (expr_eval_result): Now an int.
index 792c1782b0e5bbd34aafd8039336797f370c8f61..c37c6d2f3d533cdf27dffcb7f550650d292bc289 100644 (file)
@@ -6324,14 +6324,15 @@ get_r_debug (const int pid, const int is_elf64)
       if (is_elf64)
        {
          Elf64_Dyn *const dyn = (Elf64_Dyn *) buf;
-#ifdef DT_MIPS_RLD_MAP
+#if defined DT_MIPS_RLD_MAP || defined DT_MIPS_RLD_MAP_REL
          union
            {
              Elf64_Xword map;
              unsigned char buf[sizeof (Elf64_Xword)];
            }
          rld_map;
-
+#endif
+#ifdef DT_MIPS_RLD_MAP
          if (dyn->d_tag == DT_MIPS_RLD_MAP)
            {
              if (linux_read_memory (dyn->d_un.d_val,
@@ -6341,6 +6342,16 @@ get_r_debug (const int pid, const int is_elf64)
                break;
            }
 #endif /* DT_MIPS_RLD_MAP */
+#ifdef DT_MIPS_RLD_MAP_REL
+         if (dyn->d_tag == DT_MIPS_RLD_MAP_REL)
+           {
+             if (linux_read_memory (dyn->d_un.d_val + dynamic_memaddr,
+                                    rld_map.buf, sizeof (rld_map.buf)) == 0)
+               return rld_map.map;
+             else
+               break;
+           }
+#endif /* DT_MIPS_RLD_MAP_REL */
 
          if (dyn->d_tag == DT_DEBUG && map == -1)
            map = dyn->d_un.d_val;
@@ -6351,14 +6362,15 @@ get_r_debug (const int pid, const int is_elf64)
       else
        {
          Elf32_Dyn *const dyn = (Elf32_Dyn *) buf;
-#ifdef DT_MIPS_RLD_MAP
+#if defined DT_MIPS_RLD_MAP || defined DT_MIPS_RLD_MAP_REL
          union
            {
              Elf32_Word map;
              unsigned char buf[sizeof (Elf32_Word)];
            }
          rld_map;
-
+#endif
+#ifdef DT_MIPS_RLD_MAP
          if (dyn->d_tag == DT_MIPS_RLD_MAP)
            {
              if (linux_read_memory (dyn->d_un.d_val,
@@ -6368,6 +6380,16 @@ get_r_debug (const int pid, const int is_elf64)
                break;
            }
 #endif /* DT_MIPS_RLD_MAP */
+#ifdef DT_MIPS_RLD_MAP_REL
+         if (dyn->d_tag == DT_MIPS_RLD_MAP_REL)
+           {
+             if (linux_read_memory (dyn->d_un.d_val + dynamic_memaddr,
+                                    rld_map.buf, sizeof (rld_map.buf)) == 0)
+               return rld_map.map;
+             else
+               break;
+           }
+#endif /* DT_MIPS_RLD_MAP_REL */
 
          if (dyn->d_tag == DT_DEBUG && map == -1)
            map = dyn->d_un.d_val;
index 104530cad5b3193675b1d431a61cb8762ec35b06..1fb07d51b6db6f23901e90a81ce716a3a5146b50 100644 (file)
@@ -443,10 +443,12 @@ static int match_main (const char *);
    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.  */
+   architecture size (32-bit or 64-bit) is returned to P_ARCH_SIZE and
+   the base address of the section is returned in BASE_ADDR.  */
 
 static gdb_byte *
-read_program_header (int type, int *p_sect_size, int *p_arch_size)
+read_program_header (int type, int *p_sect_size, int *p_arch_size,
+                    CORE_ADDR *base_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
   CORE_ADDR at_phdr, at_phent, at_phnum, pt_phdr = 0;
@@ -576,6 +578,8 @@ read_program_header (int type, int *p_sect_size, int *p_arch_size)
     *p_arch_size = arch_size;
   if (p_sect_size)
     *p_sect_size = sect_size;
+  if (base_addr)
+    *base_addr = sect_addr;
 
   return buf;
 }
@@ -605,7 +609,7 @@ find_program_interpreter (void)
 
   /* If we didn't find it, use the target auxillary vector.  */
   if (!buf)
-    buf = read_program_header (PT_INTERP, NULL, NULL);
+    buf = read_program_header (PT_INTERP, NULL, NULL, NULL);
 
   return (char *) buf;
 }
@@ -615,7 +619,8 @@ find_program_interpreter (void)
    found, 1 is returned and the corresponding PTR is set.  */
 
 static int
-scan_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr)
+scan_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr,
+            CORE_ADDR *ptr_addr)
 {
   int arch_size, step, sect_size;
   long current_dyntag;
@@ -695,13 +700,15 @@ scan_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr)
           {
             struct type *ptr_type;
             gdb_byte ptr_buf[8];
-            CORE_ADDR ptr_addr;
+            CORE_ADDR ptr_addr_1;
 
             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)
+            ptr_addr_1 = dyn_addr + (buf - bufstart) + arch_size / 8;
+            if (target_read_memory (ptr_addr_1, ptr_buf, arch_size / 8) == 0)
               dyn_ptr = extract_typed_address (ptr_buf, ptr_type);
             *ptr = dyn_ptr;
+            if (ptr_addr)
+              *ptr_addr = dyn_addr + (buf - bufstart);
           }
         return 1;
        }
@@ -715,16 +722,19 @@ scan_dyntag (const int desired_dyntag, bfd *abfd, CORE_ADDR *ptr)
    is returned and the corresponding PTR is set.  */
 
 static int
-scan_dyntag_auxv (const int desired_dyntag, CORE_ADDR *ptr)
+scan_dyntag_auxv (const int desired_dyntag, CORE_ADDR *ptr,
+                 CORE_ADDR *ptr_addr)
 {
   enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
   int sect_size, arch_size, step;
   long current_dyntag;
   CORE_ADDR dyn_ptr;
+  CORE_ADDR base_addr;
   gdb_byte *bufend, *bufstart, *buf;
 
   /* Read in .dynamic section.  */
-  buf = bufstart = read_program_header (PT_DYNAMIC, &sect_size, &arch_size);
+  buf = bufstart = read_program_header (PT_DYNAMIC, &sect_size, &arch_size,
+                                       &base_addr);
   if (!buf)
     return 0;
 
@@ -761,6 +771,9 @@ scan_dyntag_auxv (const int desired_dyntag, CORE_ADDR *ptr)
        if (ptr)
          *ptr = dyn_ptr;
 
+       if (ptr_addr)
+         *ptr_addr = base_addr + buf - bufstart;
+
        xfree (bufstart);
        return 1;
       }
@@ -786,13 +799,13 @@ static CORE_ADDR
 elf_locate_base (void)
 {
   struct bound_minimal_symbol msymbol;
-  CORE_ADDR dyn_ptr;
+  CORE_ADDR dyn_ptr, dyn_ptr_addr;
 
   /* 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))
+  if (scan_dyntag (DT_MIPS_RLD_MAP, exec_bfd, &dyn_ptr, NULL)
+      || scan_dyntag_auxv (DT_MIPS_RLD_MAP, &dyn_ptr, NULL))
     {
       struct type *ptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
       gdb_byte *pbuf;
@@ -806,9 +819,27 @@ elf_locate_base (void)
       return extract_typed_address (pbuf, ptr_type);
     }
 
+  /* Then check DT_MIPS_RLD_MAP_REL.  MIPS executables now use this form
+     because of needing to support PIE.  DT_MIPS_RLD_MAP will also exist
+     in non-PIE.  */
+  if (scan_dyntag (DT_MIPS_RLD_MAP_REL, exec_bfd, &dyn_ptr, &dyn_ptr_addr)
+      || scan_dyntag_auxv (DT_MIPS_RLD_MAP_REL, &dyn_ptr, &dyn_ptr_addr))
+    {
+      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_REL contains an offset from the address of the
+        DT slot to the address of the dynamic link structure.  */
+      if (target_read_memory (dyn_ptr + dyn_ptr_addr, 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))
+  if (scan_dyntag (DT_DEBUG, exec_bfd, &dyn_ptr, NULL)
+      || scan_dyntag_auxv (DT_DEBUG, &dyn_ptr, NULL))
     return dyn_ptr;
 
   /* This may be a static executable.  Look for the symbol
@@ -2607,7 +2638,7 @@ svr4_exec_displacement (CORE_ADDR *displacementp)
       gdb_byte *buf, *buf2;
       int arch_size;
 
-      buf = read_program_header (-1, &phdrs_size, &arch_size);
+      buf = read_program_header (-1, &phdrs_size, &arch_size, NULL);
       buf2 = read_program_headers_from_bfd (exec_bfd, &phdrs2_size);
       if (buf != NULL && buf2 != NULL)
        {
@@ -3228,7 +3259,7 @@ elf_lookup_lib_symbol (struct objfile *objfile,
       abfd = objfile->obfd;
     }
 
-  if (abfd == NULL || scan_dyntag (DT_SYMBOLIC, abfd, NULL) != 1)
+  if (abfd == NULL || scan_dyntag (DT_SYMBOLIC, abfd, NULL, NULL) != 1)
     return (struct block_symbol) {NULL, NULL};
 
   return lookup_global_symbol_from_objfile (objfile, name, domain);