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
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 | 66 ++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 73f8ee5f14f..85ec3ce1dbb 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -190,6 +190,70 @@ static void test_search_path(void) ok(!strcmp(search_path, "."), "Got search path '%s', expected '.'\n", search_path); }
+static const USHORT machines[2] = +{ +#if defined(__i386__) || defined( __x86_64__) + IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386 +#elif defined(__i386__) || defined( __x86_64__) + IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARM +#else +#error To be defined for your processor +#endif +}; + +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 == machines[1], + "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); + ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); + ok(im.BaseOfImage == base1, "Wrong base address\n"); + ok(im.MachineType == (sizeof(void*) == 8) ? machines[0] : machines[1], + "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 == machines[1], + "Wrong machine %lx\n", im.MachineType); + } + + ret = SymCleanup(GetCurrentProcess()); + ok(ret, "SymCleanup failed: %lu\n", GetLastError()); +} + START_TEST(dbghelp) { BOOL ret; @@ -206,4 +270,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 85ec3ce1dbb..7ea5be9c441 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -219,7 +219,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); @@ -227,6 +226,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 == machines[1], "Wrong machine %lx\n", im.MachineType); } @@ -240,12 +240,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 == machines[1], "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 7ea5be9c441..8b65ef68670 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -226,7 +226,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 == machines[1], "Wrong machine %lx\n", im.MachineType); } @@ -245,7 +244,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 == machines[1], "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 | 5 ++-- programs/winedbg/debugger.h | 2 +- programs/winedbg/info.c | 60 +++++++++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 15 deletions(-)
diff --git a/programs/winedbg/dbg.y b/programs/winedbg/dbg.y index df1e3461032..ba7d207344a 100644 --- a/programs/winedbg/dbg.y +++ b/programs/winedbg/dbg.y @@ -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 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/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..db90bef5931 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -166,12 +166,32 @@ 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: return "arm_64"; + 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 +240,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 +263,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 +315,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 --- 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 {
From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/tests/Makefile.in | 2 +- dlls/dbghelp/tests/dbghelp.c | 168 ++++++++++++++++++++++++++++++++- 2 files changed, 167 insertions(+), 3 deletions(-)
diff --git a/dlls/dbghelp/tests/Makefile.in b/dlls/dbghelp/tests/Makefile.in index 31e5b01e8a8..40ec97eca8c 100644 --- a/dlls/dbghelp/tests/Makefile.in +++ b/dlls/dbghelp/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = dbghelp.dll -IMPORTS = dbghelp +IMPORTS = dbghelp user32
C_SRCS = \ dbghelp.c diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 8b65ef68670..c7e2b675b02 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -16,7 +16,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include "windef.h" +#include "windows.h" +#include "psapi.h" #include "verrsrc.h" #include "dbghelp.h" #include "wine/test.h" @@ -201,6 +202,67 @@ static const USHORT machines[2] = #endif };
+struct module_aggregation +{ + HANDLE process; + unsigned int num32; + unsigned int num64; + unsigned int num_exe; + unsigned int num_ntdll; + unsigned int num_wow; +}; + +static BOOL CALLBACK aggregate_cb(PCWSTR imagename, DWORD64 base, ULONG sz, PVOID usr) +{ + struct module_aggregation* aggregation = usr; + WCHAR buffer[MAX_PATH]; + IMAGEHLP_MODULEW64 im; + size_t image_len; + BOOL ret; + + memset(&im, 0, sizeof(im)); + im.SizeOfStruct = sizeof(im); + + /* MSDN states that first paramter of callback is a module name... + * Testing on Win10 show it looks more like an image pathname... sigh... + * Wine still passes module here. + * So: if that first parameter doesn't look as an imagename, get imagename from process. + */ + if (!wcschr(imagename, L'.')) + { + ret = GetModuleFileNameExW(aggregation->process, (HMODULE)(ULONG_PTR)base, buffer, ARRAY_SIZE(buffer)); + ok(ret, "GetModuleFileNameW failed: %lu\n", GetLastError()); + imagename = buffer; + } + image_len = wcslen(imagename); + + ret = SymGetModuleInfoW64(aggregation->process, base, &im); + if (ret) + ok(aggregation->num_exe && image_len >= 4 && !wcscmp(imagename + image_len - 4, L".exe"), + "%ls shouldn't already be loaded\n", imagename); + else + { + ok(!ret, "Module %ls shouldn't be loaded\n", imagename); + ret = SymLoadModuleExW(aggregation->process, NULL, imagename, NULL, base, sz, NULL, 0); + ok(ret, "SymLoadModuleExW failed on %ls: %lu\n", imagename, GetLastError()); + } + ret = SymGetModuleInfoW64(aggregation->process, base, &im); + ok(ret, "SymGetModuleInfoW64 failed: %lu\n", GetLastError()); + + if (im.MachineType == machines[1]) + aggregation->num32++; + if (im.MachineType == machines[0]) + aggregation->num64++; + if (image_len >= 4 && !wcscmp(imagename + image_len - 4, L".exe")) + aggregation->num_exe++; + if (!wcsicmp(im.ModuleName, L"ntdll")) + aggregation->num_ntdll++; + if (!memcmp(im.ModuleName, L"wow", 3 * sizeof(WCHAR))) + aggregation->num_wow++; + + return TRUE; +} + static void test_modules(void) { BOOL ret; @@ -208,6 +270,10 @@ static void test_modules(void) const DWORD64 base1 = 0x00010000; const DWORD64 base2 = 0x08010000; IMAGEHLP_MODULEW64 im; + char buffer[200] = "C:\windows\system32\notepad.exe"; + PROCESS_INFORMATION pi = {0}; + STARTUPINFOA si = {0}; + struct module_aggregation aggregation = {0};
im.SizeOfStruct = sizeof(im);
@@ -250,6 +316,104 @@ static void test_modules(void)
ret = SymCleanup(GetCurrentProcess()); ok(ret, "SymCleanup failed: %lu\n", GetLastError()); + + /* testing with child process of different machines */ + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "CreateProcess failed: %lu\n", GetLastError()); + + ret = WaitForInputIdle(pi.hProcess, 5000); + ok(!ret, "wait timed out\n"); + + ret = SymInitialize(pi.hProcess, NULL, FALSE); + ok(ret, "SymInitialize failed: %lu\n", GetLastError()); + memset(&aggregation, 0, sizeof(aggregation)); + aggregation.process = pi.hProcess; + + ret = EnumerateLoadedModulesW64(pi.hProcess, aggregate_cb, &aggregation); + ok(ret, "EnumeteLoadedModulesW64 failed: %lu\n", GetLastError()); + + if (sizeof(void *) == 8) + { + ok(!aggregation.num32 && aggregation.num64 && aggregation.num_exe == 1 && aggregation.num_ntdll == 1 && !aggregation.num_wow, + "Wrong aggreation count %u %u %u %u %u\n", + aggregation.num32, aggregation.num64, aggregation.num_exe, aggregation.num_ntdll, aggregation.num_wow); + } + else + { + ok(aggregation.num32 && !aggregation.num64 && aggregation.num_exe == 1 && aggregation.num_ntdll == 1 && !aggregation.num_wow, + "Wrong aggreation count %u %u %u %u %u\n", + aggregation.num32, aggregation.num64, aggregation.num_exe, aggregation.num_ntdll, aggregation.num_wow); + } + + SymCleanup(pi.hProcess); + TerminateProcess(pi.hProcess, 0); + + if (sizeof(void *) == 8) + { + strcpy(buffer, "C:\windows\syswow64\notepad.exe"); + + SymSetOptions(SymGetOptions() & ~SYMOPT_INCLUDE_32BIT_MODULES); + + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + if (ret) + { + ret = WaitForInputIdle(pi.hProcess, 5000); + ok(!ret, "wait timed out\n"); + + ret = SymInitialize(pi.hProcess, NULL, FALSE); + ok(ret, "SymInitialize failed: %lu\n", GetLastError()); + memset(&aggregation, 0, sizeof(aggregation)); + aggregation.process = pi.hProcess; + ret = EnumerateLoadedModulesW64(pi.hProcess, aggregate_cb, &aggregation); + ok(ret, "EnumeteLoadedModulesW64 failed: %lu\n", GetLastError()); + + todo_wine + ok(aggregation.num32 && aggregation.num64 && aggregation.num_exe == 1 && aggregation.num_ntdll == 1 && aggregation.num_wow, + "Wrong aggreation count %u %u %u %u %u\n", + aggregation.num32, aggregation.num64, aggregation.num_exe, aggregation.num_ntdll, aggregation.num_wow); + + SymCleanup(pi.hProcess); + TerminateProcess(pi.hProcess, 0); + } + else + { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + skip("Skip wow64 test on non compatible platform\n"); + else + ok(ret, "CreateProcess failed: %lu\n", GetLastError()); + } + + SymSetOptions(SymGetOptions() | SYMOPT_INCLUDE_32BIT_MODULES); + + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + if (ret) + { + ret = WaitForInputIdle(pi.hProcess, 5000); + ok(!ret, "wait timed out\n"); + + ret = SymInitialize(pi.hProcess, NULL, FALSE); + ok(ret, "SymInitialize failed: %lu\n", GetLastError()); + memset(&aggregation, 0, sizeof(aggregation)); + aggregation.process = pi.hProcess; + ret = EnumerateLoadedModulesW64(pi.hProcess, aggregate_cb, &aggregation); + ok(ret, "EnumerateLoadedModulesW64 failed: %lu\n", GetLastError()); + + todo_wine + ok(aggregation.num32 && aggregation.num64 && aggregation.num_exe == 2 && aggregation.num_ntdll == 2 && aggregation.num_wow, + "Wrong aggreation count %u %u %u %u %u\n", + aggregation.num32, aggregation.num64, aggregation.num_exe, aggregation.num_ntdll, aggregation.num_wow); + + SymCleanup(pi.hProcess); + TerminateProcess(pi.hProcess, 0); + } + else + { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + skip("Skip wow64 test on non compatible platform\n"); + else + ok(ret, "CreateProcess failed: %lu\n", GetLastError()); + } + } }
START_TEST(dbghelp) @@ -261,7 +425,7 @@ START_TEST(dbghelp) SetEnvironmentVariableA("_NT_ALT_SYMBOL_PATH", NULL);
ret = SymInitialize(GetCurrentProcess(), NULL, TRUE); - ok(ret, "got error %lu\n", GetLastError()); + ok(ret, "SymInitialize failed: %lu\n", GetLastError());
test_stack_walk(); test_search_path();
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=128943
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
dbghelp: dbghelp.c:302: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:303: Test failed: Wrong base address dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:343: Test failed: Wrong aggreation count 0 0 1 0 0
=== w7u_adm (32 bit report) ===
dbghelp: dbghelp.c:302: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:303: Test failed: Wrong base address dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:343: Test failed: Wrong aggreation count 0 0 1 0 0
=== w7u_el (32 bit report) ===
dbghelp: dbghelp.c:302: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:303: Test failed: Wrong base address dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:250: Test failed: SymGetModuleInfoW64 failed: 87 dbghelp.c:343: Test failed: Wrong aggreation count 0 0 1 0 0
Chip Davis (@cdavis5e) commented about dlls/dbghelp/tests/dbghelp.c:
ok(!strcmp(search_path, "."), "Got search path '%s', expected '.'\n", search_path);
}
+static const USHORT machines[2] = +{ +#if defined(__i386__) || defined( __x86_64__)
- IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386
+#elif defined(__i386__) || defined( __x86_64__)
- IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARM
```suggestion:-1+0 #elif defined(__arm__) || defined( __aarch64__) IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARMNT ```
Chip Davis (@cdavis5e) commented about programs/winedbg/info.c:
};
-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: return "arm_64";
```suggestion:-0+0 case IMAGE_FILE_MACHINE_ARMNT: return "arm"; ```
It isn't particularly obvious that the correct machine value for 32-bit WoA binaries is `IMAGE_FILE_MACHINE_ARMNT` (note the last two letters), not `IMAGE_FILE_MACHINE_ARM`. The latter is only used with Windows CE. It certainly seems silly to me, but if I had to wager, it's probably because the ABI is different between WinCE and WoA.
On Wed Feb 1 00:22:40 2023 +0000, Chip Davis wrote:
#elif defined(__arm__) || defined( __aarch64__) IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARMNT
anyway, I'll rewrite without the static machines array... It wouldn't work if CPU comes into play for 32bit process.
On Wed Feb 1 08:54:58 2023 +0000, eric pouech wrote:
anyway, I'll rewrite without the static machines array... It wouldn't work if CPU comes into play for 32bit process.
s/CPU/CPU emulation/