Commit af7b97e7 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

dbghelp: Reimplement EnumerateLoadedModules().

- 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: 's avatarEric Pouech <eric.pouech@gmail.com>
parent 79bae0ed
MODULE = dbghelp.dll
IMPORTLIB = dbghelp
IMPORTS = $(ZLIB_PE_LIBS)
IMPORTS = kernelbase $(ZLIB_PE_LIBS)
EXTRAINCL = $(ZLIB_PE_CFLAGS)
EXTRADEFS = -D_IMAGEHLP_SOURCE_
DELAYIMPORTS = version
......
......@@ -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)
......
......@@ -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",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment