]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Merge from trunk, revs 11448, 11449, 11458
authorJulian Seward <jseward@acm.org>
Wed, 20 Oct 2010 20:58:24 +0000 (20:58 +0000)
committerJulian Seward <jseward@acm.org>
Wed, 20 Oct 2010 20:58:24 +0000 (20:58 +0000)
(support for using build-id to find debugging information)

git-svn-id: svn://svn.valgrind.org/valgrind/branches/VALGRIND_3_6_BRANCH@11463

coregrind/m_debuginfo/readelf.c

index 12b347aa209e2465c68a270a4af9bdf918788467..7cf8ceb05de975a6cdcc250e087b9edd7ffc11df 100644 (file)
@@ -70,7 +70,9 @@
 #  define  ElfXX_Ehdr     Elf32_Ehdr
 #  define  ElfXX_Shdr     Elf32_Shdr
 #  define  ElfXX_Phdr     Elf32_Phdr
+#  define  ElfXX_Nhdr     Elf32_Nhdr
 #  define  ElfXX_Sym      Elf32_Sym
+#  define  ElfXX_Off      Elf32_Off
 #  define  ElfXX_Word     Elf32_Word
 #  define  ElfXX_Addr     Elf32_Addr
 #  define  ElfXX_Dyn      Elf32_Dyn
@@ -81,7 +83,9 @@
 #  define  ElfXX_Ehdr     Elf64_Ehdr
 #  define  ElfXX_Shdr     Elf64_Shdr
 #  define  ElfXX_Phdr     Elf64_Phdr
+#  define  ElfXX_Nhdr     Elf64_Nhdr
 #  define  ElfXX_Sym      Elf64_Sym
+#  define  ElfXX_Off      Elf64_Off
 #  define  ElfXX_Word     Elf64_Word
 #  define  ElfXX_Addr     Elf64_Addr
 #  define  ElfXX_Dyn      Elf64_Dyn
@@ -851,6 +855,56 @@ void read_elf_symtab__ppc64_linux(
 }
 
 
+/*
+ * Look for a build-id in an ELF image. The build-id specification
+ * can be found here:
+ *
+ * http://fedoraproject.org/wiki/RolandMcGrath/BuildID
+ */
+static
+Char *find_buildid(Addr image, UWord n_image)
+{
+   Char* buildid = NULL;
+   ElfXX_Ehdr* ehdr = (ElfXX_Ehdr*)image;
+
+#ifdef NT_GNU_BUILD_ID
+   if (n_image >= sizeof(ElfXX_Ehdr) &&
+       ML_(is_elf_object_file)(ehdr, n_image)) {
+      Word i;
+
+      for (i = 0; i < ehdr->e_phnum; i++) {
+         ElfXX_Phdr* phdr = (ElfXX_Phdr*)(image + ehdr->e_phoff + i * ehdr->e_phentsize);
+
+         if (phdr->p_type == PT_NOTE) {
+            ElfXX_Off offset =  phdr->p_offset;
+
+            while (offset < phdr->p_offset + phdr->p_filesz) {
+               ElfXX_Nhdr* note = (ElfXX_Nhdr*)(image + offset);
+               Char* name = (Char *)note + sizeof(ElfXX_Nhdr);
+               UChar *desc = (UChar *)name + ((note->n_namesz + 3) & ~3);
+               Word j;
+
+               if (VG_(strcmp)(name, ELF_NOTE_GNU) == 0 &&
+                   note->n_type == NT_GNU_BUILD_ID) {
+                  buildid = ML_(dinfo_zalloc)("di.fbi.1", note->n_descsz * 2 + 1);
+                  
+                  for (j = 0; j < note->n_descsz; j++) {
+                     VG_(sprintf)(buildid + VG_(strlen)(buildid), "%02x", desc[j]);
+                  }
+               }
+
+               offset = offset + sizeof(ElfXX_Nhdr)
+                               + ((note->n_namesz + 3) & ~3)
+                               + ((note->n_descsz + 3) & ~3);
+            }            
+         }
+      }    
+   }
+#endif
+
+   return buildid;
+}
+
 /*
  * This routine for calculating the CRC for a separate debug file
  * is GPLed code borrowed from GNU binutils.
@@ -926,7 +980,7 @@ calc_gnu_debuglink_crc32(UInt crc, const UChar *buf, Int len)
  * not match the value from the main object file.
  */
 static
-Addr open_debug_file( Char* name, UInt crc, /*OUT*/UWord* size )
+Addr open_debug_file( Char* name, Char* buildid, UInt crc, /*OUT*/UWord* size )
 {
    SysRes fd, sres;
    struct vg_stat stat_buf;
@@ -943,7 +997,7 @@ Addr open_debug_file( Char* name, UInt crc, /*OUT*/UWord* size )
 
    if (VG_(clo_verbosity) > 1)
       VG_(message)(Vg_DebugMsg, "  Considering %s ..\n", name);
-
+   
    *size = stat_buf.size;
    
    sres = VG_(am_mmap_file_float_valgrind)
@@ -954,18 +1008,35 @@ Addr open_debug_file( Char* name, UInt crc, /*OUT*/UWord* size )
    if (sr_isError(sres))
       return 0;
 
-   calccrc = calc_gnu_debuglink_crc32(0, (UChar*)sr_Res(sres), *size);
-   if (calccrc != crc) {
-      SysRes res = VG_(am_munmap_valgrind)(sr_Res(sres), *size);
-      vg_assert(!sr_isError(res));
+   if (buildid) {
+      Char* debug_buildid = find_buildid(sr_Res(sres), *size);
+      if (debug_buildid == NULL || VG_(strcmp)(buildid, debug_buildid) != 0) {
+         SysRes res = VG_(am_munmap_valgrind)(sr_Res(sres), *size);
+         vg_assert(!sr_isError(res));
+         if (VG_(clo_verbosity) > 1)
+            VG_(message)(Vg_DebugMsg, 
+               "  .. build-id mismatch (found %s wanted %s)\n", debug_buildid, buildid);
+         ML_(dinfo_free)(debug_buildid);
+         return 0;
+      }
+      ML_(dinfo_free)(debug_buildid);
+
       if (VG_(clo_verbosity) > 1)
-         VG_(message)(Vg_DebugMsg, 
-            "  .. CRC mismatch (computed %08x wanted %08x)\n", calccrc, crc);
-      return 0;
-   }
+         VG_(message)(Vg_DebugMsg, "  .. build-id is valid\n");
+   } else {
+      calccrc = calc_gnu_debuglink_crc32(0, (UChar*)sr_Res(sres), *size);
+      if (calccrc != crc) {
+         SysRes res = VG_(am_munmap_valgrind)(sr_Res(sres), *size);
+         vg_assert(!sr_isError(res));
+         if (VG_(clo_verbosity) > 1)
+            VG_(message)(Vg_DebugMsg, 
+               "  .. CRC mismatch (computed %08x wanted %08x)\n", calccrc, crc);
+         return 0;
+      }
 
-   if (VG_(clo_verbosity) > 1)
-      VG_(message)(Vg_DebugMsg, "  .. CRC is valid\n");
+      if (VG_(clo_verbosity) > 1)
+         VG_(message)(Vg_DebugMsg, "  .. CRC is valid\n");
+   }
    
    return sr_Res(sres);
 }
@@ -975,29 +1046,49 @@ Addr open_debug_file( Char* name, UInt crc, /*OUT*/UWord* size )
  */
 static
 Addr find_debug_file( struct _DebugInfo* di,
-                      Char* objpath, Char* debugname, 
-                      UInt crc, /*OUT*/UWord* size )
+                      Char* objpath, Char* buildid,
+                      Char* debugname, UInt crc,
+                      /*OUT*/UWord* size )
 {
-   Char *objdir = ML_(dinfo_strdup)("di.fdf.1", objpath);
-   Char *objdirptr;
-   Char *debugpath;
+   Char *debugpath = NULL;
    Addr addr = 0;
-  
-   if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL)
-      *objdirptr = '\0';
 
-   debugpath = ML_(dinfo_zalloc)(
-                  "di.fdf.2",
-                  VG_(strlen)(objdir) + VG_(strlen)(debugname) + 32);
-   
-   VG_(sprintf)(debugpath, "%s/%s", objdir, debugname);
+   if (buildid != NULL) {
+      debugpath = ML_(dinfo_zalloc)(
+                     "di.fdf.1",
+                     VG_(strlen)(buildid) + 33);
+
+      VG_(sprintf)(debugpath, "/usr/lib/debug/.build-id/%c%c/%s.debug",
+                   buildid[0], buildid[1], buildid + 2);
+
+      if ((addr = open_debug_file(debugpath, buildid, 0, size)) == 0) {
+         ML_(dinfo_free)(debugpath);
+         debugpath = NULL;
+      }
+   }
+
+   if (addr == 0 && debugname != NULL) {
+      Char *objdir = ML_(dinfo_strdup)("di.fdf.2", objpath);
+      Char *objdirptr;
+
+      if ((objdirptr = VG_(strrchr)(objdir, '/')) != NULL)
+         *objdirptr = '\0';
+
+      debugpath = ML_(dinfo_zalloc)(
+                     "di.fdf.3",
+                     VG_(strlen)(objdir) + VG_(strlen)(debugname) + 32);
 
-   if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
-      VG_(sprintf)(debugpath, "%s/.debug/%s", objdir, debugname);
-      if ((addr = open_debug_file(debugpath, crc, size)) == 0) {
-         VG_(sprintf)(debugpath, "/usr/lib/debug%s/%s", objdir, debugname);
-         addr = open_debug_file(debugpath, crc, size);
+      VG_(sprintf)(debugpath, "%s/%s", objdir, debugname);
+
+      if ((addr = open_debug_file(debugpath, NULL, crc, size)) == 0) {
+         VG_(sprintf)(debugpath, "%s/.debug/%s", objdir, debugname);
+         if ((addr = open_debug_file(debugpath, NULL, crc, size)) == 0) {
+            VG_(sprintf)(debugpath, "/usr/lib/debug%s/%s", objdir, debugname);
+            addr = open_debug_file(debugpath, NULL, crc, size);
+         }
       }
+
+      ML_(dinfo_free)(objdir);
    }
 
    if (addr) {
@@ -1006,8 +1097,7 @@ Addr find_debug_file( struct _DebugInfo* di,
    }
 
    ML_(dinfo_free)(debugpath);
-   ML_(dinfo_free)(objdir);
-   
+
    return addr;
 }
 
@@ -1100,6 +1190,9 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
    Addr     rw_svma_limit = 0;
    PtrdiffT rw_bias = 0;
 
+   /* Build ID */
+   Char* buildid = NULL;
+
    vg_assert(di);
    vg_assert(di->have_rx_map == True);
    vg_assert(di->have_rw_map == True);
@@ -1849,20 +1942,31 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
 
 #        undef FIND
       }
-         
-      /* Did we find a debuglink section? */
-      if (debuglink_img != NULL) {
-         UInt crc_offset = VG_ROUNDUP(VG_(strlen)(debuglink_img)+1, 4);
-         UInt crc;
 
-         vg_assert(crc_offset + sizeof(UInt) <= debuglink_sz);
+      /* Look for a build-id */
+      buildid = find_buildid(oimage, n_oimage);
 
-         /* Extract the CRC from the debuglink section */
-         crc = *(UInt *)(debuglink_img + crc_offset);
+      /* Look for a debug image */
+      if (buildid != NULL || debuglink_img != NULL) {
+         /* Do have a debuglink section? */
+         if (debuglink_img != NULL) {
+            UInt crc_offset = VG_ROUNDUP(VG_(strlen)(debuglink_img)+1, 4);
+            UInt crc;
+
+            vg_assert(crc_offset + sizeof(UInt) <= debuglink_sz);
+
+            /* Extract the CRC from the debuglink section */
+            crc = *(UInt *)(debuglink_img + crc_offset);
+
+            /* See if we can find a matching debug file */
+            dimage = find_debug_file( di, di->filename, buildid,
+                                      debuglink_img, crc, &n_dimage );
+         } else {
+            /* See if we can find a matching debug file */
+            dimage = find_debug_file( di, di->filename, buildid, NULL, 0, &n_dimage );
+         }
 
-         /* See if we can find a matching debug file */
-         dimage = find_debug_file( di, di->filename, debuglink_img,
-                                   crc, &n_dimage );
+         ML_(dinfo_free)(buildid);
 
          if (dimage != 0 
              && n_dimage >= sizeof(ElfXX_Ehdr)