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