comctl32/tests: Use CRT allocation functions.
[wine.git] / dlls / wow64 / syscall.c
blob764f5fb2c05739d3deb48c5d9376ea0fda6829fe
1 /*
2 * WoW64 syscall wrapping
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
21 #include <stdarg.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnt.h"
28 #include "winternl.h"
29 #include "wine/exception.h"
30 #include "wine/unixlib.h"
31 #include "wine/asm.h"
32 #include "wow64_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wow);
37 USHORT native_machine = 0;
38 USHORT current_machine = 0;
39 ULONG_PTR args_alignment = 0;
40 ULONG_PTR highest_user_address = 0x7ffeffff;
41 ULONG_PTR default_zero_bits = 0x7fffffff;
43 typedef NTSTATUS (WINAPI *syscall_thunk)( UINT *args );
45 static const syscall_thunk syscall_thunks[] =
47 #define SYSCALL_ENTRY(id,name,args) wow64_ ## name,
48 ALL_SYSCALLS32
49 #undef SYSCALL_ENTRY
52 static BYTE syscall_args[ARRAY_SIZE(syscall_thunks)] =
54 #define SYSCALL_ENTRY(id,name,args) args,
55 ALL_SYSCALLS32
56 #undef SYSCALL_ENTRY
59 static SYSTEM_SERVICE_TABLE syscall_tables[4] =
61 { (ULONG_PTR *)syscall_thunks, NULL, ARRAY_SIZE(syscall_thunks), syscall_args }
64 /* header for Wow64AllocTemp blocks; probably not the right layout */
65 struct mem_header
67 struct mem_header *next;
68 void *__pad;
69 BYTE data[1];
72 /* stack frame for user callbacks */
73 struct user_callback_frame
75 struct user_callback_frame *prev_frame;
76 struct mem_header *temp_list;
77 void **ret_ptr;
78 ULONG *ret_len;
79 NTSTATUS status;
80 __wine_jmp_buf jmpbuf;
83 /* stack frame for user APCs */
84 struct user_apc_frame
86 struct user_apc_frame *prev_frame;
87 CONTEXT *context;
88 void *wow_context;
91 SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock = NULL;
93 static WOW64INFO *wow64info;
95 /* cpu backend dll functions */
96 /* the function prototypes most likely differ from Windows */
97 static void * (WINAPI *pBTCpuGetBopCode)(void);
98 static NTSTATUS (WINAPI *pBTCpuGetContext)(HANDLE,HANDLE,void *,void *);
99 static BOOLEAN (WINAPI *pBTCpuIsProcessorFeaturePresent)(UINT);
100 static void (WINAPI *pBTCpuProcessInit)(void);
101 static NTSTATUS (WINAPI *pBTCpuSetContext)(HANDLE,HANDLE,void *,void *);
102 static void (WINAPI *pBTCpuThreadInit)(void);
103 static void (WINAPI *pBTCpuSimulate)(void);
104 static NTSTATUS (WINAPI *pBTCpuResetToConsistentState)( EXCEPTION_POINTERS * );
105 static void * (WINAPI *p__wine_get_unix_opcode)(void);
106 static void * (WINAPI *pKiRaiseUserExceptionDispatcher)(void);
107 void (WINAPI *pBTCpuNotifyFlushInstructionCache2)( const void *, SIZE_T ) = NULL;
108 void (WINAPI *pBTCpuNotifyMapViewOfSection)( void * ) = NULL;
109 void (WINAPI *pBTCpuNotifyMemoryAlloc)( void *, SIZE_T, ULONG, ULONG ) = NULL;
110 void (WINAPI *pBTCpuNotifyMemoryDirty)( void *, SIZE_T ) = NULL;
111 void (WINAPI *pBTCpuNotifyMemoryFree)( void *, SIZE_T, ULONG ) = NULL;
112 void (WINAPI *pBTCpuNotifyMemoryProtect)( void *, SIZE_T, ULONG ) = NULL;
113 void (WINAPI *pBTCpuNotifyUnmapViewOfSection)( void * ) = NULL;
114 void (WINAPI *pBTCpuUpdateProcessorInformation)( SYSTEM_CPU_INFORMATION * ) = NULL;
115 void (WINAPI *pBTCpuThreadTerm)( HANDLE ) = NULL;
117 void *dummy = RtlUnwind;
119 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved )
121 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
122 return TRUE;
125 void __cdecl __wine_spec_unimplemented_stub( const char *module, const char *function )
127 EXCEPTION_RECORD record;
129 record.ExceptionCode = EXCEPTION_WINE_STUB;
130 record.ExceptionFlags = EH_NONCONTINUABLE;
131 record.ExceptionRecord = NULL;
132 record.ExceptionAddress = __wine_spec_unimplemented_stub;
133 record.NumberParameters = 2;
134 record.ExceptionInformation[0] = (ULONG_PTR)module;
135 record.ExceptionInformation[1] = (ULONG_PTR)function;
136 for (;;) RtlRaiseException( &record );
140 static EXCEPTION_RECORD *exception_record_32to64( const EXCEPTION_RECORD32 *rec32 )
142 EXCEPTION_RECORD *rec;
143 unsigned int i;
145 rec = Wow64AllocateTemp( sizeof(*rec) );
146 rec->ExceptionCode = rec32->ExceptionCode;
147 rec->ExceptionFlags = rec32->ExceptionFlags;
148 rec->ExceptionRecord = rec32->ExceptionRecord ? exception_record_32to64( ULongToPtr(rec32->ExceptionRecord) ) : NULL;
149 rec->ExceptionAddress = ULongToPtr( rec32->ExceptionAddress );
150 rec->NumberParameters = rec32->NumberParameters;
151 for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
152 rec->ExceptionInformation[i] = rec32->ExceptionInformation[i];
153 return rec;
157 static void exception_record_64to32( EXCEPTION_RECORD32 *rec32, const EXCEPTION_RECORD *rec )
159 unsigned int i;
161 rec32->ExceptionCode = rec->ExceptionCode;
162 rec32->ExceptionFlags = rec->ExceptionFlags;
163 rec32->ExceptionRecord = PtrToUlong( rec->ExceptionRecord );
164 rec32->ExceptionAddress = PtrToUlong( rec->ExceptionAddress );
165 rec32->NumberParameters = rec->NumberParameters;
166 for (i = 0; i < rec->NumberParameters; i++)
167 rec32->ExceptionInformation[i] = rec->ExceptionInformation[i];
171 static NTSTATUS get_context_return_value( void *wow_context )
173 switch (current_machine)
175 case IMAGE_FILE_MACHINE_I386:
176 return ((I386_CONTEXT *)wow_context)->Eax;
177 case IMAGE_FILE_MACHINE_ARMNT:
178 return ((ARM_CONTEXT *)wow_context)->R0;
180 return 0;
184 /**********************************************************************
185 * call_user_exception_dispatcher
187 static void call_user_exception_dispatcher( EXCEPTION_RECORD32 *rec, void *ctx32_ptr, void *ctx64_ptr )
189 switch (current_machine)
191 case IMAGE_FILE_MACHINE_I386:
193 struct stack_layout
195 ULONG rec_ptr; /* first arg for KiUserExceptionDispatcher */
196 ULONG context_ptr; /* second arg for KiUserExceptionDispatcher */
197 EXCEPTION_RECORD32 rec;
198 I386_CONTEXT context;
199 } *stack;
200 I386_CONTEXT *context, ctx = { CONTEXT_I386_ALL };
201 CONTEXT_EX *context_ex, *src_ex = NULL;
202 ULONG size, flags;
204 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
206 if (ctx32_ptr)
208 I386_CONTEXT *ctx32 = ctx32_ptr;
210 if ((ctx32->ContextFlags & CONTEXT_I386_XSTATE) == CONTEXT_I386_XSTATE)
211 src_ex = (CONTEXT_EX *)(ctx32 + 1);
213 else if (native_machine == IMAGE_FILE_MACHINE_AMD64)
215 AMD64_CONTEXT *ctx64 = ctx64_ptr;
217 if ((ctx64->ContextFlags & CONTEXT_AMD64_FLOATING_POINT) == CONTEXT_AMD64_FLOATING_POINT)
218 memcpy( ctx.ExtendedRegisters, &ctx64->FltSave, sizeof(ctx.ExtendedRegisters) );
219 if ((ctx64->ContextFlags & CONTEXT_AMD64_XSTATE) == CONTEXT_AMD64_XSTATE)
220 src_ex = (CONTEXT_EX *)(ctx64 + 1);
223 flags = ctx.ContextFlags;
224 if (src_ex) flags |= CONTEXT_I386_XSTATE;
225 RtlGetExtendedContextLength( flags, &size );
226 size = ((size + 15) & ~15) + offsetof(struct stack_layout,context);
228 stack = (struct stack_layout *)(ULONG_PTR)(ctx.Esp - size);
229 stack->rec_ptr = PtrToUlong( &stack->rec );
230 stack->rec = *rec;
231 RtlInitializeExtendedContext( &stack->context, flags, &context_ex );
232 context = RtlLocateLegacyContext( context_ex, NULL );
233 *context = ctx;
234 context->ContextFlags = flags;
235 /* adjust Eip for breakpoints in software emulation (hardware exceptions already adjust Rip) */
236 if (rec->ExceptionCode == EXCEPTION_BREAKPOINT && (wow64info->CpuFlags & WOW64_CPUFLAGS_SOFTWARE))
237 context->Eip--;
238 stack->context_ptr = PtrToUlong( context );
240 if (src_ex)
242 XSTATE *src_xs = (XSTATE *)((char *)src_ex + src_ex->XState.Offset);
243 XSTATE *dst_xs = (XSTATE *)((char *)context_ex + context_ex->XState.Offset);
245 dst_xs->Mask = src_xs->Mask & ~(ULONG64)3;
246 dst_xs->CompactionMask = src_xs->CompactionMask;
247 if ((dst_xs->Mask & 4) &&
248 src_ex->XState.Length >= sizeof(XSTATE) &&
249 context_ex->XState.Length >= sizeof(XSTATE))
250 memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
253 ctx.Esp = PtrToUlong( stack );
254 ctx.Eip = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
255 ctx.EFlags &= ~(0x100|0x400|0x40000);
256 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
258 TRACE( "exception %08lx dispatcher %08lx stack %08lx eip %08lx\n",
259 rec->ExceptionCode, ctx.Eip, ctx.Esp, stack->context.Eip );
261 break;
263 case IMAGE_FILE_MACHINE_ARMNT:
265 struct stack_layout
267 ARM_CONTEXT context;
268 EXCEPTION_RECORD32 rec;
269 } *stack;
270 ARM_CONTEXT ctx = { CONTEXT_ARM_ALL };
272 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
273 stack = (struct stack_layout *)(ULONG_PTR)(ctx.Sp & ~3) - 1;
274 stack->rec = *rec;
275 stack->context = ctx;
277 ctx.R0 = PtrToUlong( &stack->rec ); /* first arg for KiUserExceptionDispatcher */
278 ctx.R1 = PtrToUlong( &stack->context ); /* second arg for KiUserExceptionDispatcher */
279 ctx.Sp = PtrToUlong( stack );
280 ctx.Pc = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
281 if (ctx.Pc & 1) ctx.Cpsr |= 0x20;
282 else ctx.Cpsr &= ~0x20;
283 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
285 TRACE( "exception %08lx dispatcher %08lx stack %08lx pc %08lx\n",
286 rec->ExceptionCode, ctx.Pc, ctx.Sp, stack->context.Sp );
288 break;
293 /**********************************************************************
294 * call_raise_user_exception_dispatcher
296 static void call_raise_user_exception_dispatcher( ULONG code )
298 TEB32 *teb32 = (TEB32 *)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset);
300 teb32->ExceptionCode = code;
302 switch (current_machine)
304 case IMAGE_FILE_MACHINE_I386:
306 I386_CONTEXT ctx = { CONTEXT_I386_ALL };
308 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
309 ctx.Esp -= sizeof(ULONG);
310 *(ULONG *)ULongToPtr( ctx.Esp ) = ctx.Eip;
311 ctx.Eip = (ULONG_PTR)pKiRaiseUserExceptionDispatcher;
312 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
314 break;
316 case IMAGE_FILE_MACHINE_ARMNT:
318 ARM_CONTEXT ctx = { CONTEXT_ARM_ALL };
320 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
321 ctx.Pc = (ULONG_PTR)pKiRaiseUserExceptionDispatcher;
322 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
324 break;
329 /* based on RtlRaiseException: call NtRaiseException with context setup to return to caller */
330 void WINAPI raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance );
331 #ifdef __x86_64__
332 __ASM_GLOBAL_FUNC( raise_exception,
333 "sub $0x28,%rsp\n\t"
334 __ASM_SEH(".seh_stackalloc 0x28\n\t")
335 __ASM_SEH(".seh_endprologue\n\t")
336 __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
337 "movq %rcx,(%rsp)\n\t"
338 "movq %rdx,%rcx\n\t"
339 "call " __ASM_NAME("RtlCaptureContext") "\n\t"
340 "leaq 0x30(%rsp),%rax\n\t" /* orig stack pointer */
341 "movq %rax,0x98(%rdx)\n\t" /* context->Rsp */
342 "movq (%rsp),%rcx\n\t" /* original first parameter */
343 "movq 0x28(%rsp),%rax\n\t" /* return address */
344 "movq %rax,0xf8(%rdx)\n\t" /* context->Rip */
345 "call " __ASM_NAME("NtRaiseException") )
346 #elif defined(__aarch64__)
347 __ASM_GLOBAL_FUNC( raise_exception,
348 "stp x29, x30, [sp, #-32]!\n\t"
349 __ASM_SEH(".seh_save_fplr_x 32\n\t")
350 __ASM_SEH(".seh_endprologue\n\t")
351 __ASM_CFI(".cfi_def_cfa x29, 32\n\t")
352 __ASM_CFI(".cfi_offset x30, -24\n\t")
353 __ASM_CFI(".cfi_offset x29, -32\n\t")
354 "mov x29, sp\n\t"
355 "stp x0, x1, [sp, #16]\n\t"
356 "mov x0, x1\n\t"
357 "bl " __ASM_NAME("RtlCaptureContext") "\n\t"
358 "ldp x0, x1, [sp, #16]\n\t" /* orig parameters */
359 "ldp x4, x5, [sp]\n\t" /* frame pointer, return address */
360 "stp x4, x5, [x1, #0xf0]\n\t" /* context->Fp, Lr */
361 "add x4, sp, #32\n\t" /* orig stack pointer */
362 "stp x4, x5, [x1, #0x100]\n\t" /* context->Sp, Pc */
363 "bl " __ASM_NAME("NtRaiseException") )
364 #endif
367 /**********************************************************************
368 * wow64_NtAddAtom
370 NTSTATUS WINAPI wow64_NtAddAtom( UINT *args )
372 const WCHAR *name = get_ptr( &args );
373 ULONG len = get_ulong( &args );
374 RTL_ATOM *atom = get_ptr( &args );
376 return NtAddAtom( name, len, atom );
380 /**********************************************************************
381 * wow64_NtAllocateLocallyUniqueId
383 NTSTATUS WINAPI wow64_NtAllocateLocallyUniqueId( UINT *args )
385 LUID *luid = get_ptr( &args );
387 return NtAllocateLocallyUniqueId( luid );
391 /**********************************************************************
392 * wow64_NtAllocateUuids
394 NTSTATUS WINAPI wow64_NtAllocateUuids( UINT *args )
396 ULARGE_INTEGER *time = get_ptr( &args );
397 ULONG *delta = get_ptr( &args );
398 ULONG *sequence = get_ptr( &args );
399 UCHAR *seed = get_ptr( &args );
401 return NtAllocateUuids( time, delta, sequence, seed );
405 /***********************************************************************
406 * wow64_NtCallbackReturn
408 NTSTATUS WINAPI wow64_NtCallbackReturn( UINT *args )
410 void *ret_ptr = get_ptr( &args );
411 ULONG ret_len = get_ulong( &args );
412 NTSTATUS status = get_ulong( &args );
414 struct user_callback_frame *frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA];
416 if (!frame) return STATUS_NO_CALLBACK_ACTIVE;
418 *frame->ret_ptr = ret_ptr;
419 *frame->ret_len = ret_len;
420 frame->status = status;
421 __wine_longjmp( &frame->jmpbuf, 1 );
425 /**********************************************************************
426 * wow64_NtClose
428 NTSTATUS WINAPI wow64_NtClose( UINT *args )
430 HANDLE handle = get_handle( &args );
432 return NtClose( handle );
436 /**********************************************************************
437 * wow64_NtContinue
439 NTSTATUS WINAPI wow64_NtContinue( UINT *args )
441 void *context = get_ptr( &args );
442 BOOLEAN alertable = get_ulong( &args );
444 NTSTATUS status = get_context_return_value( context );
445 struct user_apc_frame *frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST];
447 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, context );
449 while (frame && frame->wow_context != context) frame = frame->prev_frame;
450 NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST] = frame ? frame->prev_frame : NULL;
451 if (frame) NtContinue( frame->context, alertable );
453 if (alertable) NtTestAlert();
454 return status;
458 /**********************************************************************
459 * wow64_NtDeleteAtom
461 NTSTATUS WINAPI wow64_NtDeleteAtom( UINT *args )
463 RTL_ATOM atom = get_ulong( &args );
465 return NtDeleteAtom( atom );
469 /**********************************************************************
470 * wow64_NtFindAtom
472 NTSTATUS WINAPI wow64_NtFindAtom( UINT *args )
474 const WCHAR *name = get_ptr( &args );
475 ULONG len = get_ulong( &args );
476 RTL_ATOM *atom = get_ptr( &args );
478 return NtFindAtom( name, len, atom );
482 /**********************************************************************
483 * wow64_NtGetContextThread
485 NTSTATUS WINAPI wow64_NtGetContextThread( UINT *args )
487 HANDLE handle = get_handle( &args );
488 WOW64_CONTEXT *context = get_ptr( &args );
490 return RtlWow64GetThreadContext( handle, context );
494 /**********************************************************************
495 * wow64_NtGetCurrentProcessorNumber
497 NTSTATUS WINAPI wow64_NtGetCurrentProcessorNumber( UINT *args )
499 return NtGetCurrentProcessorNumber();
503 /**********************************************************************
504 * wow64_NtQueryDefaultLocale
506 NTSTATUS WINAPI wow64_NtQueryDefaultLocale( UINT *args )
508 BOOLEAN user = get_ulong( &args );
509 LCID *lcid = get_ptr( &args );
511 return NtQueryDefaultLocale( user, lcid );
515 /**********************************************************************
516 * wow64_NtQueryDefaultUILanguage
518 NTSTATUS WINAPI wow64_NtQueryDefaultUILanguage( UINT *args )
520 LANGID *lang = get_ptr( &args );
522 return NtQueryDefaultUILanguage( lang );
526 /**********************************************************************
527 * wow64_NtQueryInformationAtom
529 NTSTATUS WINAPI wow64_NtQueryInformationAtom( UINT *args )
531 RTL_ATOM atom = get_ulong( &args );
532 ATOM_INFORMATION_CLASS class = get_ulong( &args );
533 void *info = get_ptr( &args );
534 ULONG len = get_ulong( &args );
535 ULONG *retlen = get_ptr( &args );
537 if (class != AtomBasicInformation) FIXME( "class %u not supported\n", class );
538 return NtQueryInformationAtom( atom, class, info, len, retlen );
542 /**********************************************************************
543 * wow64_NtQueryInstallUILanguage
545 NTSTATUS WINAPI wow64_NtQueryInstallUILanguage( UINT *args )
547 LANGID *lang = get_ptr( &args );
549 return NtQueryInstallUILanguage( lang );
553 /**********************************************************************
554 * wow64_NtRaiseException
556 NTSTATUS WINAPI wow64_NtRaiseException( UINT *args )
558 EXCEPTION_RECORD32 *rec32 = get_ptr( &args );
559 void *context32 = get_ptr( &args );
560 BOOL first_chance = get_ulong( &args );
562 EXCEPTION_RECORD *rec = exception_record_32to64( rec32 );
563 CONTEXT context;
565 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, context32 );
567 __TRY
569 raise_exception( rec, &context, first_chance );
571 __EXCEPT_ALL
573 call_user_exception_dispatcher( rec32, context32, &context );
575 __ENDTRY
576 return STATUS_SUCCESS;
580 /**********************************************************************
581 * wow64_NtSetContextThread
583 NTSTATUS WINAPI wow64_NtSetContextThread( UINT *args )
585 HANDLE handle = get_handle( &args );
586 WOW64_CONTEXT *context = get_ptr( &args );
588 return RtlWow64SetThreadContext( handle, context );
592 /**********************************************************************
593 * wow64_NtSetDebugFilterState
595 NTSTATUS WINAPI wow64_NtSetDebugFilterState( UINT *args )
597 ULONG component_id = get_ulong( &args );
598 ULONG level = get_ulong( &args );
599 BOOLEAN state = get_ulong( &args );
601 return NtSetDebugFilterState( component_id, level, state );
605 /**********************************************************************
606 * wow64_NtSetDefaultLocale
608 NTSTATUS WINAPI wow64_NtSetDefaultLocale( UINT *args )
610 BOOLEAN user = get_ulong( &args );
611 LCID lcid = get_ulong( &args );
613 return NtSetDefaultLocale( user, lcid );
617 /**********************************************************************
618 * wow64_NtSetDefaultUILanguage
620 NTSTATUS WINAPI wow64_NtSetDefaultUILanguage( UINT *args )
622 LANGID lang = get_ulong( &args );
624 return NtSetDefaultUILanguage( lang );
628 /**********************************************************************
629 * wow64_NtWow64IsProcessorFeaturePresent
631 NTSTATUS WINAPI wow64_NtWow64IsProcessorFeaturePresent( UINT *args )
633 UINT feature = get_ulong( &args );
635 return pBTCpuIsProcessorFeaturePresent && pBTCpuIsProcessorFeaturePresent( feature );
639 /**********************************************************************
640 * init_image_mapping
642 void init_image_mapping( HMODULE module )
644 ULONG *ptr = RtlFindExportedRoutineByName( module, "Wow64Transition" );
646 if (ptr) *ptr = PtrToUlong( pBTCpuGetBopCode() );
650 /**********************************************************************
651 * load_64bit_module
653 static HMODULE load_64bit_module( const WCHAR *name )
655 NTSTATUS status;
656 HMODULE module;
657 UNICODE_STRING str;
658 WCHAR path[MAX_PATH];
659 const WCHAR *dir = get_machine_wow64_dir( IMAGE_FILE_MACHINE_TARGET_HOST );
661 swprintf( path, MAX_PATH, L"%s\\%s", dir, name );
662 RtlInitUnicodeString( &str, path );
663 if ((status = LdrLoadDll( dir, 0, &str, &module )))
665 ERR( "failed to load dll %lx\n", status );
666 NtTerminateProcess( GetCurrentProcess(), status );
668 return module;
672 /**********************************************************************
673 * get_cpu_dll_name
675 static const WCHAR *get_cpu_dll_name(void)
677 static ULONG buffer[32];
678 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
679 OBJECT_ATTRIBUTES attr;
680 UNICODE_STRING nameW;
681 const WCHAR *ret;
682 HANDLE key;
683 ULONG size;
685 switch (current_machine)
687 case IMAGE_FILE_MACHINE_I386:
688 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\x86" );
689 ret = (native_machine == IMAGE_FILE_MACHINE_ARM64 ? L"xtajit.dll" : L"wow64cpu.dll");
690 break;
691 case IMAGE_FILE_MACHINE_ARMNT:
692 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\arm" );
693 ret = L"wowarmhw.dll";
694 break;
695 default:
696 ERR( "unsupported machine %04x\n", current_machine );
697 RtlExitUserProcess( 1 );
699 InitializeObjectAttributes( &attr, &nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
700 if (NtOpenKey( &key, KEY_READ | KEY_WOW64_64KEY, &attr )) return ret;
701 RtlInitUnicodeString( &nameW, L"" );
702 size = sizeof(buffer) - sizeof(WCHAR);
703 if (!NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buffer, size, &size ) && info->Type == REG_SZ)
705 ((WCHAR *)info->Data)[info->DataLength / sizeof(WCHAR)] = 0;
706 ret = (WCHAR *)info->Data;
708 NtClose( key );
709 return ret;
713 /**********************************************************************
714 * create_cross_process_work_list
716 static NTSTATUS create_cross_process_work_list( WOW64INFO *wow64info )
718 SIZE_T map_size = 0x4000;
719 LARGE_INTEGER size;
720 NTSTATUS status;
721 HANDLE section;
722 CROSS_PROCESS_WORK_LIST *list = NULL;
723 CROSS_PROCESS_WORK_ENTRY *end;
724 UINT i;
726 size.QuadPart = map_size;
727 status = NtCreateSection( &section, SECTION_ALL_ACCESS, NULL, &size, PAGE_READWRITE, SEC_COMMIT, 0 );
728 if (status) return status;
729 status = NtMapViewOfSection( section, GetCurrentProcess(), (void **)&list, default_zero_bits, 0, NULL,
730 &map_size, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE );
731 if (status)
733 NtClose( section );
734 return status;
737 end = (CROSS_PROCESS_WORK_ENTRY *)((char *)list + map_size);
738 for (i = 0; list->entries + i + 1 <= end; i++)
739 RtlWow64PushCrossProcessWorkOntoFreeList( &list->free_list, &list->entries[i] );
741 wow64info->SectionHandle = (ULONG_PTR)section;
742 wow64info->CrossProcessWorkList = (ULONG_PTR)list;
743 return STATUS_SUCCESS;
747 /**********************************************************************
748 * process_init
750 static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **context )
752 PEB32 *peb32;
753 HMODULE module;
754 UNICODE_STRING str = RTL_CONSTANT_STRING( L"ntdll.dll" );
755 SYSTEM_BASIC_INFORMATION info;
756 ULONG *p__wine_syscall_dispatcher, *p__wine_unix_call_dispatcher;
757 const SYSTEM_SERVICE_TABLE *psdwhwin32;
759 RtlWow64GetProcessMachines( GetCurrentProcess(), &current_machine, &native_machine );
760 if (!current_machine) current_machine = native_machine;
761 args_alignment = (current_machine == IMAGE_FILE_MACHINE_I386) ? sizeof(ULONG) : sizeof(ULONG64);
762 NtQuerySystemInformation( SystemEmulationBasicInformation, &info, sizeof(info), NULL );
763 highest_user_address = (ULONG_PTR)info.HighestUserAddress;
764 default_zero_bits = (ULONG_PTR)info.HighestUserAddress | 0x7fffffff;
765 NtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information, &peb32, sizeof(peb32), NULL );
766 wow64info = (WOW64INFO *)(peb32 + 1);
767 wow64info->NativeSystemPageSize = 0x1000;
768 wow64info->NativeMachineType = native_machine;
769 wow64info->EmulatedMachineType = current_machine;
770 NtCurrentTeb()->TlsSlots[WOW64_TLS_WOW64INFO] = wow64info;
772 #define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
774 LdrGetDllHandle( NULL, 0, &str, &module );
775 GET_PTR( LdrSystemDllInitBlock );
777 module = load_64bit_module( get_cpu_dll_name() );
778 GET_PTR( BTCpuGetBopCode );
779 GET_PTR( BTCpuGetContext );
780 GET_PTR( BTCpuIsProcessorFeaturePresent );
781 GET_PTR( BTCpuProcessInit );
782 GET_PTR( BTCpuThreadInit );
783 GET_PTR( BTCpuResetToConsistentState );
784 GET_PTR( BTCpuSetContext );
785 GET_PTR( BTCpuSimulate );
786 GET_PTR( BTCpuNotifyFlushInstructionCache2 );
787 GET_PTR( BTCpuNotifyMapViewOfSection );
788 GET_PTR( BTCpuNotifyMemoryAlloc );
789 GET_PTR( BTCpuNotifyMemoryDirty );
790 GET_PTR( BTCpuNotifyMemoryFree );
791 GET_PTR( BTCpuNotifyMemoryProtect );
792 GET_PTR( BTCpuNotifyUnmapViewOfSection );
793 GET_PTR( BTCpuUpdateProcessorInformation );
794 GET_PTR( BTCpuThreadTerm );
795 GET_PTR( __wine_get_unix_opcode );
797 module = load_64bit_module( L"wow64win.dll" );
798 GET_PTR( sdwhwin32 );
799 syscall_tables[1] = *psdwhwin32;
801 pBTCpuProcessInit();
803 module = (HMODULE)(ULONG_PTR)pLdrSystemDllInitBlock->ntdll_handle;
804 init_image_mapping( module );
805 GET_PTR( KiRaiseUserExceptionDispatcher );
806 GET_PTR( __wine_syscall_dispatcher );
807 GET_PTR( __wine_unix_call_dispatcher );
809 *p__wine_syscall_dispatcher = PtrToUlong( pBTCpuGetBopCode() );
810 *p__wine_unix_call_dispatcher = PtrToUlong( p__wine_get_unix_opcode() );
812 if (wow64info->CpuFlags & WOW64_CPUFLAGS_SOFTWARE) create_cross_process_work_list( wow64info );
814 init_file_redirects();
815 return TRUE;
817 #undef GET_PTR
821 /**********************************************************************
822 * thread_init
824 static void thread_init(void)
826 void *cpu_area_ctx;
828 RtlWow64GetCurrentCpuArea( NULL, &cpu_area_ctx, NULL );
829 NtCurrentTeb()->TlsSlots[WOW64_TLS_WOW64INFO] = wow64info;
830 if (pBTCpuThreadInit) pBTCpuThreadInit();
832 /* update initial context to jump to 32-bit LdrInitializeThunk (cf. 32-bit call_init_thunk) */
833 switch (current_machine)
835 case IMAGE_FILE_MACHINE_I386:
837 I386_CONTEXT *ctx_ptr, *ctx = cpu_area_ctx;
838 ULONG *stack;
840 ctx_ptr = (I386_CONTEXT *)ULongToPtr( ctx->Esp ) - 1;
841 *ctx_ptr = *ctx;
843 stack = (ULONG *)ctx_ptr;
844 *(--stack) = 0;
845 *(--stack) = 0;
846 *(--stack) = 0;
847 *(--stack) = PtrToUlong( ctx_ptr );
848 *(--stack) = 0xdeadbabe;
849 ctx->Esp = PtrToUlong( stack );
850 ctx->Eip = pLdrSystemDllInitBlock->pLdrInitializeThunk;
851 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, ctx );
853 break;
855 case IMAGE_FILE_MACHINE_ARMNT:
857 ARM_CONTEXT *ctx_ptr, *ctx = cpu_area_ctx;
859 ctx_ptr = (ARM_CONTEXT *)ULongToPtr( ctx->Sp & ~15 ) - 1;
860 *ctx_ptr = *ctx;
862 ctx->R0 = PtrToUlong( ctx_ptr );
863 ctx->Sp = PtrToUlong( ctx_ptr );
864 ctx->Pc = pLdrSystemDllInitBlock->pLdrInitializeThunk;
865 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, ctx );
867 break;
869 default:
870 ERR( "not supported machine %x\n", current_machine );
871 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
876 /**********************************************************************
877 * free_temp_data
879 static void free_temp_data(void)
881 struct mem_header *next, *mem;
883 for (mem = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST]; mem; mem = next)
885 next = mem->next;
886 RtlFreeHeap( GetProcessHeap(), 0, mem );
888 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
892 /**********************************************************************
893 * syscall_filter
895 static LONG CALLBACK syscall_filter( EXCEPTION_POINTERS *ptrs )
897 switch (ptrs->ExceptionRecord->ExceptionCode)
899 case STATUS_INVALID_HANDLE:
900 call_raise_user_exception_dispatcher( ptrs->ExceptionRecord->ExceptionCode );
901 break;
903 return EXCEPTION_EXECUTE_HANDLER;
907 /**********************************************************************
908 * Wow64SystemServiceEx (wow64.@)
910 NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
912 NTSTATUS status;
913 UINT id = num & 0xfff;
914 const SYSTEM_SERVICE_TABLE *table = &syscall_tables[(num >> 12) & 3];
916 if (id >= table->ServiceLimit || !table->ServiceTable[id])
918 ERR( "unsupported syscall %04x\n", num );
919 return STATUS_INVALID_SYSTEM_SERVICE;
921 __TRY
923 syscall_thunk thunk = (syscall_thunk)table->ServiceTable[id];
924 status = thunk( args );
926 __EXCEPT( syscall_filter )
928 status = GetExceptionCode();
930 __ENDTRY
931 free_temp_data();
932 return status;
936 /**********************************************************************
937 * simulate_filter
939 static LONG CALLBACK simulate_filter( EXCEPTION_POINTERS *ptrs )
941 Wow64PassExceptionToGuest( ptrs );
942 return EXCEPTION_EXECUTE_HANDLER;
946 /**********************************************************************
947 * cpu_simulate
949 static void cpu_simulate(void)
951 for (;;)
953 __TRY
955 pBTCpuSimulate();
957 __EXCEPT( simulate_filter )
959 /* restart simulation loop */
961 __ENDTRY
966 /**********************************************************************
967 * Wow64AllocateTemp (wow64.@)
969 * FIXME: probably not 100% compatible.
971 void * WINAPI Wow64AllocateTemp( SIZE_T size )
973 struct mem_header *mem;
975 if (!(mem = RtlAllocateHeap( GetProcessHeap(), 0, offsetof( struct mem_header, data[size] ))))
976 return NULL;
977 mem->next = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
978 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = mem;
979 return mem->data;
983 /**********************************************************************
984 * Wow64ApcRoutine (wow64.@)
986 void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CONTEXT *context )
988 struct user_apc_frame frame;
990 frame.prev_frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST];
991 frame.context = context;
992 NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST] = &frame;
994 /* cf. 32-bit call_user_apc_dispatcher */
995 switch (current_machine)
997 case IMAGE_FILE_MACHINE_I386:
999 struct apc_stack_layout
1001 ULONG ret;
1002 ULONG context_ptr;
1003 ULONG arg1;
1004 ULONG arg2;
1005 ULONG arg3;
1006 ULONG func;
1007 I386_CONTEXT context;
1008 } *stack;
1009 I386_CONTEXT ctx = { CONTEXT_I386_FULL };
1011 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1012 stack = (struct apc_stack_layout *)ULongToPtr( ctx.Esp & ~3 ) - 1;
1013 stack->context_ptr = PtrToUlong( &stack->context );
1014 stack->func = arg1 >> 32;
1015 stack->arg1 = arg1;
1016 stack->arg2 = arg2;
1017 stack->arg3 = arg3;
1018 stack->context = ctx;
1019 ctx.Esp = PtrToUlong( stack );
1020 ctx.Eip = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
1021 frame.wow_context = &stack->context;
1022 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1023 cpu_simulate();
1025 break;
1027 case IMAGE_FILE_MACHINE_ARMNT:
1029 struct apc_stack_layout
1031 ULONG func;
1032 ULONG align[3];
1033 ARM_CONTEXT context;
1034 } *stack;
1035 ARM_CONTEXT ctx = { CONTEXT_ARM_FULL };
1037 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1038 stack = (struct apc_stack_layout *)ULongToPtr( ctx.Sp & ~15 ) - 1;
1039 stack->func = arg1 >> 32;
1040 stack->context = ctx;
1041 ctx.Sp = PtrToUlong( stack );
1042 ctx.Pc = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
1043 ctx.R0 = PtrToUlong( &stack->context );
1044 ctx.R1 = arg1;
1045 ctx.R2 = arg2;
1046 ctx.R3 = arg3;
1047 frame.wow_context = &stack->context;
1048 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1049 cpu_simulate();
1051 break;
1056 /**********************************************************************
1057 * Wow64KiUserCallbackDispatcher (wow64.@)
1059 NTSTATUS WINAPI Wow64KiUserCallbackDispatcher( ULONG id, void *args, ULONG len,
1060 void **ret_ptr, ULONG *ret_len )
1062 WOW64_CPURESERVED *cpu = NtCurrentTeb()->TlsSlots[WOW64_TLS_CPURESERVED];
1063 TEB32 *teb32 = (TEB32 *)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset);
1064 ULONG teb_frame = teb32->Tib.ExceptionList;
1065 struct user_callback_frame frame;
1066 USHORT flags = cpu->Flags;
1068 frame.prev_frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA];
1069 frame.temp_list = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
1070 frame.ret_ptr = ret_ptr;
1071 frame.ret_len = ret_len;
1073 NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = &frame;
1074 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
1076 /* cf. 32-bit KeUserModeCallback */
1077 switch (current_machine)
1079 case IMAGE_FILE_MACHINE_I386:
1081 I386_CONTEXT orig_ctx, ctx = { CONTEXT_I386_FULL };
1082 void *args_data;
1083 ULONG *stack;
1085 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1086 orig_ctx = ctx;
1088 stack = args_data = ULongToPtr( (ctx.Esp - len) & ~15 );
1089 memcpy( args_data, args, len );
1090 *(--stack) = 0;
1091 *(--stack) = len;
1092 *(--stack) = PtrToUlong( args_data );
1093 *(--stack) = id;
1094 *(--stack) = 0xdeadbabe;
1096 ctx.Esp = PtrToUlong( stack );
1097 ctx.Eip = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
1098 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1100 if (!__wine_setjmpex( &frame.jmpbuf, NULL ))
1101 cpu_simulate();
1102 else
1103 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &orig_ctx );
1105 break;
1107 case IMAGE_FILE_MACHINE_ARMNT:
1109 ARM_CONTEXT orig_ctx, ctx = { CONTEXT_ARM_FULL };
1110 void *args_data;
1112 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1113 orig_ctx = ctx;
1115 args_data = ULongToPtr( (ctx.Sp - len) & ~15 );
1116 memcpy( args_data, args, len );
1118 ctx.R0 = id;
1119 ctx.R1 = PtrToUlong( args_data );
1120 ctx.R2 = len;
1121 ctx.Sp = PtrToUlong( args_data );
1122 ctx.Pc = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
1123 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1125 if (!__wine_setjmpex( &frame.jmpbuf, NULL ))
1126 cpu_simulate();
1127 else
1128 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &orig_ctx );
1130 break;
1133 teb32->Tib.ExceptionList = teb_frame;
1134 NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = frame.prev_frame;
1135 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = frame.temp_list;
1136 cpu->Flags = flags;
1137 return frame.status;
1141 /**********************************************************************
1142 * Wow64LdrpInitialize (wow64.@)
1144 void WINAPI Wow64LdrpInitialize( CONTEXT *context )
1146 static RTL_RUN_ONCE init_done;
1148 RtlRunOnceExecuteOnce( &init_done, process_init, NULL, NULL );
1149 thread_init();
1150 cpu_simulate();
1154 /**********************************************************************
1155 * Wow64PrepareForException (wow64.@)
1157 void WINAPI Wow64PrepareForException( EXCEPTION_RECORD *rec, CONTEXT *context )
1159 EXCEPTION_POINTERS ptrs = { rec, context };
1161 pBTCpuResetToConsistentState( &ptrs );
1165 /**********************************************************************
1166 * Wow64PassExceptionToGuest (wow64.@)
1168 void WINAPI Wow64PassExceptionToGuest( EXCEPTION_POINTERS *ptrs )
1170 EXCEPTION_RECORD32 rec32;
1172 exception_record_64to32( &rec32, ptrs->ExceptionRecord );
1173 call_user_exception_dispatcher( &rec32, NULL, ptrs->ContextRecord );
1177 /**********************************************************************
1178 * Wow64ProcessPendingCrossProcessItems (wow64.@)
1180 void WINAPI Wow64ProcessPendingCrossProcessItems(void)
1182 CROSS_PROCESS_WORK_LIST *list = (void *)wow64info->CrossProcessWorkList;
1183 CROSS_PROCESS_WORK_ENTRY *entry;
1184 BOOLEAN flush = FALSE;
1185 UINT next;
1187 if (!list) return;
1188 entry = RtlWow64PopAllCrossProcessWorkFromWorkList( &list->work_list, &flush );
1190 if (flush)
1192 if (pBTCpuNotifyFlushInstructionCache2) pBTCpuNotifyFlushInstructionCache2( NULL, ~0ull );
1193 while (entry)
1195 next = entry->next;
1196 RtlWow64PushCrossProcessWorkOntoFreeList( &list->free_list, entry );
1197 entry = CROSS_PROCESS_LIST_ENTRY( &list->work_list, next );
1199 return;
1202 while (entry)
1204 switch (entry->id)
1206 case CrossProcessPreVirtualAlloc:
1207 /* FIXME */
1208 break;
1209 case CrossProcessPostVirtualAlloc:
1210 if (!pBTCpuNotifyMemoryAlloc) break;
1211 if (entry->args[2]) break;
1212 pBTCpuNotifyMemoryAlloc( (void *)entry->addr, entry->size, entry->args[0], entry->args[1] );
1213 break;
1214 case CrossProcessPreVirtualFree:
1215 if (!pBTCpuNotifyMemoryFree) break;
1216 pBTCpuNotifyMemoryFree( (void *)entry->addr, entry->size, entry->args[0] );
1217 break;
1218 case CrossProcessPostVirtualFree:
1219 /* FIXME */
1220 break;
1221 case CrossProcessPreVirtualProtect:
1222 if (!pBTCpuNotifyMemoryProtect) break;
1223 pBTCpuNotifyMemoryProtect( (void *)entry->addr, entry->size, entry->args[0] );
1224 break;
1225 case CrossProcessPostVirtualProtect:
1226 /* FIXME */
1227 break;
1228 case CrossProcessFlushCache:
1229 if (!pBTCpuNotifyFlushInstructionCache2) break;
1230 pBTCpuNotifyFlushInstructionCache2( (void *)entry->addr, entry->size );
1231 break;
1233 next = entry->next;
1234 RtlWow64PushCrossProcessWorkOntoFreeList( &list->free_list, entry );
1235 entry = CROSS_PROCESS_LIST_ENTRY( &list->work_list, next );
1240 /**********************************************************************
1241 * Wow64RaiseException (wow64.@)
1243 NTSTATUS WINAPI Wow64RaiseException( int code, EXCEPTION_RECORD *rec )
1245 EXCEPTION_RECORD32 rec32;
1246 CONTEXT context;
1247 BOOL first_chance = TRUE;
1248 union
1250 I386_CONTEXT i386;
1251 ARM_CONTEXT arm;
1252 } ctx32 = { 0 };
1254 switch (current_machine)
1256 case IMAGE_FILE_MACHINE_I386:
1258 EXCEPTION_RECORD int_rec = { 0 };
1260 ctx32.i386.ContextFlags = CONTEXT_I386_ALL;
1261 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1262 if (code == -1) break;
1263 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1264 switch (code)
1266 case 0x00: /* division by zero */
1267 int_rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
1268 break;
1269 case 0x01: /* single-step */
1270 int_rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
1271 break;
1272 case 0x03: /* breakpoint */
1273 int_rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1274 int_rec.ExceptionAddress = (void *)(ULONG_PTR)(ctx32.i386.Eip + 1);
1275 int_rec.NumberParameters = 1;
1276 break;
1277 case 0x04: /* overflow */
1278 int_rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
1279 break;
1280 case 0x05: /* array bounds */
1281 int_rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
1282 break;
1283 case 0x06: /* invalid opcode */
1284 int_rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
1285 break;
1286 case 0x09: /* coprocessor segment overrun */
1287 int_rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
1288 break;
1289 case 0x0c: /* stack fault */
1290 int_rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
1291 break;
1292 case 0x29: /* __fastfail */
1293 int_rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
1294 int_rec.ExceptionFlags = EH_NONCONTINUABLE;
1295 int_rec.NumberParameters = 1;
1296 int_rec.ExceptionInformation[0] = ctx32.i386.Ecx;
1297 first_chance = FALSE;
1298 break;
1299 case 0x2d: /* debug service */
1300 ctx32.i386.Eip++;
1301 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1302 int_rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1303 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1304 int_rec.NumberParameters = 1;
1305 int_rec.ExceptionInformation[0] = ctx32.i386.Eax;
1306 break;
1307 default:
1308 ctx32.i386.Eip -= 2;
1309 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1310 int_rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
1311 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1312 int_rec.NumberParameters = 2;
1313 int_rec.ExceptionInformation[1] = 0xffffffff;
1314 break;
1316 *rec = int_rec;
1317 break;
1320 case IMAGE_FILE_MACHINE_ARMNT:
1321 ctx32.arm.ContextFlags = CONTEXT_ARM_ALL;
1322 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.arm );
1323 break;
1326 exception_record_64to32( &rec32, rec );
1327 __TRY
1329 raise_exception( rec, &context, first_chance );
1331 __EXCEPT_ALL
1333 call_user_exception_dispatcher( &rec32, &ctx32, NULL );
1335 __ENDTRY
1336 return STATUS_SUCCESS;