[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