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