This series solves https://bugs.winehq.org/show_bug.cgi?id=54250
The two first patches address proper loading of modules in dbghelp. There are cases where the path sent in the dll load debug event isn't the real path to the loaded module.
The two last patches are to expose the real path of the module for integration in when winedbg acts as a proxy to gdb.
From: Eric Pouech eric.pouech@gmail.com
When the handle to the loaded module is passed in SymLoadModule*(), don't try to search for the module's image path and use only the file handle.
Co-authored-by: Ake Rehnman ake.rehnman@gmail.com Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/pe_module.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index 4a7e68d5483..91a018c526b 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -784,6 +784,7 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, BOOL opened = FALSE; struct module_format* modfmt; WCHAR loaded_name[MAX_PATH]; + WCHAR* real_path = NULL;
loaded_name[0] = '\0'; if (!hFile) @@ -802,11 +803,12 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, if (pe_map_file(hFile, &modfmt->u.pe_info->fmap, DMT_PE)) { struct builtin_search builtin = { NULL }; - if (modfmt->u.pe_info->fmap.u.pe.builtin && search_dll_path(pcs, loaded_name, search_builtin_pe, &builtin)) + if (opened && modfmt->u.pe_info->fmap.u.pe.builtin && search_dll_path(pcs, loaded_name, search_builtin_pe, &builtin)) { TRACE("reloaded %s from %s\n", debugstr_w(loaded_name), debugstr_w(builtin.path)); image_unmap_file(&modfmt->u.pe_info->fmap); modfmt->u.pe_info->fmap = builtin.fmap; + real_path = builtin.path; } if (!base) base = PE_FROM_OPTHDR(&modfmt->u.pe_info->fmap, ImageBase); if (!size) size = PE_FROM_OPTHDR(&modfmt->u.pe_info->fmap, SizeOfImage); @@ -817,7 +819,7 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, modfmt->u.pe_info->fmap.u.pe.file_header.Machine); if (module) { - module->real_path = builtin.path; + module->real_path = real_path; modfmt->module = module; modfmt->remove = pe_module_remove; modfmt->loc_compute = NULL; @@ -827,7 +829,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(builtin.path); + heap_free(real_path); image_unmap_file(&modfmt->u.pe_info->fmap); } }
From: Eric Pouech eric.pouech@gmail.com
In some cases (running from build tree, overriding load order...), the path to the module from the load DLL debug event isn't the real path to the loaded module. So pass the handle to loaded module's image from winedbg to dbghelp (to avoid image lookup).
(fix for bz 54250 in regular winedbg usage)
Signed-off-by: Eric Pouech eric.pouech@gmail.com Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=54250 --- programs/winedbg/winedbg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/programs/winedbg/winedbg.c b/programs/winedbg/winedbg.c index 84ec7802396..aa94f2f18ab 100644 --- a/programs/winedbg/winedbg.c +++ b/programs/winedbg/winedbg.c @@ -377,7 +377,7 @@ BOOL dbg_init(HANDLE hProc, const WCHAR* in, BOOL invade)
BOOL dbg_load_module(HANDLE hProc, HANDLE hFile, const WCHAR* name, DWORD_PTR base, DWORD size) { - BOOL ret = SymLoadModuleExW(hProc, NULL, name, NULL, base, size, NULL, 0); + BOOL ret = SymLoadModuleExW(hProc, hFile, name, NULL, base, size, NULL, 0); if (ret) { IMAGEHLP_MODULEW64 ihm;
From: Ake Rehnman ake.rehnman@gmail.com
Co-authored-by: Eric Pouech eric.pouech@gmail.com Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/pe_module.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index 91a018c526b..80c2f1a1f45 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -26,6 +26,8 @@ #include <string.h> #include <assert.h>
+#include "ntstatus.h" +#define WIN32_NO_STATUS #include "dbghelp_private.h" #include "image_private.h" #include "winternl.h" @@ -796,7 +798,31 @@ struct module* pe_load_native_module(struct process* pcs, const WCHAR* name, return NULL; opened = TRUE; } - else if (name) lstrcpyW(loaded_name, name); + else + { + ULONG sz = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR), needed; + OBJECT_NAME_INFORMATION *obj_name; + NTSTATUS nts; + + obj_name = RtlAllocateHeap(GetProcessHeap(), 0, sz); + if (obj_name) + { + nts = NtQueryObject(hFile, ObjectNameInformation, obj_name, sz, &needed); + if (nts == STATUS_BUFFER_OVERFLOW) + { + sz = needed; + obj_name = RtlReAllocateHeap(GetProcessHeap(), 0, obj_name, sz); + nts = NtQueryObject(hFile, ObjectNameInformation, obj_name, sz, &needed); + } + if (!nts) + { + obj_name->Name.Buffer[obj_name->Name.Length / sizeof(WCHAR)] = L'\0'; + real_path = wcsdup(obj_name->Name.Buffer); + } + RtlFreeHeap(GetProcessHeap(), 0, obj_name); + } + if (name) lstrcpyW(loaded_name, name); + } if (!(modfmt = HeapAlloc(GetProcessHeap(), 0, sizeof(struct module_format) + sizeof(struct pe_module_info)))) return NULL; modfmt->u.pe_info = (struct pe_module_info*)(modfmt + 1);
From: Eric Pouech eric.pouech@gmail.com
Expose the real path of a loaded module (potentially read from WINEDLLDIR or WINEBUILDDIR or overriden load order or ...). This improves gdb integration by passing the real path to the loaded modules (instead of the path:s in c:\windows\ system subdirectories). Introduce new Wine only dbghelp's extended option to enable the feature.
(fix for BZ 54250 in gdb proxy mode) ² Signed-off-by: Eric Pouech eric.pouech@gmail.com Wine-bug: https://bugs.winehq.org/show_bug.cgi?id=54250 --- dlls/dbghelp/dbghelp.c | 7 +++++++ dlls/dbghelp/dbghelp_private.h | 1 + dlls/dbghelp/module.c | 3 +++ include/dbghelp.h | 1 + programs/winedbg/gdbproxy.c | 9 ++++++--- 5 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 2facc58585e..432e9c6b248 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -67,6 +67,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
unsigned dbghelp_options = SYMOPT_UNDNAME; BOOL dbghelp_opt_native = FALSE; +BOOL dbghelp_opt_real_path = FALSE; SYSTEM_INFO sysinfo;
static struct process* process_first /* = NULL */; @@ -602,6 +603,10 @@ BOOL WINAPI SymSetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option, BOOL value) old = dbghelp_opt_native; dbghelp_opt_native = value; break; + case SYMOPT_EX_WINE_MODULE_REAL_PATH: + old = dbghelp_opt_real_path; + dbghelp_opt_real_path = value; + break; default: FIXME("Unsupported option %d with value %d\n", option, value); } @@ -619,6 +624,8 @@ BOOL WINAPI SymGetExtendedOption(IMAGEHLP_EXTENDED_OPTIONS option) { case SYMOPT_EX_WINE_NATIVE_MODULES: return dbghelp_opt_native; + case SYMOPT_EX_WINE_MODULE_REAL_PATH: + return dbghelp_opt_real_path; default: FIXME("Unsupported option %d\n", option); } diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 319a3b81047..a8ef5bfff84 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -111,6 +111,7 @@ void* hash_table_iter_up(struct hash_table_iter* hti) DECLSPEC_HIDDEN;
extern unsigned dbghelp_options DECLSPEC_HIDDEN; extern BOOL dbghelp_opt_native DECLSPEC_HIDDEN; +extern BOOL dbghelp_opt_real_path DECLSPEC_HIDDEN; extern SYSTEM_INFO sysinfo DECLSPEC_HIDDEN;
/* FIXME: this could be optimized later on by using relative offsets and smaller integral sizes */ diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index d590877497d..51ade962937 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -1439,6 +1439,9 @@ BOOL WINAPI SymGetModuleInfoW64(HANDLE hProcess, DWORD64 dwAddr,
miw64 = module->module;
+ if (dbghelp_opt_real_path && module->real_path) + lstrcpynW(miw64.LoadedImageName, module->real_path, ARRAY_SIZE(miw64.LoadedImageName)); + /* update debug information from container if any */ if (module->module.SymType == SymNone) { diff --git a/include/dbghelp.h b/include/dbghelp.h index e56d8de0d5d..31600d99429 100644 --- a/include/dbghelp.h +++ b/include/dbghelp.h @@ -1098,6 +1098,7 @@ typedef enum
#ifdef __WINESRC__ SYMOPT_EX_WINE_NATIVE_MODULES = 1000, + SYMOPT_EX_WINE_MODULE_REAL_PATH, #endif } IMAGEHLP_EXTENDED_OPTIONS;
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index 6b523b30337..68875a6d0fa 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -1765,7 +1765,7 @@ static BOOL CALLBACK packet_query_libraries_cb(PCSTR mod_name, DWORD64 base, PVO static enum packet_return packet_query_libraries(struct gdb_context* gdbctx) { struct reply_buffer* reply = &gdbctx->qxfer_buffer; - BOOL opt; + BOOL opt_native, opt_real_path;
if (!gdbctx->process) return packet_error;
@@ -1776,9 +1776,12 @@ static enum packet_return packet_query_libraries(struct gdb_context* gdbctx) SymLoadModule(gdbctx->process->handle, 0, 0, 0, 0, 0);
reply_buffer_append_str(reply, "<library-list>"); - opt = SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES, TRUE); + /* request also ELF modules, and also real path to loaded modules */ + opt_native = SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES, TRUE); + opt_real_path = SymSetExtendedOption(SYMOPT_EX_WINE_MODULE_REAL_PATH, TRUE); SymEnumerateModules64(gdbctx->process->handle, packet_query_libraries_cb, gdbctx); - SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES, opt); + SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES, opt_native); + SymSetExtendedOption(SYMOPT_EX_WINE_MODULE_REAL_PATH, opt_real_path); reply_buffer_append_str(reply, "</library-list>");
return packet_send_buffer;