dbghelp: Improve the symbol loader.
When looking for a PDB file, no longer use SymFindFileInPath as it
doesn't actually check the signatures, but use an internal function
instead.
diff --git a/dlls/dbghelp/path.c b/dlls/dbghelp/path.c
index 7057e26..8f06062 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,206 @@
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;
+}