[PATCH] [DbgHelp]: use build-id information to locate debug information (and prefer it over .debug_link when both are present)

Eric Pouech eric.pouech at orange.fr
Thu May 31 14:41:23 CDT 2012


this fixes some bad search on Linuxen where /usr/lib64 and /lib64 are merged, whilst /usr/lib/debug/lib64 and /usr/lib/debug/usr/lib64 are not

A+
---

 dlls/dbghelp/elf_module.c |  163 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 132 insertions(+), 31 deletions(-)


diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c
index e18c9ef..80352bc 100644
--- a/dlls/dbghelp/elf_module.c
+++ b/dlls/dbghelp/elf_module.c
@@ -890,25 +890,140 @@ found:
 }
 
 /******************************************************************
- *		elf_debuglink_parse
+ *		elf_locate_build_id_target
  *
- * Parses a .gnu_debuglink section and loads the debug info from
- * the external file specified there.
+ * Try to find the .so file containing the debug info out of the build-id note information
  */
-static BOOL elf_debuglink_parse(struct image_file_map* fmap, const struct module* module,
-                                const BYTE* debuglink)
+static BOOL elf_locate_build_id_target(struct image_file_map* fmap, const BYTE* id, unsigned idlen)
 {
-    /* The content of a debug link section is:
-     * 1/ a NULL terminated string, containing the file name for the
-     *    debug info
-     * 2/ padding on 4 byte boundary
-     * 3/ CRC of the linked ELF file
-     */
-    const char* dbg_link = (const char*)debuglink;
-    DWORD crc;
+    static const WCHAR globalDebugDirW[] = {'/','u','s','r','/','l','i','b','/','d','e','b','u','g','/'};
+    static const WCHAR buildidW[] = {'.','b','u','i','l','d','-','i','d','/'};
+    static const WCHAR dotDebug0W[] = {'.','d','e','b','u','g',0};
+    struct image_file_map* fmap_link = NULL;
+    WCHAR* p;
+    WCHAR* z;
+    const BYTE* idend = id + idlen;
+    struct elf_map_file_data emfd;
+
+    fmap_link = HeapAlloc(GetProcessHeap(), 0, sizeof(*fmap_link));
+    if (!fmap_link) return FALSE;
+
+    p = HeapAlloc(GetProcessHeap(), 0,
+                  sizeof(globalDebugDirW) + sizeof(buildidW) +
+                  (idlen * 2 + 1) * sizeof(WCHAR) + sizeof(dotDebug0W));
+    z = p;
+    memcpy(z, globalDebugDirW, sizeof(globalDebugDirW));
+    z += sizeof(globalDebugDirW) / sizeof(WCHAR);
+    memcpy(z, buildidW, sizeof(buildidW));
+    z += sizeof(buildidW) / sizeof(WCHAR);
+
+    if (id < idend)
+    {
+        *z++ = "0123456789abcdef"[*id >> 4  ];
+        *z++ = "0123456789abcdef"[*id & 0x0F];
+        id++;
+    }
+    if (id < idend)
+        *z++ = '/';
+    while (id < idend)
+    {
+        *z++ = "0123456789abcdef"[*id >> 4  ];
+        *z++ = "0123456789abcdef"[*id & 0x0F];
+        id++;
+    }
+    memcpy(z, dotDebug0W, sizeof(dotDebug0W));
+    TRACE("checking %s\n", wine_dbgstr_w(p));
+
+    emfd.kind = from_file;
+    emfd.u.file.filename = p;
+    if (elf_map_file(&emfd, fmap_link))
+    {
+        struct image_section_map buildid_sect;
+        if (elf_find_section(fmap_link, ".note.gnu.build-id", SHT_NULL, &buildid_sect))
+        {
+            const uint32_t* note;
 
-    crc = *(const DWORD*)(dbg_link + ((DWORD_PTR)(strlen(dbg_link) + 4) & ~3));
-    return elf_locate_debug_link(fmap, dbg_link, module->module.LoadedImageName, crc);
+            note = (const uint32_t*)image_map_section(&buildid_sect);
+            if (note != IMAGE_NO_MAP)
+            {
+                /* the usual ELF note structure: name-size desc-size type <name> <desc> */
+                if (note[2] == NT_GNU_BUILD_ID)
+                {
+                    if (note[1] == idlen &&
+                        !memcmp(note + 3 + ((note[0] + 3) >> 2), idend - idlen, idlen))
+                    {
+                        TRACE("Located debug information file at %s\n", debugstr_w(p));
+                        HeapFree(GetProcessHeap(), 0, p);
+                        fmap->u.elf.alternate = fmap_link;
+                        return TRUE;
+                    }
+                    WARN("mismatch in buildid information for %s\n", wine_dbgstr_w(p));
+                }
+            }
+            image_unmap_section(&buildid_sect);
+        }
+        elf_unmap_file(fmap_link);
+    }
+
+    TRACE("not found\n");
+    HeapFree(GetProcessHeap(), 0, p);
+    HeapFree(GetProcessHeap(), 0, fmap_link);
+    return FALSE;
+}
+
+/******************************************************************
+ *		elf_check_alternate
+ *
+ * Load alternate files for a given ELF file, looking at either .note.gnu_build-id
+ * or .gnu_debuglink sections.
+ */
+static BOOL elf_check_alternate(struct image_file_map* fmap, const struct module* module)
+{
+    BOOL ret = FALSE;
+    BOOL found = FALSE;
+    struct image_section_map buildid_sect, debuglink_sect;
+
+    /* if present, add the .gnu_debuglink file as an alternate to current one */
+    if (elf_find_section(fmap, ".note.gnu.build-id", SHT_NULL, &buildid_sect))
+    {
+        const uint32_t* note;
+
+        found = TRUE;
+        note = (const uint32_t*)image_map_section(&buildid_sect);
+        if (note != IMAGE_NO_MAP)
+        {
+            /* the usual ELF note structure: name-size desc-size type <name> <desc> */
+            if (note[2] == NT_GNU_BUILD_ID)
+            {
+                ret = elf_locate_build_id_target(fmap, (const BYTE*)(note + 3 + ((note[0] + 3) >> 2)), note[1]);
+            }
+        }
+        image_unmap_section(&buildid_sect);
+    }
+    /* if present, add the .gnu_debuglink file as an alternate to current one */
+    if (!ret && elf_find_section(fmap, ".gnu_debuglink", SHT_NULL, &debuglink_sect))
+    {
+        const char* dbg_link;
+
+        found = TRUE;
+        dbg_link = (const char*)image_map_section(&debuglink_sect);
+        if (dbg_link != IMAGE_NO_MAP)
+        {
+            /* The content of a debug link section is:
+             * 1/ a NULL terminated string, containing the file name for the
+             *    debug info
+             * 2/ padding on 4 byte boundary
+             * 3/ CRC of the linked ELF file
+             */
+            DWORD crc = *(const DWORD*)(dbg_link + ((DWORD_PTR)(strlen(dbg_link) + 4) & ~3));
+            ret = elf_locate_debug_link(fmap, dbg_link, module->module.LoadedImageName, crc);
+            if (!ret)
+                WARN("Couldn't load linked debug file for %s\n",
+                     debugstr_w(module->module.ModuleName));
+        }
+        image_unmap_section(&debuglink_sect);
+    }
+    return found ? ret : TRUE;
 }
 
 /******************************************************************
@@ -949,24 +1064,10 @@ static BOOL elf_load_debug_info_from_map(struct module* module,
     if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
     {
         struct image_section_map stab_sect, stabstr_sect;
-        struct image_section_map debuglink_sect;
 
-        /* if present, add the .gnu_debuglink file as an alternate to current one */
-	if (elf_find_section(fmap, ".gnu_debuglink", SHT_NULL, &debuglink_sect))
-        {
-            const BYTE* dbg_link;
+        /* check if we need an alternate file (from debuglink or build-id) */
+        ret = elf_check_alternate(fmap, module);
 
-            dbg_link = (const BYTE*)image_map_section(&debuglink_sect);
-            if (dbg_link != IMAGE_NO_MAP)
-            {
-                lret = elf_debuglink_parse(fmap, module, dbg_link);
-                if (!lret)
-		    WARN("Couldn't load linked debug file for %s\n",
-                         debugstr_w(module->module.ModuleName));
-                ret = ret || lret;
-            }
-            image_unmap_section(&debuglink_sect);
-        }
         if (elf_find_section(fmap, ".stab", SHT_NULL, &stab_sect) &&
             elf_find_section(fmap, ".stabstr", SHT_NULL, &stabstr_sect))
         {




More information about the wine-patches mailing list