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"
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
);
35 static NTSTATUS (WINAPI
*pRtlWow64GetCpuAreaInfo
)(WOW64_CPURESERVED
*,ULONG
,WOW64_CPU_AREA_INFO
*);
36 static NTSTATUS (WINAPI
*pRtlWow64GetThreadSelectorEntry
)(HANDLE
,THREAD_DESCRIPTOR_INFORMATION
*,ULONG
,ULONG
*);
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
*);
46 static BOOL old_wow64
; /* Wine old-style wow64 */
47 static void *code_mem
;
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
;
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
;
62 static USHORT current_machine
;
63 static USHORT native_machine
;
66 static void init(void)
68 HMODULE ntdll
= GetModuleHandleA( "ntdll.dll" );
70 if (!IsWow64Process( GetCurrentProcess(), &is_wow64
)) is_wow64
= FALSE
;
74 TEB64
*teb64
= ULongToPtr( NtCurrentTeb()->GdiBatchCount
);
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
);
93 GET_PROC( RtlWow64GetCpuAreaInfo
);
94 GET_PROC( RtlWow64GetThreadSelectorEntry
);
96 GET_PROC( NtWow64AllocateVirtualMemory64
);
97 GET_PROC( NtWow64GetNativeSystemInformation
);
98 GET_PROC( NtWow64IsProcessorFeaturePresent
);
99 GET_PROC( NtWow64ReadVirtualMemory64
);
100 GET_PROC( NtWow64WriteVirtualMemory64
);
104 if (pRtlGetNativeSystemInformation
)
106 SYSTEM_CPU_INFORMATION info
;
109 pRtlGetNativeSystemInformation( SystemCpuInformation
, &info
, sizeof(info
), &len
);
110 switch (info
.ProcessorArchitecture
)
112 case PROCESSOR_ARCHITECTURE_ARM64
:
113 native_machine
= IMAGE_FILE_MACHINE_ARM64
;
115 case PROCESSOR_ARCHITECTURE_AMD64
:
116 native_machine
= IMAGE_FILE_MACHINE_AMD64
;
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
)
128 ULONG i
, len
, buffer
[8];
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
]);
142 ok( machine
== expect_machine
, "wrong current machine %lx\n", buffer
[i
]);
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
150 ok( machine
== expect_native
, "wrong native machine %lx\n", buffer
[i
]);
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
, ¤t
, &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
);
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
) };
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" );
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
)
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
);
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
);
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
);
254 status
= pRtlWow64IsWowGuestMachineSupported( IMAGE_FILE_MACHINE_ARM64
, &ret
);
255 ok( !status
, "failed %lx\n", status
);
256 ok( !ret
, "wrong result %u\n", ret
);
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};
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
);
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
);
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
);
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
, ¶ms
, 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
);
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
), ¶ms32
, 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
);
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
);
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
);
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
);
405 ok( !proc_info
.PebBaseAddress
||
406 broken( (char *)proc_info
.PebBaseAddress
>= (char *)0x7f000000 ), /* vista */
407 "wrong peb %p\n", proc_info
.PebBaseAddress
);
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
);
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
);
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
;
466 ULONG base
, limit
, sel
, retlen
;
467 I386_CONTEXT context
= { CONTEXT_I386_CONTROL
| CONTEXT_I386_SEGMENTS
};
470 if (!pRtlWow64GetThreadSelectorEntry
)
472 win_skip( "RtlWow64GetThreadSelectorEntry not supported\n" );
475 if (!pRtlWow64GetThreadContext
|| pRtlWow64GetThreadContext( GetCurrentThread(), &context
))
477 /* hardcoded values */
479 context
.SegCs
= 0x23;
480 __asm__( "movw %%fs,%0" : "=m" (context
.SegFs
) );
481 __asm__( "movw %%ss,%0" : "=m" (context
.SegSs
) );
483 context
.SegCs
= 0x1b;
484 context
.SegSs
= 0x23;
485 context
.SegFs
= 0x3b;
488 #define GET_ENTRY(info,size,ret) \
489 pRtlWow64GetThreadSelectorEntry( GetCurrentThread(), info, size, ret )
492 GetThreadContext( GetCurrentThread(), &context
);
493 #define GET_ENTRY(info,size,ret) \
494 NtQueryInformationThread( GetCurrentThread(), ThreadDescriptorTableEntry, info, size, ret )
497 trace( "cs %04lx ss %04lx fs %04lx\n", context
.SegCs
, context
.SegSs
, context
.SegFs
);
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
);
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
);
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
++)
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
);
567 if (NtCurrentTeb()->WowTebOffset
== 0x2000)
568 ok( base
== (ULONG_PTR
)NtCurrentTeb() + 0x2000, "wrong base %lx / %p\n",
569 base
, NtCurrentTeb() );
571 ok( base
== (ULONG_PTR
)NtCurrentTeb(), "wrong base %lx / %p\n", base
, NtCurrentTeb() );
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" );
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
);
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
);
600 static void test_image_mappings(void)
602 MEM_EXTENDED_PARAMETER ext
= { .Type
= MemExtendedParameterImageMachine
};
603 HANDLE file
, mapping
, process
= GetCurrentProcess();
606 LARGE_INTEGER offset
;
609 if (!pNtMapViewOfSectionEx
)
611 win_skip( "NtMapViewOfSectionEx() not supported\n" );
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" );
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" );
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
);
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
);
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
);
670 case IMAGE_FILE_MACHINE_AMD64
:
671 ok( status
== STATUS_IMAGE_MACHINE_TYPE_MISMATCH
, "NtMapViewOfSection returned %08lx\n", status
);
672 NtUnmapViewOfSection( process
, ptr
);
675 ok( status
== STATUS_NOT_SUPPORTED
, "NtMapViewOfSection returned %08lx\n", status
);
679 else ok( status
== STATUS_NOT_SUPPORTED
, "NtMapViewOfSection returned %08lx\n", status
);
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
);
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
);
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" );
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
);
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
);
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" );
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
);
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
);
748 static void test_cpu_area(void)
750 if (pRtlWow64GetCpuAreaInfo
)
756 ULONG_PTR align
, size
, offset
, flag
;
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
},
767 WOW64_CPURESERVED
*cpu
;
768 WOW64_CPU_AREA_INFO info
;
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
);
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
);
797 else win_skip( "RtlWow64GetCpuAreaInfo not supported\n" );
802 static const BYTE call_func64_code
[] =
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) */
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 */
836 0x4c, 0x87, 0xf4, /* xchg %r14,%rsp */
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
*) )
855 LIST_ENTRY64 InLoadOrderLinks
;
856 LIST_ENTRY64 InMemoryOrderLinks
;
857 LIST_ENTRY64 InInitializationOrderLinks
;
861 UNICODE_STRING64 FullDllName
;
862 UNICODE_STRING64 BaseDllName
;
864 } LDR_DATA_TABLE_ENTRY64
;
866 TEB64
*teb64
= (TEB64
*)NtCurrentTeb()->GdiBatchCount
;
870 LDR_DATA_TABLE_ENTRY64 entry
;
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
;
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
);
892 func( entry
.DllBase
, buffer
);
893 ptr
= entry
.InLoadOrderLinks
.Flink
;
894 if (ptr
== peb64
.LdrData
+ offsetof( PEB_LDR_DATA64
, InLoadOrderModuleList
)) break;
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
;
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
]];
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
++;
956 ok( !wcsicmp( name
, p
), "wrong name %s / %s\n", debugstr_w(name
), debugstr_w(module
));
960 #define CHECK_MODULE(mod) do { if (!wcsicmp( name, L"" #mod ".dll" )) { mod ## _module = base; return; } } while(0)
963 CHECK_MODULE(wow64base
);
964 CHECK_MODULE(wow64con
);
965 CHECK_MODULE(wow64win
);
966 if (native_machine
== IMAGE_FILE_MACHINE_ARM64
)
967 CHECK_MODULE(xtajit
);
969 CHECK_MODULE(wow64cpu
);
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" );
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";
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
)
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
) );
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
);
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
);
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
) );
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
);
1068 ok( status
== STATUS_PARTIAL_COPY
|| broken( status
== STATUS_ACCESS_VIOLATION
),
1069 "NtWow64WriteVirtualMemory64 failed %lx\n", status
);
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
) );
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
)
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
);
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
);
1133 case SystemBasicInformation
:
1134 case SystemCpuInformation
:
1135 case SystemEmulationBasicInformation
:
1136 case SystemEmulationProcessorInformation
:
1137 ok( status
== expect
, "%lu: %lx / %lx\n", i
, status
, expect
);
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
);
1145 ok( status
== expect
, "%lu: %lx / %lx\n", i
, status
, expect
);
1150 else win_skip( "NtWow64GetNativeSystemInformation not supported\n" );
1152 if (pNtWow64IsProcessorFeaturePresent
)
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" );
1175 static void test_init_block(void)
1177 HMODULE ntdll
= GetModuleHandleA( "ntdll.dll" );
1178 ULONG i
, size
= 0, *init_block
;
1179 ULONG64 ptr64
, *block64
;
1182 if (!is_wow64
) return;
1183 if ((ptr
= GetProcAddress( ntdll
, "LdrSystemDllInitBlock" )))
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
);
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
);
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
);
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
);
1267 case 0xe0: /* win10 1809 */
1268 case 0xf0: /* win10 2004 */
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
);
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
]);
1290 if (size
&& (ptr64
= get_proc_address64( ntdll_module
, "LdrSystemDllInitBlock" )))
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" );
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
;
1311 IO_STATUS_BLOCK iosb32
;
1319 ULONG64 Information
;
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;
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
);
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;
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);
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)
1425 HANDLE event
, event2
;
1426 OBJECT_ATTRIBUTES attr
;
1427 UNICODE_STRING name
;
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
;
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
;
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" );
1508 static void test_cpu_area(void)
1510 TEB64
*teb64
= (TEB64
*)NtCurrentTeb()->GdiBatchCount
;
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" );
1544 test_query_architectures();
1547 test_image_mappings();