wow64: Add a thunk for the NtRaiseException syscall.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
ee99bd4bc1
commit
e30b56b1a3
|
@ -27,6 +27,8 @@
|
|||
#include "winnt.h"
|
||||
#include "winternl.h"
|
||||
#include "wow64_private.h"
|
||||
#include "wine/asm.h"
|
||||
#include "wine/exception.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(wow);
|
||||
|
@ -71,6 +73,23 @@ static BOOL is_process_id_wow64( const CLIENT_ID *id )
|
|||
}
|
||||
|
||||
|
||||
static EXCEPTION_RECORD *exception_record_32to64( const EXCEPTION_RECORD32 *rec32 )
|
||||
{
|
||||
EXCEPTION_RECORD *rec;
|
||||
unsigned int i;
|
||||
|
||||
rec = Wow64AllocateTemp( sizeof(*rec) );
|
||||
rec->ExceptionCode = rec32->ExceptionCode;
|
||||
rec->ExceptionFlags = rec32->ExceptionFlags;
|
||||
rec->ExceptionRecord = rec32->ExceptionRecord ? exception_record_32to64( ULongToPtr(rec32->ExceptionRecord) ) : NULL;
|
||||
rec->ExceptionAddress = ULongToPtr( rec32->ExceptionAddress );
|
||||
rec->NumberParameters = rec32->NumberParameters;
|
||||
for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
|
||||
rec->ExceptionInformation[i] = rec32->ExceptionInformation[i];
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
||||
static RTL_USER_PROCESS_PARAMETERS *process_params_32to64( RTL_USER_PROCESS_PARAMETERS **params,
|
||||
RTL_USER_PROCESS_PARAMETERS32 *params32 )
|
||||
{
|
||||
|
@ -274,6 +293,150 @@ void put_vm_counters( VM_COUNTERS_EX32 *info32, const VM_COUNTERS_EX *info, ULON
|
|||
}
|
||||
|
||||
|
||||
static void call_user_exception_dispatcher( EXCEPTION_RECORD32 *rec, void *ctx32_ptr, void *ctx64_ptr )
|
||||
{
|
||||
switch (current_machine)
|
||||
{
|
||||
case IMAGE_FILE_MACHINE_I386:
|
||||
{
|
||||
struct stack_layout
|
||||
{
|
||||
ULONG rec_ptr; /* first arg for KiUserExceptionDispatcher */
|
||||
ULONG context_ptr; /* second arg for KiUserExceptionDispatcher */
|
||||
EXCEPTION_RECORD32 rec;
|
||||
I386_CONTEXT context;
|
||||
} *stack;
|
||||
I386_CONTEXT *context, ctx = { CONTEXT_I386_ALL };
|
||||
CONTEXT_EX *context_ex, *src_ex = NULL;
|
||||
ULONG size, flags;
|
||||
|
||||
NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
|
||||
|
||||
if (ctx32_ptr)
|
||||
{
|
||||
I386_CONTEXT *ctx32 = ctx32_ptr;
|
||||
|
||||
if ((ctx32->ContextFlags & CONTEXT_I386_XSTATE) == CONTEXT_I386_XSTATE)
|
||||
src_ex = (CONTEXT_EX *)(ctx32 + 1);
|
||||
}
|
||||
else if (native_machine == IMAGE_FILE_MACHINE_AMD64)
|
||||
{
|
||||
AMD64_CONTEXT *ctx64 = ctx64_ptr;
|
||||
|
||||
if ((ctx64->ContextFlags & CONTEXT_AMD64_FLOATING_POINT) == CONTEXT_AMD64_FLOATING_POINT)
|
||||
memcpy( ctx.ExtendedRegisters, &ctx64->FltSave, sizeof(ctx.ExtendedRegisters) );
|
||||
if ((ctx64->ContextFlags & CONTEXT_AMD64_XSTATE) == CONTEXT_AMD64_XSTATE)
|
||||
src_ex = (CONTEXT_EX *)(ctx64 + 1);
|
||||
}
|
||||
|
||||
flags = ctx.ContextFlags;
|
||||
if (src_ex) flags |= CONTEXT_I386_XSTATE;
|
||||
RtlGetExtendedContextLength( flags, &size );
|
||||
size = ((size + 15) & ~15) + offsetof(struct stack_layout,context);
|
||||
|
||||
stack = (struct stack_layout *)(ULONG_PTR)(ctx.Esp - size);
|
||||
stack->rec_ptr = PtrToUlong( &stack->rec );
|
||||
stack->rec = *rec;
|
||||
RtlInitializeExtendedContext( &stack->context, flags, &context_ex );
|
||||
context = RtlLocateLegacyContext( context_ex, NULL );
|
||||
*context = ctx;
|
||||
context->ContextFlags = flags;
|
||||
stack->context_ptr = PtrToUlong( context );
|
||||
|
||||
if (src_ex)
|
||||
{
|
||||
XSTATE *src_xs = (XSTATE *)((char *)src_ex + src_ex->XState.Offset);
|
||||
XSTATE *dst_xs = (XSTATE *)((char *)context_ex + context_ex->XState.Offset);
|
||||
|
||||
dst_xs->Mask = src_xs->Mask & ~(ULONG64)3;
|
||||
dst_xs->CompactionMask = src_xs->CompactionMask;
|
||||
if ((dst_xs->Mask & 4) &&
|
||||
src_ex->XState.Length >= sizeof(XSTATE) &&
|
||||
context_ex->XState.Length >= sizeof(XSTATE))
|
||||
memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
|
||||
}
|
||||
|
||||
ctx.Esp = PtrToUlong( stack );
|
||||
ctx.Eip = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
|
||||
ctx.EFlags &= ~(0x100|0x400|0x40000);
|
||||
NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
|
||||
|
||||
TRACE( "exception %08x dispatcher %08x stack %08x eip %08x\n",
|
||||
rec->ExceptionCode, ctx.Eip, ctx.Esp, stack->context.Eip );
|
||||
}
|
||||
break;
|
||||
|
||||
case IMAGE_FILE_MACHINE_ARMNT:
|
||||
{
|
||||
struct stack_layout
|
||||
{
|
||||
ARM_CONTEXT context;
|
||||
EXCEPTION_RECORD32 rec;
|
||||
} *stack;
|
||||
ARM_CONTEXT ctx = { CONTEXT_ARM_ALL };
|
||||
|
||||
NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
|
||||
stack = (struct stack_layout *)(ULONG_PTR)(ctx.Sp & ~3) - 1;
|
||||
stack->rec = *rec;
|
||||
stack->context = ctx;
|
||||
|
||||
ctx.R0 = PtrToUlong( &stack->rec ); /* first arg for KiUserExceptionDispatcher */
|
||||
ctx.R1 = PtrToUlong( &stack->context ); /* second arg for KiUserExceptionDispatcher */
|
||||
ctx.Sp = PtrToUlong( stack );
|
||||
ctx.Pc = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
|
||||
if (ctx.Pc & 1) ctx.Cpsr |= 0x20;
|
||||
else ctx.Cpsr &= ~0x20;
|
||||
NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
|
||||
|
||||
TRACE( "exception %08x dispatcher %08x stack %08x pc %08x\n",
|
||||
rec->ExceptionCode, ctx.Pc, ctx.Sp, stack->context.Sp );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* based on RtlRaiseException: call NtRaiseException with context setup to return to caller */
|
||||
void WINAPI raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) DECLSPEC_HIDDEN;
|
||||
#ifdef __x86_64__
|
||||
__ASM_GLOBAL_FUNC( raise_exception,
|
||||
"sub $0x28,%rsp\n\t"
|
||||
__ASM_SEH(".seh_stackalloc 0x28\n\t")
|
||||
__ASM_SEH(".seh_endprologue\n\t")
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
|
||||
"movq %rcx,(%rsp)\n\t"
|
||||
"movq %rdx,%rcx\n\t"
|
||||
"call " __ASM_NAME("RtlCaptureContext") "\n\t"
|
||||
"leaq 0x30(%rsp),%rax\n\t" /* orig stack pointer */
|
||||
"movq %rax,0x98(%rdx)\n\t" /* context->Rsp */
|
||||
"movq (%rsp),%rcx\n\t" /* original first parameter */
|
||||
"movq 0x28(%rsp),%rax\n\t" /* return address */
|
||||
"movq %rax,0xf8(%rdx)\n\t" /* context->Rip */
|
||||
"movq %rax,0x10(%rcx)\n\t" /* rec->ExceptionAddress */
|
||||
"call " __ASM_NAME("NtRaiseException") )
|
||||
#elif defined(__aarch64__)
|
||||
__ASM_GLOBAL_FUNC( raise_exception,
|
||||
"stp x29, x30, [sp, #-32]!\n\t"
|
||||
__ASM_SEH(".seh_stackalloc 32\n\t")
|
||||
__ASM_SEH(".seh_save_fplr 0\n\t")
|
||||
__ASM_SEH(".seh_endprologue\n\t")
|
||||
__ASM_CFI(".cfi_def_cfa x29, 32\n\t")
|
||||
__ASM_CFI(".cfi_offset x30, -24\n\t")
|
||||
__ASM_CFI(".cfi_offset x29, -32\n\t")
|
||||
"mov x29, sp\n\t"
|
||||
"stp x0, x1, [sp, #16]\n\t"
|
||||
"mov x0, x1\n\t"
|
||||
"bl " __ASM_NAME("RtlCaptureContext") "\n\t"
|
||||
"ldp x0, x1, [sp, #16]\n\t" /* orig parameters */
|
||||
"ldp x4, x5, [sp]\n\t" /* frame pointer, return address */
|
||||
"stp x4, x5, [x1, #0xf0]\n\t" /* context->Fp, Lr */
|
||||
"add x4, sp, #32\n\t" /* orig stack pointer */
|
||||
"stp x4, x5, [x1, #0x100]\n\t" /* context->Sp, Pc */
|
||||
"str x5, [x0, #0x10]\n\t" /* rec->ExceptionAddress */
|
||||
"bl " __ASM_NAME("NtRaiseException") )
|
||||
#endif
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* wow64_NtAlertResumeThread
|
||||
*/
|
||||
|
@ -805,6 +968,34 @@ NTSTATUS WINAPI wow64_NtQueueApcThread( UINT *args )
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* wow64_NtRaiseException
|
||||
*/
|
||||
NTSTATUS WINAPI wow64_NtRaiseException( UINT *args )
|
||||
{
|
||||
EXCEPTION_RECORD32 *rec32 = get_ptr( &args );
|
||||
void *context32 = get_ptr( &args );
|
||||
BOOL first_chance = get_ulong( &args );
|
||||
|
||||
EXCEPTION_RECORD *rec = exception_record_32to64( rec32 );
|
||||
CONTEXT context;
|
||||
|
||||
NtSetInformationThread( GetCurrentThread(), ThreadWow64Context,
|
||||
context32, get_machine_context_size( current_machine ));
|
||||
|
||||
__TRY
|
||||
{
|
||||
raise_exception( rec, &context, first_chance );
|
||||
}
|
||||
__EXCEPT_ALL
|
||||
{
|
||||
call_user_exception_dispatcher( rec32, context32, &context );
|
||||
}
|
||||
__ENDTRY
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* wow64_NtRemoveProcessDebug
|
||||
*/
|
||||
|
|
|
@ -63,9 +63,7 @@ struct mem_header
|
|||
BYTE data[1];
|
||||
};
|
||||
|
||||
static void **pWow64Transition;
|
||||
static void **p__wine_syscall_dispatcher;
|
||||
static SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock;
|
||||
SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock = NULL;
|
||||
|
||||
/* cpu backend dll functions */
|
||||
static void * (WINAPI *pBTCpuGetBopCode)(void);
|
||||
|
@ -421,6 +419,7 @@ static HMODULE load_cpu_dll(void)
|
|||
*/
|
||||
static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **context )
|
||||
{
|
||||
void **pWow64Transition, **p__wine_syscall_dispatcher;
|
||||
HMODULE module;
|
||||
UNICODE_STRING str;
|
||||
|
||||
|
|
|
@ -171,6 +171,7 @@
|
|||
SYSCALL_ENTRY( NtQueryVirtualMemory ) \
|
||||
SYSCALL_ENTRY( NtQueryVolumeInformationFile ) \
|
||||
SYSCALL_ENTRY( NtQueueApcThread ) \
|
||||
SYSCALL_ENTRY( NtRaiseException ) \
|
||||
SYSCALL_ENTRY( NtRaiseHardError ) \
|
||||
SYSCALL_ENTRY( NtReadFile ) \
|
||||
SYSCALL_ENTRY( NtReadFileScatter ) \
|
||||
|
|
|
@ -37,6 +37,7 @@ extern BOOL get_file_redirect( OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN;
|
|||
extern USHORT native_machine DECLSPEC_HIDDEN;
|
||||
extern USHORT current_machine DECLSPEC_HIDDEN;
|
||||
extern ULONG_PTR args_alignment DECLSPEC_HIDDEN;
|
||||
extern SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock DECLSPEC_HIDDEN;
|
||||
|
||||
struct object_attr64
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue