diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index b52392aeced..eea966d6b32 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -358,6 +358,7 @@ struct module enum module_type type : 16; unsigned short is_virtual : 1; DWORD64 reloc_delta; + WCHAR* real_path; /* specific information for debug types */ struct module_format* format_info[DFI_LAST]; diff --git a/dlls/dbghelp/image_private.h b/dlls/dbghelp/image_private.h index a29794ef582..b6c7a0728f6 100644 --- a/dlls/dbghelp/image_private.h +++ b/dlls/dbghelp/image_private.h @@ -110,6 +110,7 @@ struct image_file_map { HANDLE hMap; IMAGE_NT_HEADERS ntheader; + BOOL builtin; unsigned full_count; void* full_map; struct diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index fe8ed351081..ef68a15700d 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -705,6 +705,7 @@ BOOL module_remove(struct process* pcs, struct module* module) hash_table_destroy(&module->ht_types); HeapFree(GetProcessHeap(), 0, module->sources); HeapFree(GetProcessHeap(), 0, module->addr_sorttab); + HeapFree(GetProcessHeap(), 0, module->real_path); pool_destroy(&module->pool); /* native dbghelp doesn't invoke registered callback(,CBA_SYMBOLS_UNLOADED,) here * so do we diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index 0f00b684baa..d0dca134d70 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -33,6 +33,7 @@ #include "image_private.h" #include "winternl.h" #include "wine/debug.h" +#include "wine/heap.h" WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); @@ -41,6 +42,8 @@ struct pe_module_info struct image_file_map fmap; }; +static const char builtin_signature[] = "Wine builtin DLL"; + static void* pe_map_full(struct image_file_map* fmap, IMAGE_NT_HEADERS** nth) { if (!fmap->u.pe.full_map) @@ -230,6 +233,8 @@ static BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_ty case 0x20b: fmap->addr_size = 64; break; default: return FALSE; } + + fmap->u.pe.builtin = !memcmp((const IMAGE_DOS_HEADER*)mapping + 1, builtin_signature, sizeof(builtin_signature)); section = (IMAGE_SECTION_HEADER*) ((char*)&nthdr->OptionalHeader + nthdr->FileHeader.SizeOfOptionalHeader); fmap->u.pe.sect = HeapAlloc(GetProcessHeap(), 0, @@ -722,6 +727,70 @@ BOOL pe_load_debug_info(const struct process* pcs, struct module* module) return ret; } +static WCHAR *find_builtin_pe(const WCHAR *path, HANDLE *file) +{ + const WCHAR *base_name; + size_t len, i; + WCHAR *buf; + + static const WCHAR winebuilddirW[] = {'W','I','N','E','B','U','I','L','D','D','I','R',0}; + static const WCHAR winedlldirW[] = {'W','I','N','E','D','L','L','D','I','R','%','u',0}; + + if ((base_name = strrchrW(path, '\\'))) base_name++; + else base_name = path; + + if ((len = GetEnvironmentVariableW(winebuilddirW, NULL, 0))) + { + WCHAR *p, *end; + const WCHAR dllsW[] = { '\\','d','l','l','s','\\' }; + const WCHAR programsW[] = { '\\','p','r','o','g','r','a','m','s','\\' }; + const WCHAR dot_dllW[] = {'.','d','l','l',0}; + const WCHAR dot_exeW[] = {'.','e','x','e',0}; + + if (!(buf = heap_alloc((len + 8 + 2 * lstrlenW(base_name)) * sizeof(WCHAR)))) return NULL; + end = buf + GetEnvironmentVariableW(winebuilddirW, buf, len); + + memcpy(end, dllsW, sizeof(dllsW)); + strcpyW(end + ARRAY_SIZE(dllsW), base_name); + if ((p = strchrW(end, '.')) && !lstrcmpW(p, dot_dllW)) *p = 0; + p = end + strlenW(end); + *p++ = '\\'; + strcpyW(p, base_name); + *file = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (*file != INVALID_HANDLE_VALUE) return buf; + + memcpy(end, programsW, sizeof(programsW)); + end += ARRAY_SIZE(programsW); + strcpyW(end, base_name); + if ((p = strchrW(end, '.')) && !lstrcmpW(p, dot_exeW)) *p = 0; + p = end + strlenW(end); + *p++ = '\\'; + strcpyW(p, base_name); + *file = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (*file != INVALID_HANDLE_VALUE) return buf; + + heap_free(buf); + } + + for (i = 0;; i++) + { + WCHAR name[64]; + sprintfW(name, winedlldirW, i); + if (!(len = GetEnvironmentVariableW(name, NULL, 0))) break; + if (!(buf = heap_alloc((len + lstrlenW(base_name) + 2) * sizeof(WCHAR)))) return NULL; + + GetEnvironmentVariableW(name, buf, len); + buf[len++] = '\\'; + strcpyW(buf + len, base_name); + *file = CreateFileW(buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (*file != INVALID_HANDLE_VALUE) return buf; + + heap_free(buf); + } + + return NULL; +} + /****************************************************************** * pe_load_native_module * @@ -751,6 +820,19 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, modfmt->u.pe_info = (struct pe_module_info*)(modfmt + 1); if (pe_map_file(hFile, &modfmt->u.pe_info->fmap, DMT_PE)) { + WCHAR *builtin_path = NULL; + HANDLE builtin_module; + if (modfmt->u.pe_info->fmap.u.pe.builtin && (builtin_path = find_builtin_pe(loaded_name, &builtin_module))) + { + struct image_file_map builtin_fmap; + if (pe_map_file(builtin_module, &builtin_fmap, DMT_PE)) + { + TRACE("reloaded %s from %s\n", debugstr_w(loaded_name), debugstr_w(builtin_path)); + pe_unmap_file(&modfmt->u.pe_info->fmap); + modfmt->u.pe_info->fmap = builtin_fmap; + } + CloseHandle(builtin_module); + } if (!base) base = modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.ImageBase; if (!size) size = modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.SizeOfImage; @@ -759,6 +841,7 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, modfmt->u.pe_info->fmap.u.pe.ntheader.OptionalHeader.CheckSum); if (module) { + module->real_path = builtin_path; modfmt->module = module; modfmt->remove = pe_module_remove; modfmt->loc_compute = NULL; @@ -773,6 +856,7 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, else { ERR("could not load the module '%s'\n", debugstr_w(loaded_name)); + heap_free(module->real_path); pe_unmap_file(&modfmt->u.pe_info->fmap); } }