ntdll/tests: Fix some wow64 test failures on Windows.
[wine.git] / dlls / ntdll / tests / wow64.c
blob9e09c60c32c8499e41e18f26637f119712024652
1 /*
2 * Unit test suite Wow64 functions
4 * Copyright 2021 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "ntdll_test.h"
23 #include "winioctl.h"
25 static NTSTATUS (WINAPI *pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS,void*,ULONG,ULONG*);
26 static NTSTATUS (WINAPI *pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS,void*,ULONG,void*,ULONG,ULONG*);
27 static NTSTATUS (WINAPI *pRtlGetNativeSystemInformation)(SYSTEM_INFORMATION_CLASS,void*,ULONG,ULONG*);
28 static USHORT (WINAPI *pRtlWow64GetCurrentMachine)(void);
29 static NTSTATUS (WINAPI *pRtlWow64GetProcessMachines)(HANDLE,WORD*,WORD*);
30 static NTSTATUS (WINAPI *pRtlWow64GetThreadContext)(HANDLE,WOW64_CONTEXT*);
31 static NTSTATUS (WINAPI *pRtlWow64IsWowGuestMachineSupported)(USHORT,BOOLEAN*);
32 #ifdef _WIN64
33 static NTSTATUS (WINAPI *pRtlWow64GetCpuAreaInfo)(WOW64_CPURESERVED*,ULONG,WOW64_CPU_AREA_INFO*);
34 static NTSTATUS (WINAPI *pRtlWow64GetThreadSelectorEntry)(HANDLE,THREAD_DESCRIPTOR_INFORMATION*,ULONG,ULONG*);
35 #else
36 static NTSTATUS (WINAPI *pNtWow64AllocateVirtualMemory64)(HANDLE,ULONG64*,ULONG64,ULONG64*,ULONG,ULONG);
37 static NTSTATUS (WINAPI *pNtWow64GetNativeSystemInformation)(SYSTEM_INFORMATION_CLASS,void*,ULONG,ULONG*);
38 static NTSTATUS (WINAPI *pNtWow64ReadVirtualMemory64)(HANDLE,ULONG64,void*,ULONG64,ULONG64*);
39 static NTSTATUS (WINAPI *pNtWow64WriteVirtualMemory64)(HANDLE,ULONG64,const void *,ULONG64,ULONG64*);
40 #endif
42 static BOOL is_wow64;
43 static void *code_mem;
45 static void init(void)
47 HMODULE ntdll = GetModuleHandleA( "ntdll.dll" );
49 if (!IsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
51 #define GET_PROC(func) p##func = (void *)GetProcAddress( ntdll, #func )
52 GET_PROC( NtQuerySystemInformation );
53 GET_PROC( NtQuerySystemInformationEx );
54 GET_PROC( RtlGetNativeSystemInformation );
55 GET_PROC( RtlWow64GetCurrentMachine );
56 GET_PROC( RtlWow64GetProcessMachines );
57 GET_PROC( RtlWow64GetThreadContext );
58 GET_PROC( RtlWow64IsWowGuestMachineSupported );
59 #ifdef _WIN64
60 GET_PROC( RtlWow64GetCpuAreaInfo );
61 GET_PROC( RtlWow64GetThreadSelectorEntry );
62 #else
63 GET_PROC( NtWow64AllocateVirtualMemory64 );
64 GET_PROC( NtWow64GetNativeSystemInformation );
65 GET_PROC( NtWow64ReadVirtualMemory64 );
66 GET_PROC( NtWow64WriteVirtualMemory64 );
67 #endif
68 #undef GET_PROC
70 code_mem = VirtualAlloc( NULL, 65536, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE );
73 static void test_process_architecture( HANDLE process, USHORT expect_machine, USHORT expect_native )
75 NTSTATUS status;
76 ULONG i, len, buffer[8];
78 len = 0xdead;
79 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
80 &buffer, sizeof(buffer), &len );
81 ok( !status, "failed %x\n", status );
82 ok( !(len & 3), "wrong len %x\n", len );
83 len /= sizeof(DWORD);
84 for (i = 0; i < len - 1; i++)
86 USHORT flags = HIWORD(buffer[i]);
87 USHORT machine = LOWORD(buffer[i]);
89 if (flags & 8)
90 ok( machine == expect_machine, "wrong current machine %x\n", buffer[i]);
91 else
92 ok( machine != expect_machine, "wrong machine %x\n", buffer[i]);
94 /* FIXME: not quite sure what the other flags mean,
95 * observed on amd64 Windows: (flags & 7) == 7 for MACHINE_AMD64 and 2 for MACHINE_I386
97 if (flags & 4)
98 ok( machine == expect_native, "wrong native machine %x\n", buffer[i]);
99 else
100 ok( machine != expect_native, "wrong machine %x\n", buffer[i]);
102 ok( !buffer[i], "missing terminating null\n" );
104 len = i * sizeof(DWORD);
105 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
106 &buffer, len, &len );
107 ok( status == STATUS_BUFFER_TOO_SMALL, "failed %x\n", status );
108 ok( len == (i + 1) * sizeof(DWORD), "wrong len %u\n", len );
110 if (pRtlWow64GetProcessMachines)
112 USHORT current = 0xdead, native = 0xbeef;
113 status = pRtlWow64GetProcessMachines( process, &current, &native );
114 ok( !status, "failed %x\n", status );
115 if (expect_machine == expect_native)
116 ok( current == 0, "wrong current machine %x / %x\n", current, expect_machine );
117 else
118 ok( current == expect_machine, "wrong current machine %x / %x\n", current, expect_machine );
119 ok( native == expect_native, "wrong native machine %x / %x\n", native, expect_native );
123 static void test_query_architectures(void)
125 #ifdef __i386__
126 USHORT current_machine = IMAGE_FILE_MACHINE_I386;
127 USHORT native_machine = is_wow64 ? IMAGE_FILE_MACHINE_AMD64 : IMAGE_FILE_MACHINE_I386;
128 #elif defined __x86_64__
129 USHORT current_machine = IMAGE_FILE_MACHINE_AMD64;
130 USHORT native_machine = IMAGE_FILE_MACHINE_AMD64;
131 #elif defined __arm__
132 USHORT current_machine = IMAGE_FILE_MACHINE_ARMNT;
133 USHORT native_machine = is_wow64 ? IMAGE_FILE_MACHINE_ARM64 : IMAGE_FILE_MACHINE_ARMNT;
134 #elif defined __aarch64__
135 USHORT current_machine = IMAGE_FILE_MACHINE_ARM64;
136 USHORT native_machine = IMAGE_FILE_MACHINE_ARM64;
137 #else
138 USHORT current_machine = 0;
139 USHORT native_machine = 0;
140 #endif
141 PROCESS_INFORMATION pi;
142 STARTUPINFOA si = { sizeof(si) };
143 NTSTATUS status;
144 HANDLE process;
145 ULONG len, buffer[8];
147 if (!pNtQuerySystemInformationEx) return;
149 process = GetCurrentProcess();
150 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
151 &buffer, sizeof(buffer), &len );
152 if (status == STATUS_INVALID_INFO_CLASS)
154 win_skip( "SystemSupportedProcessorArchitectures not supported\n" );
155 return;
157 ok( !status, "failed %x\n", status );
159 process = (HANDLE)0xdeadbeef;
160 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
161 &buffer, sizeof(buffer), &len );
162 ok( status == STATUS_INVALID_HANDLE, "failed %x\n", status );
163 process = (HANDLE)0xdeadbeef;
164 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, 3,
165 &buffer, sizeof(buffer), &len );
166 ok( status == STATUS_INVALID_PARAMETER || broken(status == STATUS_INVALID_HANDLE),
167 "failed %x\n", status );
168 process = GetCurrentProcess();
169 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, 3,
170 &buffer, sizeof(buffer), &len );
171 ok( status == STATUS_INVALID_PARAMETER || broken( status == STATUS_SUCCESS),
172 "failed %x\n", status );
173 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, NULL, 0,
174 &buffer, sizeof(buffer), &len );
175 ok( status == STATUS_INVALID_PARAMETER, "failed %x\n", status );
177 test_process_architecture( GetCurrentProcess(), current_machine, native_machine );
178 test_process_architecture( 0, 0, native_machine );
180 if (CreateProcessA( "C:\\Program Files\\Internet Explorer\\iexplore.exe", NULL, NULL, NULL,
181 FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
183 test_process_architecture( pi.hProcess, native_machine, native_machine );
184 TerminateProcess( pi.hProcess, 0 );
185 CloseHandle( pi.hProcess );
186 CloseHandle( pi.hThread );
188 if (CreateProcessA( "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe", NULL, NULL, NULL,
189 FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
191 test_process_architecture( pi.hProcess, IMAGE_FILE_MACHINE_I386, native_machine );
192 TerminateProcess( pi.hProcess, 0 );
193 CloseHandle( pi.hProcess );
194 CloseHandle( pi.hThread );
197 if (pRtlWow64GetCurrentMachine)
199 USHORT machine = pRtlWow64GetCurrentMachine();
200 ok( machine == current_machine, "wrong machine %x / %x\n", machine, current_machine );
202 if (pRtlWow64IsWowGuestMachineSupported)
204 BOOLEAN ret = 0xcc;
205 status = pRtlWow64IsWowGuestMachineSupported( IMAGE_FILE_MACHINE_I386, &ret );
206 ok( !status, "failed %x\n", status );
207 ok( ret == (native_machine == IMAGE_FILE_MACHINE_AMD64 ||
208 native_machine == IMAGE_FILE_MACHINE_ARM64), "wrong result %u\n", ret );
209 ret = 0xcc;
210 status = pRtlWow64IsWowGuestMachineSupported( IMAGE_FILE_MACHINE_ARMNT, &ret );
211 ok( !status, "failed %x\n", status );
212 ok( ret == (native_machine == IMAGE_FILE_MACHINE_ARM64), "wrong result %u\n", ret );
213 ret = 0xcc;
214 status = pRtlWow64IsWowGuestMachineSupported( IMAGE_FILE_MACHINE_AMD64, &ret );
215 ok( !status, "failed %x\n", status );
216 ok( !ret, "wrong result %u\n", ret );
217 ret = 0xcc;
218 status = pRtlWow64IsWowGuestMachineSupported( IMAGE_FILE_MACHINE_ARM64, &ret );
219 ok( !status, "failed %x\n", status );
220 ok( !ret, "wrong result %u\n", ret );
221 ret = 0xcc;
222 status = pRtlWow64IsWowGuestMachineSupported( 0xdead, &ret );
223 ok( !status, "failed %x\n", status );
224 ok( !ret, "wrong result %u\n", ret );
228 static void test_peb_teb(void)
230 PROCESS_BASIC_INFORMATION proc_info;
231 THREAD_BASIC_INFORMATION info;
232 PROCESS_INFORMATION pi;
233 STARTUPINFOA si = {0};
234 NTSTATUS status;
235 void *redir;
236 SIZE_T res;
237 TEB teb;
238 PEB peb;
239 TEB32 teb32;
240 PEB32 peb32;
241 RTL_USER_PROCESS_PARAMETERS params;
242 RTL_USER_PROCESS_PARAMETERS32 params32;
244 Wow64DisableWow64FsRedirection( &redir );
246 if (CreateProcessA( "C:\\windows\\syswow64\\notepad.exe", NULL, NULL, NULL,
247 FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
249 memset( &info, 0xcc, sizeof(info) );
250 status = NtQueryInformationThread( pi.hThread, ThreadBasicInformation, &info, sizeof(info), NULL );
251 ok( !status, "ThreadBasicInformation failed %x\n", status );
252 if (!ReadProcessMemory( pi.hProcess, info.TebBaseAddress, &teb, sizeof(teb), &res )) res = 0;
253 ok( res == sizeof(teb), "wrong len %lx\n", res );
254 ok( teb.Tib.Self == info.TebBaseAddress, "wrong teb %p / %p\n", teb.Tib.Self, info.TebBaseAddress );
255 if (is_wow64)
257 ok( !!teb.GdiBatchCount, "GdiBatchCount not set\n" );
258 ok( (char *)info.TebBaseAddress + teb.WowTebOffset == ULongToPtr(teb.GdiBatchCount) ||
259 broken(!NtCurrentTeb()->WowTebOffset), /* pre-win10 */
260 "wrong teb offset %d\n", teb.WowTebOffset );
262 else
264 ok( !teb.GdiBatchCount, "GdiBatchCount set\n" );
265 ok( teb.WowTebOffset == 0x2000 ||
266 broken( !teb.WowTebOffset || teb.WowTebOffset == 1 ), /* pre-win10 */
267 "wrong teb offset %d\n", teb.WowTebOffset );
268 ok( (char *)teb.Tib.ExceptionList == (char *)info.TebBaseAddress + 0x2000,
269 "wrong Tib.ExceptionList %p / %p\n",
270 (char *)teb.Tib.ExceptionList, (char *)info.TebBaseAddress + 0x2000 );
271 if (!ReadProcessMemory( pi.hProcess, teb.Tib.ExceptionList, &teb32, sizeof(teb32), &res )) res = 0;
272 ok( res == sizeof(teb32), "wrong len %lx\n", res );
273 ok( (char *)ULongToPtr(teb32.Peb) == (char *)teb.Peb + 0x1000 ||
274 broken( ULongToPtr(teb32.Peb) != teb.Peb ), /* vista */
275 "wrong peb %p / %p\n", ULongToPtr(teb32.Peb), teb.Peb );
278 status = NtQueryInformationProcess( pi.hProcess, ProcessBasicInformation,
279 &proc_info, sizeof(proc_info), NULL );
280 ok( !status, "ProcessBasicInformation failed %x\n", status );
281 ok( proc_info.PebBaseAddress == teb.Peb, "wrong peb %p / %p\n", proc_info.PebBaseAddress, teb.Peb );
283 if (!ReadProcessMemory( pi.hProcess, proc_info.PebBaseAddress, &peb, sizeof(peb), &res )) res = 0;
284 ok( res == sizeof(peb), "wrong len %lx\n", res );
285 ok( !peb.BeingDebugged, "BeingDebugged is %u\n", peb.BeingDebugged );
286 if (!is_wow64)
288 if (!ReadProcessMemory( pi.hProcess, ULongToPtr(teb32.Peb), &peb32, sizeof(peb32), &res )) res = 0;
289 ok( res == sizeof(peb32), "wrong len %lx\n", res );
290 ok( !peb32.BeingDebugged, "BeingDebugged is %u\n", peb32.BeingDebugged );
293 if (!ReadProcessMemory( pi.hProcess, peb.ProcessParameters, &params, sizeof(params), &res )) res = 0;
294 ok( res == sizeof(params), "wrong len %lx\n", res );
295 #define CHECK_STR(name) \
296 ok( (char *)params.name.Buffer >= (char *)peb.ProcessParameters && \
297 (char *)params.name.Buffer < (char *)peb.ProcessParameters + params.Size, \
298 "wrong " #name " ptr %p / %p-%p\n", params.name.Buffer, peb.ProcessParameters, \
299 (char *)peb.ProcessParameters + params.Size )
300 CHECK_STR( ImagePathName );
301 CHECK_STR( CommandLine );
302 CHECK_STR( WindowTitle );
303 CHECK_STR( Desktop );
304 CHECK_STR( ShellInfo );
305 #undef CHECK_STR
306 if (!is_wow64)
308 ok( peb32.ProcessParameters && ULongToPtr(peb32.ProcessParameters) != peb.ProcessParameters,
309 "wrong ptr32 %p / %p\n", ULongToPtr(peb32.ProcessParameters), peb.ProcessParameters );
310 if (!ReadProcessMemory( pi.hProcess, ULongToPtr(peb32.ProcessParameters), &params32, sizeof(params32), &res )) res = 0;
311 ok( res == sizeof(params32), "wrong len %lx\n", res );
312 #define CHECK_STR(name) \
313 ok( ULongToPtr(params32.name.Buffer) >= ULongToPtr(peb32.ProcessParameters) && \
314 ULongToPtr(params32.name.Buffer) < ULongToPtr(peb32.ProcessParameters + params32.Size), \
315 "wrong " #name " ptr %x / %x-%x\n", params32.name.Buffer, peb32.ProcessParameters, \
316 peb32.ProcessParameters + params.Size ); \
317 ok( params32.name.Length == params.name.Length, "wrong " #name "len %u / %u\n", \
318 params32.name.Length, params.name.Length )
319 CHECK_STR( ImagePathName );
320 CHECK_STR( CommandLine );
321 CHECK_STR( WindowTitle );
322 CHECK_STR( Desktop );
323 CHECK_STR( ShellInfo );
324 #undef CHECK_STR
325 ok( params32.EnvironmentSize == params.EnvironmentSize, "wrong size %u / %lu\n",
326 params32.EnvironmentSize, params.EnvironmentSize );
329 ok( DebugActiveProcess( pi.dwProcessId ), "debugging failed\n" );
330 if (!ReadProcessMemory( pi.hProcess, proc_info.PebBaseAddress, &peb, sizeof(peb), &res )) res = 0;
331 ok( res == sizeof(peb), "wrong len %lx\n", res );
332 ok( peb.BeingDebugged == 1, "BeingDebugged is %u\n", peb.BeingDebugged );
333 if (!is_wow64)
335 if (!ReadProcessMemory( pi.hProcess, ULongToPtr(teb32.Peb), &peb32, sizeof(peb32), &res )) res = 0;
336 ok( res == sizeof(peb32), "wrong len %lx\n", res );
337 ok( peb32.BeingDebugged == 1, "BeingDebugged is %u\n", peb32.BeingDebugged );
340 TerminateProcess( pi.hProcess, 0 );
341 CloseHandle( pi.hProcess );
342 CloseHandle( pi.hThread );
345 if (CreateProcessA( "C:\\windows\\system32\\notepad.exe", NULL, NULL, NULL,
346 FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
348 memset( &info, 0xcc, sizeof(info) );
349 status = NtQueryInformationThread( pi.hThread, ThreadBasicInformation, &info, sizeof(info), NULL );
350 ok( !status, "ThreadBasicInformation failed %x\n", status );
351 if (!is_wow64)
353 if (!ReadProcessMemory( pi.hProcess, info.TebBaseAddress, &teb, sizeof(teb), &res )) res = 0;
354 ok( res == sizeof(teb), "wrong len %lx\n", res );
355 ok( teb.Tib.Self == info.TebBaseAddress, "wrong teb %p / %p\n",
356 teb.Tib.Self, info.TebBaseAddress );
357 ok( !teb.GdiBatchCount, "GdiBatchCount set\n" );
358 ok( !teb.WowTebOffset || broken( teb.WowTebOffset == 1 ), /* vista */
359 "wrong teb offset %d\n", teb.WowTebOffset );
361 else ok( !info.TebBaseAddress, "got teb %p\n", info.TebBaseAddress );
363 status = NtQueryInformationProcess( pi.hProcess, ProcessBasicInformation,
364 &proc_info, sizeof(proc_info), NULL );
365 ok( !status, "ProcessBasicInformation failed %x\n", status );
366 if (is_wow64)
367 ok( !proc_info.PebBaseAddress ||
368 broken( (char *)proc_info.PebBaseAddress >= (char *)0x7f000000 ), /* vista */
369 "wrong peb %p\n", proc_info.PebBaseAddress );
370 else
371 ok( proc_info.PebBaseAddress == teb.Peb, "wrong peb %p / %p\n",
372 proc_info.PebBaseAddress, teb.Peb );
374 TerminateProcess( pi.hProcess, 0 );
375 CloseHandle( pi.hProcess );
376 CloseHandle( pi.hThread );
379 Wow64RevertWow64FsRedirection( redir );
381 #ifndef _WIN64
382 if (is_wow64)
384 PEB64 *peb64;
385 TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
387 ok( !!teb64, "GdiBatchCount not set\n" );
388 ok( (char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset == (char *)teb64 ||
389 broken(!NtCurrentTeb()->WowTebOffset), /* pre-win10 */
390 "wrong WowTebOffset %x (%p/%p)\n", NtCurrentTeb()->WowTebOffset, teb64, NtCurrentTeb() );
391 ok( (char *)teb64 + 0x2000 == (char *)NtCurrentTeb(), "unexpected diff %p / %p\n",
392 teb64, NtCurrentTeb() );
393 ok( (char *)teb64 + teb64->WowTebOffset == (char *)NtCurrentTeb() ||
394 broken( !teb64->WowTebOffset || teb64->WowTebOffset == 1 ), /* pre-win10 */
395 "wrong WowTebOffset %x (%p/%p)\n", teb64->WowTebOffset, teb64, NtCurrentTeb() );
396 ok( !teb64->GdiBatchCount, "GdiBatchCount set %x\n", teb64->GdiBatchCount );
397 ok( teb64->Tib.ExceptionList == PtrToUlong( NtCurrentTeb() ), "wrong Tib.ExceptionList %s / %p\n",
398 wine_dbgstr_longlong(teb64->Tib.ExceptionList), NtCurrentTeb() );
399 ok( teb64->Tib.Self == PtrToUlong( teb64 ), "wrong Tib.Self %s / %p\n",
400 wine_dbgstr_longlong(teb64->Tib.Self), teb64 );
401 ok( teb64->StaticUnicodeString.Buffer == PtrToUlong( teb64->StaticUnicodeBuffer ),
402 "wrong StaticUnicodeString %s / %p\n",
403 wine_dbgstr_longlong(teb64->StaticUnicodeString.Buffer), teb64->StaticUnicodeBuffer );
404 ok( teb64->ClientId.UniqueProcess == GetCurrentProcessId(), "wrong pid %s / %x\n",
405 wine_dbgstr_longlong(teb64->ClientId.UniqueProcess), GetCurrentProcessId() );
406 ok( teb64->ClientId.UniqueThread == GetCurrentThreadId(), "wrong tid %s / %x\n",
407 wine_dbgstr_longlong(teb64->ClientId.UniqueThread), GetCurrentThreadId() );
408 peb64 = ULongToPtr( teb64->Peb );
409 ok( peb64->ImageBaseAddress == PtrToUlong( NtCurrentTeb()->Peb->ImageBaseAddress ),
410 "wrong ImageBaseAddress %s / %p\n",
411 wine_dbgstr_longlong(peb64->ImageBaseAddress), NtCurrentTeb()->Peb->ImageBaseAddress);
412 ok( peb64->OSBuildNumber == NtCurrentTeb()->Peb->OSBuildNumber, "wrong OSBuildNumber %x / %x\n",
413 peb64->OSBuildNumber, NtCurrentTeb()->Peb->OSBuildNumber );
414 ok( peb64->OSPlatformId == NtCurrentTeb()->Peb->OSPlatformId, "wrong OSPlatformId %x / %x\n",
415 peb64->OSPlatformId, NtCurrentTeb()->Peb->OSPlatformId );
416 return;
418 #endif
419 ok( !NtCurrentTeb()->GdiBatchCount, "GdiBatchCount set to %x\n", NtCurrentTeb()->GdiBatchCount );
420 ok( !NtCurrentTeb()->WowTebOffset || broken( NtCurrentTeb()->WowTebOffset == 1 ), /* vista */
421 "WowTebOffset set to %x\n", NtCurrentTeb()->WowTebOffset );
424 static void test_selectors(void)
426 THREAD_DESCRIPTOR_INFORMATION info;
427 NTSTATUS status;
428 ULONG base, limit, sel, retlen;
429 I386_CONTEXT context = { CONTEXT_I386_CONTROL | CONTEXT_I386_SEGMENTS };
431 #ifdef _WIN64
432 if (!pRtlWow64GetThreadSelectorEntry)
434 win_skip( "RtlWow64GetThreadSelectorEntry not supported\n" );
435 return;
437 if (!pRtlWow64GetThreadContext || pRtlWow64GetThreadContext( GetCurrentThread(), &context ))
439 /* hardcoded values */
440 context.SegCs = 0x23;
441 #ifdef __x86_64__
442 __asm__( "movw %%fs,%0" : "=m" (context.SegFs) );
443 __asm__( "movw %%ss,%0" : "=m" (context.SegSs) );
444 #else
445 context.SegSs = 0x2b;
446 context.SegFs = 0x53;
447 #endif
449 #define GET_ENTRY(info,size,ret) \
450 pRtlWow64GetThreadSelectorEntry( GetCurrentThread(), info, size, ret )
452 #else
453 GetThreadContext( GetCurrentThread(), &context );
454 #define GET_ENTRY(info,size,ret) \
455 NtQueryInformationThread( GetCurrentThread(), ThreadDescriptorTableEntry, info, size, ret )
456 #endif
458 trace( "cs %04x ss %04x fs %04x\n", context.SegCs, context.SegSs, context.SegFs );
459 retlen = 0xdeadbeef;
460 info.Selector = 0;
461 status = GET_ENTRY( &info, sizeof(info) - 1, &retlen );
462 ok( status == STATUS_INFO_LENGTH_MISMATCH, "wrong status %x\n", status );
463 ok( retlen == 0xdeadbeef, "len set %u\n", retlen );
465 retlen = 0xdeadbeef;
466 status = GET_ENTRY( &info, sizeof(info) + 1, &retlen );
467 ok( status == STATUS_INFO_LENGTH_MISMATCH, "wrong status %x\n", status );
468 ok( retlen == 0xdeadbeef, "len set %u\n", retlen );
470 retlen = 0xdeadbeef;
471 status = GET_ENTRY( NULL, 0, &retlen );
472 ok( status == STATUS_INFO_LENGTH_MISMATCH, "wrong status %x\n", status );
473 ok( retlen == 0xdeadbeef, "len set %u\n", retlen );
475 status = GET_ENTRY( &info, sizeof(info), NULL );
476 ok( !status, "wrong status %x\n", status );
478 for (info.Selector = 0; info.Selector < 0x100; info.Selector++)
480 retlen = 0xdeadbeef;
481 status = GET_ENTRY( &info, sizeof(info), &retlen );
482 base = (info.Entry.BaseLow |
483 (info.Entry.HighWord.Bytes.BaseMid << 16) |
484 (info.Entry.HighWord.Bytes.BaseHi << 24));
485 limit = (info.Entry.LimitLow | info.Entry.HighWord.Bits.LimitHi << 16);
486 sel = info.Selector | 3;
488 if (sel == 0x03) /* null selector */
490 ok( !status, "wrong status %x\n", status );
491 ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
492 ok( !base, "wrong base %x\n", base );
493 ok( !limit, "wrong limit %x\n", limit );
494 ok( !info.Entry.HighWord.Bytes.Flags1, "wrong flags1 %x\n", info.Entry.HighWord.Bytes.Flags1 );
495 ok( !info.Entry.HighWord.Bytes.Flags2, "wrong flags2 %x\n", info.Entry.HighWord.Bytes.Flags2 );
497 else if (sel == context.SegCs) /* 32-bit code selector */
499 ok( !status, "wrong status %x\n", status );
500 ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
501 ok( !base, "wrong base %x\n", base );
502 ok( limit == 0xfffff, "wrong limit %x\n", limit );
503 ok( info.Entry.HighWord.Bits.Type == 0x1b, "wrong type %x\n", info.Entry.HighWord.Bits.Type );
504 ok( info.Entry.HighWord.Bits.Dpl == 3, "wrong dpl %x\n", info.Entry.HighWord.Bits.Dpl );
505 ok( info.Entry.HighWord.Bits.Pres, "wrong pres\n" );
506 ok( !info.Entry.HighWord.Bits.Sys, "wrong sys\n" );
507 ok( info.Entry.HighWord.Bits.Default_Big, "wrong big\n" );
508 ok( info.Entry.HighWord.Bits.Granularity, "wrong granularity\n" );
510 else if (sel == context.SegSs) /* 32-bit data selector */
512 ok( !status, "wrong status %x\n", status );
513 ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
514 ok( !base, "wrong base %x\n", base );
515 ok( limit == 0xfffff, "wrong limit %x\n", limit );
516 ok( info.Entry.HighWord.Bits.Type == 0x13, "wrong type %x\n", info.Entry.HighWord.Bits.Type );
517 ok( info.Entry.HighWord.Bits.Dpl == 3, "wrong dpl %x\n", info.Entry.HighWord.Bits.Dpl );
518 ok( info.Entry.HighWord.Bits.Pres, "wrong pres\n" );
519 ok( !info.Entry.HighWord.Bits.Sys, "wrong sys\n" );
520 ok( info.Entry.HighWord.Bits.Default_Big, "wrong big\n" );
521 ok( info.Entry.HighWord.Bits.Granularity, "wrong granularity\n" );
523 else if (sel == context.SegFs) /* TEB selector */
525 ok( !status, "wrong status %x\n", status );
526 ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
527 #ifdef _WIN64
528 if (NtCurrentTeb()->WowTebOffset == 0x2000)
529 ok( base == (ULONG_PTR)NtCurrentTeb() + 0x2000, "wrong base %x / %p\n",
530 base, NtCurrentTeb() );
531 #else
532 ok( base == (ULONG_PTR)NtCurrentTeb(), "wrong base %x / %p\n", base, NtCurrentTeb() );
533 #endif
534 ok( limit == 0xfff || broken(limit == 0x4000), /* <= win8 */
535 "wrong limit %x\n", limit );
536 ok( info.Entry.HighWord.Bits.Type == 0x13, "wrong type %x\n", info.Entry.HighWord.Bits.Type );
537 ok( info.Entry.HighWord.Bits.Dpl == 3, "wrong dpl %x\n", info.Entry.HighWord.Bits.Dpl );
538 ok( info.Entry.HighWord.Bits.Pres, "wrong pres\n" );
539 ok( !info.Entry.HighWord.Bits.Sys, "wrong sys\n" );
540 ok( info.Entry.HighWord.Bits.Default_Big, "wrong big\n" );
541 ok( !info.Entry.HighWord.Bits.Granularity, "wrong granularity\n" );
543 else if (!status)
545 ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
546 trace( "succeeded for %x base %x limit %x type %x\n",
547 sel, base, limit, info.Entry.HighWord.Bits.Type );
549 else
551 ok( status == STATUS_UNSUCCESSFUL ||
552 ((sel & 4) && (status == STATUS_NO_LDT)) ||
553 broken( status == STATUS_ACCESS_VIOLATION), /* <= win8 */
554 "%x: wrong status %x\n", info.Selector, status );
555 ok( retlen == 0xdeadbeef, "len set %u\n", retlen );
558 #undef GET_ENTRY
561 #ifdef _WIN64
563 static void test_cpu_area(void)
565 if (pRtlWow64GetCpuAreaInfo)
567 static const struct
569 USHORT machine;
570 NTSTATUS expect;
571 ULONG align, size, offset, flag;
572 } tests[] =
574 { IMAGE_FILE_MACHINE_I386, 0, 4, 0x2cc, 0x00, 0x00010000 },
575 { IMAGE_FILE_MACHINE_AMD64, 0, 16, 0x4d0, 0x30, 0x00100000 },
576 { IMAGE_FILE_MACHINE_ARMNT, 0, 8, 0x1a0, 0x00, 0x00200000 },
577 { IMAGE_FILE_MACHINE_ARM64, 0, 16, 0x390, 0x00, 0x00400000 },
578 { IMAGE_FILE_MACHINE_ARM, STATUS_INVALID_PARAMETER },
579 { IMAGE_FILE_MACHINE_THUMB, STATUS_INVALID_PARAMETER },
581 USHORT buffer[2048];
582 WOW64_CPURESERVED *cpu;
583 WOW64_CPU_AREA_INFO info;
584 ULONG i, j;
585 NTSTATUS status;
586 #define ALIGN(ptr,align) ((void *)(((ULONG_PTR)(ptr) + (align) - 1) & ~((align) - 1)))
588 for (i = 0; i < ARRAY_SIZE(tests); i++)
590 for (j = 0; j < 8; j++)
592 cpu = (WOW64_CPURESERVED *)(buffer + j);
593 cpu->Flags = 0;
594 cpu->Machine = tests[i].machine;
595 status = pRtlWow64GetCpuAreaInfo( cpu, 0, &info );
596 ok( status == tests[i].expect, "%u:%u: failed %x\n", i, j, status );
597 if (status) continue;
598 ok( info.Context == ALIGN( cpu + 1, tests[i].align ), "%u:%u: wrong offset %u\n",
599 i, j, (ULONG)((char *)info.Context - (char *)cpu) );
600 ok( info.ContextEx == ALIGN( (char *)info.Context + tests[i].size, sizeof(void*) ),
601 "%u:%u: wrong ex offset %u\n", i, j, (ULONG)((char *)info.ContextEx - (char *)cpu) );
602 ok( info.ContextFlagsLocation == (char *)info.Context + tests[i].offset,
603 "%u:%u: wrong flags offset %u\n",
604 i, j, (ULONG)((char *)info.ContextFlagsLocation - (char *)info.Context) );
605 ok( info.CpuReserved == cpu, "%u:%u: wrong cpu %p / %p\n", info.CpuReserved, cpu );
606 ok( info.ContextFlag == tests[i].flag, "%u:%u: wrong flag %08x\n", i, j, info.ContextFlag );
607 ok( info.Machine == tests[i].machine, "%u:%u: wrong machine %x\n", i, j, info.Machine );
610 #undef ALIGN
612 else win_skip( "RtlWow64GetCpuAreaInfo not supported\n" );
615 #else /* _WIN64 */
617 static const BYTE call_func64_code[] =
619 0x58, /* pop %eax */
620 0x0e, /* push %cs */
621 0x50, /* push %eax */
622 0x6a, 0x33, /* push $0x33 */
623 0xe8, 0x00, 0x00, 0x00, 0x00, /* call 1f */
624 0x83, 0x04, 0x24, 0x05, /* 1: addl $0x5,(%esp) */
625 0xcb, /* lret */
626 /* in 64-bit mode: */
627 0x4c, 0x87, 0xf4, /* xchg %r14,%rsp */
628 0x55, /* push %rbp */
629 0x48, 0x89, 0xe5, /* mov %rsp,%rbp */
630 0x56, /* push %rsi */
631 0x57, /* push %rdi */
632 0x41, 0x8b, 0x4e, 0x10, /* mov 0x10(%r14),%ecx */
633 0x41, 0x8b, 0x76, 0x14, /* mov 0x14(%r14),%esi */
634 0x67, 0x8d, 0x04, 0xcd, 0, 0, 0, 0, /* lea 0x0(,%ecx,8),%eax */
635 0x83, 0xf8, 0x20, /* cmp $0x20,%eax */
636 0x7d, 0x05, /* jge 1f */
637 0xb8, 0x20, 0x00, 0x00, 0x00, /* mov $0x20,%eax */
638 0x48, 0x29, 0xc4, /* 1: sub %rax,%rsp */
639 0x48, 0x83, 0xe4, 0xf0, /* and $~15,%rsp */
640 0x48, 0x89, 0xe7, /* mov %rsp,%rdi */
641 0xf3, 0x48, 0xa5, /* rep movsq */
642 0x48, 0x8b, 0x0c, 0x24, /* mov (%rsp),%rcx */
643 0x48, 0x8b, 0x54, 0x24, 0x08, /* mov 0x8(%rsp),%rdx */
644 0x4c, 0x8b, 0x44, 0x24, 0x10, /* mov 0x10(%rsp),%r8 */
645 0x4c, 0x8b, 0x4c, 0x24, 0x18, /* mov 0x18(%rsp),%r9 */
646 0x41, 0xff, 0x56, 0x08, /* callq *0x8(%r14) */
647 0x48, 0x8d, 0x65, 0xf0, /* lea -0x10(%rbp),%rsp */
648 0x5f, /* pop %rdi */
649 0x5e, /* pop %rsi */
650 0x5d, /* pop %rbp */
651 0x4c, 0x87, 0xf4, /* xchg %r14,%rsp */
652 0xcb, /* lret */
655 static NTSTATUS call_func64( ULONG64 func64, int nb_args, ULONG64 *args )
657 NTSTATUS (WINAPI *func)( ULONG64 func64, int nb_args, ULONG64 *args ) = code_mem;
659 memcpy( code_mem, call_func64_code, sizeof(call_func64_code) );
660 return func( func64, nb_args, args );
663 static ULONG64 main_module, ntdll_module, wow64_module, wow64cpu_module, wow64win_module;
665 static void enum_modules64( void (*func)(ULONG64,const WCHAR *) )
667 typedef struct
669 LIST_ENTRY64 InLoadOrderLinks;
670 LIST_ENTRY64 InMemoryOrderLinks;
671 LIST_ENTRY64 InInitializationOrderLinks;
672 ULONG64 DllBase;
673 ULONG64 EntryPoint;
674 ULONG SizeOfImage;
675 UNICODE_STRING64 FullDllName;
676 UNICODE_STRING64 BaseDllName;
677 /* etc. */
678 } LDR_DATA_TABLE_ENTRY64;
680 TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
681 PEB64 peb64;
682 ULONG64 ptr;
683 PEB_LDR_DATA64 ldr;
684 LDR_DATA_TABLE_ENTRY64 entry;
685 NTSTATUS status;
686 HANDLE process;
688 process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
689 ok( process != 0, "failed to open current process %u\n", GetLastError() );
690 status = pNtWow64ReadVirtualMemory64( process, teb64->Peb, &peb64, sizeof(peb64), NULL );
691 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
692 todo_wine
693 ok( peb64.LdrData, "LdrData not initialized\n" );
694 if (!peb64.LdrData) goto done;
695 status = pNtWow64ReadVirtualMemory64( process, peb64.LdrData, &ldr, sizeof(ldr), NULL );
696 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
697 ptr = ldr.InLoadOrderModuleList.Flink;
698 for (;;)
700 WCHAR buffer[256];
701 status = pNtWow64ReadVirtualMemory64( process, ptr, &entry, sizeof(entry), NULL );
702 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
703 status = pNtWow64ReadVirtualMemory64( process, entry.BaseDllName.Buffer, buffer, sizeof(buffer), NULL );
704 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
705 if (status) break;
706 func( entry.DllBase, buffer );
707 ptr = entry.InLoadOrderLinks.Flink;
708 if (ptr == peb64.LdrData + offsetof( PEB_LDR_DATA64, InLoadOrderModuleList )) break;
710 done:
711 NtClose( process );
714 static ULONG64 get_proc_address64( ULONG64 module, const char *name )
716 IMAGE_DOS_HEADER dos;
717 IMAGE_NT_HEADERS64 nt;
718 IMAGE_EXPORT_DIRECTORY exports;
719 ULONG i, *names, *funcs;
720 USHORT *ordinals;
721 NTSTATUS status;
722 HANDLE process;
723 ULONG64 ret = 0;
724 char buffer[64];
726 if (!module) return 0;
727 process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
728 ok( process != 0, "failed to open current process %u\n", GetLastError() );
729 status = pNtWow64ReadVirtualMemory64( process, module, &dos, sizeof(dos), NULL );
730 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
731 status = pNtWow64ReadVirtualMemory64( process, module + dos.e_lfanew, &nt, sizeof(nt), NULL );
732 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
733 status = pNtWow64ReadVirtualMemory64( process, module + nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
734 &exports, sizeof(exports), NULL );
735 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
736 names = calloc( exports.NumberOfNames, sizeof(*names) );
737 ordinals = calloc( exports.NumberOfNames, sizeof(*ordinals) );
738 funcs = calloc( exports.NumberOfFunctions, sizeof(*funcs) );
739 status = pNtWow64ReadVirtualMemory64( process, module + exports.AddressOfNames,
740 names, exports.NumberOfNames * sizeof(*names), NULL );
741 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
742 status = pNtWow64ReadVirtualMemory64( process, module + exports.AddressOfNameOrdinals,
743 ordinals, exports.NumberOfNames * sizeof(*ordinals), NULL );
744 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
745 status = pNtWow64ReadVirtualMemory64( process, module + exports.AddressOfFunctions,
746 funcs, exports.NumberOfFunctions * sizeof(*funcs), NULL );
747 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
748 for (i = 0; i < exports.NumberOfNames && !ret; i++)
750 status = pNtWow64ReadVirtualMemory64( process, module + names[i], buffer, sizeof(buffer), NULL );
751 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
752 if (!strcmp( buffer, name )) ret = module + funcs[ordinals[i]];
754 free( funcs );
755 free( ordinals );
756 free( names );
757 NtClose( process );
758 return ret;
761 static void check_module( ULONG64 base, const WCHAR *name )
763 if (base == (ULONG_PTR)GetModuleHandleW(0))
765 WCHAR *p, module[MAX_PATH];
767 GetModuleFileNameW( 0, module, MAX_PATH );
768 if ((p = wcsrchr( module, '\\' ))) p++;
769 else p = module;
770 ok( !wcsicmp( name, p ), "wrong name %s / %s\n", debugstr_w(name), debugstr_w(module));
771 main_module = base;
772 return;
774 #define CHECK_MODULE(mod) if (!wcsicmp( name, L"" #mod ".dll" )) { mod ## _module = base; return; }
775 CHECK_MODULE(ntdll);
776 CHECK_MODULE(wow64);
777 CHECK_MODULE(wow64cpu);
778 CHECK_MODULE(wow64win);
779 #undef CHECK_MODULE
780 ok( 0, "unknown module %s %s found\n", wine_dbgstr_longlong(base), wine_dbgstr_w(name));
783 static void test_modules(void)
785 if (!is_wow64) return;
786 if (!pNtWow64ReadVirtualMemory64) return;
787 enum_modules64( check_module );
788 todo_wine
790 ok( main_module, "main module not found\n" );
791 ok( ntdll_module, "64-bit ntdll not found\n" );
792 ok( wow64_module, "wow64.dll not found\n" );
793 ok( wow64cpu_module, "wow64cpu.dll not found\n" );
794 ok( wow64win_module, "wow64win.dll not found\n" );
798 static void test_nt_wow64(void)
800 const char str[] = "hello wow64";
801 char buffer[100];
802 NTSTATUS status;
803 ULONG64 res;
804 HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
806 ok( process != 0, "failed to open current process %u\n", GetLastError() );
807 if (pNtWow64ReadVirtualMemory64)
809 status = pNtWow64ReadVirtualMemory64( process, (ULONG_PTR)str, buffer, sizeof(str), &res );
810 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
811 ok( res == sizeof(str), "wrong size %s\n", wine_dbgstr_longlong(res) );
812 ok( !strcmp( buffer, str ), "wrong data %s\n", debugstr_a(buffer) );
813 status = pNtWow64WriteVirtualMemory64( process, (ULONG_PTR)buffer, " bye ", 5, &res );
814 ok( !status, "NtWow64WriteVirtualMemory64 failed %x\n", status );
815 ok( res == 5, "wrong size %s\n", wine_dbgstr_longlong(res) );
816 ok( !strcmp( buffer, " bye wow64" ), "wrong data %s\n", debugstr_a(buffer) );
817 /* current process pseudo-handle is broken on some Windows versions */
818 status = pNtWow64ReadVirtualMemory64( GetCurrentProcess(), (ULONG_PTR)str, buffer, sizeof(str), &res );
819 ok( !status || broken( status == STATUS_INVALID_HANDLE ),
820 "NtWow64ReadVirtualMemory64 failed %x\n", status );
821 status = pNtWow64WriteVirtualMemory64( GetCurrentProcess(), (ULONG_PTR)buffer, " bye ", 5, &res );
822 ok( !status || broken( status == STATUS_INVALID_HANDLE ),
823 "NtWow64WriteVirtualMemory64 failed %x\n", status );
825 else win_skip( "NtWow64ReadVirtualMemory64 not supported\n" );
827 if (pNtWow64AllocateVirtualMemory64)
829 ULONG64 ptr = 0;
830 ULONG64 size = 0x2345;
832 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
833 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
834 ok( !status, "NtWow64AllocateVirtualMemory64 failed %x\n", status );
835 ok( ptr, "ptr not set\n" );
836 ok( size == 0x3000, "size not set %s\n", wine_dbgstr_longlong(size) );
837 ptr += 0x1000;
838 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
839 MEM_RESERVE | MEM_COMMIT, PAGE_READONLY );
840 ok( status == STATUS_CONFLICTING_ADDRESSES, "NtWow64AllocateVirtualMemory64 failed %x\n", status );
841 ptr = 0;
842 size = 0;
843 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
844 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
845 ok( status == STATUS_INVALID_PARAMETER || status == STATUS_INVALID_PARAMETER_4,
846 "NtWow64AllocateVirtualMemory64 failed %x\n", status );
847 size = 0x1000;
848 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 22, &size,
849 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
850 ok( status == STATUS_INVALID_PARAMETER || status == STATUS_INVALID_PARAMETER_3,
851 "NtWow64AllocateVirtualMemory64 failed %x\n", status );
852 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 33, &size,
853 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
854 ok( status == STATUS_INVALID_PARAMETER || status == STATUS_INVALID_PARAMETER_3,
855 "NtWow64AllocateVirtualMemory64 failed %x\n", status );
856 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0x3fffffff, &size,
857 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
858 todo_wine_if( !is_wow64 )
859 ok( !status, "NtWow64AllocateVirtualMemory64 failed %x\n", status );
860 ok( ptr < 0x40000000, "got wrong ptr %s\n", wine_dbgstr_longlong(ptr) );
861 if (!status && pNtWow64WriteVirtualMemory64)
863 status = pNtWow64WriteVirtualMemory64( process, ptr, str, sizeof(str), &res );
864 ok( !status, "NtWow64WriteVirtualMemory64 failed %x\n", status );
865 ok( res == sizeof(str), "wrong size %s\n", wine_dbgstr_longlong(res) );
866 ok( !strcmp( (char *)(ULONG_PTR)ptr, str ), "wrong data %s\n",
867 debugstr_a((char *)(ULONG_PTR)ptr) );
868 ptr = 0;
869 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
870 MEM_RESERVE | MEM_COMMIT, PAGE_READONLY );
871 ok( !status, "NtWow64AllocateVirtualMemory64 failed %x\n", status );
872 status = pNtWow64WriteVirtualMemory64( process, ptr, str, sizeof(str), &res );
873 todo_wine
874 ok( status == STATUS_PARTIAL_COPY || broken( status == STATUS_ACCESS_VIOLATION ),
875 "NtWow64WriteVirtualMemory64 failed %x\n", status );
876 todo_wine
877 ok( !res || broken(res) /* win10 1709 */, "wrong size %s\n", wine_dbgstr_longlong(res) );
879 ptr = 0x9876543210ull;
880 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
881 MEM_RESERVE | MEM_COMMIT, PAGE_READONLY );
882 todo_wine
883 ok( !status || broken( status == STATUS_CONFLICTING_ADDRESSES ),
884 "NtWow64AllocateVirtualMemory64 failed %x\n", status );
885 if (!status) ok( ptr == 0x9876540000ull || broken(ptr == 0x76540000), /* win 8.1 */
886 "wrong ptr %s\n", wine_dbgstr_longlong(ptr) );
887 ptr = 0;
888 status = pNtWow64AllocateVirtualMemory64( GetCurrentProcess(), &ptr, 0, &size,
889 MEM_RESERVE | MEM_COMMIT, PAGE_READONLY );
890 ok( !status || broken( status == STATUS_INVALID_HANDLE ),
891 "NtWow64AllocateVirtualMemory64 failed %x\n", status );
893 else win_skip( "NtWow64AllocateVirtualMemory64 not supported\n" );
895 if (pNtWow64GetNativeSystemInformation)
897 ULONG i, len;
898 SYSTEM_BASIC_INFORMATION sbi, sbi2, sbi3;
900 memset( &sbi, 0xcc, sizeof(sbi) );
901 status = pNtQuerySystemInformation( SystemBasicInformation, &sbi, sizeof(sbi), &len );
902 ok( status == STATUS_SUCCESS, "failed %x\n", status );
903 ok( len == sizeof(sbi), "wrong length %d\n", len );
905 memset( &sbi2, 0xcc, sizeof(sbi2) );
906 status = pRtlGetNativeSystemInformation( SystemBasicInformation, &sbi2, sizeof(sbi2), &len );
907 ok( status == STATUS_SUCCESS, "failed %x\n", status );
908 ok( len == sizeof(sbi2), "wrong length %d\n", len );
910 ok( sbi.HighestUserAddress == (void *)0x7ffeffff, "wrong limit %p\n", sbi.HighestUserAddress);
911 todo_wine_if( is_wow64 )
912 ok( sbi2.HighestUserAddress == (is_wow64 ? (void *)0xfffeffff : (void *)0x7ffeffff),
913 "wrong limit %p\n", sbi.HighestUserAddress);
915 memset( &sbi3, 0xcc, sizeof(sbi3) );
916 status = pNtWow64GetNativeSystemInformation( SystemBasicInformation, &sbi3, sizeof(sbi3), &len );
917 ok( status == STATUS_SUCCESS, "failed %x\n", status );
918 ok( len == sizeof(sbi3), "wrong length %d\n", len );
919 ok( !memcmp( &sbi2, &sbi3, offsetof(SYSTEM_BASIC_INFORMATION,NumberOfProcessors)+1 ),
920 "info is different\n" );
922 memset( &sbi3, 0xcc, sizeof(sbi3) );
923 status = pNtWow64GetNativeSystemInformation( SystemEmulationBasicInformation, &sbi3, sizeof(sbi3), &len );
924 ok( status == STATUS_SUCCESS, "failed %x\n", status );
925 ok( len == sizeof(sbi3), "wrong length %d\n", len );
926 ok( !memcmp( &sbi, &sbi3, offsetof(SYSTEM_BASIC_INFORMATION,NumberOfProcessors)+1 ),
927 "info is different\n" );
929 for (i = 0; i < 256; i++)
931 NTSTATUS expect = pNtQuerySystemInformation( i, NULL, 0, &len );
932 status = pNtWow64GetNativeSystemInformation( i, NULL, 0, &len );
933 switch (i)
935 case SystemNativeBasicInformation:
936 ok( status == STATUS_INVALID_INFO_CLASS || status == STATUS_INFO_LENGTH_MISMATCH ||
937 broken(status == STATUS_NOT_IMPLEMENTED) /* vista */, "%u: %x / %x\n", i, status, expect );
938 break;
939 case SystemBasicInformation:
940 case SystemCpuInformation:
941 case SystemEmulationBasicInformation:
942 case SystemEmulationProcessorInformation:
943 ok( status == expect, "%u: %x / %x\n", i, status, expect );
944 break;
945 default:
946 if (is_wow64) /* only a few info classes are supported on Wow64 */
947 ok( status == STATUS_INVALID_INFO_CLASS ||
948 broken(status == STATUS_NOT_IMPLEMENTED), /* vista */
949 "%u: %x\n", i, status );
950 else
951 ok( status == expect, "%u: %x / %x\n", i, status, expect );
952 break;
956 else win_skip( "NtWow64GetNativeSystemInformation not supported\n" );
958 NtClose( process );
961 static void test_init_block(void)
963 HMODULE ntdll = GetModuleHandleA( "ntdll.dll" );
964 ULONG i, size = 0, *init_block;
965 ULONG64 ptr64, *block64;
966 void *ptr;
968 if (!is_wow64) return;
969 if ((ptr = GetProcAddress( ntdll, "LdrSystemDllInitBlock" )))
971 init_block = ptr;
972 trace( "got init block %08x\n", init_block[0] );
973 #define CHECK_FUNC(val,func) \
974 ok( (val) == (ULONG_PTR)GetProcAddress( ntdll, func ), \
975 "got %p for %s %p\n", (void *)(ULONG_PTR)(val), func, GetProcAddress( ntdll, func ))
976 switch (init_block[0])
978 case 0x44: /* vistau64 */
979 CHECK_FUNC( init_block[1], "LdrInitializeThunk" );
980 CHECK_FUNC( init_block[2], "KiUserExceptionDispatcher" );
981 CHECK_FUNC( init_block[3], "KiUserApcDispatcher" );
982 CHECK_FUNC( init_block[4], "KiUserCallbackDispatcher" );
983 CHECK_FUNC( init_block[5], "LdrHotPatchRoutine" );
984 CHECK_FUNC( init_block[6], "ExpInterlockedPopEntrySListFault" );
985 CHECK_FUNC( init_block[7], "ExpInterlockedPopEntrySListResume" );
986 CHECK_FUNC( init_block[8], "ExpInterlockedPopEntrySListEnd" );
987 CHECK_FUNC( init_block[9], "RtlUserThreadStart" );
988 CHECK_FUNC( init_block[10], "RtlpQueryProcessDebugInformationRemote" );
989 CHECK_FUNC( init_block[11], "EtwpNotificationThread" );
990 ok( init_block[12] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
991 (void *)(ULONG_PTR)init_block[12], ntdll );
992 size = 13 * sizeof(*init_block);
993 break;
994 case 0x50: /* win7 */
995 CHECK_FUNC( init_block[4], "LdrInitializeThunk" );
996 CHECK_FUNC( init_block[5], "KiUserExceptionDispatcher" );
997 CHECK_FUNC( init_block[6], "KiUserApcDispatcher" );
998 CHECK_FUNC( init_block[7], "KiUserCallbackDispatcher" );
999 CHECK_FUNC( init_block[8], "LdrHotPatchRoutine" );
1000 CHECK_FUNC( init_block[9], "ExpInterlockedPopEntrySListFault" );
1001 CHECK_FUNC( init_block[10], "ExpInterlockedPopEntrySListResume" );
1002 CHECK_FUNC( init_block[11], "ExpInterlockedPopEntrySListEnd" );
1003 CHECK_FUNC( init_block[12], "RtlUserThreadStart" );
1004 CHECK_FUNC( init_block[13], "RtlpQueryProcessDebugInformationRemote" );
1005 CHECK_FUNC( init_block[14], "EtwpNotificationThread" );
1006 ok( init_block[15] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1007 (void *)(ULONG_PTR)init_block[15], ntdll );
1008 CHECK_FUNC( init_block[16], "LdrSystemDllInitBlock" );
1009 size = 17 * sizeof(*init_block);
1010 break;
1011 case 0x70: /* win8 */
1012 CHECK_FUNC( init_block[4], "LdrInitializeThunk" );
1013 CHECK_FUNC( init_block[5], "KiUserExceptionDispatcher" );
1014 CHECK_FUNC( init_block[6], "KiUserApcDispatcher" );
1015 CHECK_FUNC( init_block[7], "KiUserCallbackDispatcher" );
1016 CHECK_FUNC( init_block[8], "ExpInterlockedPopEntrySListFault" );
1017 CHECK_FUNC( init_block[9], "ExpInterlockedPopEntrySListResume" );
1018 CHECK_FUNC( init_block[10], "ExpInterlockedPopEntrySListEnd" );
1019 CHECK_FUNC( init_block[11], "RtlUserThreadStart" );
1020 CHECK_FUNC( init_block[12], "RtlpQueryProcessDebugInformationRemote" );
1021 ok( init_block[13] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1022 (void *)(ULONG_PTR)init_block[13], ntdll );
1023 CHECK_FUNC( init_block[14], "LdrSystemDllInitBlock" );
1024 size = 15 * sizeof(*init_block);
1025 break;
1026 case 0x80: /* win10 1507 */
1027 CHECK_FUNC( init_block[4], "LdrInitializeThunk" );
1028 CHECK_FUNC( init_block[5], "KiUserExceptionDispatcher" );
1029 CHECK_FUNC( init_block[6], "KiUserApcDispatcher" );
1030 CHECK_FUNC( init_block[7], "KiUserCallbackDispatcher" );
1031 if (GetProcAddress( ntdll, "ExpInterlockedPopEntrySListFault" ))
1033 CHECK_FUNC( init_block[8], "ExpInterlockedPopEntrySListFault" );
1034 CHECK_FUNC( init_block[9], "ExpInterlockedPopEntrySListResume" );
1035 CHECK_FUNC( init_block[10], "ExpInterlockedPopEntrySListEnd" );
1036 CHECK_FUNC( init_block[11], "RtlUserThreadStart" );
1037 CHECK_FUNC( init_block[12], "RtlpQueryProcessDebugInformationRemote" );
1038 ok( init_block[13] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1039 (void *)(ULONG_PTR)init_block[13], ntdll );
1040 CHECK_FUNC( init_block[14], "LdrSystemDllInitBlock" );
1041 size = 15 * sizeof(*init_block);
1043 else /* win10 1607 */
1045 CHECK_FUNC( init_block[8], "RtlUserThreadStart" );
1046 CHECK_FUNC( init_block[9], "RtlpQueryProcessDebugInformationRemote" );
1047 ok( init_block[10] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1048 (void *)(ULONG_PTR)init_block[10], ntdll );
1049 CHECK_FUNC( init_block[11], "LdrSystemDllInitBlock" );
1050 size = 12 * sizeof(*init_block);
1052 break;
1053 case 0xe0: /* win10 1809 */
1054 case 0xf0: /* win10 2004 */
1055 block64 = ptr;
1056 CHECK_FUNC( block64[3], "LdrInitializeThunk" );
1057 CHECK_FUNC( block64[4], "KiUserExceptionDispatcher" );
1058 CHECK_FUNC( block64[5], "KiUserApcDispatcher" );
1059 CHECK_FUNC( block64[6], "KiUserCallbackDispatcher" );
1060 CHECK_FUNC( block64[7], "RtlUserThreadStart" );
1061 CHECK_FUNC( block64[8], "RtlpQueryProcessDebugInformationRemote" );
1062 todo_wine ok( block64[9] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1063 (void *)(ULONG_PTR)block64[9], ntdll );
1064 CHECK_FUNC( block64[10], "LdrSystemDllInitBlock" );
1065 CHECK_FUNC( block64[11], "RtlpFreezeTimeBias" );
1066 size = 12 * sizeof(*block64);
1067 break;
1068 default:
1069 ok( 0, "unknown init block %08x\n", init_block[0] );
1070 for (i = 0; i < 32; i++) trace("%04x: %08x\n", i, init_block[i]);
1071 break;
1073 #undef CHECK_FUNC
1075 if (size && (ptr64 = get_proc_address64( ntdll_module, "LdrSystemDllInitBlock" )))
1077 DWORD buffer[64];
1078 HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
1079 NTSTATUS status = pNtWow64ReadVirtualMemory64( process, ptr64, buffer, size, NULL );
1080 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
1081 ok( !memcmp( buffer, init_block, size ), "wrong 64-bit init block\n" );
1082 NtClose( process );
1085 else todo_wine win_skip( "LdrSystemDllInitBlock not supported\n" );
1089 static void test_iosb(void)
1091 static const char pipe_name[] = "\\\\.\\pipe\\wow64iosbnamedpipe";
1092 HANDLE client, server;
1093 NTSTATUS status;
1094 ULONG64 func;
1095 DWORD id;
1096 IO_STATUS_BLOCK iosb32;
1097 struct
1099 union
1101 NTSTATUS Status;
1102 ULONG64 Pointer;
1104 ULONG64 Information;
1105 } iosb64;
1106 ULONG64 args[] = { 0, 0, 0, 0, (ULONG_PTR)&iosb64, FSCTL_PIPE_LISTEN, 0, 0, 0, 0 };
1108 if (!is_wow64) return;
1109 if (!ntdll_module) return;
1110 func = get_proc_address64( ntdll_module, "NtFsControlFile" );
1112 /* async calls set iosb32 but not iosb64 */
1114 server = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
1115 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1116 4, 1024, 1024, 1000, NULL );
1117 ok( server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError() );
1119 memset( &iosb32, 0x55, sizeof(iosb32) );
1120 iosb64.Pointer = PtrToUlong( &iosb32 );
1121 iosb64.Information = 0xdeadbeef;
1123 args[0] = (LONG_PTR)server;
1124 status = call_func64( func, ARRAY_SIZE(args), args );
1125 ok( status == STATUS_PENDING, "NtFsControlFile returned %x\n", status );
1126 ok( U(iosb32).Status == 0x55555555, "status changed to %x\n", U(iosb32).Status );
1127 ok( U(iosb64).Pointer == PtrToUlong(&iosb32), "status changed to %x\n", U(iosb64).Status );
1128 ok( iosb64.Information == 0xdeadbeef, "info changed to %lx\n", (ULONG_PTR)iosb64.Information );
1130 client = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
1131 FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
1132 ok( client != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError() );
1134 ok( U(iosb32).Status == 0, "Wrong iostatus %x\n", U(iosb32).Status );
1135 ok( U(iosb64).Pointer == PtrToUlong(&iosb32), "status changed to %x\n", U(iosb64).Status );
1136 ok( iosb64.Information == 0xdeadbeef, "info changed to %lx\n", (ULONG_PTR)iosb64.Information );
1138 memset( &iosb32, 0x55, sizeof(iosb32) );
1139 iosb64.Pointer = PtrToUlong( &iosb32 );
1140 iosb64.Information = 0xdeadbeef;
1141 id = 0xdeadbeef;
1143 args[5] = FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE;
1144 args[6] = (ULONG_PTR)"ClientProcessId";
1145 args[7] = sizeof("ClientProcessId");
1146 args[8] = (ULONG_PTR)&id;
1147 args[9] = sizeof(id);
1149 status = call_func64( func, ARRAY_SIZE(args), args );
1150 ok( status == STATUS_PENDING || status == STATUS_SUCCESS, "NtFsControlFile returned %x\n", status );
1151 todo_wine
1153 ok( U(iosb32).Status == STATUS_SUCCESS, "status changed to %x\n", U(iosb32).Status );
1154 ok( iosb32.Information == sizeof(id), "info changed to %lx\n", iosb32.Information );
1155 ok( U(iosb64).Pointer == PtrToUlong(&iosb32), "status changed to %x\n", U(iosb64).Status );
1156 ok( iosb64.Information == 0xdeadbeef, "info changed to %lx\n", (ULONG_PTR)iosb64.Information );
1158 ok( id == GetCurrentProcessId(), "wrong id %x / %x\n", id, GetCurrentProcessId() );
1159 CloseHandle( client );
1160 CloseHandle( server );
1162 /* synchronous calls set iosb64 but not iosb32 */
1164 server = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND,
1165 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1166 4, 1024, 1024, 1000, NULL );
1167 ok( server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %u\n", GetLastError() );
1169 client = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
1170 FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
1171 ok( client != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError() );
1173 memset( &iosb32, 0x55, sizeof(iosb32) );
1174 iosb64.Pointer = PtrToUlong( &iosb32 );
1175 iosb64.Information = 0xdeadbeef;
1176 id = 0xdeadbeef;
1178 args[0] = (LONG_PTR)server;
1179 status = call_func64( func, ARRAY_SIZE(args), args );
1180 ok( status == STATUS_SUCCESS, "NtFsControlFile returned %x\n", status );
1181 ok( U(iosb32).Status == 0x55555555, "status changed to %x\n", U(iosb32).Status );
1182 ok( iosb32.Information == 0x55555555, "info changed to %lx\n", iosb32.Information );
1183 ok( U(iosb64).Pointer == STATUS_SUCCESS, "status changed to %x\n", U(iosb64).Status );
1184 ok( iosb64.Information == sizeof(id), "info changed to %lx\n", (ULONG_PTR)iosb64.Information );
1185 ok( id == GetCurrentProcessId(), "wrong id %x / %x\n", id, GetCurrentProcessId() );
1186 CloseHandle( client );
1187 CloseHandle( server );
1190 static NTSTATUS invoke_syscall( const char *name, ULONG args32[] )
1192 ULONG64 args64[] = { -1, PtrToUlong( args32 ) };
1193 ULONG64 func = get_proc_address64( wow64_module, "Wow64SystemServiceEx" );
1194 BYTE *syscall = (BYTE *)GetProcAddress( GetModuleHandleA("ntdll.dll"), name );
1196 ok( syscall != NULL, "syscall %s not found\n", name );
1197 if (syscall[0] == 0xb8)
1198 args64[0] = *(DWORD *)(syscall + 1);
1199 else
1200 win_skip( "syscall thunk %s not recognized\n", name );
1202 return call_func64( func, ARRAY_SIZE(args64), args64 );
1205 static void test_syscalls(void)
1207 ULONG64 func;
1208 ULONG args32[8];
1209 HANDLE event, event2;
1210 OBJECT_ATTRIBUTES attr;
1211 UNICODE_STRING name;
1212 NTSTATUS status;
1214 if (!is_wow64) return;
1215 if (!ntdll_module) return;
1217 func = get_proc_address64( wow64_module, "Wow64SystemServiceEx" );
1218 ok( func, "Wow64SystemServiceEx not found\n" );
1220 event = CreateEventA( NULL, FALSE, FALSE, NULL );
1222 status = NtSetEvent( event, NULL );
1223 ok( !status, "NtSetEvent failed %x\n", status );
1224 args32[0] = HandleToLong( event );
1225 status = invoke_syscall( "NtClose", args32 );
1226 ok( !status, "syscall failed %x\n", status );
1227 status = NtSetEvent( event, NULL );
1228 ok( status == STATUS_INVALID_HANDLE, "NtSetEvent failed %x\n", status );
1229 status = invoke_syscall( "NtClose", args32 );
1230 ok( status == STATUS_INVALID_HANDLE, "syscall failed %x\n", status );
1231 args32[0] = 0xdeadbeef;
1232 status = invoke_syscall( "NtClose", args32 );
1233 ok( status == STATUS_INVALID_HANDLE, "syscall failed %x\n", status );
1235 RtlInitUnicodeString( &name, L"\\BaseNamedObjects\\wow64-test");
1236 InitializeObjectAttributes( &attr, &name, OBJ_OPENIF, 0, NULL );
1237 event = (HANDLE)0xdeadbeef;
1238 args32[0] = PtrToUlong(&event );
1239 args32[1] = EVENT_ALL_ACCESS;
1240 args32[2] = PtrToUlong( &attr );
1241 args32[3] = NotificationEvent;
1242 args32[4] = 0;
1243 status = invoke_syscall( "NtCreateEvent", args32 );
1244 ok( !status, "syscall failed %x\n", status );
1245 status = NtSetEvent( event, NULL );
1246 ok( !status, "NtSetEvent failed %x\n", status );
1248 event2 = (HANDLE)0xdeadbeef;
1249 args32[0] = PtrToUlong( &event2 );
1250 status = invoke_syscall( "NtOpenEvent", args32 );
1251 ok( !status, "syscall failed %x\n", status );
1252 status = NtSetEvent( event2, NULL );
1253 ok( !status, "NtSetEvent failed %x\n", status );
1254 args32[0] = HandleToLong( event2 );
1255 status = invoke_syscall( "NtClose", args32 );
1256 ok( !status, "syscall failed %x\n", status );
1258 event2 = (HANDLE)0xdeadbeef;
1259 args32[0] = PtrToUlong( &event2 );
1260 status = invoke_syscall( "NtCreateEvent", args32 );
1261 ok( status == STATUS_OBJECT_NAME_EXISTS, "syscall failed %x\n", status );
1262 status = NtSetEvent( event2, NULL );
1263 ok( !status, "NtSetEvent failed %x\n", status );
1264 args32[0] = HandleToLong( event2 );
1265 status = invoke_syscall( "NtClose", args32 );
1266 ok( !status, "syscall failed %x\n", status );
1268 status = NtClose( event );
1269 ok( !status, "NtClose failed %x\n", status );
1271 if (pNtWow64ReadVirtualMemory64)
1273 TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
1274 PEB64 peb64, peb64_2;
1275 ULONG64 res, res2;
1276 HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
1277 ULONG args32[] = { HandleToLong( process ), (ULONG)teb64->Peb, teb64->Peb >> 32,
1278 PtrToUlong(&peb64_2), sizeof(peb64_2), 0, PtrToUlong(&res2) };
1280 ok( process != 0, "failed to open current process %u\n", GetLastError() );
1281 status = pNtWow64ReadVirtualMemory64( process, teb64->Peb, &peb64, sizeof(peb64), &res );
1282 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
1283 status = invoke_syscall( "NtWow64ReadVirtualMemory64", args32 );
1284 ok( !status, "NtWow64ReadVirtualMemory64 failed %x\n", status );
1285 ok( res2 == res, "wrong len %s / %s\n", wine_dbgstr_longlong(res), wine_dbgstr_longlong(res2) );
1286 ok( !memcmp( &peb64, &peb64_2, res ), "data is different\n" );
1287 NtClose( process );
1291 static void test_cpu_area(void)
1293 TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
1294 ULONG64 ptr;
1295 NTSTATUS status;
1297 if (!is_wow64) return;
1298 if (!ntdll_module) return;
1300 if ((ptr = get_proc_address64( ntdll_module, "RtlWow64GetCurrentCpuArea" )))
1302 USHORT machine = 0xdead;
1303 ULONG64 context, context_ex;
1304 ULONG64 args[] = { (ULONG_PTR)&machine, (ULONG_PTR)&context, (ULONG_PTR)&context_ex };
1306 status = call_func64( ptr, ARRAY_SIZE(args), args );
1307 ok( !status, "RtlWow64GetCpuAreaInfo failed %x\n", status );
1308 ok( machine == IMAGE_FILE_MACHINE_I386, "wrong machine %x\n", machine );
1309 ok( context == teb64->TlsSlots[WOW64_TLS_CPURESERVED] + 4, "wrong context %s / %s\n",
1310 wine_dbgstr_longlong(context), wine_dbgstr_longlong(teb64->TlsSlots[WOW64_TLS_CPURESERVED]) );
1311 ok( !context_ex, "got context_ex %s\n", wine_dbgstr_longlong(context_ex) );
1312 args[0] = args[1] = args[2] = 0;
1313 status = call_func64( ptr, ARRAY_SIZE(args), args );
1314 ok( !status, "RtlWow64GetCpuAreaInfo failed %x\n", status );
1316 else win_skip( "RtlWow64GetCpuAreaInfo not supported\n" );
1320 #endif /* _WIN64 */
1323 START_TEST(wow64)
1325 init();
1326 test_query_architectures();
1327 test_peb_teb();
1328 test_selectors();
1329 #ifndef _WIN64
1330 test_nt_wow64();
1331 test_modules();
1332 test_init_block();
1333 test_iosb();
1334 test_syscalls();
1335 #endif
1336 test_cpu_area();