Alexandre Julliard : ntdll/tests: Add tests for RtlWow64GetCurrentCpuArea().
Alexandre Julliard
julliard at winehq.org
Wed Jun 30 16:10:59 CDT 2021
Module: wine
Branch: master
Commit: c9d23a15cef7c8508bc9b82a9247b10a12d4fb49
URL: https://source.winehq.org/git/wine.git/?a=commit;h=c9d23a15cef7c8508bc9b82a9247b10a12d4fb49
Author: Alexandre Julliard <julliard at winehq.org>
Date: Wed Jun 30 11:12:46 2021 +0200
ntdll/tests: Add tests for RtlWow64GetCurrentCpuArea().
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/tests/wow64.c | 130 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 127 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/wow64.c b/dlls/ntdll/tests/wow64.c
index d31afa373e2..b7b63f3fd8c 100644
--- a/dlls/ntdll/tests/wow64.c
+++ b/dlls/ntdll/tests/wow64.c
@@ -34,6 +34,7 @@ static NTSTATUS (WINAPI *pNtWow64WriteVirtualMemory64)(HANDLE,ULONG64,const void
#endif
static BOOL is_wow64;
+static void *code_mem;
static void init(void)
{
@@ -54,6 +55,8 @@ static void init(void)
GET_PROC( NtWow64WriteVirtualMemory64 );
#endif
#undef GET_PROC
+
+ code_mem = VirtualAlloc( NULL, 65536, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE );
}
static void test_process_architecture( HANDLE process, USHORT expect_machine, USHORT expect_native )
@@ -463,6 +466,52 @@ static void test_cpu_area(void)
#else /* _WIN64 */
+static const BYTE call_func64_code[] =
+{
+ 0x58, /* pop %eax */
+ 0x0e, /* push %cs */
+ 0x50, /* push %eax */
+ 0x6a, 0x33, /* push $0x33 */
+ 0xe8, 0x00, 0x00, 0x00, 0x00, /* call 1f */
+ 0x83, 0x04, 0x24, 0x05, /* 1: addl $0x5,(%esp) */
+ 0xcb, /* lret */
+ /* in 64-bit mode: */
+ 0x4c, 0x87, 0xf4, /* xchg %r14,%rsp */
+ 0x55, /* push %rbp */
+ 0x48, 0x89, 0xe5, /* mov %rsp,%rbp */
+ 0x56, /* push %rsi */
+ 0x57, /* push %rdi */
+ 0x41, 0x8b, 0x4e, 0x10, /* mov 0x10(%r14),%ecx */
+ 0x41, 0x8b, 0x76, 0x14, /* mov 0x14(%r14),%esi */
+ 0x67, 0x8d, 0x04, 0xcd, 0, 0, 0, 0, /* lea 0x0(,%ecx,8),%eax */
+ 0x83, 0xf8, 0x20, /* cmp $0x20,%eax */
+ 0x7d, 0x05, /* jge 1f */
+ 0xb8, 0x20, 0x00, 0x00, 0x00, /* mov $0x20,%eax */
+ 0x48, 0x29, 0xc4, /* 1: sub %rax,%rsp */
+ 0x48, 0x83, 0xe4, 0xf0, /* and $~15,%rsp */
+ 0x48, 0x89, 0xe7, /* mov %rsp,%rdi */
+ 0xf3, 0x48, 0xa5, /* rep movsq */
+ 0x48, 0x8b, 0x0c, 0x24, /* mov (%rsp),%rcx */
+ 0x48, 0x8b, 0x54, 0x24, 0x08, /* mov 0x8(%rsp),%rdx */
+ 0x4c, 0x8b, 0x44, 0x24, 0x10, /* mov 0x10(%rsp),%r8 */
+ 0x4c, 0x8b, 0x4c, 0x24, 0x18, /* mov 0x18(%rsp),%r9 */
+ 0x41, 0xff, 0x56, 0x08, /* callq *0x8(%r14) */
+ 0x48, 0x8d, 0x65, 0xf0, /* lea -0x10(%rbp),%rsp */
+ 0x5f, /* pop %rdi */
+ 0x5e, /* pop %rsi */
+ 0x5d, /* pop %rbp */
+ 0x4c, 0x87, 0xf4, /* xchg %r14,%rsp */
+ 0xcb, /* lret */
+};
+
+static NTSTATUS call_func64( ULONG64 func64, int nb_args, ULONG64 *args )
+{
+ NTSTATUS (WINAPI *func)( ULONG64 func64, int nb_args, ULONG64 *args ) = code_mem;
+
+ memcpy( code_mem, call_func64_code, sizeof(call_func64_code) );
+ return func( func64, nb_args, args );
+}
+
static ULONG64 main_module, ntdll_module, wow64_module, wow64cpu_module, wow64win_module;
static void enum_modules64( void (*func)(ULONG64,const WCHAR *) )
@@ -514,6 +563,53 @@ done:
NtClose( process );
}
+static ULONG64 get_proc_address64( ULONG64 module, const char *name )
+{
+ IMAGE_DOS_HEADER dos;
+ IMAGE_NT_HEADERS64 nt;
+ IMAGE_EXPORT_DIRECTORY exports;
+ ULONG i, *names, *funcs;
+ USHORT *ordinals;
+ NTSTATUS status;
+ HANDLE process;
+ ULONG64 ret = 0;
+ char buffer[64];
+
+ if (!module) return 0;
+ process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
+ ok( process != 0, "failed to open current process %u\n", GetLastError() );
+ status = pNtWow64ReadVirtualMemory64( process, module, &dos, sizeof(dos), NULL );
+ ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
+ status = pNtWow64ReadVirtualMemory64( process, module + dos.e_lfanew, &nt, sizeof(nt), NULL );
+ ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
+ status = pNtWow64ReadVirtualMemory64( process, module + nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
+ &exports, sizeof(exports), NULL );
+ ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
+ names = calloc( exports.NumberOfNames, sizeof(*names) );
+ ordinals = calloc( exports.NumberOfNames, sizeof(*ordinals) );
+ funcs = calloc( exports.NumberOfFunctions, sizeof(*funcs) );
+ status = pNtWow64ReadVirtualMemory64( process, module + exports.AddressOfNames,
+ names, exports.NumberOfNames * sizeof(*names), NULL );
+ ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
+ status = pNtWow64ReadVirtualMemory64( process, module + exports.AddressOfNameOrdinals,
+ ordinals, exports.NumberOfNames * sizeof(*ordinals), NULL );
+ ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
+ status = pNtWow64ReadVirtualMemory64( process, module + exports.AddressOfFunctions,
+ funcs, exports.NumberOfFunctions * sizeof(*funcs), NULL );
+ ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
+ for (i = 0; i < exports.NumberOfNames && !ret; i++)
+ {
+ status = pNtWow64ReadVirtualMemory64( process, module + names[i], buffer, sizeof(buffer), NULL );
+ ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
+ if (!strcmp( buffer, name )) ret = module + funcs[ordinals[i]];
+ }
+ free( funcs );
+ free( ordinals );
+ free( names );
+ NtClose( process );
+ return ret;
+}
+
static void check_module( ULONG64 base, const WCHAR *name )
{
if (base == (ULONG_PTR)GetModuleHandleW(0))
@@ -650,6 +746,35 @@ static void test_nt_wow64(void)
NtClose( process );
}
+static void test_cpu_area(void)
+{
+ TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
+ ULONG64 ptr;
+ NTSTATUS status;
+
+ if (!is_wow64) return;
+ if (!ntdll_module) return;
+
+ if ((ptr = get_proc_address64( ntdll_module, "RtlWow64GetCurrentCpuArea" )))
+ {
+ USHORT machine = 0xdead;
+ ULONG64 context, context_ex;
+ ULONG64 args[] = { (ULONG_PTR)&machine, (ULONG_PTR)&context, (ULONG_PTR)&context_ex };
+
+ status = call_func64( ptr, ARRAY_SIZE(args), args );
+ ok( !status, "RtlWow64GetCpuAreaInfo failed %x\n", status );
+ ok( machine == IMAGE_FILE_MACHINE_I386, "wrong machine %x\n", machine );
+ ok( context == teb64->TlsSlots[WOW64_TLS_CPURESERVED] + 4, "wrong context %s / %s\n",
+ wine_dbgstr_longlong(context), wine_dbgstr_longlong(teb64->TlsSlots[WOW64_TLS_CPURESERVED]) );
+ ok( !context_ex, "got context_ex %s\n", wine_dbgstr_longlong(context_ex) );
+ args[0] = args[1] = args[2] = 0;
+ status = call_func64( ptr, ARRAY_SIZE(args), args );
+ ok( !status, "RtlWow64GetCpuAreaInfo failed %x\n", status );
+ }
+ else win_skip( "RtlWow64GetCpuAreaInfo not supported\n" );
+
+}
+
#endif /* _WIN64 */
@@ -658,10 +783,9 @@ START_TEST(wow64)
init();
test_query_architectures();
test_peb_teb();
-#ifdef _WIN64
- test_cpu_area();
-#else
+#ifndef _WIN64
test_nt_wow64();
test_modules();
#endif
+ test_cpu_area();
}
More information about the wine-cvs
mailing list