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.
This commit is contained in:
Eric Pouech 2008-08-29 21:50:46 +02:00 committed by Alexandre Julliard
parent 3cce9ad9c6
commit d600115387
3 changed files with 212 additions and 20 deletions

View file

@ -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*

View file

@ -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)

View file

@ -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 @@ 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;
}