mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
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:
parent
3cce9ad9c6
commit
d600115387
3 changed files with 212 additions and 20 deletions
|
@ -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*
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue