From: Eric Pouech eric.pouech@gmail.com
Signed-off-by: Eric Pouech eric.pouech@gmail.com --- dlls/kernelbase/debug.c | 149 ++++++++++++++++++++++++++++++++-- dlls/psapi/tests/psapi_main.c | 31 ++++--- 2 files changed, 159 insertions(+), 21 deletions(-)
diff --git a/dlls/kernelbase/debug.c b/dlls/kernelbase/debug.c index cd8e0d7f87d..6645b82a660 100644 --- a/dlls/kernelbase/debug.c +++ b/dlls/kernelbase/debug.c @@ -772,19 +772,19 @@ struct module_iterator };
-static BOOL init_module_iterator( struct module_iterator *iter, HANDLE process ) +/* Caller must ensure that wow64=TRUE is only passed from 64bit for 'process' being a wow64 process */ +static BOOL init_module_iterator( struct module_iterator *iter, HANDLE process, BOOL wow64 ) { PROCESS_BASIC_INFORMATION pbi; PPEB_LDR_DATA ldr_data;
- if (!IsWow64Process( process, &iter->wow64 )) return FALSE; - /* get address of PEB */ if (!set_ntstatus( NtQueryInformationProcess( process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL ))) return FALSE;
- if (is_win64 && iter->wow64) + iter->wow64 = wow64; + if (wow64) { PEB_LDR_DATA32 *ldr_data32_ptr; DWORD ldr_data32, first_module; @@ -807,6 +807,12 @@ static BOOL init_module_iterator( struct module_iterator *iter, HANDLE process ) if (!ReadProcessMemory( process, &pbi.PebBaseAddress->LdrData, &ldr_data, sizeof(ldr_data), NULL )) return FALSE;
+ /* This happens when running "old" wow64 configuration. Mark it as such. */ + if (!ldr_data) + { + SetLastError( ERROR_EMPTY ); + return FALSE; + } /* read address of first module from LdrData */ if (!ReadProcessMemory( process, &ldr_data->InLoadOrderModuleList.Flink, &iter->current, sizeof(iter->current), NULL )) @@ -849,7 +855,7 @@ static BOOL get_ldr_module( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENTRY struct module_iterator iter; INT ret;
- if (!init_module_iterator( &iter, process )) return FALSE; + if (!init_module_iterator( &iter, process, FALSE )) return FALSE;
while ((ret = module_iterator_next( &iter )) > 0) /* When hModule is NULL we return the process image - which will be @@ -870,7 +876,7 @@ static BOOL get_ldr_module32( HANDLE process, HMODULE module, LDR_DATA_TABLE_ENT struct module_iterator iter; INT ret;
- if (!init_module_iterator( &iter, process )) return FALSE; + if (!init_module_iterator( &iter, process, TRUE )) return FALSE;
while ((ret = module_iterator_next( &iter )) > 0) /* When hModule is NULL we return the process image - which will be @@ -939,6 +945,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH EnumProcessModules( HANDLE process, HMODULE *modul { struct module_iterator iter; DWORD size = 0; + BOOL target_wow64; INT ret;
if (process == GetCurrentProcess()) @@ -972,7 +979,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH EnumProcessModules( HANDLE process, HMODULE *modul return TRUE; }
- if (!init_module_iterator( &iter, process )) return FALSE; + if (!IsWow64Process( process, &target_wow64 )) return FALSE; + if (!init_module_iterator( &iter, process, is_win64 && target_wow64 )) return FALSE;
if (count && !module) { @@ -1003,6 +1011,41 @@ BOOL WINAPI DECLSPEC_HOTPATCH EnumProcessModules( HANDLE process, HMODULE *modul }
+struct module_push +{ + HMODULE *module; + unsigned count; + unsigned size; +}; + +static void module_push( struct module_push *mp, HMODULE module ) +{ + if (mp->count >= sizeof(HMODULE)) + { + *mp->module++ = module; + mp->count -= sizeof(HMODULE); + } + mp->size += sizeof(HMODULE); +} + +static void module_push_iter( struct module_push *mp, struct module_iterator *iter ) +{ + if (sizeof(void *) == 8 && iter->wow64) + module_push( mp, (HMODULE) (DWORD_PTR)iter->ldr_module32.BaseAddress ); + else + module_push( mp, iter->ldr_module.DllBase ); +} + +static int module_push_all( struct module_push *mp, struct module_iterator *iter ) +{ + int ret; + + while ((ret = module_iterator_next( iter )) > 0) + module_push_iter( mp, iter ); + + return ret; +} + /*********************************************************************** * EnumProcessModulesEx (kernelbase.@) * K32EnumProcessModulesEx (kernelbase.@) @@ -1010,8 +1053,96 @@ BOOL WINAPI DECLSPEC_HOTPATCH EnumProcessModules( HANDLE process, HMODULE *modul BOOL WINAPI EnumProcessModulesEx( HANDLE process, HMODULE *module, DWORD count, DWORD *needed, DWORD filter ) { - FIXME( "(%p, %p, %ld, %p, %ld) semi-stub\n", process, module, count, needed, filter ); - return EnumProcessModules( process, module, count, needed ); + struct module_push mp = {module, count, 0}; + unsigned list_mode; + BOOL target_wow64; + INT ret = 0; + + TRACE( "(%p, %p, %ld, %p, %ld)\n", process, module, count, needed, filter ); + + if (process != GetCurrentProcess()) + { + if (!IsWow64Process( process, &target_wow64 )) return FALSE; + } + else target_wow64 = is_wow64; + + if (filter & ~LIST_MODULES_ALL) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + list_mode = filter & LIST_MODULES_ALL; + /* Can't access 64bit process from (wow64) 32bit */ + if (is_wow64 && !target_wow64) + { + SetLastError( ERROR_PARTIAL_COPY ); + return FALSE; + } + if (count && !module) + { + SetLastError( ERROR_NOACCESS ); + return FALSE; + } + + if (process == GetCurrentProcess()) + { + if (!(is_win64 && list_mode == LIST_MODULES_32BIT)) + { + PPEB_LDR_DATA ldr_data = NtCurrentTeb()->Peb->LdrData; + PLIST_ENTRY head = &ldr_data->InLoadOrderModuleList; + PLIST_ENTRY entry = head->Flink; + + while (entry != head) + { + LDR_DATA_TABLE_ENTRY *ldr = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks ); + module_push( &mp, ldr->DllBase ); + entry = entry->Flink; + } + } + } + else + { + struct module_iterator iter; + + if (is_win64 && target_wow64 && (list_mode & LIST_MODULES_32BIT)) + { + if (!init_module_iterator( &iter, process, TRUE ) || module_push_all( &mp, &iter ) < 0) + return FALSE; + } + if (!(is_win64 && list_mode == LIST_MODULES_32BIT)) + { + if (init_module_iterator( &iter, process, FALSE )) + { + if (is_win64 && target_wow64 && (list_mode & LIST_MODULES_64BIT)) + /* Don't add main module twice in _ALL mode */ + ret = module_iterator_next( &iter ); + if (ret >= 0) ret = module_push_all( &mp, &iter ); + } + else if (GetLastError() == ERROR_EMPTY) + { + /* We're running on "old" wow configuration. + * Fallback to PEB32 to get at least main module if requested. + */ + if (list_mode == LIST_MODULES_DEFAULT) + { + if (init_module_iterator( &iter, process, TRUE ) && module_iterator_next( &iter ) > 0) + module_push_iter( &mp, &iter ); + else + ret = -1; + } + } + else + return FALSE; + } + } + + if (!needed) + { + SetLastError( ERROR_NOACCESS ); + return FALSE; + } + *needed = mp.size; + return ret == 0; }
diff --git a/dlls/psapi/tests/psapi_main.c b/dlls/psapi/tests/psapi_main.c index 3ab5a2a5e7d..71eadc7114e 100644 --- a/dlls/psapi/tests/psapi_main.c +++ b/dlls/psapi/tests/psapi_main.c @@ -215,6 +215,10 @@ static BOOL test_EnumProcessModulesEx_snapshot(HANDLE proc, struct moduleex_snap MODULEINFO info; int i, j; BOOL ret; + BOOL fail, wow64; + + ret = IsWow64Process(proc, &wow64); + ok(ret, "IsWow64Process failed: %lu\n", GetLastError());
for (i = 0; i < numsnap; i++) { @@ -227,16 +231,29 @@ static BOOL test_EnumProcessModulesEx_snapshot(HANDLE proc, struct moduleex_snap mxsnap[i].num_modules = min(needed, sizeof(mxsnap[i].modules)) / sizeof(HMODULE); for (j = 0; j < mxsnap[i].num_modules; j++) { + /* temporary todo until GetModuleBaseName and friends are fixed */ + if ((fail = sizeof(void*) == 8 && wow64)) + switch (mxsnap[i].list) + { + case LIST_MODULES_32BIT: fail = FALSE; break; + case LIST_MODULES_DEFAULT: fail = j >= 1; break; + case LIST_MODULES_ALL: fail = j >= mxsnap[0].num_modules; break; + case LIST_MODULES_64BIT: break; + } ret = GetModuleBaseNameA(proc, mxsnap[i].modules[j], buffer, sizeof(buffer)); + todo_wine_if(fail) ok(ret, "GetModuleBaseName failed: %lu (%u/%lu=%p)\n", GetLastError(), j, mxsnap[i].num_modules, mxsnap[i].modules[j]); ret = GetModuleFileNameExA(proc, mxsnap[i].modules[j], buffer, sizeof(buffer)); + todo_wine_if(fail) ok(ret, "GetModuleFileNameEx failed: %lu (%u/%lu=%p)\n", GetLastError(), j, mxsnap[i].num_modules, mxsnap[i].modules[j]); memset(&info, 0, sizeof(info)); ret = GetModuleInformation(proc, mxsnap[i].modules[j], &info, sizeof(info)); + todo_wine_if(fail) { ok(ret, "GetModuleInformation failed: %lu\n", GetLastError()); ok(info.lpBaseOfDll == mxsnap[i].modules[j], "expected %p, got %p\n", mxsnap[i].modules[j], info.lpBaseOfDll); ok(info.SizeOfImage, "image size was 0\n"); /* info.EntryPoint to be checked */ + } } winetest_pop_context(); } @@ -356,7 +373,6 @@ static void test_EnumProcessModulesEx(void) if (sizeof(void *) == 8) { test_EnumProcessModulesEx_snapshot(hpQV, snap, ARRAY_SIZE(snap)); - todo_wine ok(snapshot_is_empty(&snap[0]), "didn't expect 32bit module\n"); ok(snapshot_is_equal(&snap[1], &snap[2]), "mismatch in modules count\n"); ok(snapshot_is_equal(&snap[2], &snap[3]), "mismatch in modules count\n"); @@ -369,9 +385,7 @@ static void test_EnumProcessModulesEx(void) */ SetLastError(0xdeadbeef); ret = EnumProcessModulesEx(hpQV, &hMod, sizeof(HMODULE), &cbNeeded, 0x400); - todo_wine ok(!ret, "succeeded\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected error=ERROR_INVALID_PARAMETER but got %ld\n", GetLastError()); } else if (wow64) @@ -397,7 +411,6 @@ static void test_EnumProcessModulesEx(void) { winetest_push_context("pcs-6464"); test_EnumProcessModulesEx_snapshot(pi.hProcess, snap, ARRAY_SIZE(snap)); - todo_wine ok(snapshot_is_empty(&snap[0]), "didn't expect 32bit module\n"); ok(snapshot_is_subset(&snap[1], &snap[2]), "64bit and default module lists should match\n"); ok(snapshot_is_subset(&snap[2], &snap[3]), "default and all module lists should match\n"); @@ -411,9 +424,7 @@ static void test_EnumProcessModulesEx(void) */ SetLastError(0xdeadbeef); ret = EnumProcessModulesEx(hpQV, &hMod, sizeof(HMODULE), &cbNeeded, 0x400); - todo_wine ok(!ret, "succeeded\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected error=ERROR_INVALID_PARAMETER but got %ld\n", GetLastError()); } else if (wow64) @@ -446,20 +457,19 @@ static void test_EnumProcessModulesEx(void) winetest_push_context("pcs-6432"); test_EnumProcessModulesEx_snapshot(pi.hProcess, snap, ARRAY_SIZE(snap)); ok(!snapshot_is_empty(&snap[0]), "expecting 32bit modules\n"); + /* FIXME: this tests fails on Wine "old" wow configuration, but succceeds in "multi-arch" and Windows */ + todo_wine_if(snapshot_is_empty(&snap[1])) ok(!snapshot_is_empty(&snap[1]), "expecting 64bit modules\n"); ok(snapshot_is_subset(&snap[1], &snap[2]), "64bit and default module lists should match\n"); - todo_wine ok(snapshot_are_disjoint(&snap[0], &snap[1], 0), "32bit and 64bit list should be disjoint\n"); /* Main module (even 32bit) is present in both 32bit (makes sense) but also default * (even if all the other modules are 64bit) */ - todo_wine ok(snapshot_are_disjoint(&snap[0], &snap[2], 1), "32bit and default list should be disjoint\n"); ok(snapshot_is_subset(&snap[0], &snap[3]), "32bit and all module lists should match\n"); ok(snapshot_is_subset(&snap[1], &snap[3]), "64bit and all module lists should match\n"); ok(snapshot_is_subset(&snap[2], &snap[3]), "default and all module list should match\n"); snapshot_check_first_main_module(&snap[0], pi.hProcess, buffer); - todo_wine ok(!snapshot_contains(&snap[1], snap[0].modules[0]), "main module shouldn't be present in 64bit list\n"); snapshot_check_first_main_module(&snap[2], pi.hProcess, buffer); snapshot_check_first_main_module(&snap[3], pi.hProcess, buffer); @@ -469,9 +479,7 @@ static void test_EnumProcessModulesEx(void) */ SetLastError(0xdeadbeef); ret = EnumProcessModulesEx(hpQV, &hMod, sizeof(HMODULE), &cbNeeded, 0x400); - todo_wine ok(!ret, "succeeded\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "expected error=ERROR_INVALID_PARAMETER but got %ld\n", GetLastError());
winetest_pop_context(); @@ -503,7 +511,6 @@ static void test_EnumProcessModulesEx(void) SetLastError(0xdeadbeef); ret = EnumProcessModulesEx(pi.hProcess, &hMod, sizeof(HMODULE), &cbNeeded, snap[i].list); ok(!ret, "succeeded\n"); - todo_wine ok(GetLastError() == ERROR_PARTIAL_COPY, "expected error=ERROR_PARTIAL_COPY but got %ld\n", GetLastError()); } winetest_pop_context();