From: Eric Pouech eric.pouech@gmail.com
- correctly taking into accoung SYMOPT_INCLUDE_32BIT_MODULES option - converting, for 32bit modules requested from a 64bit module, the system32 paths into syswow64
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/dbghelp/Makefile.in | 2 +- dlls/dbghelp/module.c | 139 +++++++++++++++++++++++++---------- dlls/dbghelp/tests/dbghelp.c | 35 --------- 3 files changed, 103 insertions(+), 73 deletions(-)
diff --git a/dlls/dbghelp/Makefile.in b/dlls/dbghelp/Makefile.in index 22be2612eeb..74647820126 100644 --- a/dlls/dbghelp/Makefile.in +++ b/dlls/dbghelp/Makefile.in @@ -1,6 +1,6 @@ MODULE = dbghelp.dll IMPORTLIB = dbghelp -IMPORTS = $(ZLIB_PE_LIBS) +IMPORTS = kernelbase $(ZLIB_PE_LIBS) EXTRAINCL = $(ZLIB_PE_CFLAGS) EXTRADEFS = -D_IMAGEHLP_SOURCE_ DELAYIMPORTS = version diff --git a/dlls/dbghelp/module.c b/dlls/dbghelp/module.c index ee559cfd99e..bae4a77f16e 100644 --- a/dlls/dbghelp/module.c +++ b/dlls/dbghelp/module.c @@ -1262,53 +1262,118 @@ BOOL WINAPI EnumerateLoadedModules(HANDLE hProcess, return EnumerateLoadedModulesW64(hProcess, enum_load_modW64_32, &x); }
+static unsigned int load_and_grow_modules(HANDLE process, HMODULE** hmods, unsigned start, unsigned* alloc, DWORD filter) +{ + DWORD needed; + BOOL ret; + + while ((ret = EnumProcessModulesEx(process, *hmods + start, (*alloc - start) * sizeof(HMODULE), + &needed, filter)) && + needed > (*alloc - start) * sizeof(HMODULE)) + { + HMODULE* new = HeapReAlloc(GetProcessHeap(), 0, *hmods, (*alloc) * 2 * sizeof(HMODULE)); + if (!new) return 0; + *hmods = new; + *alloc *= 2; + } + return ret ? needed / sizeof(HMODULE) : 0; +} + /****************************************************************** * EnumerateLoadedModulesW64 (DBGHELP.@) * */ -BOOL WINAPI EnumerateLoadedModulesW64(HANDLE hProcess, - PENUMLOADED_MODULES_CALLBACKW64 EnumLoadedModulesCallback, - PVOID UserContext) -{ - HMODULE* hMods; - WCHAR imagenameW[MAX_PATH]; - DWORD i, sz; - MODULEINFO mi; - BOOL wow64; - DWORD filter = LIST_MODULES_DEFAULT; - - hMods = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(hMods[0])); - if (!hMods) return FALSE; - - if (sizeof(void*) > sizeof(int) && - IsWow64Process(hProcess, &wow64) && - wow64) - filter = LIST_MODULES_32BIT; - - if (!EnumProcessModulesEx(hProcess, hMods, 256 * sizeof(hMods[0]), &sz, filter)) - { - /* hProcess should also be a valid process handle !! */ - HeapFree(GetProcessHeap(), 0, hMods); +BOOL WINAPI EnumerateLoadedModulesW64(HANDLE process, + PENUMLOADED_MODULES_CALLBACKW64 enum_cb, + PVOID user) +{ + HMODULE* hmods; + unsigned alloc = 256, count, count32, i; + USHORT pcs_machine, native_machine; + BOOL with_32bit_modules; + WCHAR imagenameW[MAX_PATH]; + MODULEINFO mi; + WCHAR* sysdir = NULL; + WCHAR* wowdir = NULL; + size_t sysdir_len = 0, wowdir_len = 0; + + /* process might not be a handle to a live process */ + if (!IsWow64Process2(process, &pcs_machine, &native_machine)) return FALSE; + with_32bit_modules = sizeof(void*) > sizeof(int) && + pcs_machine != IMAGE_FILE_MACHINE_UNKNOWN && + (dbghelp_options & SYMOPT_INCLUDE_32BIT_MODULES); + + if (!(hmods = HeapAlloc(GetProcessHeap(), 0, alloc * sizeof(hmods[0])))) return FALSE; - } - if (sz > 256 * sizeof(hMods[0])) + + /* Note: + * - we report modules returned from kernelbase.EnumProcessModulesEx + * - appending 32bit modules when possible and requested + * + * When considering 32bit modules in a wow64 child process, required from + * a 64bit process: + * - native returns from kernelbase.EnumProcessModulesEx + * redirected paths (that is in system32 directory), while + * dbghelp.EnumerateLoadedModulesWine returns the effective path + * (eg. syswow64 for x86_64). + * - (Except for the main module, if gotten from syswow64, where kernelbase + * will return the effective path) + * - Wine kernelbase (and ntdll) incorrectly return these modules from + * syswow64 (except for ntdll which is returned from system32). + * => for these modules, always perform a system32 => syswow64 path + * conversion (it'll work even if ntdll/kernelbase is fixed). + */ + if ((count = load_and_grow_modules(process, &hmods, 0, &alloc, LIST_MODULES_DEFAULT)) && with_32bit_modules) { - hMods = HeapReAlloc(GetProcessHeap(), 0, hMods, sz); - if (!hMods || !EnumProcessModulesEx(hProcess, hMods, sz, &sz, filter)) - return FALSE; + /* append 32bit modules when required */ + if ((count32 = load_and_grow_modules(process, &hmods, count, &alloc, LIST_MODULES_32BIT))) + { + sysdir_len = GetSystemDirectoryW(NULL, 0); + wowdir_len = GetSystemWow64Directory2W(NULL, 0, pcs_machine); + + if (!sysdir_len || !wowdir_len || + !(sysdir = HeapAlloc(GetProcessHeap(), 0, (sysdir_len + 1 + wowdir_len + 1) * sizeof(WCHAR)))) + { + HeapFree(GetProcessHeap(), 0, hmods); + return FALSE; + } + wowdir = sysdir + sysdir_len + 1; + if (GetSystemDirectoryW(sysdir, sysdir_len) >= sysdir_len) + FIXME("shouldn't happen\n"); + if (GetSystemWow64Directory2W(wowdir, wowdir_len, pcs_machine) >= wowdir_len) + FIXME("shouldn't happen\n"); + wcscat(sysdir, L"\"); + wcscat(wowdir, L"\"); + } } - sz /= sizeof(HMODULE); - for (i = 0; i < sz; i++) + else count32 = 0; + + for (i = 0; i < count + count32; i++) { - if (!GetModuleInformation(hProcess, hMods[i], &mi, sizeof(mi)) || - !GetModuleFileNameExW(hProcess, hMods[i], imagenameW, ARRAY_SIZE(imagenameW))) - continue; - EnumLoadedModulesCallback(imagenameW, (DWORD_PTR)mi.lpBaseOfDll, mi.SizeOfImage, - UserContext); + if (GetModuleInformation(process, hmods[i], &mi, sizeof(mi)) && + GetModuleFileNameExW(process, hmods[i], imagenameW, ARRAY_SIZE(imagenameW))) + { + /* rewrite path in system32 into syswow64 for 32bit modules */ + if (i >= count) + { + size_t len = wcslen(imagenameW); + + if (!wcsnicmp(imagenameW, sysdir, sysdir_len) && + (len - sysdir_len + wowdir_len) + 1 <= ARRAY_SIZE(imagenameW)) + { + memmove(&imagenameW[wowdir_len], &imagenameW[sysdir_len], (len - sysdir_len) * sizeof(WCHAR)); + memcpy(imagenameW, wowdir, wowdir_len * sizeof(WCHAR)); + } + } + if (!enum_cb(imagenameW, (DWORD_PTR)mi.lpBaseOfDll, mi.SizeOfImage, user)) + break; + } } - HeapFree(GetProcessHeap(), 0, hMods);
- return sz != 0 && i == sz; + HeapFree(GetProcessHeap(), 0, hmods); + HeapFree(GetProcessHeap(), 0, sysdir); + + return count != 0; }
static void dbghelp_str_WtoA(const WCHAR *src, char *dst, int dst_len) diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 211843dfd37..6e3edc7c952 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -776,24 +776,19 @@ static void test_loaded_modules(void) ok(0, "Unknown process kind\n"); break; case PCSKIND_WINE_OLD_WOW64: - todo_wine ok(aggregation.count_32bit == 1 && !aggregation.count_64bit, "Wrong bitness aggregation count %u %u\n", aggregation.count_32bit, aggregation.count_64bit); - todo_wine ok(aggregation.count_exe == 1 && aggregation.count_ntdll == 0, "Wrong kind aggregation count %u %u\n", aggregation.count_exe, aggregation.count_ntdll); - todo_wine ok(aggregation.count_systemdir == 0 && aggregation.count_wowdir == 1, "Wrong directory aggregation count %u %u\n", aggregation.count_systemdir, aggregation.count_wowdir); break; case PCSKIND_WOW64: - todo_wine ok(aggregation.count_32bit == 1 && aggregation.count_64bit, "Wrong bitness aggregation count %u %u\n", aggregation.count_32bit, aggregation.count_64bit); ok(aggregation.count_exe == 1 && aggregation.count_ntdll == 1, "Wrong kind aggregation count %u %u\n", aggregation.count_exe, aggregation.count_ntdll); - todo_wine ok(aggregation.count_systemdir > 2 && aggregation.count_64bit == aggregation.count_systemdir && aggregation.count_wowdir == 1, "Wrong directory aggregation count %u %u\n", aggregation.count_systemdir, aggregation.count_wowdir); @@ -834,13 +829,10 @@ static void test_loaded_modules(void) case PCSKIND_ERROR: break; case PCSKIND_WINE_OLD_WOW64: - todo_wine ok(aggregation2.count_32bit && !aggregation2.count_64bit, "Wrong bitness aggregation count %u %u\n", aggregation2.count_32bit, aggregation2.count_64bit); - todo_wine ok(aggregation2.count_exe == 2 && aggregation2.count_ntdll == 1, "Wrong kind aggregation count %u %u\n", aggregation2.count_exe, aggregation2.count_ntdll); - todo_wine ok(aggregation2.count_systemdir == 0 && aggregation2.count_32bit == aggregation2.count_wowdir + 1 && aggregation2.count_wowdir > 2, "Wrong directory aggregation count %u %u\n", aggregation2.count_systemdir, aggregation2.count_wowdir); @@ -848,10 +840,8 @@ static void test_loaded_modules(void) default: ok(aggregation2.count_32bit && aggregation2.count_64bit, "Wrong bitness aggregation count %u %u\n", aggregation2.count_32bit, aggregation2.count_64bit); - todo_wine ok(aggregation2.count_exe == 2 && aggregation2.count_ntdll == 2, "Wrong kind aggregation count %u %u\n", aggregation2.count_exe, aggregation2.count_ntdll); - todo_wine ok(aggregation2.count_systemdir > 2 && aggregation2.count_64bit == aggregation2.count_systemdir && aggregation2.count_wowdir > 2, "Wrong directory aggregation count %u %u\n", aggregation2.count_systemdir, aggregation2.count_wowdir); @@ -1168,41 +1158,30 @@ static void test_live_modules_proc(WCHAR* exename, BOOL with_32) /* in fact the first ntdll is reported twice (at same address) in two consecutive events */ "Unexpected event.count_ntdll %u\n", aggregation_event.count_ntdll);
- todo_wine_if(with_32) ok(aggregation_enum.count_exe == 1 + XTRAEXE, "Unexpected enum.count_exe %u\n", aggregation_enum.count_exe); if (with_32) ok(aggregation_enum.count_32bit >= MODCOUNT, "Unexpected enum.count_32bit %u\n", aggregation_enum.count_32bit); else - todo_wine ok(aggregation_enum.count_32bit == 1, "Unexpected enum.count_32bit %u\n", aggregation_enum.count_32bit); - todo_wine ok(aggregation_enum.count_64bit >= MODWOWCOUNT, "Unexpected enum.count_64bit %u\n", aggregation_enum.count_64bit); - todo_wine ok(aggregation_enum.count_systemdir >= MODWOWCOUNT, "Unexpected enum.count_systemdir %u\n", aggregation_enum.count_systemdir); if (with_32) ok(aggregation_enum.count_wowdir >= MODCOUNT, "Unexpected enum.count_wowdir %u\n", aggregation_enum.count_wowdir); else - todo_wine ok(aggregation_enum.count_wowdir == 1, "Unexpected enum.count_wowdir %u\n", aggregation_enum.count_wowdir); - todo_wine_if(with_32) ok(aggregation_enum.count_ntdll == 1 + XTRANTDLL, "Unexpected enum.count_ntdll %u\n", aggregation_enum.count_ntdll);
ok(aggregation_sym.count_exe == 1, "Unexpected sym.count_exe %u\n", aggregation_sym.count_exe); if (with_32) ok(aggregation_sym.count_32bit >= MODCOUNT, "Unexpected sym.count_32bit %u\n", aggregation_sym.count_32bit); else - todo_wine ok(aggregation_sym.count_32bit == 1, "Unexpected sym.count_32bit %u\n", aggregation_sym.count_32bit); - todo_wine ok(aggregation_sym.count_64bit >= MODWOWCOUNT, "Unexpected sym.count_64bit %u\n", aggregation_sym.count_64bit); - todo_wine ok(aggregation_sym.count_systemdir >= MODWOWCOUNT, "Unexpected sym.count_systemdir %u\n", aggregation_sym.count_systemdir); if (with_32) ok(aggregation_sym.count_wowdir >= MODCOUNT, "Unexpected sym.count_wowdir %u\n", aggregation_sym.count_wowdir); else - todo_wine ok(aggregation_sym.count_wowdir == 1, "Unexpected sym.count_wowdir %u\n", aggregation_sym.count_wowdir); - todo_wine_if(with_32) ok(aggregation_sym.count_ntdll == 1 + XTRANTDLL, "Unexpected sym.count_ntdll %u\n", aggregation_sym.count_ntdll); } else if (!is_win64 && pcskind == PCSKIND_WOW64) /* 32/32 */ @@ -1244,40 +1223,30 @@ static void test_live_modules_proc(WCHAR* exename, BOOL with_32) ok(aggregation_event.count_wowdir >= MODCOUNT - 1, "Unexpected event.count_wowdir %u\n", aggregation_event.count_wowdir); ok(aggregation_event.count_ntdll == 1, "Unexpected event.count_ntdll %u\n", aggregation_event.count_ntdll);
- todo_wine_if(with_32) ok(aggregation_enum.count_exe == 1 + XTRAEXE, "Unexpected enum.count_exe %u\n", aggregation_enum.count_exe); if (with_32) ok(aggregation_enum.count_32bit >= MODCOUNT, "Unexpected enum.count_32bit %u\n", aggregation_enum.count_32bit); else - todo_wine ok(aggregation_enum.count_32bit <= 1, "Unexpected enum.count_32bit %u\n", aggregation_enum.count_32bit); ok(aggregation_enum.count_64bit == 0, "Unexpected enum.count_64bit %u\n", aggregation_enum.count_64bit); - todo_wine ok(aggregation_enum.count_systemdir == 0, "Unexpected enum.count_systemdir %u\n", aggregation_enum.count_systemdir); if (with_32) ok(aggregation_enum.count_wowdir >= MODCOUNT, "Unexpected enum.count_wowdir %u\n", aggregation_enum.count_wowdir); else - todo_wine ok(aggregation_enum.count_wowdir <= 1, "Unexpected enum.count_wowdir %u\n", aggregation_enum.count_wowdir); - todo_wine_if(!with_32) ok(aggregation_enum.count_ntdll == XTRANTDLL, "Unexpected enum.count_ntdll %u\n", aggregation_enum.count_ntdll);
ok(aggregation_sym.count_exe == 1, "Unexpected sym.count_exe %u\n", aggregation_sym.count_exe); if (with_32) ok(aggregation_sym.count_32bit >= MODCOUNT, "Unexpected sym.count_32bit %u\n", aggregation_sym.count_32bit); else - todo_wine ok(aggregation_sym.count_wowdir <= 1, "Unexpected sym.count_32bit %u\n", aggregation_sym.count_32bit); - todo_wine ok(aggregation_sym.count_64bit == 0, "Unexpected sym.count_64bit %u\n", aggregation_sym.count_64bit); - todo_wine ok(aggregation_sym.count_systemdir == 0, "Unexpected sym.count_systemdir %u\n", aggregation_sym.count_systemdir); if (with_32) ok(aggregation_sym.count_wowdir >= MODCOUNT, "Unexpected sym.count_wowdir %u\n", aggregation_sym.count_wowdir); else - todo_wine ok(aggregation_sym.count_wowdir <= 1, "Unexpected sym.count_wowdir %u\n", aggregation_sym.count_wowdir); - todo_wine_if(!with_32) ok(aggregation_sym.count_ntdll == XTRANTDLL, "Unexpected sym.count_ntdll %u\n", aggregation_sym.count_ntdll); } else if (!is_win64 && pcskind == PCSKIND_WINE_OLD_WOW64) /* 32/32 */ @@ -1313,18 +1282,14 @@ static void test_live_modules_proc(WCHAR* exename, BOOL with_32) ok(0, "Unexpected process kind %u\n", pcskind);
/* main module is enumerated twice in enum when including 32bit modules */ - todo_wine_if(is_win64 && (pcskind == PCSKIND_WOW64 || pcskind == PCSKIND_WINE_OLD_WOW64) && !with_32) ok(aggregation_sym.count_32bit + XTRAEXE == aggregation_enum.count_32bit, "Different sym/enum count32_bit (%u/%u)\n", aggregation_sym.count_32bit, aggregation_enum.count_32bit); - todo_wine_if(is_win64 && (pcskind == PCSKIND_WOW64 || pcskind == PCSKIND_WINE_OLD_WOW64)) ok(aggregation_sym.count_64bit == aggregation_enum.count_64bit, "Different sym/enum count64_bit (%u/%u)\n", aggregation_sym.count_64bit, aggregation_enum.count_64bit); ok(aggregation_sym.count_systemdir == aggregation_enum.count_systemdir, "Different sym/enum systemdir (%u/%u)\n", aggregation_sym.count_systemdir, aggregation_enum.count_systemdir); - todo_wine_if(with_32) ok(aggregation_sym.count_wowdir + XTRAEXE == aggregation_enum.count_wowdir, "Different sym/enum wowdir (%u/%u)\n", aggregation_sym.count_wowdir, aggregation_enum.count_wowdir); - todo_wine_if(with_32) ok(aggregation_sym.count_exe + XTRAEXE == aggregation_enum.count_exe, "Different sym/enum exe (%u/%u)\n", aggregation_sym.count_exe, aggregation_enum.count_exe); ok(aggregation_sym.count_ntdll == aggregation_enum.count_ntdll, "Different sym/enum exe (%u/%u)\n",