[PATCH 1/3] [DbgHelp]: improve the symbol loader

Eric Pouech eric.pouech at orange.fr
Fri Aug 29 14:50:46 CDT 2008


- when looking for a PDB file, no longer use SymFindFileInPath as it doesn't actually check the signatures, but use an internal function instead
- allow the search to be done in a multi-pass manner:
	+ first, find in the process search directory list for a file matching all attributes
	+ if not found, then search in the same list for a file matching partially the attributes
          if SYMOPT_LOAD_ANYTHING option is activated

A+
---

 dlls/dbghelp/dbghelp_private.h |    4 +
 dlls/dbghelp/msc.c             |   23 +---
 dlls/dbghelp/path.c            |  206 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+), 20 deletions(-)


diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h
index e4cae5b..ec221be 100644
--- a/dlls/dbghelp/dbghelp_private.h
+++ b/dlls/dbghelp/dbghelp_private.h
@@ -473,6 +473,10 @@ extern BOOL         pe_load_debug_directory(const struct process* pcs,
                                             const IMAGE_DEBUG_DIRECTORY* dbg, int nDbg);
 extern BOOL         pdb_fetch_file_info(struct pdb_lookup* pdb_lookup);
 
+/* path.c */
+extern BOOL         path_find_symbol_file(const struct process* pcs, PCSTR full_path,
+                                          const GUID* guid, DWORD dw1, DWORD dw2, PSTR buffer);
+
 /* pe_module.c */
 extern BOOL         pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth);
 extern struct module*
diff --git a/dlls/dbghelp/msc.c b/dlls/dbghelp/msc.c
index 022ad24..04b0224 100644
--- a/dlls/dbghelp/msc.c
+++ b/dlls/dbghelp/msc.c
@@ -1952,18 +1952,6 @@ static void pdb_convert_symbol_file(const PDB_SYMBOLS* symbols,
     }
 }
 
-static BOOL CALLBACK pdb_match(const char* file, void* user)
-{
-    /* accept first file that exists */
-    HANDLE h = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-    TRACE("match with %s returns %p\n", file, h);
-    if (INVALID_HANDLE_VALUE != h) {
-        CloseHandle(h);
-        return FALSE;
-    }
-    return TRUE;
-}
-
 static HANDLE open_pdb_file(const struct process* pcs,
                             const struct pdb_lookup* lookup)
 {
@@ -1974,15 +1962,12 @@ static HANDLE open_pdb_file(const struct process* pcs,
     switch (lookup->kind)
     {
     case PDB_JG:
-        ret = SymFindFileInPath(pcs->handle, NULL, lookup->filename, 
-                                (PVOID)(DWORD_PTR)lookup->u.jg.timestamp,
-                                lookup->age, 0, SSRVOPT_DWORD,
-                                dbg_file_path, pdb_match, NULL);
+        ret = path_find_symbol_file(pcs, lookup->filename, NULL, lookup->u.jg.timestamp,
+                                    lookup->age, dbg_file_path);
         break;
     case PDB_DS:
-        ret = SymFindFileInPath(pcs->handle, NULL, lookup->filename, 
-                                (PVOID)&lookup->u.ds.guid, lookup->age, 0, 
-                                SSRVOPT_GUIDPTR, dbg_file_path, pdb_match, NULL);
+        ret = path_find_symbol_file(pcs, lookup->filename, &lookup->u.ds.guid, 0,
+                                    lookup->age, dbg_file_path);
         break;
     }
     if (!ret)
diff --git a/dlls/dbghelp/path.c b/dlls/dbghelp/path.c
index 7057e26..04a0a0c 100644
--- a/dlls/dbghelp/path.c
+++ b/dlls/dbghelp/path.c
@@ -1,7 +1,7 @@
 /*
  * File path.c - managing path in debugging environments
  *
- * Copyright (C) 2004, Eric Pouech
+ * Copyright (C) 2004,2008, Eric Pouech
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -555,3 +555,207 @@ BOOL WINAPI SymFindFileInPath(HANDLE hProcess, PCSTR searchPath, PCSTR full_path
         WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
     return ret;
 }
+
+struct module_find
+{
+    enum module_type            kind;
+    /* pe:  dw1         DWORD:timestamp
+     *      dw2         size of image (from PE header)
+     * pdb: guid        PDB guid (if DS PDB file)
+     *      or dw1      PDB timestamp (if JG PDB file)
+     *      dw2         PDB age
+     * elf: dw1         DWORD:CRC 32 of ELF image (Wine only)
+     */
+    const GUID*                 guid;
+    DWORD                       dw1;
+    DWORD                       dw2;
+    WCHAR                       filename[MAX_PATH];
+    unsigned                    matched;
+};
+
+/* checks that buffer (as found by matching the name) matches the info
+ * (information is based on file type)
+ * returns TRUE when file is found, FALSE to continue searching
+ * (NB this is the opposite convention of SymFindFileInPathProc)
+ */
+static BOOL CALLBACK module_find_cb(PCWSTR buffer, PVOID user)
+{
+    struct module_find* mf = (struct module_find*)user;
+    DWORD               size, checksum;
+    unsigned            matched = 0;
+
+    /* the matching weights:
+     * +1 if a file with same name is found and is a decent file of expected type
+     * +1 if first parameter and second parameter match
+     */
+
+    /* FIXME: should check that id/two match the file pointed
+     * by buffer
+     */
+    switch (mf->kind)
+    {
+    case DMT_PE:
+        {
+            HANDLE  hFile, hMap;
+            void*   mapping;
+            DWORD   timestamp;
+
+            timestamp = ~mf->dw1;
+            size = ~mf->dw2;
+            hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, NULL,
+                                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+            if (hFile == INVALID_HANDLE_VALUE) return FALSE;
+            if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
+            {
+                if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
+                {
+                    IMAGE_NT_HEADERS*   nth = RtlImageNtHeader(mapping);
+
+                    matched++;
+                    timestamp = nth->FileHeader.TimeDateStamp;
+                    size = nth->OptionalHeader.SizeOfImage;
+                    UnmapViewOfFile(mapping);
+                }
+                CloseHandle(hMap);
+            }
+            CloseHandle(hFile);
+            if (timestamp != mf->dw1)
+                WARN("Found %s, but wrong timestamp\n", debugstr_w(buffer));
+            if (size != mf->dw2)
+                WARN("Found %s, but wrong size\n", debugstr_w(buffer));
+            if (timestamp == mf->dw1 && size == mf->dw2) matched++;
+        }
+        break;
+    case DMT_ELF:
+        if (elf_fetch_file_info(buffer, 0, &size, &checksum))
+        {
+            matched++;
+            if (checksum == mf->dw1) matched++;
+            else
+                WARN("Found %s, but wrong checksums: %08x %08x\n",
+                     debugstr_w(buffer), checksum, mf->dw1);
+        }
+        else
+        {
+            WARN("Couldn't read %s\n", debugstr_w(buffer));
+            return FALSE;
+        }
+        break;
+    case DMT_PDB:
+        {
+            struct pdb_lookup   pdb_lookup;
+            char                fn[MAX_PATH];
+
+            WideCharToMultiByte(CP_ACP, 0, buffer, -1, fn, MAX_PATH, NULL, NULL);
+            pdb_lookup.filename = fn;
+
+            if (!pdb_fetch_file_info(&pdb_lookup)) return FALSE;
+            matched++;
+            switch (pdb_lookup.kind)
+            {
+            case PDB_JG:
+                if (mf->guid)
+                {
+                    WARN("Found %s, but wrong PDB version\n", debugstr_w(buffer));
+                }
+                else if (pdb_lookup.u.jg.timestamp == mf->dw1)
+                    matched++;
+                else
+                    WARN("Found %s, but wrong signature: %08x %08x\n",
+                         debugstr_w(buffer), pdb_lookup.u.jg.timestamp, mf->dw1);
+                break;
+            case PDB_DS:
+                if (!mf->guid)
+                {
+                    WARN("Found %s, but wrong PDB version\n", debugstr_w(buffer));
+                }
+                else if (!memcmp(&pdb_lookup.u.ds.guid, mf->guid, sizeof(GUID)))
+                    matched++;
+                else
+                    WARN("Found %s, but wrong GUID: %s %s\n",
+                         debugstr_w(buffer), debugstr_guid(&pdb_lookup.u.ds.guid),
+                         debugstr_guid(mf->guid));
+                break;
+            }
+            if (pdb_lookup.age != mf->dw2)
+            {
+                matched--;
+                WARN("Found %s, but wrong age: %08x %08x\n",
+                     debugstr_w(buffer), pdb_lookup.age, mf->dw2);
+            }
+        }
+        break;
+    default:
+        FIXME("What the heck??\n");
+        return FALSE;
+    }
+    if (matched > mf->matched)
+    {
+        strcpyW(mf->filename, buffer);
+        mf->matched = matched;
+    }
+    /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
+     * convention to stop/continue enumeration. sigh.
+     */
+    return mf->matched == 2;
+}
+
+BOOL path_find_symbol_file(const struct process* pcs, PCSTR full_path,
+                           const GUID* guid, DWORD dw1, DWORD dw2, PSTR buffer)
+{
+    struct module_find  mf;
+    WCHAR               full_pathW[MAX_PATH];
+    WCHAR               tmp[MAX_PATH];
+    WCHAR*              ptr;
+    const WCHAR*        filename;
+    WCHAR*              searchPath = pcs->search_path;
+
+    TRACE("(pcs = %p, full_path = %s, guid = %s, dw1 = 0x%08x, dw2 = 0x%08x, buffer = %p)\n",
+          pcs, debugstr_a(full_path), debugstr_guid(guid), dw1, dw2, buffer);
+
+    mf.guid = guid;
+    mf.dw1 = dw1;
+    mf.dw2 = dw2;
+    mf.matched = 0;
+
+    MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH);
+    filename = file_nameW(full_pathW);
+    mf.kind = module_get_type_by_name(filename);
+
+    /* first check full path to file */
+    if (module_find_cb(full_pathW, &mf))
+    {
+        WideCharToMultiByte(CP_ACP, 0, full_pathW, -1, buffer, MAX_PATH, NULL, NULL);
+        return TRUE;
+    }
+
+    while (searchPath)
+    {
+        ptr = strchrW(searchPath, ';');
+        if (ptr)
+        {
+            memcpy(tmp, searchPath, (ptr - searchPath) * sizeof(WCHAR));
+            tmp[ptr - searchPath] = '\0';
+            searchPath = ptr + 1;
+        }
+        else
+        {
+            strcpyW(tmp, searchPath);
+            searchPath = NULL;
+        }
+        if (do_searchW(filename, tmp, FALSE, module_find_cb, &mf))
+        {
+            /* return first fully matched file */
+            WideCharToMultiByte(CP_ACP, 0, tmp, -1, buffer, MAX_PATH, NULL, NULL);
+            return TRUE;
+        }
+    }
+    /* if no fully matching file is found, return the best matching file if any */
+    if ((dbghelp_options & SYMOPT_LOAD_ANYTHING) && mf.matched)
+    {
+        WideCharToMultiByte(CP_ACP, 0, mf.filename, -1, buffer, MAX_PATH, NULL, NULL);
+        return TRUE;
+    }
+    return FALSE;
+}
+





More information about the wine-patches mailing list