This series brings some improvements for debugging support in the new wow64 environment: - detects and adapt to the new environement - fixes a couple of bugs appearing now - adds a couple of tests - extends winedbg to hide or display the modules when multiple machines are used in the same process
-- v2: dbghelp: Identify a 32bit multi-arch wow64 debuggee as a live target. winedbg: Don't expose to gdb module which machine isn't the process' one. winedbg: Handle multi-machine process in command 'info share'. dbghelp: Filter on machine when searching for Wine system PE modules. dbghelp: Allow loading modules for different machines. dbghelp: Add tests about modules loading. dbghelp: Stop unwinding on potential 64bit frame for i386 cpu.
From: Eric Pouech eric.pouech@gmail.com
Transform potential error on 32 => 64 bit transition with end of stack (needed in new wow64 for dbghelp's stackwalk tests).
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/cpu_i386.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/dlls/dbghelp/cpu_i386.c b/dlls/dbghelp/cpu_i386.c index c45c45f434c..dcc576cf295 100644 --- a/dlls/dbghelp/cpu_i386.c +++ b/dlls/dbghelp/cpu_i386.c @@ -473,7 +473,14 @@ static BOOL i386_stack_walk(struct cpu_stack_walk *csw, STACKFRAME64 *frame, union ctx newctx = *context;
if (!fetch_next_frame32(csw, &newctx, frame->AddrPC.Offset - deltapc)) - goto done_err; + { + /* When running on wow64 setup, frame below can a 64 bit frame. + * As we don't expose 64bit frames for now, pretend it's the first frame. + */ + if (frame->AddrPC.Offset == 0) + goto done_err; + newctx.x86.Eip = 0; + } frame->AddrReturn.Mode = AddrModeFlat; frame->AddrReturn.Offset = newctx.x86.Eip;
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/tests/dbghelp.c | 93 ++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 73f8ee5f14f..3676f4345ba 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -20,6 +20,7 @@ #include "verrsrc.h" #include "dbghelp.h" #include "wine/test.h" +#include "winternl.h"
#if defined(__i386__) || defined(__x86_64__)
@@ -190,6 +191,96 @@ static void test_search_path(void) ok(!strcmp(search_path, "."), "Got search path '%s', expected '.'\n", search_path); }
+static USHORT get_module_machine(const char* path) +{ + BOOL ret; + HANDLE hFile, hMap; + void* mapping; + IMAGE_NT_HEADERS *nthdr; + USHORT machine; + + hFile = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + ok(hFile != INVALID_HANDLE_VALUE, "Couldn't open file %s (%lu)\n", path, GetLastError()); + hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + ok(hMap != NULL, "Couldn't create map (%lu)\n", GetLastError()); + mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); + ok(mapping != NULL, "Couldn't map (%lu)\n", GetLastError()); + nthdr = RtlImageNtHeader(mapping); + ok(nthdr != NULL, "Cannot get NT headers out of %s\n", path); + machine = nthdr ? nthdr->FileHeader.Machine : IMAGE_FILE_MACHINE_UNKNOWN; + ret = UnmapViewOfFile(mapping); + ok(ret, "Couldn't unmap (%lu)\n", GetLastError()); + CloseHandle(hMap); + CloseHandle(hFile); + return machine; +} + +static void test_modules(void) +{ + BOOL ret; + DWORD attr; + const DWORD64 base1 = 0x00010000; + const DWORD64 base2 = 0x08010000; + IMAGEHLP_MODULEW64 im; + + im.SizeOfStruct = sizeof(im); + + /* can sym load an exec of different bitness even if 32Bit flag not set */ + + SymSetOptions(SymGetOptions() & ~SYMOPT_INCLUDE_32BIT_MODULES); + ret = SymInitialize(GetCurrentProcess(), 0, FALSE); + ok(ret, "SymInitialize failed: %lu\n", GetLastError()); + + /* not always present */ + attr = GetFileAttributesA("C:\windows\syswow64\notepad.exe"); + todo_wine_if(sizeof(void*) == 8) + if (attr != INVALID_FILE_ATTRIBUTES) + { + ret = SymLoadModule(GetCurrentProcess(), NULL, "C:\windows\syswow64\notepad.exe", NULL, base2, 0); + ok(ret, "SymLoadModule failed: %lu\n", GetLastError()); + ret = SymGetModuleInfoW64(GetCurrentProcess(), base2, &im); + ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); + ok(im.BaseOfImage == base2, "Wrong base address\n"); + ok(im.MachineType == get_module_machine("C:\windows\syswow64\notepad.exe"), + "Wrong machine %lx\n", im.MachineType); + } + + ret = SymLoadModule(GetCurrentProcess(), NULL, "C:\windows\system32\notepad.exe", NULL, base1, 0); + ok(ret, "SymLoadModule failed: %lu\n", GetLastError()); + ret = SymGetModuleInfoW64(GetCurrentProcess(), base1, &im); + /* we want to access IMAGEHLP_MODULE.MachineType, so ensure that error stems from a too old + * dbghelp (on Windows), not supporting new enlarged IMAGEHLP_MODULE structures. + */ + if (broken(!ret && GetLastError() == ERROR_INVALID_PARAMETER)) + { + IMAGEHLP_MODULE im0 = {sizeof(im0)}; + ret = SymGetModuleInfo(GetCurrentProcess(), base1, &im0); + ok(ret, "Unexpected error: %lu\n", GetLastError()); + skip("Too old dbghelp. Skipping module tests\n"); + ret = SymCleanup(GetCurrentProcess()); + ok(ret, "SymCleanup failed: %lu\n", GetLastError()); + return; + } + ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); + ok(im.BaseOfImage == base1, "Wrong base address\n"); + ok(im.MachineType == get_module_machine("C:\windows\system32\notepad.exe"), + "Wrong machine %lx\n", im.MachineType); + + /* still can access first module after loading second */ + todo_wine_if(sizeof(void*) == 8) + if (attr != INVALID_FILE_ATTRIBUTES) + { + ret = SymGetModuleInfoW64(GetCurrentProcess(), base2, &im); + ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); + ok(im.BaseOfImage == base2, "Wrong base address\n"); + ok(im.MachineType == get_module_machine("C:\windows\syswow64\notepad.exe"), + "Wrong machine %lx\n", im.MachineType); + } + + ret = SymCleanup(GetCurrentProcess()); + ok(ret, "SymCleanup failed: %lu\n", GetLastError()); +} + START_TEST(dbghelp) { BOOL ret; @@ -206,4 +297,6 @@ START_TEST(dbghelp)
ret = SymCleanup(GetCurrentProcess()); ok(ret, "got error %lu\n", GetLastError()); + + test_modules(); }
From: Eric Pouech eric.pouech@gmail.com
SYMOPT_INCLUDE_32BIT_MODULES option applies when enumerating loaded modules, but not when actually loading debug information for a module.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/pe_module.c | 5 ----- dlls/dbghelp/tests/dbghelp.c | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index 80c2f1a1f45..3262f93db9c 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -269,11 +269,6 @@ BOOL pe_map_file(HANDLE file, struct image_file_map* fmap, enum module_type mt) switch (nthdr->OptionalHeader.Magic) { case IMAGE_NT_OPTIONAL_HDR32_MAGIC: - if (sizeof(void*) == 8 && !(SymGetOptions() & SYMOPT_INCLUDE_32BIT_MODULES)) - { - TRACE("Won't load 32bit module in 64bit dbghelp when options don't ask for it\n"); - goto error; - } fmap->addr_size = 32; memcpy(&fmap->u.pe.opt.header32, &nthdr->OptionalHeader, sizeof(fmap->u.pe.opt.header32)); break; diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 3676f4345ba..b9f922c69df 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -233,7 +233,6 @@ static void test_modules(void)
/* not always present */ attr = GetFileAttributesA("C:\windows\syswow64\notepad.exe"); - todo_wine_if(sizeof(void*) == 8) if (attr != INVALID_FILE_ATTRIBUTES) { ret = SymLoadModule(GetCurrentProcess(), NULL, "C:\windows\syswow64\notepad.exe", NULL, base2, 0); @@ -241,6 +240,7 @@ static void test_modules(void) ret = SymGetModuleInfoW64(GetCurrentProcess(), base2, &im); ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); ok(im.BaseOfImage == base2, "Wrong base address\n"); + todo_wine_if(sizeof(void*) == 8) ok(im.MachineType == get_module_machine("C:\windows\syswow64\notepad.exe"), "Wrong machine %lx\n", im.MachineType); } @@ -267,12 +267,12 @@ static void test_modules(void) "Wrong machine %lx\n", im.MachineType);
/* still can access first module after loading second */ - todo_wine_if(sizeof(void*) == 8) if (attr != INVALID_FILE_ATTRIBUTES) { ret = SymGetModuleInfoW64(GetCurrentProcess(), base2, &im); ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); ok(im.BaseOfImage == base2, "Wrong base address\n"); + todo_wine_if(sizeof(void*) == 8) ok(im.MachineType == get_module_machine("C:\windows\syswow64\notepad.exe"), "Wrong machine %lx\n", im.MachineType); }
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/dbghelp_private.h | 4 ++-- dlls/dbghelp/elf_module.c | 2 +- dlls/dbghelp/macho_module.c | 2 +- dlls/dbghelp/path.c | 5 +++-- dlls/dbghelp/pe_module.c | 3 ++- dlls/dbghelp/tests/dbghelp.c | 2 -- 6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index a8ef5bfff84..96169ae1bf6 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -764,8 +764,8 @@ extern BOOL path_find_symbol_file(const struct process* pcs, const struc PCSTR full_path, enum module_type type, const GUID* guid, DWORD dw1, DWORD dw2, WCHAR *buffer, BOOL* is_unmatched) DECLSPEC_HIDDEN; extern WCHAR *get_dos_file_name(const WCHAR *filename) __WINE_DEALLOC(HeapFree, 3) __WINE_MALLOC DECLSPEC_HIDDEN; -extern BOOL search_dll_path(const struct process* process, const WCHAR *name, - BOOL (*match)(void*, HANDLE, const WCHAR*), void *param) DECLSPEC_HIDDEN; +extern BOOL search_dll_path(const struct process* process, const WCHAR *name, WORD machine, + BOOL (*match)(void*, HANDLE, const WCHAR*), void *param) DECLSPEC_HIDDEN; extern BOOL search_unix_path(const WCHAR *name, const WCHAR *path, BOOL (*match)(void*, HANDLE, const WCHAR*), void *param) DECLSPEC_HIDDEN; extern const WCHAR* file_name(const WCHAR* str) DECLSPEC_HIDDEN; extern const char* file_nameA(const char* str) DECLSPEC_HIDDEN; diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c index bc063bf1466..1a38949a321 100644 --- a/dlls/dbghelp/elf_module.c +++ b/dlls/dbghelp/elf_module.c @@ -1445,7 +1445,7 @@ static BOOL elf_search_and_load_file(struct process* pcs, const WCHAR* filename, load_elf.elf_info = elf_info;
ret = search_unix_path(filename, process_getenv(pcs, L"LD_LIBRARY_PATH"), elf_load_file_cb, &load_elf) - || search_dll_path(pcs, filename, elf_load_file_cb, &load_elf); + || search_dll_path(pcs, filename, IMAGE_FILE_MACHINE_UNKNOWN, elf_load_file_cb, &load_elf); }
return ret; diff --git a/dlls/dbghelp/macho_module.c b/dlls/dbghelp/macho_module.c index 4852f5beaa4..f1b3107408c 100644 --- a/dlls/dbghelp/macho_module.c +++ b/dlls/dbghelp/macho_module.c @@ -1583,7 +1583,7 @@ static BOOL macho_search_and_load_file(struct process* pcs, const WCHAR* filenam ret = search_unix_path(p, fallback, macho_load_file_cb, &load_params); } if (!ret && p == filename) - ret = search_dll_path(pcs, filename, macho_load_file_cb, &load_params); + ret = search_dll_path(pcs, filename, IMAGE_FILE_MACHINE_UNKNOWN, macho_load_file_cb, &load_params);
return ret; } diff --git a/dlls/dbghelp/path.c b/dlls/dbghelp/path.c index d23a4b5733e..fe1da8849eb 100644 --- a/dlls/dbghelp/path.c +++ b/dlls/dbghelp/path.c @@ -722,7 +722,7 @@ static BOOL try_match_file(const WCHAR *name, BOOL (*match)(void*, HANDLE, const return FALSE; }
-BOOL search_dll_path(const struct process *process, const WCHAR *name, BOOL (*match)(void*, HANDLE, const WCHAR*), void *param) +BOOL search_dll_path(const struct process *process, const WCHAR *name, WORD machine, BOOL (*match)(void*, HANDLE, const WCHAR*), void *param) { const WCHAR *env; WCHAR *p, *end; @@ -733,7 +733,8 @@ BOOL search_dll_path(const struct process *process, const WCHAR *name, BOOL (*ma
name = file_name(name);
- cpu = process_get_cpu(process); + cpu = machine == IMAGE_FILE_MACHINE_UNKNOWN ? process_get_cpu(process) : cpu_find(machine); + for (machine_dir = all_machine_dir; machine_dir < all_machine_dir + ARRAY_SIZE(all_machine_dir); machine_dir++) if (machine_dir->machine == cpu->machine) break; if (machine_dir >= all_machine_dir + ARRAY_SIZE(all_machine_dir)) return FALSE; diff --git a/dlls/dbghelp/pe_module.c b/dlls/dbghelp/pe_module.c index 3262f93db9c..7aeb1cf8901 100644 --- a/dlls/dbghelp/pe_module.c +++ b/dlls/dbghelp/pe_module.c @@ -824,7 +824,8 @@ 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 (opened && 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, modfmt->u.pe_info->fmap.u.pe.file_header.Machine, 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); diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index b9f922c69df..713c93b0a02 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -240,7 +240,6 @@ static void test_modules(void) ret = SymGetModuleInfoW64(GetCurrentProcess(), base2, &im); ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); ok(im.BaseOfImage == base2, "Wrong base address\n"); - todo_wine_if(sizeof(void*) == 8) ok(im.MachineType == get_module_machine("C:\windows\syswow64\notepad.exe"), "Wrong machine %lx\n", im.MachineType); } @@ -272,7 +271,6 @@ static void test_modules(void) ret = SymGetModuleInfoW64(GetCurrentProcess(), base2, &im); ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); ok(im.BaseOfImage == base2, "Wrong base address\n"); - todo_wine_if(sizeof(void*) == 8) ok(im.MachineType == get_module_machine("C:\windows\syswow64\notepad.exe"), "Wrong machine %lx\n", im.MachineType); }
From: Eric Pouech eric.pouech@gmail.com
- filter out native machine on wow64 configuration. - add option to info share to print all modules.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- programs/winedbg/dbg.y | 7 +++-- programs/winedbg/debug.l | 1 + programs/winedbg/debugger.h | 2 +- programs/winedbg/info.c | 61 +++++++++++++++++++++++++++++-------- 4 files changed, 55 insertions(+), 16 deletions(-)
diff --git a/programs/winedbg/dbg.y b/programs/winedbg/dbg.y index df1e3461032..f46e665e6b9 100644 --- a/programs/winedbg/dbg.y +++ b/programs/winedbg/dbg.y @@ -59,7 +59,7 @@ static void parser(const char*); %token <integer> tNUM tFORMAT %token <type> tTYPEDEF %token tSYMBOLFILE tRUN tATTACH tDETACH tKILL tMAINTENANCE tTYPE tMINIDUMP -%token tNOPROCESS +%token tNOPROCESS tWOW
/* can be prefixed by module name */ %token <string> tVOID tCHAR tWCHAR tSHORT tINT tLONG tFLOAT tDOUBLE tUNSIGNED tSIGNED @@ -269,8 +269,9 @@ display_command:
info_command: tINFO tBREAK { break_info(); } - | tINFO tSHARE { info_win32_module(0); } - | tINFO tSHARE expr_rvalue { info_win32_module($3); } + | tINFO tSHARE { info_win32_module(0, FALSE); } + | tINFO tWOW tSHARE { info_win32_module(0, TRUE); } + | tINFO tSHARE expr_rvalue { info_win32_module($3, FALSE); } | tINFO tREGS { dbg_curr_process->be_cpu->print_context(dbg_curr_thread->handle, &dbg_context, 0); } | tINFO tALLREGS { dbg_curr_process->be_cpu->print_context(dbg_curr_thread->handle, &dbg_context, 1); } | tINFO tSEGMENTS expr_rvalue { info_win32_segments($3 >> 3, 1); } diff --git a/programs/winedbg/debug.l b/programs/winedbg/debug.l index be528fed986..0b76ba74329 100644 --- a/programs/winedbg/debug.l +++ b/programs/winedbg/debug.l @@ -216,6 +216,7 @@ STRING "(\[^\n]|[^\"\n])*" <INITIAL>show|sho|sh { BEGIN(SHOW_CMD); return tSHOW; } <INITIAL,NOPROCESS>source|sourc|sour|src { BEGIN(PATH_EXPECTED); return tSOURCE; } <INITIAL>symbolfile|symbols|symbol|sf { BEGIN(PATH_EXPECTED); return tSYMBOLFILE; } +<INITIAL,INFO_CMD>wow { return tWOW; }
<INITIAL,INFO_CMD,BD_CMD>break|brea|bre|br|b { BEGIN(PATH_ACCEPTED); return tBREAK; } <INITIAL,INFO_CMD,BD_CMD>hbreak|hbrea|hbre|hbr|hb { BEGIN(PATH_ACCEPTED); return tHBREAK; } diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h index 61fb055e53f..6a313efbb5e 100644 --- a/programs/winedbg/debugger.h +++ b/programs/winedbg/debugger.h @@ -387,7 +387,7 @@ extern BOOL expr_print(const struct expr* exp); /* info.c */ extern void print_help(void); extern void info_help(void); -extern void info_win32_module(DWORD64 mod); +extern void info_win32_module(DWORD64 mod, BOOL multi_machine); extern void info_win32_class(HWND hWnd, const char* clsName); extern void info_win32_window(HWND hWnd, BOOL detailed); extern void info_win32_processes(void); diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index 5d6b45d715f..6ffcf99392a 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -166,12 +166,33 @@ struct info_modules unsigned num_used; };
-static void module_print_info(const struct info_module *module, BOOL is_embedded) +static const char* get_machine_str(DWORD machine) { - dbg_printf("%*.*I64x-%*.*I64x\t%-16s%s\n", - ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage, - ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage + module->mi.ImageSize, - is_embedded ? "\" : get_symtype_str(&module->mi), module->name); + static char tmp[32]; + switch (machine) + { + case IMAGE_FILE_MACHINE_AMD64: return "x86_64"; + case IMAGE_FILE_MACHINE_I386: return "i386"; + case IMAGE_FILE_MACHINE_ARM64: return "arm64"; + case IMAGE_FILE_MACHINE_ARM: + case IMAGE_FILE_MACHINE_ARMNT: return "arm"; + default: sprintf(tmp, "<%lx>", machine); return tmp; + } +} + +static void module_print_info(const struct info_module *module, BOOL is_embedded, BOOL multi_machine) +{ + if (multi_machine) + dbg_printf("%16I64x-%16I64x\t%s\t%-16s%s\n", + module->mi.BaseOfImage, + module->mi.BaseOfImage + module->mi.ImageSize, + get_machine_str(module->mi.MachineType), + is_embedded ? "\" : get_symtype_str(&module->mi), module->name); + else + dbg_printf("%*.*I64x-%*.*I64x\t%-16s%s\n", + ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage, + ADDRWIDTH, ADDRWIDTH, module->mi.BaseOfImage + module->mi.ImageSize, + is_embedded ? "\" : get_symtype_str(&module->mi), module->name); }
static int __cdecl module_compare(const void* p1, const void* p2) @@ -220,11 +241,12 @@ static BOOL CALLBACK info_mod_cb(PCSTR mod_name, DWORD64 base, PVOID ctx) * * Display information about a given module (DLL or EXE), or about all modules */ -void info_win32_module(DWORD64 base) +void info_win32_module(DWORD64 base, BOOL multi_machine) { struct info_modules im; UINT i, j, num_printed = 0; BOOL opt; + DWORD machine;
if (!dbg_curr_process) { @@ -242,27 +264,42 @@ void info_win32_module(DWORD64 base) SymEnumerateModules64(dbg_curr_process->handle, info_mod_cb, &im); SymSetExtendedOption(SYMOPT_EX_WINE_NATIVE_MODULES, opt);
+ if (!im.num_used) return; + qsort(im.modules, im.num_used, sizeof(im.modules[0]), module_compare); + machine = im.modules[0].mi.MachineType;
- dbg_printf("Module\tAddress\t\t\t%sDebug info\tName (%d modules)\n", - ADDRWIDTH == 16 ? "\t\t" : "", im.num_used); + if (multi_machine) + dbg_printf("Module\tAddress\t\t\t\t\tMachine\tDebug info\tName (%d modules)\n", im.num_used); + else + { + unsigned same_machine = 0; + for (i = 0; i < im.num_used; i++) + if (machine == im.modules[i].mi.MachineType) same_machine++; + dbg_printf("Module\tAddress\t\t\t%sDebug info\tName (%d modules", + ADDRWIDTH == 16 ? "\t\t" : "", same_machine); + if (same_machine != im.num_used) + dbg_printf(", %u for wow64 not listed", im.num_used - same_machine); + dbg_printf(")\n"); + }
for (i = 0; i < im.num_used; i++) { - if (base && + if (base && (base < im.modules[i].mi.BaseOfImage || base >= im.modules[i].mi.BaseOfImage + im.modules[i].mi.ImageSize)) continue; + if (!multi_machine && machine != im.modules[i].mi.MachineType) continue; if (strstr(im.modules[i].name, "<elf>")) { dbg_printf("ELF\t"); - module_print_info(&im.modules[i], FALSE); + module_print_info(&im.modules[i], FALSE, multi_machine); /* print all modules embedded in this one */ for (j = 0; j < im.num_used; j++) { if (!strstr(im.modules[j].name, "<elf>") && module_is_container(&im.modules[i], &im.modules[j])) { dbg_printf(" \-PE\t"); - module_print_info(&im.modules[j], TRUE); + module_print_info(&im.modules[j], TRUE, multi_machine); } } } @@ -279,7 +316,7 @@ void info_win32_module(DWORD64 base) dbg_printf("ELF\t"); else dbg_printf("PE\t"); - module_print_info(&im.modules[i], FALSE); + module_print_info(&im.modules[i], FALSE, multi_machine); } num_printed++; }
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- programs/winedbg/gdbproxy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index 68875a6d0fa..8fab5c0cd39 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -1692,7 +1692,9 @@ static BOOL CALLBACK packet_query_libraries_cb(PCSTR mod_name, DWORD64 base, PVO char buffer[0x400];
mod.SizeOfStruct = sizeof(mod); - SymGetModuleInfo64(gdbctx->process->handle, base, &mod); + if (!SymGetModuleInfo64(gdbctx->process->handle, base, &mod) || + mod.MachineType != gdbctx->process->be_cpu->machine) + return TRUE;
reply_buffer_append_str(reply, "<library name=""); if (strcmp(mod.LoadedImageName, "[vdso].so") == 0)
From: Eric Pouech eric.pouech@gmail.com
Note: from now on, winedbg will 'see' the ELF 64 bit modules (not yet the PE ones) in multi-arch wow64 use case. Modules can be displayed in 'info wow share' command and their debug information is loaded. Stack manipulation and backtracking are not available.
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/dbghelp.c | 44 ++++++++++++++++++++++++---------- dlls/dbghelp/dbghelp_private.h | 1 + dlls/dbghelp/elf_module.c | 4 ++-- 3 files changed, 34 insertions(+), 15 deletions(-)
diff --git a/dlls/dbghelp/dbghelp.c b/dlls/dbghelp/dbghelp.c index 432e9c6b248..67ac7765c6f 100644 --- a/dlls/dbghelp/dbghelp.c +++ b/dlls/dbghelp/dbghelp.c @@ -350,7 +350,8 @@ const struct cpu* process_get_cpu(const struct process* pcs) static BOOL check_live_target(struct process* pcs, BOOL wow64, BOOL child_wow64) { PROCESS_BASIC_INFORMATION pbi; - ULONG_PTR base = 0, env = 0; + DWORD64 base = 0, env = 0; + const char* peb_addr;
if (!GetProcessId(pcs->handle)) return FALSE; if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE; @@ -359,27 +360,44 @@ static BOOL check_live_target(struct process* pcs, BOOL wow64, BOOL child_wow64) &pbi, sizeof(pbi), NULL )) return FALSE;
+ /* Note: we have to deal with the PEB64 and PEB32 in debuggee process + * while debugger can be in same or different bitness. + * For a 64 bit debuggee, use PEB64 and underlying ELF/system 64 (easy). + * For a 32 bit debuggee, + * - for environment variables, we need PEB32 + * - for ELF/system base address, we need PEB32 when run in pure 32bit + * or run in old wow configuration, but PEB64 when run in new wow + * configuration. + * - this must be read from a debugger in either 32 or 64 bit setup. + */ + peb_addr = (const char*)pbi.PebBaseAddress; if (!pcs->is_64bit) { - const char* peb32_addr; DWORD env32; PEB32 peb32;
C_ASSERT(sizeof(void*) != 4 || FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment) == 0x48); - peb32_addr = (const char*)pbi.PebBaseAddress; + if (!wow64 && child_wow64) /* current process is 64bit, while child process is 32 bit, need to read 32bit PEB */ - peb32_addr += 0x1000; - if (!ReadProcessMemory(pcs->handle, peb32_addr, &peb32, sizeof(peb32), NULL)) return FALSE; - if (!ReadProcessMemory(pcs->handle, peb32_addr + 0x460 /* CloudFileFlags */, &base, sizeof(base), NULL)) return FALSE; + peb_addr += 0x1000; + if (!ReadProcessMemory(pcs->handle, peb_addr, &peb32, sizeof(peb32), NULL)) return FALSE; + base = *(const DWORD*)((const char*)&peb32 + 0x460 /* CloudFileFlags */); + pcs->is_system_64bit = FALSE; if (read_process_memory(pcs, peb32.ProcessParameters + 0x48, &env32, sizeof(env32))) env = env32; } - else + if (pcs->is_64bit || base == 0) { - PEB peb; - if (!ReadProcessMemory(pcs->handle, pbi.PebBaseAddress, &peb, sizeof(peb), NULL)) return FALSE; - if (!ReadProcessMemory(pcs->handle, (char *)pbi.PebBaseAddress + FIELD_OFFSET(PEB, CloudFileFlags), &base, sizeof(base), NULL)) return FALSE; - ReadProcessMemory(pcs->handle, (char *)peb.ProcessParameters + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment), &env, sizeof(env), NULL); + PEB64 peb; + + if (!pcs->is_64bit) peb_addr -= 0x1000; /* PEB32 => PEB64 */ + if (!ReadProcessMemory(pcs->handle, peb_addr, &peb, sizeof(peb), NULL)) return FALSE; + base = peb.CloudFileFlags; + pcs->is_system_64bit = TRUE; + if (pcs->is_64bit) + ReadProcessMemory(pcs->handle, + (char *)(ULONG_PTR)peb.ProcessParameters + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment), + &env, sizeof(env), NULL); }
/* read debuggee environment block */ @@ -420,9 +438,9 @@ static BOOL check_live_target(struct process* pcs, BOOL wow64, BOOL child_wow64)
if (!base) return FALSE;
- TRACE("got debug info address %#Ix from PEB %p\n", base, pbi.PebBaseAddress); + TRACE("got debug info address %#I64x from PEB %p\n", base, pbi.PebBaseAddress); if (!elf_read_wine_loader_dbg_info(pcs, base) && !macho_read_wine_loader_dbg_info(pcs, base)) - WARN("couldn't load process debug info at %#Ix\n", base); + WARN("couldn't load process debug info at %#I64x\n", base); return TRUE; }
diff --git a/dlls/dbghelp/dbghelp_private.h b/dlls/dbghelp/dbghelp_private.h index 96169ae1bf6..1852aef1795 100644 --- a/dlls/dbghelp/dbghelp_private.h +++ b/dlls/dbghelp/dbghelp_private.h @@ -515,6 +515,7 @@ struct process void* buffer;
BOOL is_64bit; + BOOL is_system_64bit; };
static inline BOOL read_process_memory(const struct process *process, UINT64 addr, void *buf, size_t size) diff --git a/dlls/dbghelp/elf_module.c b/dlls/dbghelp/elf_module.c index 1a38949a321..3c1e225e195 100644 --- a/dlls/dbghelp/elf_module.c +++ b/dlls/dbghelp/elf_module.c @@ -1373,7 +1373,7 @@ static BOOL elf_search_auxv(const struct process* pcs, unsigned type, ULONG_PTR* while (addr < str_max && ReadProcessMemory(pcs->handle, addr, &str, sizeof(str), NULL) && str == NULL) addr = (void*)((DWORD_PTR)addr + sizeof(str));
- if (pcs->is_64bit) + if (pcs->is_system_64bit) { struct { @@ -1467,7 +1467,7 @@ static BOOL elf_enum_modules_internal(const struct process* pcs, char bufstr[256]; ULONG_PTR lm_addr;
- if (pcs->is_64bit) + if (pcs->is_system_64bit) { struct {
V2: - fixed test failures on Window7 - removed hard coded machine values and use file image instead - included @cdavis5e winedbg's remarks - added protection for gdb proxy mode now that 64bit modules can be exposed to a 32bit process - changed syntax of gdb command ('info wow share') for extended shared library view - removed EnumerateLoadedModules test (now split in two patches, and getting the series too big; still ready for next one)
Note: most the changes above require fixing nested exception to be fully functional.