server: Return STATUS_IMAGE_MACHINE_TYPE_MISMATCH when the mapping's machine differs...
[wine.git] / dlls / ntdll / tests / wow64.c
blobb99b22fb1afb06b2aa640aaee4715ac0175a7a16
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"
24 #include "ddk/wdm.h"
26 static NTSTATUS (WINAPI *pNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS,void*,ULONG,ULONG*);
27 static NTSTATUS (WINAPI *pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS,void*,ULONG,void*,ULONG,ULONG*);
28 static NTSTATUS (WINAPI *pRtlGetNativeSystemInformation)(SYSTEM_INFORMATION_CLASS,void*,ULONG,ULONG*);
29 static USHORT (WINAPI *pRtlWow64GetCurrentMachine)(void);
30 static NTSTATUS (WINAPI *pRtlWow64GetProcessMachines)(HANDLE,WORD*,WORD*);
31 static NTSTATUS (WINAPI *pRtlWow64GetThreadContext)(HANDLE,WOW64_CONTEXT*);
32 static NTSTATUS (WINAPI *pRtlWow64IsWowGuestMachineSupported)(USHORT,BOOLEAN*);
33 static NTSTATUS (WINAPI *pNtMapViewOfSectionEx)(HANDLE,HANDLE,PVOID*,const LARGE_INTEGER*,SIZE_T*,ULONG,ULONG,MEM_EXTENDED_PARAMETER*,ULONG);
34 #ifdef _WIN64
35 static NTSTATUS (WINAPI *pRtlWow64GetCpuAreaInfo)(WOW64_CPURESERVED*,ULONG,WOW64_CPU_AREA_INFO*);
36 static NTSTATUS (WINAPI *pRtlWow64GetThreadSelectorEntry)(HANDLE,THREAD_DESCRIPTOR_INFORMATION*,ULONG,ULONG*);
37 #else
38 static NTSTATUS (WINAPI *pNtWow64AllocateVirtualMemory64)(HANDLE,ULONG64*,ULONG64,ULONG64*,ULONG,ULONG);
39 static NTSTATUS (WINAPI *pNtWow64GetNativeSystemInformation)(SYSTEM_INFORMATION_CLASS,void*,ULONG,ULONG*);
40 static NTSTATUS (WINAPI *pNtWow64IsProcessorFeaturePresent)(ULONG);
41 static NTSTATUS (WINAPI *pNtWow64ReadVirtualMemory64)(HANDLE,ULONG64,void*,ULONG64,ULONG64*);
42 static NTSTATUS (WINAPI *pNtWow64WriteVirtualMemory64)(HANDLE,ULONG64,const void *,ULONG64,ULONG64*);
43 #endif
45 static BOOL is_wow64;
46 static BOOL old_wow64; /* Wine old-style wow64 */
47 static void *code_mem;
49 #ifdef __i386__
50 static USHORT current_machine = IMAGE_FILE_MACHINE_I386;
51 static USHORT native_machine = IMAGE_FILE_MACHINE_I386;
52 #elif defined __x86_64__
53 static USHORT current_machine = IMAGE_FILE_MACHINE_AMD64;
54 static USHORT native_machine = IMAGE_FILE_MACHINE_AMD64;
55 #elif defined __arm__
56 static USHORT current_machine = IMAGE_FILE_MACHINE_ARMNT;
57 static USHORT native_machine = IMAGE_FILE_MACHINE_ARMNT;
58 #elif defined __aarch64__
59 static USHORT current_machine = IMAGE_FILE_MACHINE_ARM64;
60 static USHORT native_machine = IMAGE_FILE_MACHINE_ARM64;
61 #else
62 static USHORT current_machine;
63 static USHORT native_machine;
64 #endif
66 static void init(void)
68 HMODULE ntdll = GetModuleHandleA( "ntdll.dll" );
70 if (!IsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
72 if (is_wow64)
74 TEB64 *teb64 = ULongToPtr( NtCurrentTeb()->GdiBatchCount );
76 if (teb64)
78 PEB64 *peb64 = ULongToPtr(teb64->Peb);
79 old_wow64 = !peb64->LdrData;
83 #define GET_PROC(func) p##func = (void *)GetProcAddress( ntdll, #func )
84 GET_PROC( NtMapViewOfSectionEx );
85 GET_PROC( NtQuerySystemInformation );
86 GET_PROC( NtQuerySystemInformationEx );
87 GET_PROC( RtlGetNativeSystemInformation );
88 GET_PROC( RtlWow64GetCurrentMachine );
89 GET_PROC( RtlWow64GetProcessMachines );
90 GET_PROC( RtlWow64GetThreadContext );
91 GET_PROC( RtlWow64IsWowGuestMachineSupported );
92 #ifdef _WIN64
93 GET_PROC( RtlWow64GetCpuAreaInfo );
94 GET_PROC( RtlWow64GetThreadSelectorEntry );
95 #else
96 GET_PROC( NtWow64AllocateVirtualMemory64 );
97 GET_PROC( NtWow64GetNativeSystemInformation );
98 GET_PROC( NtWow64IsProcessorFeaturePresent );
99 GET_PROC( NtWow64ReadVirtualMemory64 );
100 GET_PROC( NtWow64WriteVirtualMemory64 );
101 #endif
102 #undef GET_PROC
104 if (pRtlGetNativeSystemInformation)
106 SYSTEM_CPU_INFORMATION info;
107 ULONG len;
109 pRtlGetNativeSystemInformation( SystemCpuInformation, &info, sizeof(info), &len );
110 switch (info.ProcessorArchitecture)
112 case PROCESSOR_ARCHITECTURE_ARM64:
113 native_machine = IMAGE_FILE_MACHINE_ARM64;
114 break;
115 case PROCESSOR_ARCHITECTURE_AMD64:
116 native_machine = IMAGE_FILE_MACHINE_AMD64;
117 break;
121 if (native_machine == IMAGE_FILE_MACHINE_AMD64)
122 code_mem = VirtualAlloc( NULL, 65536, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE );
125 static void test_process_architecture( HANDLE process, USHORT expect_machine, USHORT expect_native )
127 NTSTATUS status;
128 ULONG i, len, buffer[8];
130 len = 0xdead;
131 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
132 &buffer, sizeof(buffer), &len );
133 ok( !status, "failed %lx\n", status );
134 ok( !(len & 3), "wrong len %lx\n", len );
135 len /= sizeof(DWORD);
136 for (i = 0; i < len - 1; i++)
138 USHORT flags = HIWORD(buffer[i]);
139 USHORT machine = LOWORD(buffer[i]);
141 if (flags & 8)
142 ok( machine == expect_machine, "wrong current machine %lx\n", buffer[i]);
143 else
144 ok( machine != expect_machine, "wrong machine %lx\n", buffer[i]);
146 /* FIXME: not quite sure what the other flags mean,
147 * observed on amd64 Windows: (flags & 7) == 7 for MACHINE_AMD64 and 2 for MACHINE_I386
149 if (flags & 4)
150 ok( machine == expect_native, "wrong native machine %lx\n", buffer[i]);
151 else
152 ok( machine != expect_native, "wrong machine %lx\n", buffer[i]);
154 ok( !buffer[i], "missing terminating null\n" );
156 len = i * sizeof(DWORD);
157 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
158 &buffer, len, &len );
159 ok( status == STATUS_BUFFER_TOO_SMALL, "failed %lx\n", status );
160 ok( len == (i + 1) * sizeof(DWORD), "wrong len %lu\n", len );
162 if (pRtlWow64GetProcessMachines)
164 USHORT current = 0xdead, native = 0xbeef;
165 status = pRtlWow64GetProcessMachines( process, &current, &native );
166 ok( !status, "failed %lx\n", status );
167 if (expect_machine == expect_native)
168 ok( current == 0, "wrong current machine %x / %x\n", current, expect_machine );
169 else
170 ok( current == expect_machine, "wrong current machine %x / %x\n", current, expect_machine );
171 ok( native == expect_native, "wrong native machine %x / %x\n", native, expect_native );
175 static void test_query_architectures(void)
177 PROCESS_INFORMATION pi;
178 STARTUPINFOA si = { sizeof(si) };
179 NTSTATUS status;
180 HANDLE process;
181 ULONG len, buffer[8];
183 if (!pNtQuerySystemInformationEx) return;
185 process = GetCurrentProcess();
186 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
187 &buffer, sizeof(buffer), &len );
188 if (status == STATUS_INVALID_INFO_CLASS)
190 win_skip( "SystemSupportedProcessorArchitectures not supported\n" );
191 return;
193 ok( !status, "failed %lx\n", status );
195 process = (HANDLE)0xdeadbeef;
196 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
197 &buffer, sizeof(buffer), &len );
198 ok( status == STATUS_INVALID_HANDLE, "failed %lx\n", status );
199 process = (HANDLE)0xdeadbeef;
200 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, 3,
201 &buffer, sizeof(buffer), &len );
202 ok( status == STATUS_INVALID_PARAMETER || broken(status == STATUS_INVALID_HANDLE),
203 "failed %lx\n", status );
204 process = GetCurrentProcess();
205 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, 3,
206 &buffer, sizeof(buffer), &len );
207 ok( status == STATUS_INVALID_PARAMETER || broken( status == STATUS_SUCCESS),
208 "failed %lx\n", status );
209 status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, NULL, 0,
210 &buffer, sizeof(buffer), &len );
211 ok( status == STATUS_INVALID_PARAMETER, "failed %lx\n", status );
213 test_process_architecture( GetCurrentProcess(), current_machine, native_machine );
214 test_process_architecture( 0, 0, native_machine );
216 if (CreateProcessA( "C:\\Program Files\\Internet Explorer\\iexplore.exe", NULL, NULL, NULL,
217 FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
219 test_process_architecture( pi.hProcess, native_machine, native_machine );
220 TerminateProcess( pi.hProcess, 0 );
221 CloseHandle( pi.hProcess );
222 CloseHandle( pi.hThread );
224 if (CreateProcessA( "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe", NULL, NULL, NULL,
225 FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
227 test_process_architecture( pi.hProcess, IMAGE_FILE_MACHINE_I386, native_machine );
228 TerminateProcess( pi.hProcess, 0 );
229 CloseHandle( pi.hProcess );
230 CloseHandle( pi.hThread );
233 if (pRtlWow64GetCurrentMachine)
235 USHORT machine = pRtlWow64GetCurrentMachine();
236 ok( machine == current_machine, "wrong machine %x / %x\n", machine, current_machine );
238 if (pRtlWow64IsWowGuestMachineSupported)
240 BOOLEAN ret = 0xcc;
241 status = pRtlWow64IsWowGuestMachineSupported( IMAGE_FILE_MACHINE_I386, &ret );
242 ok( !status, "failed %lx\n", status );
243 ok( ret == (native_machine == IMAGE_FILE_MACHINE_AMD64 ||
244 native_machine == IMAGE_FILE_MACHINE_ARM64), "wrong result %u\n", ret );
245 ret = 0xcc;
246 status = pRtlWow64IsWowGuestMachineSupported( IMAGE_FILE_MACHINE_ARMNT, &ret );
247 ok( !status, "failed %lx\n", status );
248 ok( !ret || native_machine == IMAGE_FILE_MACHINE_ARM64, "wrong result %u\n", ret );
249 ret = 0xcc;
250 status = pRtlWow64IsWowGuestMachineSupported( IMAGE_FILE_MACHINE_AMD64, &ret );
251 ok( !status, "failed %lx\n", status );
252 ok( !ret || native_machine == IMAGE_FILE_MACHINE_ARM64, "wrong result %u\n", ret );
253 ret = 0xcc;
254 status = pRtlWow64IsWowGuestMachineSupported( IMAGE_FILE_MACHINE_ARM64, &ret );
255 ok( !status, "failed %lx\n", status );
256 ok( !ret, "wrong result %u\n", ret );
257 ret = 0xcc;
258 status = pRtlWow64IsWowGuestMachineSupported( 0xdead, &ret );
259 ok( !status, "failed %lx\n", status );
260 ok( !ret, "wrong result %u\n", ret );
264 static void test_peb_teb(void)
266 PROCESS_BASIC_INFORMATION proc_info;
267 THREAD_BASIC_INFORMATION info;
268 PROCESS_INFORMATION pi;
269 STARTUPINFOA si = {0};
270 NTSTATUS status;
271 void *redir;
272 SIZE_T res;
273 BOOL ret;
274 TEB teb;
275 PEB peb;
276 TEB32 teb32;
277 PEB32 peb32;
278 RTL_USER_PROCESS_PARAMETERS params;
279 RTL_USER_PROCESS_PARAMETERS32 params32;
281 Wow64DisableWow64FsRedirection( &redir );
283 if (CreateProcessA( "C:\\windows\\syswow64\\msinfo32.exe", NULL, NULL, NULL,
284 FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
286 memset( &info, 0xcc, sizeof(info) );
287 status = NtQueryInformationThread( pi.hThread, ThreadBasicInformation, &info, sizeof(info), NULL );
288 ok( !status, "ThreadBasicInformation failed %lx\n", status );
289 if (!ReadProcessMemory( pi.hProcess, info.TebBaseAddress, &teb, sizeof(teb), &res )) res = 0;
290 ok( res == sizeof(teb), "wrong len %Ix\n", res );
291 ok( teb.Tib.Self == info.TebBaseAddress, "wrong teb %p / %p\n", teb.Tib.Self, info.TebBaseAddress );
292 if (is_wow64)
294 ok( !!teb.GdiBatchCount, "GdiBatchCount not set\n" );
295 ok( (char *)info.TebBaseAddress + teb.WowTebOffset == ULongToPtr(teb.GdiBatchCount) ||
296 broken(!NtCurrentTeb()->WowTebOffset), /* pre-win10 */
297 "wrong teb offset %ld\n", teb.WowTebOffset );
299 else
301 ok( !teb.GdiBatchCount, "GdiBatchCount set\n" );
302 ok( teb.WowTebOffset == 0x2000 ||
303 broken( !teb.WowTebOffset || teb.WowTebOffset == 1 ), /* pre-win10 */
304 "wrong teb offset %ld\n", teb.WowTebOffset );
305 ok( (char *)teb.Tib.ExceptionList == (char *)info.TebBaseAddress + 0x2000,
306 "wrong Tib.ExceptionList %p / %p\n",
307 (char *)teb.Tib.ExceptionList, (char *)info.TebBaseAddress + 0x2000 );
308 if (!ReadProcessMemory( pi.hProcess, teb.Tib.ExceptionList, &teb32, sizeof(teb32), &res )) res = 0;
309 ok( res == sizeof(teb32), "wrong len %Ix\n", res );
310 ok( (char *)ULongToPtr(teb32.Peb) == (char *)teb.Peb + 0x1000 ||
311 broken( ULongToPtr(teb32.Peb) != teb.Peb ), /* vista */
312 "wrong peb %p / %p\n", ULongToPtr(teb32.Peb), teb.Peb );
315 status = NtQueryInformationProcess( pi.hProcess, ProcessBasicInformation,
316 &proc_info, sizeof(proc_info), NULL );
317 ok( !status, "ProcessBasicInformation failed %lx\n", status );
318 ok( proc_info.PebBaseAddress == teb.Peb, "wrong peb %p / %p\n", proc_info.PebBaseAddress, teb.Peb );
320 if (!ReadProcessMemory( pi.hProcess, proc_info.PebBaseAddress, &peb, sizeof(peb), &res )) res = 0;
321 ok( res == sizeof(peb), "wrong len %Ix\n", res );
322 ok( !peb.BeingDebugged, "BeingDebugged is %u\n", peb.BeingDebugged );
323 if (!is_wow64)
325 if (!ReadProcessMemory( pi.hProcess, ULongToPtr(teb32.Peb), &peb32, sizeof(peb32), &res )) res = 0;
326 ok( res == sizeof(peb32), "wrong len %Ix\n", res );
327 ok( !peb32.BeingDebugged, "BeingDebugged is %u\n", peb32.BeingDebugged );
330 if (!ReadProcessMemory( pi.hProcess, peb.ProcessParameters, &params, sizeof(params), &res )) res = 0;
331 ok( res == sizeof(params), "wrong len %Ix\n", res );
332 #define CHECK_STR(name) \
333 ok( (char *)params.name.Buffer >= (char *)peb.ProcessParameters && \
334 (char *)params.name.Buffer < (char *)peb.ProcessParameters + params.Size, \
335 "wrong " #name " ptr %p / %p-%p\n", params.name.Buffer, peb.ProcessParameters, \
336 (char *)peb.ProcessParameters + params.Size )
337 CHECK_STR( ImagePathName );
338 CHECK_STR( CommandLine );
339 CHECK_STR( WindowTitle );
340 CHECK_STR( Desktop );
341 CHECK_STR( ShellInfo );
342 #undef CHECK_STR
343 if (!is_wow64)
345 ok( peb32.ProcessParameters && ULongToPtr(peb32.ProcessParameters) != peb.ProcessParameters,
346 "wrong ptr32 %p / %p\n", ULongToPtr(peb32.ProcessParameters), peb.ProcessParameters );
347 if (!ReadProcessMemory( pi.hProcess, ULongToPtr(peb32.ProcessParameters), &params32, sizeof(params32), &res )) res = 0;
348 ok( res == sizeof(params32), "wrong len %Ix\n", res );
349 #define CHECK_STR(name) \
350 ok( ULongToPtr(params32.name.Buffer) >= ULongToPtr(peb32.ProcessParameters) && \
351 ULongToPtr(params32.name.Buffer) < ULongToPtr(peb32.ProcessParameters + params32.Size), \
352 "wrong " #name " ptr %lx / %lx-%lx\n", params32.name.Buffer, peb32.ProcessParameters, \
353 peb32.ProcessParameters + params.Size ); \
354 ok( params32.name.Length == params.name.Length, "wrong " #name "len %u / %u\n", \
355 params32.name.Length, params.name.Length )
356 CHECK_STR( ImagePathName );
357 CHECK_STR( CommandLine );
358 CHECK_STR( WindowTitle );
359 CHECK_STR( Desktop );
360 CHECK_STR( ShellInfo );
361 #undef CHECK_STR
362 ok( params32.EnvironmentSize == params.EnvironmentSize, "wrong size %lu / %Iu\n",
363 params32.EnvironmentSize, params.EnvironmentSize );
366 ret = DebugActiveProcess( pi.dwProcessId );
367 ok( ret, "debugging failed\n" );
368 if (!ReadProcessMemory( pi.hProcess, proc_info.PebBaseAddress, &peb, sizeof(peb), &res )) res = 0;
369 ok( res == sizeof(peb), "wrong len %Ix\n", res );
370 ok( peb.BeingDebugged == !!ret, "BeingDebugged is %u\n", peb.BeingDebugged );
371 if (!is_wow64)
373 if (!ReadProcessMemory( pi.hProcess, ULongToPtr(teb32.Peb), &peb32, sizeof(peb32), &res )) res = 0;
374 ok( res == sizeof(peb32), "wrong len %Ix\n", res );
375 ok( peb32.BeingDebugged == !!ret, "BeingDebugged is %u\n", peb32.BeingDebugged );
378 TerminateProcess( pi.hProcess, 0 );
379 CloseHandle( pi.hProcess );
380 CloseHandle( pi.hThread );
383 if (CreateProcessA( "C:\\windows\\system32\\msinfo32.exe", NULL, NULL, NULL,
384 FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
386 memset( &info, 0xcc, sizeof(info) );
387 status = NtQueryInformationThread( pi.hThread, ThreadBasicInformation, &info, sizeof(info), NULL );
388 ok( !status, "ThreadBasicInformation failed %lx\n", status );
389 if (!is_wow64)
391 if (!ReadProcessMemory( pi.hProcess, info.TebBaseAddress, &teb, sizeof(teb), &res )) res = 0;
392 ok( res == sizeof(teb), "wrong len %Ix\n", res );
393 ok( teb.Tib.Self == info.TebBaseAddress, "wrong teb %p / %p\n",
394 teb.Tib.Self, info.TebBaseAddress );
395 ok( !teb.GdiBatchCount, "GdiBatchCount set\n" );
396 ok( !teb.WowTebOffset || broken( teb.WowTebOffset == 1 ), /* vista */
397 "wrong teb offset %ld\n", teb.WowTebOffset );
399 else ok( !info.TebBaseAddress, "got teb %p\n", info.TebBaseAddress );
401 status = NtQueryInformationProcess( pi.hProcess, ProcessBasicInformation,
402 &proc_info, sizeof(proc_info), NULL );
403 ok( !status, "ProcessBasicInformation failed %lx\n", status );
404 if (is_wow64)
405 ok( !proc_info.PebBaseAddress ||
406 broken( (char *)proc_info.PebBaseAddress >= (char *)0x7f000000 ), /* vista */
407 "wrong peb %p\n", proc_info.PebBaseAddress );
408 else
409 ok( proc_info.PebBaseAddress == teb.Peb, "wrong peb %p / %p\n",
410 proc_info.PebBaseAddress, teb.Peb );
412 TerminateProcess( pi.hProcess, 0 );
413 CloseHandle( pi.hProcess );
414 CloseHandle( pi.hThread );
417 Wow64RevertWow64FsRedirection( redir );
419 #ifndef _WIN64
420 if (is_wow64)
422 PEB64 *peb64;
423 TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
425 ok( !!teb64, "GdiBatchCount not set\n" );
426 ok( (char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset == (char *)teb64 ||
427 broken(!NtCurrentTeb()->WowTebOffset), /* pre-win10 */
428 "wrong WowTebOffset %lx (%p/%p)\n", NtCurrentTeb()->WowTebOffset, teb64, NtCurrentTeb() );
429 ok( (char *)teb64 + 0x2000 == (char *)NtCurrentTeb(), "unexpected diff %p / %p\n",
430 teb64, NtCurrentTeb() );
431 ok( (char *)teb64 + teb64->WowTebOffset == (char *)NtCurrentTeb() ||
432 broken( !teb64->WowTebOffset || teb64->WowTebOffset == 1 ), /* pre-win10 */
433 "wrong WowTebOffset %lx (%p/%p)\n", teb64->WowTebOffset, teb64, NtCurrentTeb() );
434 ok( !teb64->GdiBatchCount, "GdiBatchCount set %lx\n", teb64->GdiBatchCount );
435 ok( teb64->Tib.ExceptionList == PtrToUlong( NtCurrentTeb() ), "wrong Tib.ExceptionList %s / %p\n",
436 wine_dbgstr_longlong(teb64->Tib.ExceptionList), NtCurrentTeb() );
437 ok( teb64->Tib.Self == PtrToUlong( teb64 ), "wrong Tib.Self %s / %p\n",
438 wine_dbgstr_longlong(teb64->Tib.Self), teb64 );
439 ok( teb64->StaticUnicodeString.Buffer == PtrToUlong( teb64->StaticUnicodeBuffer ),
440 "wrong StaticUnicodeString %s / %p\n",
441 wine_dbgstr_longlong(teb64->StaticUnicodeString.Buffer), teb64->StaticUnicodeBuffer );
442 ok( teb64->ClientId.UniqueProcess == GetCurrentProcessId(), "wrong pid %s / %lx\n",
443 wine_dbgstr_longlong(teb64->ClientId.UniqueProcess), GetCurrentProcessId() );
444 ok( teb64->ClientId.UniqueThread == GetCurrentThreadId(), "wrong tid %s / %lx\n",
445 wine_dbgstr_longlong(teb64->ClientId.UniqueThread), GetCurrentThreadId() );
446 peb64 = ULongToPtr( teb64->Peb );
447 ok( peb64->ImageBaseAddress == PtrToUlong( NtCurrentTeb()->Peb->ImageBaseAddress ),
448 "wrong ImageBaseAddress %s / %p\n",
449 wine_dbgstr_longlong(peb64->ImageBaseAddress), NtCurrentTeb()->Peb->ImageBaseAddress);
450 ok( peb64->OSBuildNumber == NtCurrentTeb()->Peb->OSBuildNumber, "wrong OSBuildNumber %lx / %lx\n",
451 peb64->OSBuildNumber, NtCurrentTeb()->Peb->OSBuildNumber );
452 ok( peb64->OSPlatformId == NtCurrentTeb()->Peb->OSPlatformId, "wrong OSPlatformId %lx / %lx\n",
453 peb64->OSPlatformId, NtCurrentTeb()->Peb->OSPlatformId );
454 return;
456 #endif
457 ok( !NtCurrentTeb()->GdiBatchCount, "GdiBatchCount set to %lx\n", NtCurrentTeb()->GdiBatchCount );
458 ok( !NtCurrentTeb()->WowTebOffset || broken( NtCurrentTeb()->WowTebOffset == 1 ), /* vista */
459 "WowTebOffset set to %lx\n", NtCurrentTeb()->WowTebOffset );
462 static void test_selectors(void)
464 THREAD_DESCRIPTOR_INFORMATION info;
465 NTSTATUS status;
466 ULONG base, limit, sel, retlen;
467 I386_CONTEXT context = { CONTEXT_I386_CONTROL | CONTEXT_I386_SEGMENTS };
469 #ifdef _WIN64
470 if (!pRtlWow64GetThreadSelectorEntry)
472 win_skip( "RtlWow64GetThreadSelectorEntry not supported\n" );
473 return;
475 if (!pRtlWow64GetThreadContext || pRtlWow64GetThreadContext( GetCurrentThread(), &context ))
477 /* hardcoded values */
478 #ifdef __x86_64__
479 context.SegCs = 0x23;
480 __asm__( "movw %%fs,%0" : "=m" (context.SegFs) );
481 __asm__( "movw %%ss,%0" : "=m" (context.SegSs) );
482 #else
483 context.SegCs = 0x1b;
484 context.SegSs = 0x23;
485 context.SegFs = 0x3b;
486 #endif
488 #define GET_ENTRY(info,size,ret) \
489 pRtlWow64GetThreadSelectorEntry( GetCurrentThread(), info, size, ret )
491 #else
492 GetThreadContext( GetCurrentThread(), &context );
493 #define GET_ENTRY(info,size,ret) \
494 NtQueryInformationThread( GetCurrentThread(), ThreadDescriptorTableEntry, info, size, ret )
495 #endif
497 trace( "cs %04lx ss %04lx fs %04lx\n", context.SegCs, context.SegSs, context.SegFs );
498 retlen = 0xdeadbeef;
499 info.Selector = 0;
500 status = GET_ENTRY( &info, sizeof(info) - 1, &retlen );
501 ok( status == STATUS_INFO_LENGTH_MISMATCH, "wrong status %lx\n", status );
502 ok( retlen == 0xdeadbeef, "len set %lu\n", retlen );
504 retlen = 0xdeadbeef;
505 status = GET_ENTRY( &info, sizeof(info) + 1, &retlen );
506 ok( status == STATUS_INFO_LENGTH_MISMATCH, "wrong status %lx\n", status );
507 ok( retlen == 0xdeadbeef, "len set %lu\n", retlen );
509 retlen = 0xdeadbeef;
510 status = GET_ENTRY( NULL, 0, &retlen );
511 ok( status == STATUS_INFO_LENGTH_MISMATCH, "wrong status %lx\n", status );
512 ok( retlen == 0xdeadbeef, "len set %lu\n", retlen );
514 status = GET_ENTRY( &info, sizeof(info), NULL );
515 ok( !status, "wrong status %lx\n", status );
517 for (info.Selector = 0; info.Selector < 0x100; info.Selector++)
519 retlen = 0xdeadbeef;
520 status = GET_ENTRY( &info, sizeof(info), &retlen );
521 base = (info.Entry.BaseLow |
522 (info.Entry.HighWord.Bytes.BaseMid << 16) |
523 (info.Entry.HighWord.Bytes.BaseHi << 24));
524 limit = (info.Entry.LimitLow | info.Entry.HighWord.Bits.LimitHi << 16);
525 sel = info.Selector | 3;
527 if (sel == 0x03) /* null selector */
529 ok( !status, "wrong status %lx\n", status );
530 ok( retlen == sizeof(info.Entry), "len set %lu\n", retlen );
531 ok( !base, "wrong base %lx\n", base );
532 ok( !limit, "wrong limit %lx\n", limit );
533 ok( !info.Entry.HighWord.Bytes.Flags1, "wrong flags1 %x\n", info.Entry.HighWord.Bytes.Flags1 );
534 ok( !info.Entry.HighWord.Bytes.Flags2, "wrong flags2 %x\n", info.Entry.HighWord.Bytes.Flags2 );
536 else if (sel == context.SegCs) /* 32-bit code selector */
538 ok( !status, "wrong status %lx\n", status );
539 ok( retlen == sizeof(info.Entry), "len set %lu\n", retlen );
540 ok( !base, "wrong base %lx\n", base );
541 ok( limit == 0xfffff, "wrong limit %lx\n", limit );
542 ok( info.Entry.HighWord.Bits.Type == 0x1b, "wrong type %x\n", info.Entry.HighWord.Bits.Type );
543 ok( info.Entry.HighWord.Bits.Dpl == 3, "wrong dpl %x\n", info.Entry.HighWord.Bits.Dpl );
544 ok( info.Entry.HighWord.Bits.Pres, "wrong pres\n" );
545 ok( !info.Entry.HighWord.Bits.Sys, "wrong sys\n" );
546 ok( info.Entry.HighWord.Bits.Default_Big, "wrong big\n" );
547 ok( info.Entry.HighWord.Bits.Granularity, "wrong granularity\n" );
549 else if (sel == context.SegSs) /* 32-bit data selector */
551 ok( !status, "wrong status %lx\n", status );
552 ok( retlen == sizeof(info.Entry), "len set %lu\n", retlen );
553 ok( !base, "wrong base %lx\n", base );
554 ok( limit == 0xfffff, "wrong limit %lx\n", limit );
555 ok( info.Entry.HighWord.Bits.Type == 0x13, "wrong type %x\n", info.Entry.HighWord.Bits.Type );
556 ok( info.Entry.HighWord.Bits.Dpl == 3, "wrong dpl %x\n", info.Entry.HighWord.Bits.Dpl );
557 ok( info.Entry.HighWord.Bits.Pres, "wrong pres\n" );
558 ok( !info.Entry.HighWord.Bits.Sys, "wrong sys\n" );
559 ok( info.Entry.HighWord.Bits.Default_Big, "wrong big\n" );
560 ok( info.Entry.HighWord.Bits.Granularity, "wrong granularity\n" );
562 else if (sel == context.SegFs) /* TEB selector */
564 ok( !status, "wrong status %lx\n", status );
565 ok( retlen == sizeof(info.Entry), "len set %lu\n", retlen );
566 #ifdef _WIN64
567 if (NtCurrentTeb()->WowTebOffset == 0x2000)
568 ok( base == (ULONG_PTR)NtCurrentTeb() + 0x2000, "wrong base %lx / %p\n",
569 base, NtCurrentTeb() );
570 #else
571 ok( base == (ULONG_PTR)NtCurrentTeb(), "wrong base %lx / %p\n", base, NtCurrentTeb() );
572 #endif
573 ok( limit == 0xfff || broken(limit == 0x4000), /* <= win8 */
574 "wrong limit %lx\n", limit );
575 ok( info.Entry.HighWord.Bits.Type == 0x13, "wrong type %x\n", info.Entry.HighWord.Bits.Type );
576 ok( info.Entry.HighWord.Bits.Dpl == 3, "wrong dpl %x\n", info.Entry.HighWord.Bits.Dpl );
577 ok( info.Entry.HighWord.Bits.Pres, "wrong pres\n" );
578 ok( !info.Entry.HighWord.Bits.Sys, "wrong sys\n" );
579 ok( info.Entry.HighWord.Bits.Default_Big, "wrong big\n" );
580 ok( !info.Entry.HighWord.Bits.Granularity, "wrong granularity\n" );
582 else if (!status)
584 ok( retlen == sizeof(info.Entry), "len set %lu\n", retlen );
585 trace( "succeeded for %lx base %lx limit %lx type %x\n",
586 sel, base, limit, info.Entry.HighWord.Bits.Type );
588 else
590 ok( status == STATUS_UNSUCCESSFUL ||
591 ((sel & 4) && (status == STATUS_NO_LDT)) ||
592 broken( status == STATUS_ACCESS_VIOLATION), /* <= win8 */
593 "%lx: wrong status %lx\n", info.Selector, status );
594 ok( retlen == 0xdeadbeef, "len set %lu\n", retlen );
597 #undef GET_ENTRY
600 static void test_image_mappings(void)
602 MEM_EXTENDED_PARAMETER ext = { .Type = MemExtendedParameterImageMachine };
603 HANDLE file, mapping, process = GetCurrentProcess();
604 NTSTATUS status;
605 SIZE_T size;
606 LARGE_INTEGER offset;
607 void *ptr;
609 if (!pNtMapViewOfSectionEx)
611 win_skip( "NtMapViewOfSectionEx() not supported\n" );
612 return;
615 offset.QuadPart = 0;
616 file = CreateFileA( "c:\\windows\\system32\\version.dll", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 );
617 ok( file != INVALID_HANDLE_VALUE, "Failed to open version.dll\n" );
618 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL );
619 ok( mapping != 0, "CreateFileMapping failed\n" );
620 CloseHandle( file );
622 ptr = NULL;
623 size = 0;
624 ext.ULong = IMAGE_FILE_MACHINE_AMD64;
625 status = pNtMapViewOfSectionEx( mapping, process, &ptr, &offset, &size, 0, PAGE_READONLY, &ext, 1 );
626 if (status == STATUS_INVALID_PARAMETER)
628 win_skip( "MemExtendedParameterImageMachine not supported\n" );
629 NtClose( mapping );
630 return;
632 if (current_machine == IMAGE_FILE_MACHINE_AMD64)
634 ok( status == STATUS_SUCCESS || status == STATUS_IMAGE_NOT_AT_BASE,
635 "NtMapViewOfSection returned %08lx\n", status );
636 NtUnmapViewOfSection( process, ptr );
638 else if (current_machine == IMAGE_FILE_MACHINE_ARM64)
640 ok( status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH, "NtMapViewOfSection returned %08lx\n", status );
641 NtUnmapViewOfSection( process, ptr );
643 else ok( status == STATUS_NOT_SUPPORTED, "NtMapViewOfSection returned %08lx\n", status );
645 ptr = NULL;
646 size = 0;
647 ext.ULong = IMAGE_FILE_MACHINE_I386;
648 status = pNtMapViewOfSectionEx( mapping, process, &ptr, &offset, &size, 0, PAGE_READONLY, &ext, 1 );
649 if (current_machine == IMAGE_FILE_MACHINE_I386)
651 ok( status == STATUS_SUCCESS || status == STATUS_IMAGE_NOT_AT_BASE,
652 "NtMapViewOfSection returned %08lx\n", status );
653 NtUnmapViewOfSection( process, ptr );
655 else ok( status == STATUS_NOT_SUPPORTED, "NtMapViewOfSection returned %08lx\n", status );
657 ptr = NULL;
658 size = 0;
659 ext.ULong = IMAGE_FILE_MACHINE_ARM64;
660 status = pNtMapViewOfSectionEx( mapping, process, &ptr, &offset, &size, 0, PAGE_READONLY, &ext, 1 );
661 if (native_machine == IMAGE_FILE_MACHINE_ARM64)
663 switch (current_machine)
665 case IMAGE_FILE_MACHINE_ARM64:
666 ok( status == STATUS_SUCCESS || status == STATUS_IMAGE_NOT_AT_BASE,
667 "NtMapViewOfSection returned %08lx\n", status );
668 NtUnmapViewOfSection( process, ptr );
669 break;
670 case IMAGE_FILE_MACHINE_AMD64:
671 ok( status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH, "NtMapViewOfSection returned %08lx\n", status );
672 NtUnmapViewOfSection( process, ptr );
673 break;
674 default:
675 ok( status == STATUS_NOT_SUPPORTED, "NtMapViewOfSection returned %08lx\n", status );
676 break;
679 else ok( status == STATUS_NOT_SUPPORTED, "NtMapViewOfSection returned %08lx\n", status );
681 ptr = NULL;
682 size = 0;
683 ext.ULong = IMAGE_FILE_MACHINE_R3000;
684 status = pNtMapViewOfSectionEx( mapping, process, &ptr, &offset, &size, 0, PAGE_READONLY, &ext, 1 );
685 ok( status == STATUS_NOT_SUPPORTED, "NtMapViewOfSection returned %08lx\n", status );
687 ptr = NULL;
688 size = 0;
689 ext.ULong = 0;
690 status = pNtMapViewOfSectionEx( mapping, process, &ptr, &offset, &size, 0, PAGE_READONLY, &ext, 1 );
691 ok( status == STATUS_SUCCESS || status == STATUS_IMAGE_NOT_AT_BASE,
692 "NtMapViewOfSection returned %08lx\n", status );
693 NtUnmapViewOfSection( process, ptr );
695 NtClose( mapping );
697 if (is_wow64)
699 file = CreateFileA( "c:\\windows\\sysnative\\version.dll", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 );
700 ok( file != INVALID_HANDLE_VALUE, "Failed to open version.dll\n" );
702 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL );
703 ok( mapping != 0, "CreateFileMapping failed\n" );
704 CloseHandle( file );
706 ptr = NULL;
707 size = 0;
708 ext.ULong = native_machine;
709 status = pNtMapViewOfSectionEx( mapping, process, &ptr, &offset, &size, 0, PAGE_READONLY, &ext, 1 );
710 ok( status == STATUS_SUCCESS || status == STATUS_IMAGE_NOT_AT_BASE,
711 "NtMapViewOfSection returned %08lx\n", status );
712 NtUnmapViewOfSection( process, ptr );
714 ptr = NULL;
715 size = 0;
716 ext.ULong = IMAGE_FILE_MACHINE_I386;
717 status = pNtMapViewOfSectionEx( mapping, process, &ptr, &offset, &size, 0, PAGE_READONLY, &ext, 1 );
718 ok( status == STATUS_NOT_SUPPORTED, "NtMapViewOfSection returned %08lx\n", status );
719 NtClose( mapping );
721 else if (native_machine == IMAGE_FILE_MACHINE_AMD64 || native_machine == IMAGE_FILE_MACHINE_ARM64)
723 file = CreateFileA( "c:\\windows\\syswow64\\version.dll", GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0 );
724 ok( file != INVALID_HANDLE_VALUE, "Failed to open version.dll\n" );
726 mapping = CreateFileMappingA( file, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL );
727 ok( mapping != 0, "CreateFileMapping failed\n" );
728 CloseHandle( file );
730 ptr = NULL;
731 size = 0;
732 ext.ULong = native_machine;
733 status = pNtMapViewOfSectionEx( mapping, process, &ptr, &offset, &size, 0, PAGE_READONLY, &ext, 1 );
734 ok( status == STATUS_NOT_SUPPORTED, "NtMapViewOfSection returned %08lx\n", status );
736 ptr = NULL;
737 size = 0;
738 ext.ULong = IMAGE_FILE_MACHINE_I386;
739 status = pNtMapViewOfSectionEx( mapping, process, &ptr, &offset, &size, 0, PAGE_READONLY, &ext, 1 );
740 ok( status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH, "NtMapViewOfSection returned %08lx\n", status );
741 NtUnmapViewOfSection( process, ptr );
742 NtClose( mapping );
746 #ifdef _WIN64
748 static void test_cpu_area(void)
750 if (pRtlWow64GetCpuAreaInfo)
752 static const struct
754 USHORT machine;
755 NTSTATUS expect;
756 ULONG_PTR align, size, offset, flag;
757 } tests[] =
759 { IMAGE_FILE_MACHINE_I386, 0, 4, 0x2cc, 0x00, 0x00010000 },
760 { IMAGE_FILE_MACHINE_AMD64, 0, 16, 0x4d0, 0x30, 0x00100000 },
761 { IMAGE_FILE_MACHINE_ARMNT, 0, 8, 0x1a0, 0x00, 0x00200000 },
762 { IMAGE_FILE_MACHINE_ARM64, 0, 16, 0x390, 0x00, 0x00400000 },
763 { IMAGE_FILE_MACHINE_ARM, STATUS_INVALID_PARAMETER },
764 { IMAGE_FILE_MACHINE_THUMB, STATUS_INVALID_PARAMETER },
766 USHORT buffer[2048];
767 WOW64_CPURESERVED *cpu;
768 WOW64_CPU_AREA_INFO info;
769 ULONG i, j;
770 NTSTATUS status;
771 #define ALIGN(ptr,align) ((void *)(((ULONG_PTR)(ptr) + (align) - 1) & ~((align) - 1)))
773 for (i = 0; i < ARRAY_SIZE(tests); i++)
775 for (j = 0; j < 8; j++)
777 cpu = (WOW64_CPURESERVED *)(buffer + j);
778 cpu->Flags = 0;
779 cpu->Machine = tests[i].machine;
780 status = pRtlWow64GetCpuAreaInfo( cpu, 0, &info );
781 ok( status == tests[i].expect, "%lu:%lu: failed %lx\n", i, j, status );
782 if (status) continue;
783 ok( info.Context == ALIGN( cpu + 1, tests[i].align ), "%lu:%lu: wrong offset %lu\n",
784 i, j, (ULONG)((char *)info.Context - (char *)cpu) );
785 ok( info.ContextEx == ALIGN( (char *)info.Context + tests[i].size, sizeof(void*) ),
786 "%lu:%lu: wrong ex offset %lu\n", i, j, (ULONG)((char *)info.ContextEx - (char *)cpu) );
787 ok( info.ContextFlagsLocation == (char *)info.Context + tests[i].offset,
788 "%lu:%lu: wrong flags offset %lu\n",
789 i, j, (ULONG)((char *)info.ContextFlagsLocation - (char *)info.Context) );
790 ok( info.CpuReserved == cpu, "%lu:%lu: wrong cpu %p / %p\n", i, j, info.CpuReserved, cpu );
791 ok( info.ContextFlag == tests[i].flag, "%lu:%lu: wrong flag %08lx\n", i, j, info.ContextFlag );
792 ok( info.Machine == tests[i].machine, "%lu:%lu: wrong machine %x\n", i, j, info.Machine );
795 #undef ALIGN
797 else win_skip( "RtlWow64GetCpuAreaInfo not supported\n" );
800 #else /* _WIN64 */
802 static const BYTE call_func64_code[] =
804 0x58, /* pop %eax */
805 0x0e, /* push %cs */
806 0x50, /* push %eax */
807 0x6a, 0x33, /* push $0x33 */
808 0xe8, 0x00, 0x00, 0x00, 0x00, /* call 1f */
809 0x83, 0x04, 0x24, 0x05, /* 1: addl $0x5,(%esp) */
810 0xcb, /* lret */
811 /* in 64-bit mode: */
812 0x4c, 0x87, 0xf4, /* xchg %r14,%rsp */
813 0x55, /* push %rbp */
814 0x48, 0x89, 0xe5, /* mov %rsp,%rbp */
815 0x56, /* push %rsi */
816 0x57, /* push %rdi */
817 0x41, 0x8b, 0x4e, 0x10, /* mov 0x10(%r14),%ecx */
818 0x41, 0x8b, 0x76, 0x14, /* mov 0x14(%r14),%esi */
819 0x67, 0x8d, 0x04, 0xcd, 0, 0, 0, 0, /* lea 0x0(,%ecx,8),%eax */
820 0x83, 0xf8, 0x20, /* cmp $0x20,%eax */
821 0x7d, 0x05, /* jge 1f */
822 0xb8, 0x20, 0x00, 0x00, 0x00, /* mov $0x20,%eax */
823 0x48, 0x29, 0xc4, /* 1: sub %rax,%rsp */
824 0x48, 0x83, 0xe4, 0xf0, /* and $~15,%rsp */
825 0x48, 0x89, 0xe7, /* mov %rsp,%rdi */
826 0xf3, 0x48, 0xa5, /* rep movsq */
827 0x48, 0x8b, 0x0c, 0x24, /* mov (%rsp),%rcx */
828 0x48, 0x8b, 0x54, 0x24, 0x08, /* mov 0x8(%rsp),%rdx */
829 0x4c, 0x8b, 0x44, 0x24, 0x10, /* mov 0x10(%rsp),%r8 */
830 0x4c, 0x8b, 0x4c, 0x24, 0x18, /* mov 0x18(%rsp),%r9 */
831 0x41, 0xff, 0x56, 0x08, /* callq *0x8(%r14) */
832 0x48, 0x8d, 0x65, 0xf0, /* lea -0x10(%rbp),%rsp */
833 0x5f, /* pop %rdi */
834 0x5e, /* pop %rsi */
835 0x5d, /* pop %rbp */
836 0x4c, 0x87, 0xf4, /* xchg %r14,%rsp */
837 0xcb, /* lret */
840 static NTSTATUS call_func64( ULONG64 func64, int nb_args, ULONG64 *args )
842 NTSTATUS (WINAPI *func)( ULONG64 func64, int nb_args, ULONG64 *args ) = code_mem;
844 memcpy( code_mem, call_func64_code, sizeof(call_func64_code) );
845 return func( func64, nb_args, args );
848 static ULONG64 main_module, ntdll_module, wow64_module, wow64base_module, wow64con_module,
849 wow64cpu_module, xtajit_module, wow64win_module;
851 static void enum_modules64( void (*func)(ULONG64,const WCHAR *) )
853 typedef struct
855 LIST_ENTRY64 InLoadOrderLinks;
856 LIST_ENTRY64 InMemoryOrderLinks;
857 LIST_ENTRY64 InInitializationOrderLinks;
858 ULONG64 DllBase;
859 ULONG64 EntryPoint;
860 ULONG SizeOfImage;
861 UNICODE_STRING64 FullDllName;
862 UNICODE_STRING64 BaseDllName;
863 /* etc. */
864 } LDR_DATA_TABLE_ENTRY64;
866 TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
867 PEB64 peb64;
868 ULONG64 ptr;
869 PEB_LDR_DATA64 ldr;
870 LDR_DATA_TABLE_ENTRY64 entry;
871 NTSTATUS status;
872 HANDLE process;
874 process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
875 ok( process != 0, "failed to open current process %lu\n", GetLastError() );
876 status = pNtWow64ReadVirtualMemory64( process, teb64->Peb, &peb64, sizeof(peb64), NULL );
877 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
878 todo_wine_if( old_wow64 )
879 ok( peb64.LdrData, "LdrData not initialized\n" );
880 if (!peb64.LdrData) goto done;
881 status = pNtWow64ReadVirtualMemory64( process, peb64.LdrData, &ldr, sizeof(ldr), NULL );
882 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
883 ptr = ldr.InLoadOrderModuleList.Flink;
884 for (;;)
886 WCHAR buffer[256];
887 status = pNtWow64ReadVirtualMemory64( process, ptr, &entry, sizeof(entry), NULL );
888 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
889 status = pNtWow64ReadVirtualMemory64( process, entry.BaseDllName.Buffer, buffer, sizeof(buffer), NULL );
890 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
891 if (status) break;
892 func( entry.DllBase, buffer );
893 ptr = entry.InLoadOrderLinks.Flink;
894 if (ptr == peb64.LdrData + offsetof( PEB_LDR_DATA64, InLoadOrderModuleList )) break;
896 done:
897 NtClose( process );
900 static ULONG64 get_proc_address64( ULONG64 module, const char *name )
902 IMAGE_DOS_HEADER dos;
903 IMAGE_NT_HEADERS64 nt;
904 IMAGE_EXPORT_DIRECTORY exports;
905 ULONG i, *names, *funcs;
906 USHORT *ordinals;
907 NTSTATUS status;
908 HANDLE process;
909 ULONG64 ret = 0;
910 char buffer[64];
912 if (!module) return 0;
913 process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
914 ok( process != 0, "failed to open current process %lu\n", GetLastError() );
915 status = pNtWow64ReadVirtualMemory64( process, module, &dos, sizeof(dos), NULL );
916 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
917 status = pNtWow64ReadVirtualMemory64( process, module + dos.e_lfanew, &nt, sizeof(nt), NULL );
918 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
919 status = pNtWow64ReadVirtualMemory64( process, module + nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress,
920 &exports, sizeof(exports), NULL );
921 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
922 names = calloc( exports.NumberOfNames, sizeof(*names) );
923 ordinals = calloc( exports.NumberOfNames, sizeof(*ordinals) );
924 funcs = calloc( exports.NumberOfFunctions, sizeof(*funcs) );
925 status = pNtWow64ReadVirtualMemory64( process, module + exports.AddressOfNames,
926 names, exports.NumberOfNames * sizeof(*names), NULL );
927 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
928 status = pNtWow64ReadVirtualMemory64( process, module + exports.AddressOfNameOrdinals,
929 ordinals, exports.NumberOfNames * sizeof(*ordinals), NULL );
930 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
931 status = pNtWow64ReadVirtualMemory64( process, module + exports.AddressOfFunctions,
932 funcs, exports.NumberOfFunctions * sizeof(*funcs), NULL );
933 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
934 for (i = 0; i < exports.NumberOfNames && !ret; i++)
936 status = pNtWow64ReadVirtualMemory64( process, module + names[i], buffer, sizeof(buffer), NULL );
937 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
938 if (!strcmp( buffer, name )) ret = module + funcs[ordinals[i]];
940 free( funcs );
941 free( ordinals );
942 free( names );
943 NtClose( process );
944 return ret;
947 static void check_module( ULONG64 base, const WCHAR *name )
949 if (base == (ULONG_PTR)GetModuleHandleW(0))
951 WCHAR *p, module[MAX_PATH];
953 GetModuleFileNameW( 0, module, MAX_PATH );
954 if ((p = wcsrchr( module, '\\' ))) p++;
955 else p = module;
956 ok( !wcsicmp( name, p ), "wrong name %s / %s\n", debugstr_w(name), debugstr_w(module));
957 main_module = base;
958 return;
960 #define CHECK_MODULE(mod) do { if (!wcsicmp( name, L"" #mod ".dll" )) { mod ## _module = base; return; } } while(0)
961 CHECK_MODULE(ntdll);
962 CHECK_MODULE(wow64);
963 CHECK_MODULE(wow64base);
964 CHECK_MODULE(wow64con);
965 CHECK_MODULE(wow64win);
966 if (native_machine == IMAGE_FILE_MACHINE_ARM64)
967 CHECK_MODULE(xtajit);
968 else
969 CHECK_MODULE(wow64cpu);
970 #undef CHECK_MODULE
971 ok( 0, "unknown module %s %s found\n", wine_dbgstr_longlong(base), wine_dbgstr_w(name));
974 static void test_modules(void)
976 if (!is_wow64) return;
977 if (!pNtWow64ReadVirtualMemory64) return;
978 enum_modules64( check_module );
979 todo_wine_if( old_wow64 )
981 ok( main_module, "main module not found\n" );
982 ok( ntdll_module, "64-bit ntdll not found\n" );
983 ok( wow64_module, "wow64.dll not found\n" );
984 if (native_machine == IMAGE_FILE_MACHINE_ARM64)
985 ok( xtajit_module, "xtajit.dll not found\n" );
986 else
987 ok( wow64cpu_module, "wow64cpu.dll not found\n" );
988 ok( wow64win_module, "wow64win.dll not found\n" );
992 static void test_nt_wow64(void)
994 const char str[] = "hello wow64";
995 char buffer[100];
996 NTSTATUS status;
997 ULONG64 res;
998 HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
1000 ok( process != 0, "failed to open current process %lu\n", GetLastError() );
1001 if (pNtWow64ReadVirtualMemory64)
1003 status = pNtWow64ReadVirtualMemory64( process, (ULONG_PTR)str, buffer, sizeof(str), &res );
1004 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
1005 ok( res == sizeof(str), "wrong size %s\n", wine_dbgstr_longlong(res) );
1006 ok( !strcmp( buffer, str ), "wrong data %s\n", debugstr_a(buffer) );
1007 status = pNtWow64WriteVirtualMemory64( process, (ULONG_PTR)buffer, " bye ", 5, &res );
1008 ok( !status, "NtWow64WriteVirtualMemory64 failed %lx\n", status );
1009 ok( res == 5, "wrong size %s\n", wine_dbgstr_longlong(res) );
1010 ok( !strcmp( buffer, " bye wow64" ), "wrong data %s\n", debugstr_a(buffer) );
1011 /* current process pseudo-handle is broken on some Windows versions */
1012 status = pNtWow64ReadVirtualMemory64( GetCurrentProcess(), (ULONG_PTR)str, buffer, sizeof(str), &res );
1013 ok( !status || broken( status == STATUS_INVALID_HANDLE ),
1014 "NtWow64ReadVirtualMemory64 failed %lx\n", status );
1015 status = pNtWow64WriteVirtualMemory64( GetCurrentProcess(), (ULONG_PTR)buffer, " bye ", 5, &res );
1016 ok( !status || broken( status == STATUS_INVALID_HANDLE ),
1017 "NtWow64WriteVirtualMemory64 failed %lx\n", status );
1019 else win_skip( "NtWow64ReadVirtualMemory64 not supported\n" );
1021 if (pNtWow64AllocateVirtualMemory64)
1023 ULONG64 ptr = 0;
1024 ULONG64 size = 0x2345;
1026 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
1027 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
1028 ok( !status, "NtWow64AllocateVirtualMemory64 failed %lx\n", status );
1029 ok( ptr, "ptr not set\n" );
1030 ok( size == 0x3000, "size not set %s\n", wine_dbgstr_longlong(size) );
1031 ptr += 0x1000;
1032 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
1033 MEM_RESERVE | MEM_COMMIT, PAGE_READONLY );
1034 ok( status == STATUS_CONFLICTING_ADDRESSES, "NtWow64AllocateVirtualMemory64 failed %lx\n", status );
1035 ptr = 0;
1036 size = 0;
1037 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
1038 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
1039 ok( status == STATUS_INVALID_PARAMETER || status == STATUS_INVALID_PARAMETER_4,
1040 "NtWow64AllocateVirtualMemory64 failed %lx\n", status );
1041 size = 0x1000;
1042 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 22, &size,
1043 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
1044 ok( status == STATUS_INVALID_PARAMETER || status == STATUS_INVALID_PARAMETER_3,
1045 "NtWow64AllocateVirtualMemory64 failed %lx\n", status );
1046 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 33, &size,
1047 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
1048 ok( status == STATUS_INVALID_PARAMETER || status == STATUS_INVALID_PARAMETER_3,
1049 "NtWow64AllocateVirtualMemory64 failed %lx\n", status );
1050 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0x3fffffff, &size,
1051 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
1052 todo_wine_if( !is_wow64 )
1053 ok( !status, "NtWow64AllocateVirtualMemory64 failed %lx\n", status );
1054 ok( ptr < 0x40000000, "got wrong ptr %s\n", wine_dbgstr_longlong(ptr) );
1055 if (!status && pNtWow64WriteVirtualMemory64)
1057 status = pNtWow64WriteVirtualMemory64( process, ptr, str, sizeof(str), &res );
1058 ok( !status, "NtWow64WriteVirtualMemory64 failed %lx\n", status );
1059 ok( res == sizeof(str), "wrong size %s\n", wine_dbgstr_longlong(res) );
1060 ok( !strcmp( (char *)(ULONG_PTR)ptr, str ), "wrong data %s\n",
1061 debugstr_a((char *)(ULONG_PTR)ptr) );
1062 ptr = 0;
1063 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
1064 MEM_RESERVE | MEM_COMMIT, PAGE_READONLY );
1065 ok( !status, "NtWow64AllocateVirtualMemory64 failed %lx\n", status );
1066 status = pNtWow64WriteVirtualMemory64( process, ptr, str, sizeof(str), &res );
1067 todo_wine
1068 ok( status == STATUS_PARTIAL_COPY || broken( status == STATUS_ACCESS_VIOLATION ),
1069 "NtWow64WriteVirtualMemory64 failed %lx\n", status );
1070 todo_wine
1071 ok( !res || broken(res) /* win10 1709 */, "wrong size %s\n", wine_dbgstr_longlong(res) );
1073 ptr = 0x9876543210ull;
1074 status = pNtWow64AllocateVirtualMemory64( process, &ptr, 0, &size,
1075 MEM_RESERVE | MEM_COMMIT, PAGE_READONLY );
1076 todo_wine_if( !is_wow64 || old_wow64 )
1077 ok( !status || broken( status == STATUS_CONFLICTING_ADDRESSES ),
1078 "NtWow64AllocateVirtualMemory64 failed %lx\n", status );
1079 if (!status) ok( ptr == 0x9876540000ull || broken(ptr == 0x76540000), /* win 8.1 */
1080 "wrong ptr %s\n", wine_dbgstr_longlong(ptr) );
1081 ptr = 0;
1082 status = pNtWow64AllocateVirtualMemory64( GetCurrentProcess(), &ptr, 0, &size,
1083 MEM_RESERVE | MEM_COMMIT, PAGE_READONLY );
1084 ok( !status || broken( status == STATUS_INVALID_HANDLE ),
1085 "NtWow64AllocateVirtualMemory64 failed %lx\n", status );
1087 else win_skip( "NtWow64AllocateVirtualMemory64 not supported\n" );
1089 if (pNtWow64GetNativeSystemInformation)
1091 ULONG i, len;
1092 SYSTEM_BASIC_INFORMATION sbi, sbi2, sbi3;
1094 memset( &sbi, 0xcc, sizeof(sbi) );
1095 status = pNtQuerySystemInformation( SystemBasicInformation, &sbi, sizeof(sbi), &len );
1096 ok( status == STATUS_SUCCESS, "failed %lx\n", status );
1097 ok( len == sizeof(sbi), "wrong length %ld\n", len );
1099 memset( &sbi2, 0xcc, sizeof(sbi2) );
1100 status = pRtlGetNativeSystemInformation( SystemBasicInformation, &sbi2, sizeof(sbi2), &len );
1101 ok( status == STATUS_SUCCESS, "failed %lx\n", status );
1102 ok( len == sizeof(sbi2), "wrong length %ld\n", len );
1104 ok( sbi.HighestUserAddress == (void *)0x7ffeffff, "wrong limit %p\n", sbi.HighestUserAddress);
1105 todo_wine_if( old_wow64 )
1106 ok( sbi2.HighestUserAddress == (is_wow64 ? (void *)0xfffeffff : (void *)0x7ffeffff),
1107 "wrong limit %p\n", sbi.HighestUserAddress);
1109 memset( &sbi3, 0xcc, sizeof(sbi3) );
1110 status = pNtWow64GetNativeSystemInformation( SystemBasicInformation, &sbi3, sizeof(sbi3), &len );
1111 ok( status == STATUS_SUCCESS, "failed %lx\n", status );
1112 ok( len == sizeof(sbi3), "wrong length %ld\n", len );
1113 ok( !memcmp( &sbi2, &sbi3, offsetof(SYSTEM_BASIC_INFORMATION,NumberOfProcessors)+1 ),
1114 "info is different\n" );
1116 memset( &sbi3, 0xcc, sizeof(sbi3) );
1117 status = pNtWow64GetNativeSystemInformation( SystemEmulationBasicInformation, &sbi3, sizeof(sbi3), &len );
1118 ok( status == STATUS_SUCCESS, "failed %lx\n", status );
1119 ok( len == sizeof(sbi3), "wrong length %ld\n", len );
1120 ok( !memcmp( &sbi, &sbi3, offsetof(SYSTEM_BASIC_INFORMATION,NumberOfProcessors)+1 ),
1121 "info is different\n" );
1123 for (i = 0; i < 256; i++)
1125 NTSTATUS expect = pNtQuerySystemInformation( i, NULL, 0, &len );
1126 status = pNtWow64GetNativeSystemInformation( i, NULL, 0, &len );
1127 switch (i)
1129 case SystemNativeBasicInformation:
1130 ok( status == STATUS_INVALID_INFO_CLASS || status == STATUS_INFO_LENGTH_MISMATCH ||
1131 broken(status == STATUS_NOT_IMPLEMENTED) /* vista */, "%lu: %lx / %lx\n", i, status, expect );
1132 break;
1133 case SystemBasicInformation:
1134 case SystemCpuInformation:
1135 case SystemEmulationBasicInformation:
1136 case SystemEmulationProcessorInformation:
1137 ok( status == expect, "%lu: %lx / %lx\n", i, status, expect );
1138 break;
1139 default:
1140 if (is_wow64) /* only a few info classes are supported on Wow64 */
1141 ok( status == STATUS_INVALID_INFO_CLASS ||
1142 broken(status == STATUS_NOT_IMPLEMENTED), /* vista */
1143 "%lu: %lx\n", i, status );
1144 else
1145 ok( status == expect, "%lu: %lx / %lx\n", i, status, expect );
1146 break;
1150 else win_skip( "NtWow64GetNativeSystemInformation not supported\n" );
1152 if (pNtWow64IsProcessorFeaturePresent)
1154 ULONG i;
1156 for (i = 0; i < 64; i++)
1157 ok( pNtWow64IsProcessorFeaturePresent( i ) == IsProcessorFeaturePresent( i ),
1158 "mismatch %lu wow64 returned %lx\n", i, pNtWow64IsProcessorFeaturePresent( i ));
1160 if (native_machine == IMAGE_FILE_MACHINE_ARM64)
1162 KSHARED_USER_DATA *user_shared_data = ULongToPtr( 0x7ffe0000 );
1164 ok( user_shared_data->ProcessorFeatures[PF_ARM_V8_INSTRUCTIONS_AVAILABLE], "no ARM_V8\n" );
1165 ok( user_shared_data->ProcessorFeatures[PF_MMX_INSTRUCTIONS_AVAILABLE], "no MMX\n" );
1166 ok( !pNtWow64IsProcessorFeaturePresent( PF_ARM_V8_INSTRUCTIONS_AVAILABLE ), "ARM_V8 present\n" );
1167 ok( pNtWow64IsProcessorFeaturePresent( PF_MMX_INSTRUCTIONS_AVAILABLE ), "MMX not present\n" );
1170 else win_skip( "NtWow64IsProcessorFeaturePresent not supported\n" );
1172 NtClose( process );
1175 static void test_init_block(void)
1177 HMODULE ntdll = GetModuleHandleA( "ntdll.dll" );
1178 ULONG i, size = 0, *init_block;
1179 ULONG64 ptr64, *block64;
1180 void *ptr;
1182 if (!is_wow64) return;
1183 if ((ptr = GetProcAddress( ntdll, "LdrSystemDllInitBlock" )))
1185 init_block = ptr;
1186 trace( "got init block %08lx\n", init_block[0] );
1187 #define CHECK_FUNC(val,func) \
1188 ok( (val) == (ULONG_PTR)GetProcAddress( ntdll, func ), \
1189 "got %p for %s %p\n", (void *)(ULONG_PTR)(val), func, GetProcAddress( ntdll, func ))
1190 switch (init_block[0])
1192 case 0x44: /* vistau64 */
1193 CHECK_FUNC( init_block[1], "LdrInitializeThunk" );
1194 CHECK_FUNC( init_block[2], "KiUserExceptionDispatcher" );
1195 CHECK_FUNC( init_block[3], "KiUserApcDispatcher" );
1196 CHECK_FUNC( init_block[4], "KiUserCallbackDispatcher" );
1197 CHECK_FUNC( init_block[5], "LdrHotPatchRoutine" );
1198 CHECK_FUNC( init_block[6], "ExpInterlockedPopEntrySListFault" );
1199 CHECK_FUNC( init_block[7], "ExpInterlockedPopEntrySListResume" );
1200 CHECK_FUNC( init_block[8], "ExpInterlockedPopEntrySListEnd" );
1201 CHECK_FUNC( init_block[9], "RtlUserThreadStart" );
1202 CHECK_FUNC( init_block[10], "RtlpQueryProcessDebugInformationRemote" );
1203 CHECK_FUNC( init_block[11], "EtwpNotificationThread" );
1204 ok( init_block[12] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1205 (void *)(ULONG_PTR)init_block[12], ntdll );
1206 size = 13 * sizeof(*init_block);
1207 break;
1208 case 0x50: /* win7 */
1209 CHECK_FUNC( init_block[4], "LdrInitializeThunk" );
1210 CHECK_FUNC( init_block[5], "KiUserExceptionDispatcher" );
1211 CHECK_FUNC( init_block[6], "KiUserApcDispatcher" );
1212 CHECK_FUNC( init_block[7], "KiUserCallbackDispatcher" );
1213 CHECK_FUNC( init_block[8], "LdrHotPatchRoutine" );
1214 CHECK_FUNC( init_block[9], "ExpInterlockedPopEntrySListFault" );
1215 CHECK_FUNC( init_block[10], "ExpInterlockedPopEntrySListResume" );
1216 CHECK_FUNC( init_block[11], "ExpInterlockedPopEntrySListEnd" );
1217 CHECK_FUNC( init_block[12], "RtlUserThreadStart" );
1218 CHECK_FUNC( init_block[13], "RtlpQueryProcessDebugInformationRemote" );
1219 CHECK_FUNC( init_block[14], "EtwpNotificationThread" );
1220 ok( init_block[15] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1221 (void *)(ULONG_PTR)init_block[15], ntdll );
1222 CHECK_FUNC( init_block[16], "LdrSystemDllInitBlock" );
1223 size = 17 * sizeof(*init_block);
1224 break;
1225 case 0x70: /* win8 */
1226 CHECK_FUNC( init_block[4], "LdrInitializeThunk" );
1227 CHECK_FUNC( init_block[5], "KiUserExceptionDispatcher" );
1228 CHECK_FUNC( init_block[6], "KiUserApcDispatcher" );
1229 CHECK_FUNC( init_block[7], "KiUserCallbackDispatcher" );
1230 CHECK_FUNC( init_block[8], "ExpInterlockedPopEntrySListFault" );
1231 CHECK_FUNC( init_block[9], "ExpInterlockedPopEntrySListResume" );
1232 CHECK_FUNC( init_block[10], "ExpInterlockedPopEntrySListEnd" );
1233 CHECK_FUNC( init_block[11], "RtlUserThreadStart" );
1234 CHECK_FUNC( init_block[12], "RtlpQueryProcessDebugInformationRemote" );
1235 ok( init_block[13] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1236 (void *)(ULONG_PTR)init_block[13], ntdll );
1237 CHECK_FUNC( init_block[14], "LdrSystemDllInitBlock" );
1238 size = 15 * sizeof(*init_block);
1239 break;
1240 case 0x80: /* win10 1507 */
1241 CHECK_FUNC( init_block[4], "LdrInitializeThunk" );
1242 CHECK_FUNC( init_block[5], "KiUserExceptionDispatcher" );
1243 CHECK_FUNC( init_block[6], "KiUserApcDispatcher" );
1244 CHECK_FUNC( init_block[7], "KiUserCallbackDispatcher" );
1245 if (GetProcAddress( ntdll, "ExpInterlockedPopEntrySListFault" ))
1247 CHECK_FUNC( init_block[8], "ExpInterlockedPopEntrySListFault" );
1248 CHECK_FUNC( init_block[9], "ExpInterlockedPopEntrySListResume" );
1249 CHECK_FUNC( init_block[10], "ExpInterlockedPopEntrySListEnd" );
1250 CHECK_FUNC( init_block[11], "RtlUserThreadStart" );
1251 CHECK_FUNC( init_block[12], "RtlpQueryProcessDebugInformationRemote" );
1252 ok( init_block[13] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1253 (void *)(ULONG_PTR)init_block[13], ntdll );
1254 CHECK_FUNC( init_block[14], "LdrSystemDllInitBlock" );
1255 size = 15 * sizeof(*init_block);
1257 else /* win10 1607 */
1259 CHECK_FUNC( init_block[8], "RtlUserThreadStart" );
1260 CHECK_FUNC( init_block[9], "RtlpQueryProcessDebugInformationRemote" );
1261 ok( init_block[10] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1262 (void *)(ULONG_PTR)init_block[10], ntdll );
1263 CHECK_FUNC( init_block[11], "LdrSystemDllInitBlock" );
1264 size = 12 * sizeof(*init_block);
1266 break;
1267 case 0xe0: /* win10 1809 */
1268 case 0xf0: /* win10 2004 */
1269 block64 = ptr;
1270 CHECK_FUNC( block64[3], "LdrInitializeThunk" );
1271 CHECK_FUNC( block64[4], "KiUserExceptionDispatcher" );
1272 CHECK_FUNC( block64[5], "KiUserApcDispatcher" );
1273 CHECK_FUNC( block64[6], "KiUserCallbackDispatcher" );
1274 CHECK_FUNC( block64[7], "RtlUserThreadStart" );
1275 CHECK_FUNC( block64[8], "RtlpQueryProcessDebugInformationRemote" );
1276 todo_wine_if( old_wow64 )
1277 ok( block64[9] == (ULONG_PTR)ntdll, "got %p for ntdll %p\n",
1278 (void *)(ULONG_PTR)block64[9], ntdll );
1279 CHECK_FUNC( block64[10], "LdrSystemDllInitBlock" );
1280 CHECK_FUNC( block64[11], "RtlpFreezeTimeBias" );
1281 size = 12 * sizeof(*block64);
1282 break;
1283 default:
1284 ok( 0, "unknown init block %08lx\n", init_block[0] );
1285 for (i = 0; i < 32; i++) trace("%04lx: %08lx\n", i, init_block[i]);
1286 break;
1288 #undef CHECK_FUNC
1290 if (size && (ptr64 = get_proc_address64( ntdll_module, "LdrSystemDllInitBlock" )))
1292 DWORD buffer[64];
1293 HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
1294 NTSTATUS status = pNtWow64ReadVirtualMemory64( process, ptr64, buffer, size, NULL );
1295 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
1296 ok( !memcmp( buffer, init_block, size ), "wrong 64-bit init block\n" );
1297 NtClose( process );
1300 else todo_wine win_skip( "LdrSystemDllInitBlock not supported\n" );
1304 static void test_iosb(void)
1306 static const char pipe_name[] = "\\\\.\\pipe\\wow64iosbnamedpipe";
1307 HANDLE client, server;
1308 NTSTATUS status;
1309 ULONG64 func;
1310 DWORD id;
1311 IO_STATUS_BLOCK iosb32;
1312 struct
1314 union
1316 NTSTATUS Status;
1317 ULONG64 Pointer;
1319 ULONG64 Information;
1320 } iosb64;
1321 ULONG64 args[] = { 0, 0, 0, 0, (ULONG_PTR)&iosb64, FSCTL_PIPE_LISTEN, 0, 0, 0, 0 };
1323 if (!is_wow64) return;
1324 if (!code_mem) return;
1325 if (!ntdll_module) return;
1326 func = get_proc_address64( ntdll_module, "NtFsControlFile" );
1328 /* async calls set iosb32 but not iosb64 */
1330 server = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
1331 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1332 4, 1024, 1024, 1000, NULL );
1333 ok( server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError() );
1335 memset( &iosb32, 0x55, sizeof(iosb32) );
1336 iosb64.Pointer = PtrToUlong( &iosb32 );
1337 iosb64.Information = 0xdeadbeef;
1339 args[0] = (LONG_PTR)server;
1340 status = call_func64( func, ARRAY_SIZE(args), args );
1341 ok( status == STATUS_PENDING, "NtFsControlFile returned %lx\n", status );
1342 ok( U(iosb32).Status == 0x55555555, "status changed to %lx\n", U(iosb32).Status );
1343 ok( U(iosb64).Pointer == PtrToUlong(&iosb32), "status changed to %lx\n", U(iosb64).Status );
1344 ok( iosb64.Information == 0xdeadbeef, "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
1346 client = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
1347 FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
1348 ok( client != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError() );
1350 ok( U(iosb32).Status == 0, "Wrong iostatus %lx\n", U(iosb32).Status );
1351 ok( U(iosb64).Pointer == PtrToUlong(&iosb32), "status changed to %lx\n", U(iosb64).Status );
1352 ok( iosb64.Information == 0xdeadbeef, "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
1354 memset( &iosb32, 0x55, sizeof(iosb32) );
1355 iosb64.Pointer = PtrToUlong( &iosb32 );
1356 iosb64.Information = 0xdeadbeef;
1357 id = 0xdeadbeef;
1359 args[5] = FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE;
1360 args[6] = (ULONG_PTR)"ClientProcessId";
1361 args[7] = sizeof("ClientProcessId");
1362 args[8] = (ULONG_PTR)&id;
1363 args[9] = sizeof(id);
1365 status = call_func64( func, ARRAY_SIZE(args), args );
1366 ok( status == STATUS_PENDING || status == STATUS_SUCCESS, "NtFsControlFile returned %lx\n", status );
1367 todo_wine
1369 ok( U(iosb32).Status == STATUS_SUCCESS, "status changed to %lx\n", U(iosb32).Status );
1370 ok( iosb32.Information == sizeof(id), "info changed to %Ix\n", iosb32.Information );
1371 ok( U(iosb64).Pointer == PtrToUlong(&iosb32), "status changed to %lx\n", U(iosb64).Status );
1372 ok( iosb64.Information == 0xdeadbeef, "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
1374 ok( id == GetCurrentProcessId(), "wrong id %lx / %lx\n", id, GetCurrentProcessId() );
1375 CloseHandle( client );
1376 CloseHandle( server );
1378 /* synchronous calls set iosb64 but not iosb32 */
1380 server = CreateNamedPipeA( pipe_name, PIPE_ACCESS_INBOUND,
1381 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1382 4, 1024, 1024, 1000, NULL );
1383 ok( server != INVALID_HANDLE_VALUE, "CreateNamedPipe failed: %lu\n", GetLastError() );
1385 client = CreateFileA( pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
1386 FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL );
1387 ok( client != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError() );
1389 memset( &iosb32, 0x55, sizeof(iosb32) );
1390 iosb64.Pointer = PtrToUlong( &iosb32 );
1391 iosb64.Information = 0xdeadbeef;
1392 id = 0xdeadbeef;
1394 args[0] = (LONG_PTR)server;
1395 status = call_func64( func, ARRAY_SIZE(args), args );
1396 ok( status == STATUS_SUCCESS, "NtFsControlFile returned %lx\n", status );
1397 ok( U(iosb32).Status == 0x55555555, "status changed to %lx\n", U(iosb32).Status );
1398 ok( iosb32.Information == 0x55555555, "info changed to %Ix\n", iosb32.Information );
1399 ok( U(iosb64).Pointer == STATUS_SUCCESS, "status changed to %lx\n", U(iosb64).Status );
1400 ok( iosb64.Information == sizeof(id), "info changed to %Ix\n", (ULONG_PTR)iosb64.Information );
1401 ok( id == GetCurrentProcessId(), "wrong id %lx / %lx\n", id, GetCurrentProcessId() );
1402 CloseHandle( client );
1403 CloseHandle( server );
1406 static NTSTATUS invoke_syscall( const char *name, ULONG args32[] )
1408 ULONG64 args64[] = { -1, PtrToUlong( args32 ) };
1409 ULONG64 func = get_proc_address64( wow64_module, "Wow64SystemServiceEx" );
1410 BYTE *syscall = (BYTE *)GetProcAddress( GetModuleHandleA("ntdll.dll"), name );
1412 ok( syscall != NULL, "syscall %s not found\n", name );
1413 if (syscall[0] == 0xb8)
1414 args64[0] = *(DWORD *)(syscall + 1);
1415 else
1416 win_skip( "syscall thunk %s not recognized\n", name );
1418 return call_func64( func, ARRAY_SIZE(args64), args64 );
1421 static void test_syscalls(void)
1423 ULONG64 func;
1424 ULONG args32[8];
1425 HANDLE event, event2;
1426 OBJECT_ATTRIBUTES attr;
1427 UNICODE_STRING name;
1428 NTSTATUS status;
1430 if (!is_wow64) return;
1431 if (!code_mem) return;
1432 if (!ntdll_module) return;
1434 func = get_proc_address64( wow64_module, "Wow64SystemServiceEx" );
1435 ok( func, "Wow64SystemServiceEx not found\n" );
1437 event = CreateEventA( NULL, FALSE, FALSE, NULL );
1439 status = NtSetEvent( event, NULL );
1440 ok( !status, "NtSetEvent failed %lx\n", status );
1441 args32[0] = HandleToLong( event );
1442 status = invoke_syscall( "NtClose", args32 );
1443 ok( !status, "syscall failed %lx\n", status );
1444 status = NtSetEvent( event, NULL );
1445 ok( status == STATUS_INVALID_HANDLE, "NtSetEvent failed %lx\n", status );
1446 status = invoke_syscall( "NtClose", args32 );
1447 ok( status == STATUS_INVALID_HANDLE, "syscall failed %lx\n", status );
1448 args32[0] = 0xdeadbeef;
1449 status = invoke_syscall( "NtClose", args32 );
1450 ok( status == STATUS_INVALID_HANDLE, "syscall failed %lx\n", status );
1452 RtlInitUnicodeString( &name, L"\\BaseNamedObjects\\wow64-test");
1453 InitializeObjectAttributes( &attr, &name, OBJ_OPENIF, 0, NULL );
1454 event = (HANDLE)0xdeadbeef;
1455 args32[0] = PtrToUlong(&event );
1456 args32[1] = EVENT_ALL_ACCESS;
1457 args32[2] = PtrToUlong( &attr );
1458 args32[3] = NotificationEvent;
1459 args32[4] = 0;
1460 status = invoke_syscall( "NtCreateEvent", args32 );
1461 ok( !status, "syscall failed %lx\n", status );
1462 status = NtSetEvent( event, NULL );
1463 ok( !status, "NtSetEvent failed %lx\n", status );
1465 event2 = (HANDLE)0xdeadbeef;
1466 args32[0] = PtrToUlong( &event2 );
1467 status = invoke_syscall( "NtOpenEvent", args32 );
1468 ok( !status, "syscall failed %lx\n", status );
1469 status = NtSetEvent( event2, NULL );
1470 ok( !status, "NtSetEvent failed %lx\n", status );
1471 args32[0] = HandleToLong( event2 );
1472 status = invoke_syscall( "NtClose", args32 );
1473 ok( !status, "syscall failed %lx\n", status );
1475 event2 = (HANDLE)0xdeadbeef;
1476 args32[0] = PtrToUlong( &event2 );
1477 status = invoke_syscall( "NtCreateEvent", args32 );
1478 ok( status == STATUS_OBJECT_NAME_EXISTS, "syscall failed %lx\n", status );
1479 status = NtSetEvent( event2, NULL );
1480 ok( !status, "NtSetEvent failed %lx\n", status );
1481 args32[0] = HandleToLong( event2 );
1482 status = invoke_syscall( "NtClose", args32 );
1483 ok( !status, "syscall failed %lx\n", status );
1485 status = NtClose( event );
1486 ok( !status, "NtClose failed %lx\n", status );
1488 if (pNtWow64ReadVirtualMemory64)
1490 TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
1491 PEB64 peb64, peb64_2;
1492 ULONG64 res, res2;
1493 HANDLE process = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
1494 ULONG args32[] = { HandleToLong( process ), (ULONG)teb64->Peb, teb64->Peb >> 32,
1495 PtrToUlong(&peb64_2), sizeof(peb64_2), 0, PtrToUlong(&res2) };
1497 ok( process != 0, "failed to open current process %lu\n", GetLastError() );
1498 status = pNtWow64ReadVirtualMemory64( process, teb64->Peb, &peb64, sizeof(peb64), &res );
1499 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
1500 status = invoke_syscall( "NtWow64ReadVirtualMemory64", args32 );
1501 ok( !status, "NtWow64ReadVirtualMemory64 failed %lx\n", status );
1502 ok( res2 == res, "wrong len %s / %s\n", wine_dbgstr_longlong(res), wine_dbgstr_longlong(res2) );
1503 ok( !memcmp( &peb64, &peb64_2, res ), "data is different\n" );
1504 NtClose( process );
1508 static void test_cpu_area(void)
1510 TEB64 *teb64 = (TEB64 *)NtCurrentTeb()->GdiBatchCount;
1511 ULONG64 ptr;
1512 NTSTATUS status;
1514 if (!is_wow64) return;
1515 if (!code_mem) return;
1516 if (!ntdll_module) return;
1518 if ((ptr = get_proc_address64( ntdll_module, "RtlWow64GetCurrentCpuArea" )))
1520 USHORT machine = 0xdead;
1521 ULONG64 context, context_ex;
1522 ULONG64 args[] = { (ULONG_PTR)&machine, (ULONG_PTR)&context, (ULONG_PTR)&context_ex };
1524 status = call_func64( ptr, ARRAY_SIZE(args), args );
1525 ok( !status, "RtlWow64GetCpuAreaInfo failed %lx\n", status );
1526 ok( machine == IMAGE_FILE_MACHINE_I386, "wrong machine %x\n", machine );
1527 ok( context == teb64->TlsSlots[WOW64_TLS_CPURESERVED] + 4, "wrong context %s / %s\n",
1528 wine_dbgstr_longlong(context), wine_dbgstr_longlong(teb64->TlsSlots[WOW64_TLS_CPURESERVED]) );
1529 ok( !context_ex, "got context_ex %s\n", wine_dbgstr_longlong(context_ex) );
1530 args[0] = args[1] = args[2] = 0;
1531 status = call_func64( ptr, ARRAY_SIZE(args), args );
1532 ok( !status, "RtlWow64GetCpuAreaInfo failed %lx\n", status );
1534 else win_skip( "RtlWow64GetCpuAreaInfo not supported\n" );
1538 #endif /* _WIN64 */
1541 START_TEST(wow64)
1543 init();
1544 test_query_architectures();
1545 test_peb_teb();
1546 test_selectors();
1547 test_image_mappings();
1548 #ifndef _WIN64
1549 test_nt_wow64();
1550 test_modules();
1551 test_init_block();
1552 test_iosb();
1553 test_syscalls();
1554 #endif
1555 test_cpu_area();