From 7ea69cc7eac3d8c96dfdf6fc8433be38ecf61626 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Tue, 29 Mar 2005 13:14:08 +0000 Subject: [PATCH] - Various improvements for minidump module information . added timestamp & checksum in PE module . added size & checksum in ELF module . wine loader now appears with its pathname. - Implemented PE & ELF timestamp & checksum validation in SymFindFileInPath. --- dlls/dbghelp/dbghelp_private.h | 5 ++ dlls/dbghelp/elf_module.c | 68 +++++++++++++++++------ dlls/dbghelp/minidump.c | 54 +++++++++++++------ dlls/dbghelp/module.c | 58 +++++++++++--------- dlls/dbghelp/path.c | 98 ++++++++++++++++++++++++++++++---- dlls/dbghelp/pe_module.c | 24 ++++++--- include/dbghelp.h | 29 ++++++++++ 7 files changed, 262 insertions(+), 74 deletions(-) diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index b9ef1eb5d31..2480fae37be 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -249,6 +249,7 @@ enum module_type DMT_UNKNOWN, /* for lookup, not actually used for a module */ DMT_ELF, /* a real ELF shared module */ DMT_PE, /* a native or builtin PE module */ + DMT_PDB, /* PDB file */ }; struct module @@ -295,6 +296,7 @@ extern HANDLE hMsvcrt; /* elf_module.c */ typedef BOOL (*elf_enum_modules_cb)(const char*, unsigned long addr, void* user); extern BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb, void*); +extern BOOL elf_fetch_file_info(const char* name, DWORD* base, DWORD* size, DWORD* checksum); struct elf_file_map; extern BOOL elf_load_debug_info(struct module* module, struct elf_file_map* fmap); extern struct module* @@ -324,6 +326,8 @@ extern struct module* extern struct module* module_get_containee(const struct process* pcs, const struct module* inner); +extern enum module_type + module_get_type_by_name(const char* name); extern void module_reset_debug_info(struct module* module); extern BOOL module_remove(struct process* pcs, struct module* module); @@ -334,6 +338,7 @@ extern BOOL pe_load_debug_directory(const struct process* pcs, const IMAGE_SECTION_HEADER* sectp, DWORD nsect, const IMAGE_DEBUG_DIRECTORY* dbg, int nDbg); /* pe_module.c */ +extern BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth); extern struct module* pe_load_module(struct process* pcs, char* name, HANDLE hFile, DWORD base, DWORD size); diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c index a5d3c02dd9c..6f6351f01d2 100644 --- a/dlls/dbghelp/elf_module.c +++ b/dlls/dbghelp/elf_module.c @@ -81,12 +81,14 @@ struct elf_module_info #define ELF_INFO_DEBUG_HEADER 0x0001 #define ELF_INFO_MODULE 0x0002 +#define ELF_INFO_NAME 0x0004 struct elf_info { unsigned flags; /* IN one (or several) of the ELF_INFO constants */ unsigned long dbg_hdr_addr; /* OUT address of debug header (if ELF_INFO_DEBUG_HEADER is set) */ struct module* module; /* OUT loaded module (if ELF_INFO_MODULE is set) */ + const char* module_name; /* OUT found module name (if ELF_INFO_NAME is set) */ }; #define NO_MAP ((const void*)0xffffffff) @@ -139,7 +141,8 @@ static const char* elf_map_section(struct elf_file_map* fmap, int sidx) return NO_MAP; /* align required information on page size (we assume pagesize is a power of 2) */ ofst = fmap->sect[sidx].shdr.sh_offset & ~(pgsz - 1); - size = (fmap->sect[sidx].shdr.sh_offset + fmap->sect[sidx].shdr.sh_size + pgsz - 1) & ~(pgsz - 1); + size = (fmap->sect[sidx].shdr.sh_offset + + fmap->sect[sidx].shdr.sh_size + pgsz - 1) & ~(pgsz - 1); fmap->sect[sidx].mapped = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fmap->fd, ofst); if (fmap->sect[sidx].mapped == NO_MAP) return NO_MAP; return fmap->sect[sidx].mapped + (fmap->sect[sidx].shdr.sh_offset & (pgsz - 1)); @@ -188,7 +191,8 @@ static BOOL elf_map_file(const char* filename, struct elf_file_map* fmap) if (memcmp(fmap->elfhdr.e_ident, elf_signature, sizeof(elf_signature))) return FALSE; - fmap->sect = HeapAlloc(GetProcessHeap(), 0, fmap->elfhdr.e_shnum * sizeof(fmap->sect[0])); + fmap->sect = HeapAlloc(GetProcessHeap(), 0, + fmap->elfhdr.e_shnum * sizeof(fmap->sect[0])); if (!fmap->sect) return FALSE; lseek(fmap->fd, fmap->elfhdr.e_shoff, SEEK_SET); @@ -800,7 +804,8 @@ static BOOL elf_load_debug_info_from_map(struct module* module, shstrtab = elf_map_section(fmap, fmap->elfhdr.e_shstrndx); if (shstrtab == NO_MAP) return FALSE; - symtab_sect = dynsym_sect = stab_sect = stabstr_sect = debug_sect = debuglink_sect = -1; + symtab_sect = dynsym_sect = stab_sect = stabstr_sect = + debug_sect = debuglink_sect = -1; for (i = 0; i < fmap->elfhdr.e_shnum; i++) { @@ -867,7 +872,8 @@ static BOOL elf_load_debug_info_from_map(struct module* module, else if (debug_sect != -1) { /* Dwarf 2 debug information */ - FIXME("Unsupported Dwarf2 information for %s\n", module->module.ModuleName); + FIXME("Unsupported Dwarf2 information for %s\n", + module->module.ModuleName); } else if (debuglink_sect != -1) { @@ -876,7 +882,8 @@ static BOOL elf_load_debug_info_from_map(struct module* module, dbg_link = elf_map_section(fmap, debuglink_sect); /* The content of a debug link section is: - * 1/ a NULL terminated string, containing the file name for the debug info + * 1/ a NULL terminated string, containing the file name for the + * debug info * 2/ padding on 4 byte boundary * 3/ CRC of the linked ELF file */ @@ -884,11 +891,14 @@ static BOOL elf_load_debug_info_from_map(struct module* module, { fmap_link.crc = *(const DWORD*)(dbg_link + ((DWORD_PTR)(strlen(dbg_link) + 4) & ~3)); fmap_link.with_crc = 1; - ret = elf_load_debug_info_from_map(module, &fmap_link, pool, ht_symtab); + ret = elf_load_debug_info_from_map(module, &fmap_link, pool, + ht_symtab); if (!ret) WARN("Couldn't load debug information from %s\n", dbg_link); } - else WARN("Couldn't load linked debug file for %s\n", module->module.ModuleName); + else + WARN("Couldn't load linked debug file for %s\n", + module->module.ModuleName); elf_unmap_file(&fmap_link); } } @@ -940,6 +950,22 @@ BOOL elf_load_debug_info(struct module* module, struct elf_file_map* fmap) return ret; } +/****************************************************************** + * elf_fetch_file_info + * + * Gathers some more information for an ELF module from a given file + */ +BOOL elf_fetch_file_info(const char* name, DWORD* base, + DWORD* size, DWORD* checksum) +{ + struct elf_file_map fmap; + if (!elf_map_file(name, &fmap)) return FALSE; + if (base) *base = fmap.elf_start; + *size = fmap.elf_size; + *checksum = calc_crc32(&fmap); + elf_unmap_file(&fmap); + return TRUE; +} /****************************************************************** * is_dt_flag_valid @@ -1033,7 +1059,7 @@ static BOOL elf_load_file(struct process* pcs, const char* filename, if (!elf_module_info) goto leave; elf_info->module = module_new(pcs, filename, DMT_ELF, (load_offset) ? load_offset : fmap.elf_start, - fmap.elf_size, 0, 0); + fmap.elf_size, 0, calc_crc32(&fmap)); if (!elf_info->module) { HeapFree(GetProcessHeap(), 0, elf_module_info); @@ -1053,6 +1079,11 @@ static BOOL elf_load_file(struct process* pcs, const char* filename, elf_info->module->elf_info->elf_loader = 0; } else ret = TRUE; + if (elf_info->flags & ELF_INFO_NAME) + { + elf_info->module_name = strcpy(HeapAlloc(GetProcessHeap(), 0, + strlen(filename) + 1), filename); + } leave: elf_unmap_file(&fmap); @@ -1137,6 +1168,7 @@ static BOOL elf_search_and_load_file(struct process* pcs, const char* filename, * Enumerate ELF modules from a running process */ static BOOL elf_enum_modules_internal(const struct process* pcs, + const char* main_name, elf_enum_modules_cb cb, void* user) { struct r_debug dbg_hdr; @@ -1164,7 +1196,8 @@ static BOOL elf_enum_modules_internal(const struct process* pcs, ReadProcessMemory(pcs->handle, lm.l_name, bufstr, sizeof(bufstr), NULL)) { bufstr[sizeof(bufstr) - 1] = '\0'; - if (!cb(bufstr, lm.l_addr, user)) break; + if (main_name && !bufstr[0]) strcpy(bufstr, main_name); + if (!cb(bufstr, (unsigned long)lm.l_addr, user)) break; } } return TRUE; @@ -1204,7 +1237,7 @@ BOOL elf_synchronize_module_list(struct process* pcs) es.pcs = pcs; es.elf_info.flags = ELF_INFO_MODULE; - if (!elf_enum_modules_internal(pcs, elf_enum_sync_cb, &es)) + if (!elf_enum_modules_internal(pcs, NULL, elf_enum_sync_cb, &es)) return FALSE; module = pcs->lmodules; @@ -1277,13 +1310,16 @@ BOOL elf_enum_modules(HANDLE hProc, elf_enum_modules_cb cb, void* user) { struct process pcs; struct elf_info elf_info; + BOOL ret; memset(&pcs, 0, sizeof(pcs)); pcs.handle = hProc; - elf_info.flags = ELF_INFO_DEBUG_HEADER; + elf_info.flags = ELF_INFO_DEBUG_HEADER | ELF_INFO_NAME; if (!elf_search_loader(&pcs, &elf_info)) return FALSE; pcs.dbg_hdr_addr = elf_info.dbg_hdr_addr; - return elf_enum_modules_internal(&pcs, cb, user); + ret = elf_enum_modules_internal(&pcs, elf_info.module_name, cb, user); + HeapFree(GetProcessHeap(), 0, (char*)elf_info.module_name); + return ret; } struct elf_load @@ -1329,7 +1365,7 @@ struct module* elf_load_module(struct process* pcs, const char* name, DWORD add { struct elf_load el; - TRACE("(%p %s)\n", pcs, name); + TRACE("(%p %s %08lx)\n", pcs, name, addr); el.elf_info.flags = ELF_INFO_MODULE; el.ret = FALSE; @@ -1337,14 +1373,14 @@ struct module* elf_load_module(struct process* pcs, const char* name, DWORD add if (pcs->dbg_hdr_addr) /* we're debugging a life target */ { el.pcs = pcs; - /* do only the lookup from the filename, not the path (as we lookup module name - * in the process' loaded module list) + /* do only the lookup from the filename, not the path (as we lookup module + * name in the process' loaded module list) */ el.name = strrchr(name, '/'); if (!el.name++) el.name = name; el.ret = FALSE; - if (!elf_enum_modules_internal(pcs, elf_load_cb, &el)) + if (!elf_enum_modules_internal(pcs, NULL, elf_load_cb, &el)) return NULL; } else if (addr) diff --git a/dlls/dbghelp/minidump.c b/dlls/dbghelp/minidump.c index abaa5b3bc70..315f1763a94 100644 --- a/dlls/dbghelp/minidump.c +++ b/dlls/dbghelp/minidump.c @@ -1,7 +1,7 @@ /* * File minidump.c - management of dumps (read & write) * - * Copyright (C) 2004, Eric Pouech + * Copyright (C) 2004-2005, Eric Pouech * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -45,6 +45,8 @@ struct dump_module unsigned is_elf; ULONG base; ULONG size; + DWORD timestamp; + DWORD checksum; char name[MAX_PATH]; }; @@ -182,12 +184,15 @@ static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx, * Add a module to a dump context */ static BOOL add_module(struct dump_context* dc, const char* name, - DWORD base, DWORD size, BOOL is_elf) + DWORD base, DWORD size, DWORD timestamp, DWORD checksum, + BOOL is_elf) { if (!dc->module) - dc->module = HeapAlloc(GetProcessHeap(), 0, ++dc->num_module * sizeof(*dc->module)); + dc->module = HeapAlloc(GetProcessHeap(), 0, + ++dc->num_module * sizeof(*dc->module)); else - dc->module = HeapReAlloc(GetProcessHeap(), 0, dc->module, ++dc->num_module * sizeof(*dc->module)); + dc->module = HeapReAlloc(GetProcessHeap(), 0, dc->module, + ++dc->num_module * sizeof(*dc->module)); if (!dc->module) return FALSE; if (is_elf || !GetModuleFileNameExA(dc->hProcess, (HMODULE)base, @@ -197,6 +202,8 @@ static BOOL add_module(struct dump_context* dc, const char* name, sizeof(dc->module[dc->num_module - 1].name)); dc->module[dc->num_module - 1].base = base; dc->module[dc->num_module - 1].size = size; + dc->module[dc->num_module - 1].timestamp = timestamp; + dc->module[dc->num_module - 1].checksum = checksum; dc->module[dc->num_module - 1].is_elf = is_elf; return TRUE; @@ -210,7 +217,14 @@ static BOOL add_module(struct dump_context* dc, const char* name, static BOOL WINAPI fetch_pe_module_info_cb(char* name, DWORD base, DWORD size, void* user) { - return add_module((struct dump_context*)user, name, base, size, FALSE); + struct dump_context* dc = (struct dump_context*)user; + IMAGE_NT_HEADERS nth; + + if (pe_load_nt_header(dc->hProcess, base, &nth)) + add_module((struct dump_context*)user, name, base, size, + nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum, + FALSE); + return TRUE; } /****************************************************************** @@ -221,13 +235,22 @@ static BOOL WINAPI fetch_pe_module_info_cb(char* name, DWORD base, DWORD size, static BOOL fetch_elf_module_info_cb(const char* name, unsigned long base, void* user) { - return add_module((struct dump_context*)user, name, - base, 0 /* FIXME */, TRUE); + struct dump_context* dc = (struct dump_context*)user; + DWORD size, checksum; + + /* FIXME: there's no relevant timestamp on ELF modules */ + /* NB: if we have a non-null base from the live-target use it (whenever + * the ELF module is relocatable or not). If we have a null base (ELF + * module isn't relocatable) then grab its base address from ELF file + */ + if (!elf_fetch_file_info(name, base ? NULL : &base, &size, &checksum)) + size = checksum = 0; + add_module(dc, name, base, size, 0 /* FIXME */, checksum, TRUE); + return TRUE; } static void fetch_module_info(struct dump_context* dc) { - WINE_FIXME("--> %p\n", dc->hProcess); EnumerateLoadedModules(dc->hProcess, fetch_pe_module_info_cb, dc); /* Since we include ELF modules in a separate stream from the regular PE ones, * we can always include those ELF modules (they don't eat lots of space) @@ -352,7 +375,8 @@ static void dump_modules(struct dump_context* dc, BOOL dump_elf) for (i = nmod = 0; i < dc->num_module; i++) { - if ((dc->module[i].is_elf && dump_elf) || (!dc->module[i].is_elf && !dump_elf)) + if ((dc->module[i].is_elf && dump_elf) || + (!dc->module[i].is_elf && !dump_elf)) nmod++; } @@ -366,7 +390,8 @@ static void dump_modules(struct dump_context* dc, BOOL dump_elf) dc->rva += sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod; for (i = 0; i < dc->num_module; i++) { - if ((dc->module[i].is_elf && !dump_elf) || (!dc->module[i].is_elf && dump_elf)) + if ((dc->module[i].is_elf && !dump_elf) || + (!dc->module[i].is_elf && dump_elf)) continue; flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord; @@ -396,8 +421,8 @@ static void dump_modules(struct dump_context* dc, BOOL dump_elf) cbin.u.Module.FullPath = ms->Buffer; cbin.u.Module.BaseOfImage = dc->module[i].base; cbin.u.Module.SizeOfImage = dc->module[i].size; - cbin.u.Module.CheckSum = 0; /* FIXME */ - cbin.u.Module.TimeDateStamp = 0; /* FIXME */ + cbin.u.Module.CheckSum = dc->module[i].checksum; + cbin.u.Module.TimeDateStamp = dc->module[i].timestamp; memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo)); cbin.u.Module.CvRecord = NULL; cbin.u.Module.SizeOfCvRecord = 0; @@ -413,8 +438,8 @@ static void dump_modules(struct dump_context* dc, BOOL dump_elf) { mdModule.BaseOfImage = dc->module[i].base; mdModule.SizeOfImage = dc->module[i].size; - mdModule.CheckSum = 0; /* FIXME */ - mdModule.TimeDateStamp = 0; /* FIXME */ + mdModule.CheckSum = dc->module[i].checksum; + mdModule.TimeDateStamp = dc->module[i].timestamp; mdModule.ModuleNameRva = dc->rva; ms->Length -= sizeof(WCHAR); append(dc, ms, sizeof(ULONG) + ms->Length); @@ -619,7 +644,6 @@ static void dump_misc_info(struct dump_context* dc) /****************************************************************** * MiniDumpWriteDump (DEBUGHLP.@) * - * */ BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile, MINIDUMP_TYPE DumpType, diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index 8d62759fd4d..eae5d75e154 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -76,6 +76,7 @@ struct module* module_new(struct process* pcs, const char* name, { struct module* module; + assert(type == DMT_ELF || type == DMT_PE); if (!(module = HeapAlloc(GetProcessHeap(), 0, sizeof(*module)))) return NULL; @@ -93,7 +94,8 @@ struct module* module_new(struct process* pcs, const char* name, module->module.SizeOfStruct = sizeof(module->module); module->module.BaseOfImage = mod_addr; module->module.ImageSize = size; - module_fill_module(name, module->module.ModuleName, sizeof(module->module.ModuleName)); + module_fill_module(name, module->module.ModuleName, + sizeof(module->module.ModuleName)); module->module.ImageName[0] = '\0'; lstrcpynA(module->module.LoadedImageName, name, sizeof(module->module.LoadedImageName)); module->module.SymType = SymNone; @@ -139,13 +141,15 @@ struct module* module_find_by_name(const struct process* pcs, for (module = pcs->lmodules; module; module = module->next) { - if (type == module->type && !strcasecmp(name, module->module.LoadedImageName)) + if (type == module->type && + !strcasecmp(name, module->module.LoadedImageName)) return module; } module_fill_module(name, modname, sizeof(modname)); for (module = pcs->lmodules; module; module = module->next) { - if (type == module->type && !strcasecmp(modname, module->module.ModuleName)) + if (type == module->type && + !strcasecmp(modname, module->module.ModuleName)) return module; } } @@ -258,7 +262,7 @@ struct module* module_find_by_addr(const struct process* pcs, unsigned long addr return module; } -static BOOL module_is_elf_container_loaded(struct process* pcs, const char* ImageName, +static BOOL module_is_elf_container_loaded(struct process* pcs, const char* ImageName, const char* ModuleName) { char buffer[MAX_PATH]; @@ -281,31 +285,34 @@ static BOOL module_is_elf_container_loaded(struct process* pcs, const char* Imag return FALSE; } -static BOOL elf_is_shared_by_name(const char* name) +/****************************************************************** + * module_get_type_by_name + * + * Guesses a filename type from its extension + */ +enum module_type module_get_type_by_name(const char* name) { const char* ptr; int len = strlen(name); - /* check for terminating .so or .so.[digit]+ */ - while (len) + /* check for terminating .so or .so.[digit] */ + ptr = strrchr(name, '.'); + if (ptr) { - for (ptr = name + len - 1; ptr >= name; ptr--) if (*ptr == '.') break; - if (ptr < name) break; - if (ptr == name + len - 2 && isdigit(ptr[1])) - { - len -= 2; - continue; - } - if (ptr == name + len - 3 && ptr[1] == 's' && ptr[2] == 'o') - return TRUE; - break; + if (!strcmp(ptr, ".so") || + (isdigit(ptr[1]) && !ptr[2] && ptr >= name + 3 && !memcmp(ptr - 3, ".so", 3))) + return DMT_ELF; + else if (!strcasecmp(ptr, ".pdb")) + return DMT_PDB; } - /* wine-[kp]thread is valid too */ - if (((len > 12 && name[len - 13] == '/') || len == 12) && + /* wine-[kp]thread is also an ELF module */ + else if (((len > 12 && name[len - 13] == '/') || len == 12) && (!strcasecmp(name + len - 12, "wine-pthread") || !strcasecmp(name + len - 12, "wine-kthread"))) - return TRUE; - return FALSE; + { + return DMT_ELF; + } + return DMT_PE; } /*********************************************************************** @@ -333,7 +340,8 @@ DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, char* ImageName, if (module_is_elf_container_loaded(pcs, ImageName, ModuleName)) { /* force the loading of DLL as builtin */ - if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll))) + if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, + BaseOfDll, SizeOfDll))) goto done; WARN("Couldn't locate %s\n", ImageName); return 0; @@ -341,12 +349,13 @@ DWORD WINAPI SymLoadModule(HANDLE hProcess, HANDLE hFile, char* ImageName, TRACE("Assuming %s as native DLL\n", ImageName); if (!(module = pe_load_module(pcs, ImageName, hFile, BaseOfDll, SizeOfDll))) { - if (elf_is_shared_by_name(ImageName) && + if (module_get_type_by_name(ImageName) == DMT_ELF && (module = elf_load_module(pcs, ImageName, BaseOfDll))) goto done; FIXME("Should have successfully loaded debug information for image %s\n", ImageName); - if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, BaseOfDll, SizeOfDll))) + if ((module = pe_load_module_from_pcs(pcs, ImageName, ModuleName, + BaseOfDll, SizeOfDll))) goto done; WARN("Couldn't locate %s\n", ImageName); return 0; @@ -461,7 +470,6 @@ BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess, !GetModuleBaseNameA(hProcess, hMods[i], base, sizeof(base))) continue; module_fill_module(base, mod, sizeof(mod)); - EnumLoadedModulesCallback(mod, (DWORD)mi.lpBaseOfDll, mi.SizeOfImage, UserContext); } diff --git a/dlls/dbghelp/path.c b/dlls/dbghelp/path.c index 604998fde3e..dac09baaeee 100644 --- a/dlls/dbghelp/path.c +++ b/dlls/dbghelp/path.c @@ -24,6 +24,10 @@ #include #include "dbghelp_private.h" +#include "ntstatus.h" +#include "winnls.h" +#include "winreg.h" +#include "winternl.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); @@ -140,7 +144,7 @@ BOOL WINAPI SymMatchFileName(char* file, char* match, return mptr == match - 1; } -static BOOL do_search(const char* file, char* buffer, +static BOOL do_search(const char* file, char* buffer, BOOL recurse, PENUMDIRTREE_CALLBACK cb, void* user) { HANDLE h; @@ -161,8 +165,8 @@ static BOOL do_search(const char* file, char* buffer, if (!strcmp(fd.cFileName, ".") || !strcmp(fd.cFileName, "..")) continue; strcpy(buffer + pos, fd.cFileName); - if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - found = do_search(file, buffer, cb, user); + if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + found = do_search(file, buffer, TRUE, cb, user); else if (SymMatchFileName(buffer, (char*)file, NULL, NULL)) { if (!cb || cb(buffer, user)) found = TRUE; @@ -182,7 +186,7 @@ BOOL WINAPI SearchTreeForFile(LPSTR root, LPSTR file, LPSTR buffer) TRACE("(%s, %s, %p)\n", debugstr_a(root), debugstr_a(file), buffer); strcpy(buffer, root); - return do_search(file, buffer, NULL, NULL); + return do_search(file, buffer, TRUE, NULL, NULL); } /****************************************************************** @@ -196,11 +200,19 @@ BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file, TRACE("(%p %s %s %p %p %p)\n", hProcess, root, file, buffer, cb, user); strcpy(buffer, root); - return do_search(file, buffer, cb, user); + return do_search(file, buffer, TRUE, cb, user); } struct sffip { + enum module_type kind; + /* pe: id -> DWORD:timestamp + * two -> size of image (from PE header) + * pdb: id -> PDB signature + * I think either DWORD:timestamp or GUID:guid depending on PDB version + * two -> PDB age ??? + * elf: id -> DWORD:CRC 32 of ELF image (Wine only) + */ PVOID id; DWORD two; DWORD three; @@ -212,11 +224,66 @@ struct sffip static BOOL CALLBACK sffip_cb(LPCSTR buffer, void* user) { struct sffip* s = (struct sffip*)user; - + DWORD size, checksum; + DWORD_PTR timestamp; /* FIXME: should check that id/two/three match the file pointed * by buffer */ - /* yes, EnumDirTree and SymFindFileInPath callbacks use the opposite + switch (s->kind) + { + case DMT_PE: + { + HANDLE hFile, hMap; + void* mapping; + + timestamp = ~(DWORD_PTR)s->id; + size = ~s->two; + hFile = CreateFileA(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) return TRUE; + if ((hMap = CreateFileMappingA(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); + timestamp = nth->FileHeader.TimeDateStamp; + size = nth->OptionalHeader.SizeOfImage; + UnmapViewOfFile(mapping); + } + CloseHandle(hMap); + } + CloseHandle(hFile); + if (timestamp != (DWORD_PTR)s->id || size != s->two) + { + WARN("Found %s, but wrong size or timestamp\n", buffer); + return TRUE; + } + } + break; + case DMT_ELF: + if (elf_fetch_file_info(buffer, 0, &size, &checksum)) + { + if (checksum != (DWORD_PTR)s->id) + { + WARN("Found %s, but wrong checksums: %08lx %08lx\n", + buffer, checksum, (DWORD_PTR)s->id); + return TRUE; + } + } + else + { + WARN("Couldn't read %s\n", buffer); + return TRUE; + } + break; + case DMT_PDB: + FIXME("NIY on '%s'\n", buffer); + break; + default: + FIXME("What the heck??\n"); + return TRUE; + } + /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite * convention to stop/continue enumeration. sigh. */ return !(s->cb)((char*)buffer, s->user); @@ -226,7 +293,7 @@ static BOOL CALLBACK sffip_cb(LPCSTR buffer, void* user) * SymFindFileInPath (DBGHELP.@) * */ -BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR file, +BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR full_path, PVOID id, DWORD two, DWORD three, DWORD flags, LPSTR buffer, PFINDFILEINPATHCALLBACK cb, PVOID user) @@ -235,9 +302,10 @@ BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR file, struct process* pcs = process_find_by_handle(hProcess); char tmp[MAX_PATH]; char* ptr; + char* filename; TRACE("(%p %s %s %p %08lx %08lx %08lx %p %p %p)\n", - hProcess, searchPath, file, id, two, three, flags, + hProcess, searchPath, full_path, id, two, three, flags, buffer, cb, user); if (!pcs) return FALSE; @@ -250,7 +318,15 @@ BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR file, s.cb = cb; s.user = user; - file = file_name(file); + filename = file_name(full_path); + s.kind = module_get_type_by_name(filename); + + /* first check full path to file */ + if (sffip_cb(full_path, &s)) + { + strcpy(buffer, full_path); + return TRUE; + } while (searchPath) { @@ -266,7 +342,7 @@ BOOL WINAPI SymFindFileInPath(HANDLE hProcess, LPSTR searchPath, LPSTR file, strcpy(tmp, searchPath); searchPath = NULL; } - if (EnumDirTree(hProcess, tmp, file, buffer, sffip_cb, &s)) return TRUE; + if (do_search(filename, tmp, FALSE, sffip_cb, &s)) return TRUE; } return FALSE; } diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index d92d2409a82..7ec5bf23417 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -341,7 +341,7 @@ struct module* pe_load_module(struct process* pcs, char* name, /* FIXME SetLastError */ return NULL; } - if ((hFile = FindExecutableImage(name, NULL, loaded_name)) == NULL) + if ((hFile = FindExecutableImage(name, pcs->search_path, loaded_name)) == NULL) return NULL; opened = TRUE; } @@ -380,6 +380,21 @@ struct module* pe_load_module(struct process* pcs, char* name, return module; } +/****************************************************************** + * pe_load_nt_header + * + */ +BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth) +{ + IMAGE_DOS_HEADER dos; + + return ReadProcessMemory(hProc, (char*)base, &dos, sizeof(dos), NULL) && + dos.e_magic == IMAGE_DOS_SIGNATURE && + ReadProcessMemory(hProc, (char*)(base + dos.e_lfanew), + nth, sizeof(*nth), NULL) && + nth->Signature == IMAGE_NT_SIGNATURE; +} + /****************************************************************** * pe_load_module_from_pcs * @@ -408,14 +423,9 @@ struct module* pe_load_module_from_pcs(struct process* pcs, const char* name, { if (pcs->dbg_hdr_addr) { - IMAGE_DOS_HEADER dos; IMAGE_NT_HEADERS nth; - if (ReadProcessMemory(pcs->handle, (char*)base, &dos, sizeof(dos), NULL) && - dos.e_magic == IMAGE_DOS_SIGNATURE && - ReadProcessMemory(pcs->handle, (char*)(base + dos.e_lfanew), - &nth, sizeof(nth), NULL) && - nth.Signature == IMAGE_NT_SIGNATURE) + if (pe_load_nt_header(pcs->handle, base, &nth)) { if (!size) size = nth.OptionalHeader.SizeOfImage; module = module_new(pcs, name, DMT_PE, base, size, diff --git a/include/dbghelp.h b/include/dbghelp.h index aa7bff3593b..7685fbdf06c 100644 --- a/include/dbghelp.h +++ b/include/dbghelp.h @@ -887,6 +887,35 @@ BOOL WINAPI UnmapDebugInformation(PIMAGE_DEBUG_INFORMATION); DWORD WINAPI SymGetOptions(void); DWORD WINAPI SymSetOptions(DWORD); +/* Symbol server bits */ +typedef BOOL (WINAPI* PSYMBOLSERVERPROC)(LPCSTR, LPCSTR, PVOID, DWORD, DWORD, LPSTR); +typedef BOOL (WINAPI* PSYMBOLSERVEROPENPROC)(void); +typedef BOOL (WINAPI* PSYMBOLSERVERCLOSEPROC)(void); +typedef BOOL (WINAPI* PSYMBOLSERVERSETOPTIONSPROC)(UINT_PTR, ULONG64); +typedef BOOL (CALLBACK* PSYMBOLSERVERCALLBACKPROC)(UINT_PTR, ULONG64, ULONG64); +typedef UINT_PTR (WINAPI* PSYMBOLSERVERGETOPTIONSPROC)(); +typedef BOOL (WINAPI* PSYMBOLSERVERPINGPROC)(LPCSTR); + +#define SSRVOPT_CALLBACK 0x0001 +#define SSRVOPT_DWORD 0x0002 +#define SSRVOPT_DWORDPTR 0x0004 +#define SSRVOPT_GUIDPTR 0x0008 +#define SSRVOPT_OLDGUIDPTR 0x0010 +#define SSRVOPT_UNATTENDED 0x0020 +#define SSRVOPT_NOCOPY 0x0040 +#define SSRVOPT_PARENTWIN 0x0080 +#define SSRVOPT_PARAMTYPE 0x0100 +#define SSRVOPT_SECURE 0x0200 +#define SSRVOPT_TRACE 0x0400 +#define SSRVOPT_SETCONTEXT 0x0800 +#define SSRVOPT_PROXY 0x1000 +#define SSRVOPT_DOWNSTREAM_STORE 0x2000 +#define SSRVOPT_RESET ((ULONG_PTR)-1) + +#define SSRVACTION_TRACE 1 +#define SSRVACTION_QUERYCANCEL 2 +#define SSRVACTION_EVENT 3 + #ifdef __cplusplus } /* extern "C" */ #endif /* defined(__cplusplus) */