dwfl_link_map_report: Handle PIE-generated core.
authorRoland McGrath <roland@redhat.com>
Wed, 5 May 2010 01:05:22 +0000 (18:05 -0700)
committerRoland McGrath <roland@redhat.com>
Wed, 5 May 2010 02:10:56 +0000 (19:10 -0700)
libdwfl/ChangeLog
libdwfl/link_map.c

index 9f4a745..f7a3b84 100644 (file)
@@ -1,5 +1,8 @@
 2010-05-04  Roland McGrath  <roland@redhat.com>
 
+       * link_map.c (dwfl_link_map_report): Detect bias of embedded phdrs and
+       apply it to PT_DYNAMIC p_vaddr so we handle a PIE correctly.
+
        * core-file.c (dwfl_core_file_report): Return any nonzero count of
        modules reported, even if link_map grovelling failed and only sniffing
        found anything.
index fe7f40c..403b2df 100644 (file)
@@ -684,6 +684,33 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
       /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC.  */
       GElf_Addr dyn_vaddr = 0;
       GElf_Xword dyn_filesz = 0;
+      GElf_Addr dyn_bias = (GElf_Addr) -1;
+
+      inline bool consider_phdr (GElf_Word type,
+                                GElf_Addr vaddr, GElf_Xword filesz)
+      {
+       switch (type)
+         {
+         case PT_PHDR:
+           if (dyn_bias == (GElf_Addr) -1
+               /* Do a sanity check on the putative address.  */
+               && ((vaddr & (dwfl->segment_align - 1))
+                   == (phdr & (dwfl->segment_align - 1))))
+             {
+               dyn_bias = phdr - vaddr;
+               return dyn_vaddr != 0;
+             }
+           break;
+
+         case PT_DYNAMIC:
+           dyn_vaddr = vaddr;
+           dyn_filesz = filesz;
+           return dyn_bias != (GElf_Addr) -1;
+         }
+
+       return false;
+      }
+
       if (phdr != 0 && phnum != 0)
        {
          Dwfl_Module *phdr_mod;
@@ -725,22 +752,18 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
                  if (elfclass == ELFCLASS32)
                    {
                      for (size_t i = 0; i < phnum; ++i)
-                       if (u->p32[i].p_type == PT_DYNAMIC)
-                         {
-                           dyn_vaddr = u->p32[i].p_vaddr;
-                           dyn_filesz = u->p32[i].p_filesz;
-                           break;
-                         }
+                       if (consider_phdr (u->p32[i].p_type,
+                                          u->p32[i].p_vaddr,
+                                          u->p32[i].p_filesz))
+                         break;
                    }
                  else
                    {
                      for (size_t i = 0; i < phnum; ++i)
-                       if (u->p64[i].p_type == PT_DYNAMIC)
-                         {
-                           dyn_vaddr = u->p64[i].p_vaddr;
-                           dyn_filesz = u->p64[i].p_filesz;
-                           break;
-                         }
+                       if (consider_phdr (u->p64[i].p_type,
+                                          u->p64[i].p_vaddr,
+                                          u->p64[i].p_filesz))
+                         break;
                    }
                }
 
@@ -775,6 +798,9 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
       /* If we found PT_DYNAMIC, search it for DT_DEBUG.  */
       if (dyn_filesz != 0)
        {
+         if (dyn_bias != (GElf_Addr) -1)
+           dyn_vaddr += dyn_bias;
+
          Elf_Data in =
            {
              .d_type = ELF_T_DYN,