wow64: Add a thunk for the NtRaiseException syscall.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-08-20 15:02:25 +02:00
parent ee99bd4bc1
commit e30b56b1a3
4 changed files with 195 additions and 3 deletions

View File

@ -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
*/

View File

@ -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;

View File

@ -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 ) \

View File

@ -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
{