1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/dlls/ntdll/unix/signal_arm64.c
2024-02-29 18:14:48 +01:00

1658 lines
61 KiB
C

/*
* ARM64 signal handling routines
*
* Copyright 2010-2013 André Hentschel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#if 0
#pragma makedep unix
#endif
#ifdef __aarch64__
#include "config.h"
#include <assert.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_SYSCALL_H
# include <syscall.h>
#else
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
#endif
#ifdef HAVE_SYS_SIGNAL_H
# include <sys/signal.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winnt.h"
#include "winternl.h"
#include "wine/asm.h"
#include "unix_private.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(seh);
#define NTDLL_DWARF_H_NO_UNWINDER
#include "dwarf.h"
/***********************************************************************
* signal context platform-specific definitions
*/
#ifdef linux
/* All Registers access - only for local access */
# define REG_sig(reg_name, context) ((context)->uc_mcontext.reg_name)
# define REGn_sig(reg_num, context) ((context)->uc_mcontext.regs[reg_num])
/* Special Registers access */
# define SP_sig(context) REG_sig(sp, context) /* Stack pointer */
# define PC_sig(context) REG_sig(pc, context) /* Program counter */
# define PSTATE_sig(context) REG_sig(pstate, context) /* Current State Register */
# define FP_sig(context) REGn_sig(29, context) /* Frame pointer */
# define LR_sig(context) REGn_sig(30, context) /* Link Register */
static struct _aarch64_ctx *get_extended_sigcontext( const ucontext_t *sigcontext, unsigned int magic )
{
struct _aarch64_ctx *ctx = (struct _aarch64_ctx *)sigcontext->uc_mcontext.__reserved;
while ((char *)ctx < (char *)(&sigcontext->uc_mcontext + 1) && ctx->magic && ctx->size)
{
if (ctx->magic == magic) return ctx;
ctx = (struct _aarch64_ctx *)((char *)ctx + ctx->size);
}
return NULL;
}
static struct fpsimd_context *get_fpsimd_context( const ucontext_t *sigcontext )
{
return (struct fpsimd_context *)get_extended_sigcontext( sigcontext, FPSIMD_MAGIC );
}
static DWORD64 get_fault_esr( ucontext_t *sigcontext )
{
struct esr_context *esr = (struct esr_context *)get_extended_sigcontext( sigcontext, ESR_MAGIC );
if (esr) return esr->esr;
return 0;
}
#elif defined(__APPLE__)
/* All Registers access - only for local access */
# define REG_sig(reg_name, context) ((context)->uc_mcontext->__ss.__ ## reg_name)
# define REGn_sig(reg_num, context) ((context)->uc_mcontext->__ss.__x[reg_num])
/* Special Registers access */
# define SP_sig(context) REG_sig(sp, context) /* Stack pointer */
# define PC_sig(context) REG_sig(pc, context) /* Program counter */
# define PSTATE_sig(context) REG_sig(cpsr, context) /* Current State Register */
# define FP_sig(context) REG_sig(fp, context) /* Frame pointer */
# define LR_sig(context) REG_sig(lr, context) /* Link Register */
static DWORD64 get_fault_esr( ucontext_t *sigcontext )
{
return sigcontext->uc_mcontext->__es.__esr;
}
#endif /* linux */
/* stack layout when calling KiUserExceptionDispatcher */
struct exc_stack_layout
{
CONTEXT context; /* 000 */
EXCEPTION_RECORD rec; /* 390 */
ULONG64 align; /* 428 */
ULONG64 redzone[2]; /* 430 */
};
C_ASSERT( offsetof(struct exc_stack_layout, rec) == 0x390 );
C_ASSERT( sizeof(struct exc_stack_layout) == 0x440 );
/* stack layout when calling KiUserApcDispatcher */
struct apc_stack_layout
{
void *func; /* 000 APC to call*/
ULONG64 args[3]; /* 008 function arguments */
ULONG64 alertable; /* 020 */
ULONG64 align; /* 028 */
CONTEXT context; /* 030 */
ULONG64 redzone[2]; /* 3c0 */
};
C_ASSERT( offsetof(struct apc_stack_layout, context) == 0x30 );
C_ASSERT( sizeof(struct apc_stack_layout) == 0x3d0 );
/* stack layout when calling KiUserCallbackDispatcher */
struct callback_stack_layout
{
void *args; /* 000 arguments */
ULONG len; /* 008 arguments len */
ULONG id; /* 00c function id */
ULONG64 unknown; /* 010 */
ULONG64 lr; /* 018 */
ULONG64 sp; /* 020 sp+pc (machine frame) */
ULONG64 pc; /* 028 */
BYTE args_data[0]; /* 030 copied argument data*/
};
C_ASSERT( offsetof(struct callback_stack_layout, sp) == 0x20 );
C_ASSERT( sizeof(struct callback_stack_layout) == 0x30 );
struct syscall_frame
{
ULONG64 x[29]; /* 000 */
ULONG64 fp; /* 0e8 */
ULONG64 lr; /* 0f0 */
ULONG64 sp; /* 0f8 */
ULONG64 pc; /* 100 */
ULONG cpsr; /* 108 */
ULONG restore_flags; /* 10c */
struct syscall_frame *prev_frame; /* 110 */
void *syscall_cfa; /* 118 */
ULONG64 align; /* 120 */
ULONG fpcr; /* 128 */
ULONG fpsr; /* 12c */
NEON128 v[32]; /* 130 */
};
C_ASSERT( sizeof( struct syscall_frame ) == 0x330 );
struct arm64_thread_data
{
struct syscall_frame *syscall_frame; /* 02f0 frame pointer on syscall entry */
SYSTEM_SERVICE_TABLE *syscall_table; /* 02f8 syscall table */
};
C_ASSERT( sizeof(struct arm64_thread_data) <= sizeof(((struct ntdll_thread_data *)0)->cpu_data) );
C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct arm64_thread_data, syscall_frame ) == 0x2f0 );
C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct arm64_thread_data, syscall_table ) == 0x2f8 );
static inline struct arm64_thread_data *arm64_thread_data(void)
{
return (struct arm64_thread_data *)ntdll_get_thread_data()->cpu_data;
}
static BOOL is_inside_syscall( ucontext_t *sigcontext )
{
return ((char *)SP_sig(sigcontext) >= (char *)ntdll_get_thread_data()->kernel_stack &&
(char *)SP_sig(sigcontext) <= (char *)arm64_thread_data()->syscall_frame);
}
/***********************************************************************
* unwind_builtin_dll
*
* Equivalent of RtlVirtualUnwind for builtin modules.
*/
NTSTATUS unwind_builtin_dll( void *args )
{
return STATUS_UNSUCCESSFUL;
}
/***********************************************************************
* syscall_frame_fixup_for_fastpath
*
* Fixes up the given syscall frame such that the syscall dispatcher
* can return via the fast path if CONTEXT_INTEGER is set in
* restore_flags.
*
* Clobbers the frame's X16 and X17 register values.
*/
static void syscall_frame_fixup_for_fastpath( struct syscall_frame *frame )
{
frame->x[16] = frame->pc;
frame->x[17] = frame->sp;
}
/***********************************************************************
* save_fpu
*
* Set the FPU context from a sigcontext.
*/
static void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
{
#ifdef linux
struct fpsimd_context *fp = get_fpsimd_context( sigcontext );
if (!fp) return;
context->ContextFlags |= CONTEXT_FLOATING_POINT;
context->Fpcr = fp->fpcr;
context->Fpsr = fp->fpsr;
memcpy( context->V, fp->vregs, sizeof(context->V) );
#elif defined(__APPLE__)
context->ContextFlags |= CONTEXT_FLOATING_POINT;
context->Fpcr = sigcontext->uc_mcontext->__ns.__fpcr;
context->Fpsr = sigcontext->uc_mcontext->__ns.__fpsr;
memcpy( context->V, sigcontext->uc_mcontext->__ns.__v, sizeof(context->V) );
#endif
}
/***********************************************************************
* restore_fpu
*
* Restore the FPU context to a sigcontext.
*/
static void restore_fpu( const CONTEXT *context, ucontext_t *sigcontext )
{
#ifdef linux
struct fpsimd_context *fp = get_fpsimd_context( sigcontext );
if (!fp) return;
fp->fpcr = context->Fpcr;
fp->fpsr = context->Fpsr;
memcpy( fp->vregs, context->V, sizeof(fp->vregs) );
#elif defined(__APPLE__)
sigcontext->uc_mcontext->__ns.__fpcr = context->Fpcr;
sigcontext->uc_mcontext->__ns.__fpsr = context->Fpsr;
memcpy( sigcontext->uc_mcontext->__ns.__v, context->V, sizeof(context->V) );
#endif
}
/***********************************************************************
* save_context
*
* Set the register values from a sigcontext.
*/
static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
{
DWORD i;
context->ContextFlags = CONTEXT_FULL;
context->Fp = FP_sig(sigcontext); /* Frame pointer */
context->Lr = LR_sig(sigcontext); /* Link register */
context->Sp = SP_sig(sigcontext); /* Stack pointer */
context->Pc = PC_sig(sigcontext); /* Program Counter */
context->Cpsr = PSTATE_sig(sigcontext); /* Current State Register */
for (i = 0; i <= 28; i++) context->X[i] = REGn_sig( i, sigcontext );
save_fpu( context, sigcontext );
}
/***********************************************************************
* restore_context
*
* Build a sigcontext from the register values.
*/
static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
{
DWORD i;
FP_sig(sigcontext) = context->Fp; /* Frame pointer */
LR_sig(sigcontext) = context->Lr; /* Link register */
SP_sig(sigcontext) = context->Sp; /* Stack pointer */
PC_sig(sigcontext) = context->Pc; /* Program Counter */
PSTATE_sig(sigcontext) = context->Cpsr; /* Current State Register */
for (i = 0; i <= 28; i++) REGn_sig( i, sigcontext ) = context->X[i];
restore_fpu( context, sigcontext );
}
/***********************************************************************
* signal_set_full_context
*/
NTSTATUS signal_set_full_context( CONTEXT *context )
{
NTSTATUS status = NtSetContextThread( GetCurrentThread(), context );
if (!status && (context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
arm64_thread_data()->syscall_frame->restore_flags |= CONTEXT_INTEGER;
return status;
}
/***********************************************************************
* get_native_context
*/
void *get_native_context( CONTEXT *context )
{
return context;
}
/***********************************************************************
* get_wow_context
*/
void *get_wow_context( CONTEXT *context )
{
return get_cpu_area( main_image_info.Machine );
}
/***********************************************************************
* NtSetContextThread (NTDLL.@)
* ZwSetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
{
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
NTSTATUS ret = STATUS_SUCCESS;
BOOL self = (handle == GetCurrentThread());
DWORD flags = context->ContextFlags & ~CONTEXT_ARM64;
if (self && (flags & CONTEXT_DEBUG_REGISTERS)) self = FALSE;
if (!self)
{
ret = set_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_ARM64 );
if (ret || !self) return ret;
}
if (flags & CONTEXT_INTEGER)
{
memcpy( frame->x, context->X, sizeof(context->X[0]) * 18 );
/* skip x18 */
memcpy( frame->x + 19, context->X + 19, sizeof(context->X[0]) * 10 );
}
if (flags & CONTEXT_CONTROL)
{
frame->fp = context->Fp;
frame->lr = context->Lr;
frame->sp = context->Sp;
frame->pc = context->Pc;
frame->cpsr = context->Cpsr;
}
if (flags & CONTEXT_FLOATING_POINT)
{
frame->fpcr = context->Fpcr;
frame->fpsr = context->Fpsr;
memcpy( frame->v, context->V, sizeof(frame->v) );
}
if (flags & CONTEXT_ARM64_X18)
{
frame->x[18] = context->X[18];
}
if (flags & CONTEXT_DEBUG_REGISTERS) FIXME( "debug registers not supported\n" );
frame->restore_flags |= flags & ~CONTEXT_INTEGER;
return STATUS_SUCCESS;
}
/***********************************************************************
* NtGetContextThread (NTDLL.@)
* ZwGetContextThread (NTDLL.@)
*/
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
{
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
DWORD needed_flags = context->ContextFlags & ~CONTEXT_ARM64;
BOOL self = (handle == GetCurrentThread());
if (!self)
{
NTSTATUS ret = get_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_ARM64 );
if (ret || !self) return ret;
}
if (needed_flags & CONTEXT_INTEGER)
{
memcpy( context->X, frame->x, sizeof(context->X[0]) * 29 );
context->ContextFlags |= CONTEXT_INTEGER;
}
if (needed_flags & CONTEXT_CONTROL)
{
context->Fp = frame->fp;
context->Lr = frame->lr;
context->Sp = frame->sp;
context->Pc = frame->pc;
context->Cpsr = frame->cpsr;
context->ContextFlags |= CONTEXT_CONTROL;
}
if (needed_flags & CONTEXT_FLOATING_POINT)
{
context->Fpcr = frame->fpcr;
context->Fpsr = frame->fpsr;
memcpy( context->V, frame->v, sizeof(context->V) );
context->ContextFlags |= CONTEXT_FLOATING_POINT;
}
if (needed_flags & CONTEXT_DEBUG_REGISTERS) FIXME( "debug registers not supported\n" );
return STATUS_SUCCESS;
}
/***********************************************************************
* set_thread_wow64_context
*/
NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size )
{
BOOL self = (handle == GetCurrentThread());
USHORT machine;
void *frame;
switch (size)
{
case sizeof(I386_CONTEXT): machine = IMAGE_FILE_MACHINE_I386; break;
case sizeof(ARM_CONTEXT): machine = IMAGE_FILE_MACHINE_ARMNT; break;
default: return STATUS_INFO_LENGTH_MISMATCH;
}
if (!self)
{
NTSTATUS ret = set_thread_context( handle, ctx, &self, machine );
if (ret || !self) return ret;
}
if (!(frame = get_cpu_area( machine ))) return STATUS_INVALID_PARAMETER;
switch (machine)
{
case IMAGE_FILE_MACHINE_I386:
{
I386_CONTEXT *wow_frame = frame;
const I386_CONTEXT *context = ctx;
DWORD flags = context->ContextFlags & ~CONTEXT_i386;
if (flags & CONTEXT_I386_INTEGER)
{
wow_frame->Eax = context->Eax;
wow_frame->Ebx = context->Ebx;
wow_frame->Ecx = context->Ecx;
wow_frame->Edx = context->Edx;
wow_frame->Esi = context->Esi;
wow_frame->Edi = context->Edi;
}
if (flags & CONTEXT_I386_CONTROL)
{
WOW64_CPURESERVED *cpu = NtCurrentTeb()->TlsSlots[WOW64_TLS_CPURESERVED];
wow_frame->Esp = context->Esp;
wow_frame->Ebp = context->Ebp;
wow_frame->Eip = context->Eip;
wow_frame->EFlags = context->EFlags;
wow_frame->SegCs = context->SegCs;
wow_frame->SegSs = context->SegSs;
cpu->Flags |= WOW64_CPURESERVED_FLAG_RESET_STATE;
}
if (flags & CONTEXT_I386_SEGMENTS)
{
wow_frame->SegDs = context->SegDs;
wow_frame->SegEs = context->SegEs;
wow_frame->SegFs = context->SegFs;
wow_frame->SegGs = context->SegGs;
}
if (flags & CONTEXT_I386_DEBUG_REGISTERS)
{
wow_frame->Dr0 = context->Dr0;
wow_frame->Dr1 = context->Dr1;
wow_frame->Dr2 = context->Dr2;
wow_frame->Dr3 = context->Dr3;
wow_frame->Dr6 = context->Dr6;
wow_frame->Dr7 = context->Dr7;
}
if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
{
memcpy( &wow_frame->ExtendedRegisters, context->ExtendedRegisters, sizeof(context->ExtendedRegisters) );
}
if (flags & CONTEXT_I386_FLOATING_POINT)
{
memcpy( &wow_frame->FloatSave, &context->FloatSave, sizeof(context->FloatSave) );
}
/* FIXME: CONTEXT_I386_XSTATE */
break;
}
case IMAGE_FILE_MACHINE_ARMNT:
{
ARM_CONTEXT *wow_frame = frame;
const ARM_CONTEXT *context = ctx;
DWORD flags = context->ContextFlags & ~CONTEXT_ARM;
if (flags & CONTEXT_INTEGER)
{
wow_frame->R0 = context->R0;
wow_frame->R1 = context->R1;
wow_frame->R2 = context->R2;
wow_frame->R3 = context->R3;
wow_frame->R4 = context->R4;
wow_frame->R5 = context->R5;
wow_frame->R6 = context->R6;
wow_frame->R7 = context->R7;
wow_frame->R8 = context->R8;
wow_frame->R9 = context->R9;
wow_frame->R10 = context->R10;
wow_frame->R11 = context->R11;
wow_frame->R12 = context->R12;
}
if (flags & CONTEXT_CONTROL)
{
wow_frame->Sp = context->Sp;
wow_frame->Lr = context->Lr;
wow_frame->Pc = context->Pc & ~1;
wow_frame->Cpsr = context->Cpsr;
if (context->Cpsr & 0x20) wow_frame->Pc |= 1; /* thumb */
}
if (flags & CONTEXT_FLOATING_POINT)
{
wow_frame->Fpscr = context->Fpscr;
memcpy( wow_frame->D, context->D, sizeof(context->D) );
}
break;
}
}
return STATUS_SUCCESS;
}
/***********************************************************************
* get_thread_wow64_context
*/
NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size )
{
BOOL self = (handle == GetCurrentThread());
USHORT machine;
void *frame;
switch (size)
{
case sizeof(I386_CONTEXT): machine = IMAGE_FILE_MACHINE_I386; break;
case sizeof(ARM_CONTEXT): machine = IMAGE_FILE_MACHINE_ARMNT; break;
default: return STATUS_INFO_LENGTH_MISMATCH;
}
if (!self)
{
NTSTATUS ret = get_thread_context( handle, ctx, &self, machine );
if (ret || !self) return ret;
}
if (!(frame = get_cpu_area( machine ))) return STATUS_INVALID_PARAMETER;
switch (machine)
{
case IMAGE_FILE_MACHINE_I386:
{
I386_CONTEXT *wow_frame = frame, *context = ctx;
DWORD needed_flags = context->ContextFlags & ~CONTEXT_i386;
if (needed_flags & CONTEXT_I386_INTEGER)
{
context->Eax = wow_frame->Eax;
context->Ebx = wow_frame->Ebx;
context->Ecx = wow_frame->Ecx;
context->Edx = wow_frame->Edx;
context->Esi = wow_frame->Esi;
context->Edi = wow_frame->Edi;
context->ContextFlags |= CONTEXT_I386_INTEGER;
}
if (needed_flags & CONTEXT_I386_CONTROL)
{
context->Esp = wow_frame->Esp;
context->Ebp = wow_frame->Ebp;
context->Eip = wow_frame->Eip;
context->EFlags = wow_frame->EFlags;
context->SegCs = wow_frame->SegCs;
context->SegSs = wow_frame->SegSs;
context->ContextFlags |= CONTEXT_I386_CONTROL;
}
if (needed_flags & CONTEXT_I386_SEGMENTS)
{
context->SegDs = wow_frame->SegDs;
context->SegEs = wow_frame->SegEs;
context->SegFs = wow_frame->SegFs;
context->SegGs = wow_frame->SegGs;
context->ContextFlags |= CONTEXT_I386_SEGMENTS;
}
if (needed_flags & CONTEXT_I386_EXTENDED_REGISTERS)
{
memcpy( context->ExtendedRegisters, &wow_frame->ExtendedRegisters, sizeof(context->ExtendedRegisters) );
context->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
}
if (needed_flags & CONTEXT_I386_FLOATING_POINT)
{
memcpy( &context->FloatSave, &wow_frame->FloatSave, sizeof(context->FloatSave) );
context->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
}
if (needed_flags & CONTEXT_I386_DEBUG_REGISTERS)
{
context->Dr0 = wow_frame->Dr0;
context->Dr1 = wow_frame->Dr1;
context->Dr2 = wow_frame->Dr2;
context->Dr3 = wow_frame->Dr3;
context->Dr6 = wow_frame->Dr6;
context->Dr7 = wow_frame->Dr7;
}
/* FIXME: CONTEXT_I386_XSTATE */
break;
}
case IMAGE_FILE_MACHINE_ARMNT:
{
ARM_CONTEXT *wow_frame = frame, *context = ctx;
DWORD needed_flags = context->ContextFlags & ~CONTEXT_ARM;
if (needed_flags & CONTEXT_INTEGER)
{
context->R0 = wow_frame->R0;
context->R1 = wow_frame->R1;
context->R2 = wow_frame->R2;
context->R3 = wow_frame->R3;
context->R4 = wow_frame->R4;
context->R5 = wow_frame->R5;
context->R6 = wow_frame->R6;
context->R7 = wow_frame->R7;
context->R8 = wow_frame->R8;
context->R9 = wow_frame->R9;
context->R10 = wow_frame->R10;
context->R11 = wow_frame->R11;
context->R12 = wow_frame->R12;
context->ContextFlags |= CONTEXT_INTEGER;
}
if (needed_flags & CONTEXT_CONTROL)
{
context->Sp = wow_frame->Sp;
context->Lr = wow_frame->Lr;
context->Pc = wow_frame->Pc;
context->Cpsr = wow_frame->Cpsr;
context->ContextFlags |= CONTEXT_CONTROL;
}
if (needed_flags & CONTEXT_FLOATING_POINT)
{
context->Fpscr = wow_frame->Fpscr;
memcpy( context->D, wow_frame->D, sizeof(wow_frame->D) );
context->ContextFlags |= CONTEXT_FLOATING_POINT;
}
break;
}
}
return STATUS_SUCCESS;
}
/***********************************************************************
* setup_raise_exception
*/
static void setup_raise_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec, CONTEXT *context )
{
struct exc_stack_layout *stack;
void *stack_ptr = (void *)(SP_sig(sigcontext) & ~15);
NTSTATUS status;
status = send_debug_event( rec, context, TRUE );
if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
{
restore_context( context, sigcontext );
return;
}
/* fix up instruction pointer in context for EXCEPTION_BREAKPOINT */
if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Pc -= 4;
stack = virtual_setup_exception( stack_ptr, sizeof(*stack), rec );
stack->rec = *rec;
stack->context = *context;
SP_sig(sigcontext) = (ULONG_PTR)stack;
PC_sig(sigcontext) = (ULONG_PTR)pKiUserExceptionDispatcher;
REGn_sig(18, sigcontext) = (ULONG_PTR)NtCurrentTeb();
}
/***********************************************************************
* setup_exception
*
* Modify the signal context to call the exception raise function.
*/
static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
{
CONTEXT context;
rec->ExceptionAddress = (void *)PC_sig(sigcontext);
save_context( &context, sigcontext );
setup_raise_exception( sigcontext, rec, &context );
}
/***********************************************************************
* call_user_apc_dispatcher
*/
NTSTATUS call_user_apc_dispatcher( CONTEXT *context, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3,
PNTAPCFUNC func, NTSTATUS status )
{
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
ULONG64 sp = context ? context->Sp : frame->sp;
struct apc_stack_layout *stack;
sp &= ~15;
stack = (struct apc_stack_layout *)sp - 1;
if (context)
{
memmove( &stack->context, context, sizeof(stack->context) );
NtSetContextThread( GetCurrentThread(), &stack->context );
}
else
{
stack->context.ContextFlags = CONTEXT_FULL;
NtGetContextThread( GetCurrentThread(), &stack->context );
stack->context.X0 = status;
}
stack->func = func;
stack->args[0] = arg1;
stack->args[1] = arg2;
stack->args[2] = arg3;
stack->alertable = TRUE;
frame->sp = (ULONG64)stack;
frame->pc = (ULONG64)pKiUserApcDispatcher;
frame->restore_flags |= CONTEXT_CONTROL;
syscall_frame_fixup_for_fastpath( frame );
return status;
}
/***********************************************************************
* call_raise_user_exception_dispatcher
*/
void call_raise_user_exception_dispatcher(void)
{
arm64_thread_data()->syscall_frame->pc = (UINT64)pKiRaiseUserExceptionDispatcher;
}
/***********************************************************************
* call_user_exception_dispatcher
*/
NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context )
{
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
struct exc_stack_layout *stack;
NTSTATUS status = NtSetContextThread( GetCurrentThread(), context );
if (status) return status;
stack = (struct exc_stack_layout *)(context->Sp & ~15) - 1;
memmove( &stack->context, context, sizeof(*context) );
memmove( &stack->rec, rec, sizeof(*rec) );
frame->pc = (ULONG64)pKiUserExceptionDispatcher;
frame->sp = (ULONG64)stack;
frame->restore_flags |= CONTEXT_CONTROL;
syscall_frame_fixup_for_fastpath( frame );
return status;
}
/***********************************************************************
* call_user_mode_callback
*/
extern NTSTATUS call_user_mode_callback( ULONG64 user_sp, void **ret_ptr, ULONG *ret_len,
void *func, TEB *teb );
__ASM_GLOBAL_FUNC( call_user_mode_callback,
"stp x29, x30, [sp,#-0xc0]!\n\t"
__ASM_CFI(".cfi_def_cfa_offset 0xc0\n\t")
__ASM_CFI(".cfi_offset 29,-0xc0\n\t")
__ASM_CFI(".cfi_offset 30,-0xb8\n\t")
"mov x29, sp\n\t"
__ASM_CFI(".cfi_def_cfa_register 29\n\t")
"stp x19, x20, [x29, #0x10]\n\t"
__ASM_CFI(".cfi_rel_offset 19,0x10\n\t")
__ASM_CFI(".cfi_rel_offset 20,0x18\n\t")
"stp x21, x22, [x29, #0x20]\n\t"
__ASM_CFI(".cfi_rel_offset 21,0x20\n\t")
__ASM_CFI(".cfi_rel_offset 22,0x28\n\t")
"stp x23, x24, [x29, #0x30]\n\t"
__ASM_CFI(".cfi_rel_offset 23,0x30\n\t")
__ASM_CFI(".cfi_rel_offset 24,0x38\n\t")
"stp x25, x26, [x29, #0x40]\n\t"
__ASM_CFI(".cfi_rel_offset 25,0x40\n\t")
__ASM_CFI(".cfi_rel_offset 26,0x48\n\t")
"stp x27, x28, [x29, #0x50]\n\t"
__ASM_CFI(".cfi_rel_offset 27,0x50\n\t")
__ASM_CFI(".cfi_rel_offset 28,0x58\n\t")
"stp d8, d9, [x29, #0x60]\n\t"
"stp d10, d11, [x29, #0x70]\n\t"
"stp d12, d13, [x29, #0x80]\n\t"
"stp d14, d15, [x29, #0x90]\n\t"
"stp x1, x2, [x29, #0xa0]\n\t" /* ret_ptr, ret_len */
"mov x18, x4\n\t" /* teb */
"mrs x1, fpcr\n\t"
"mrs x2, fpsr\n\t"
"bfi x1, x2, #0, #32\n\t"
"ldr x2, [x18]\n\t" /* teb->Tib.ExceptionList */
"stp x1, x2, [x29, #0xb0]\n\t"
"ldr x7, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
"sub x1, sp, #0x330\n\t" /* sizeof(struct syscall_frame) */
"str x1, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
"add x8, x29, #0xc0\n\t"
"stp x7, x8, [x1, #0x110]\n\t" /* frame->prev_frame,syscall_cfa */
/* switch to user stack */
"mov sp, x0\n\t" /* user_sp */
"br x3" )
/***********************************************************************
* user_mode_callback_return
*/
extern void DECLSPEC_NORETURN user_mode_callback_return( void *ret_ptr, ULONG ret_len,
NTSTATUS status, TEB *teb );
__ASM_GLOBAL_FUNC( user_mode_callback_return,
"ldr x4, [x3, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
"ldp x5, x29, [x4,#0x110]\n\t" /* prev_frame,syscall_cfa */
"str x5, [x3, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
"sub x29, x29, #0xc0\n\t"
__ASM_CFI(".cfi_def_cfa_register 29\n\t")
__ASM_CFI(".cfi_rel_offset 29,0x00\n\t")
__ASM_CFI(".cfi_rel_offset 30,0x08\n\t")
__ASM_CFI(".cfi_rel_offset 19,0x10\n\t")
__ASM_CFI(".cfi_rel_offset 20,0x18\n\t")
__ASM_CFI(".cfi_rel_offset 21,0x20\n\t")
__ASM_CFI(".cfi_rel_offset 22,0x28\n\t")
__ASM_CFI(".cfi_rel_offset 23,0x30\n\t")
__ASM_CFI(".cfi_rel_offset 24,0x38\n\t")
__ASM_CFI(".cfi_rel_offset 25,0x40\n\t")
__ASM_CFI(".cfi_rel_offset 26,0x48\n\t")
__ASM_CFI(".cfi_rel_offset 27,0x50\n\t")
__ASM_CFI(".cfi_rel_offset 28,0x58\n\t")
"ldp x5, x6, [x29, #0xb0]\n\t"
"str x6, [x3]\n\t" /* teb->Tib.ExceptionList */
"msr fpcr, x5\n\t"
"lsr x5, x5, #32\n\t"
"msr fpsr, x5\n\t"
"ldp x19, x20, [x29, #0x10]\n\t"
__ASM_CFI(".cfi_same_value 19\n\t")
__ASM_CFI(".cfi_same_value 20\n\t")
"ldp x21, x22, [x29, #0x20]\n\t"
__ASM_CFI(".cfi_same_value 21\n\t")
__ASM_CFI(".cfi_same_value 22\n\t")
"ldp x23, x24, [x29, #0x30]\n\t"
__ASM_CFI(".cfi_same_value 23\n\t")
__ASM_CFI(".cfi_same_value 24\n\t")
"ldp x25, x26, [x29, #0x40]\n\t"
__ASM_CFI(".cfi_same_value 25\n\t")
__ASM_CFI(".cfi_same_value 26\n\t")
"ldp x27, x28, [x29, #0x50]\n\t"
__ASM_CFI(".cfi_same_value 27\n\t")
__ASM_CFI(".cfi_same_value 28\n\t")
"ldp d8, d9, [x29, #0x60]\n\t"
"ldp d10, d11, [x29, #0x70]\n\t"
"ldp d12, d13, [x29, #0x80]\n\t"
"ldp d14, d15, [x29, #0x90]\n\t"
"ldp x5, x6, [x29, #0xa0]\n\t" /* ret_ptr, ret_len */
"str x0, [x5]\n\t" /* ret_ptr */
"str w1, [x6]\n\t" /* ret_len */
"mov x0, x2\n\t" /* status */
"mov sp, x29\n\t"
"ldp x29, x30, [sp], #0xc0\n\t"
"ret" )
/***********************************************************************
* user_mode_abort_thread
*/
extern void DECLSPEC_NORETURN user_mode_abort_thread( NTSTATUS status, struct syscall_frame *frame );
__ASM_GLOBAL_FUNC( user_mode_abort_thread,
"ldr x1, [x1, #0x110]\n\t" /* frame->syscall_cfa */
"sub x29, x1, #0xc0\n\t"
/* switch to kernel stack */
"mov sp, x29\n\t"
__ASM_CFI(".cfi_def_cfa 29,0xc0\n\t")
__ASM_CFI(".cfi_offset 29,-0xc0\n\t")
__ASM_CFI(".cfi_offset 30,-0xb8\n\t")
__ASM_CFI(".cfi_offset 19,-0xb0\n\t")
__ASM_CFI(".cfi_offset 20,-0xa8\n\t")
__ASM_CFI(".cfi_offset 21,-0xa0\n\t")
__ASM_CFI(".cfi_offset 22,-0x98\n\t")
__ASM_CFI(".cfi_offset 23,-0x90\n\t")
__ASM_CFI(".cfi_offset 24,-0x88\n\t")
__ASM_CFI(".cfi_offset 25,-0x80\n\t")
__ASM_CFI(".cfi_offset 26,-0x78\n\t")
__ASM_CFI(".cfi_offset 27,-0x70\n\t")
__ASM_CFI(".cfi_offset 28,-0x68\n\t")
"bl " __ASM_NAME("abort_thread") )
/***********************************************************************
* KeUserModeCallback
*/
NTSTATUS KeUserModeCallback( ULONG id, const void *args, ULONG len, void **ret_ptr, ULONG *ret_len )
{
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
ULONG64 sp = (frame->sp - offsetof( struct callback_stack_layout, args_data[len] ) - 16) & ~15;
struct callback_stack_layout *stack = (struct callback_stack_layout *)sp;
if ((char *)ntdll_get_thread_data()->kernel_stack + min_kernel_stack > (char *)&frame)
return STATUS_STACK_OVERFLOW;
stack->args = stack->args_data;
stack->len = len;
stack->id = id;
stack->lr = frame->lr;
stack->sp = frame->sp;
stack->pc = frame->pc;
memcpy( stack->args_data, args, len );
return call_user_mode_callback( sp, ret_ptr, ret_len, pKiUserCallbackDispatcher, NtCurrentTeb() );
}
/***********************************************************************
* NtCallbackReturn (NTDLL.@)
*/
NTSTATUS WINAPI NtCallbackReturn( void *ret_ptr, ULONG ret_len, NTSTATUS status )
{
if (!arm64_thread_data()->syscall_frame->prev_frame) return STATUS_NO_CALLBACK_ACTIVE;
user_mode_callback_return( ret_ptr, ret_len, status, NtCurrentTeb() );
}
/***********************************************************************
* handle_syscall_fault
*
* Handle a page fault happening during a system call.
*/
static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec )
{
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
DWORD i;
if (!is_inside_syscall( context )) return FALSE;
TRACE( "code=%x flags=%x addr=%p pc=%p tid=%04x\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
(void *)PC_sig(context), GetCurrentThreadId() );
for (i = 0; i < rec->NumberParameters; i++)
TRACE( " info[%d]=%016lx\n", i, rec->ExceptionInformation[i] );
TRACE(" x0=%016lx x1=%016lx x2=%016lx x3=%016lx\n",
(DWORD64)REGn_sig(0, context), (DWORD64)REGn_sig(1, context),
(DWORD64)REGn_sig(2, context), (DWORD64)REGn_sig(3, context) );
TRACE(" x4=%016lx x5=%016lx x6=%016lx x7=%016lx\n",
(DWORD64)REGn_sig(4, context), (DWORD64)REGn_sig(5, context),
(DWORD64)REGn_sig(6, context), (DWORD64)REGn_sig(7, context) );
TRACE(" x8=%016lx x9=%016lx x10=%016lx x11=%016lx\n",
(DWORD64)REGn_sig(8, context), (DWORD64)REGn_sig(9, context),
(DWORD64)REGn_sig(10, context), (DWORD64)REGn_sig(11, context) );
TRACE(" x12=%016lx x13=%016lx x14=%016lx x15=%016lx\n",
(DWORD64)REGn_sig(12, context), (DWORD64)REGn_sig(13, context),
(DWORD64)REGn_sig(14, context), (DWORD64)REGn_sig(15, context) );
TRACE(" x16=%016lx x17=%016lx x18=%016lx x19=%016lx\n",
(DWORD64)REGn_sig(16, context), (DWORD64)REGn_sig(17, context),
(DWORD64)REGn_sig(18, context), (DWORD64)REGn_sig(19, context) );
TRACE(" x20=%016lx x21=%016lx x22=%016lx x23=%016lx\n",
(DWORD64)REGn_sig(20, context), (DWORD64)REGn_sig(21, context),
(DWORD64)REGn_sig(22, context), (DWORD64)REGn_sig(23, context) );
TRACE(" x24=%016lx x25=%016lx x26=%016lx x27=%016lx\n",
(DWORD64)REGn_sig(24, context), (DWORD64)REGn_sig(25, context),
(DWORD64)REGn_sig(26, context), (DWORD64)REGn_sig(27, context) );
TRACE(" x28=%016lx fp=%016lx lr=%016lx sp=%016lx\n",
(DWORD64)REGn_sig(28, context), (DWORD64)FP_sig(context),
(DWORD64)LR_sig(context), (DWORD64)SP_sig(context) );
if (ntdll_get_thread_data()->jmp_buf)
{
TRACE( "returning to handler\n" );
REGn_sig(0, context) = (ULONG_PTR)ntdll_get_thread_data()->jmp_buf;
REGn_sig(1, context) = 1;
PC_sig(context) = (ULONG_PTR)longjmp;
ntdll_get_thread_data()->jmp_buf = NULL;
}
else
{
TRACE( "returning to user mode ip=%p ret=%08x\n", (void *)frame->pc, rec->ExceptionCode );
REGn_sig(0, context) = (ULONG_PTR)frame;
REGn_sig(1, context) = rec->ExceptionCode;
PC_sig(context) = (ULONG_PTR)__wine_syscall_dispatcher_return;
}
return TRUE;
}
/**********************************************************************
* segv_handler
*
* Handler for SIGSEGV.
*/
static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
EXCEPTION_RECORD rec = { 0 };
ucontext_t *context = sigcontext;
rec.NumberParameters = 2;
rec.ExceptionInformation[0] = (get_fault_esr( context ) & 0x40) != 0;
rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr;
rec.ExceptionCode = virtual_handle_fault( siginfo->si_addr, rec.ExceptionInformation[0],
(void *)SP_sig(context) );
if (!rec.ExceptionCode) return;
if (handle_syscall_fault( context, &rec )) return;
setup_exception( context, &rec );
}
/**********************************************************************
* ill_handler
*
* Handler for SIGILL.
*/
static void ill_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
EXCEPTION_RECORD rec = { EXCEPTION_ILLEGAL_INSTRUCTION };
setup_exception( sigcontext, &rec );
}
/**********************************************************************
* bus_handler
*
* Handler for SIGBUS.
*/
static void bus_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
EXCEPTION_RECORD rec = { EXCEPTION_DATATYPE_MISALIGNMENT };
setup_exception( sigcontext, &rec );
}
/**********************************************************************
* trap_handler
*
* Handler for SIGTRAP.
*/
static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
EXCEPTION_RECORD rec = { 0 };
ucontext_t *context = sigcontext;
CONTEXT ctx;
rec.ExceptionAddress = (void *)PC_sig(context);
save_context( &ctx, sigcontext );
switch (siginfo->si_code)
{
case TRAP_TRACE:
rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
break;
case TRAP_BRKPT:
default:
/* debug exceptions do not update ESR on Linux, so we fetch the instruction directly. */
if (!(PSTATE_sig( context ) & 0x10) && /* AArch64 (not WoW) */
!(PC_sig( context ) & 3) &&
*(ULONG *)PC_sig( context ) == 0xd43e0060UL) /* brk #0xf003 -> __fastfail */
{
rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
rec.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
rec.NumberParameters = 1;
rec.ExceptionInformation[0] = ctx.X[0];
NtRaiseException( &rec, &ctx, FALSE );
return;
}
ctx.Pc += 4; /* skip the brk instruction */
rec.ExceptionCode = EXCEPTION_BREAKPOINT;
rec.NumberParameters = 1;
break;
}
setup_raise_exception( sigcontext, &rec, &ctx );
}
/**********************************************************************
* fpe_handler
*
* Handler for SIGFPE.
*/
static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
EXCEPTION_RECORD rec = { 0 };
switch (siginfo->si_code & 0xffff )
{
#ifdef FPE_FLTSUB
case FPE_FLTSUB:
rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
break;
#endif
#ifdef FPE_INTDIV
case FPE_INTDIV:
rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
break;
#endif
#ifdef FPE_INTOVF
case FPE_INTOVF:
rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
break;
#endif
#ifdef FPE_FLTDIV
case FPE_FLTDIV:
rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
break;
#endif
#ifdef FPE_FLTOVF
case FPE_FLTOVF:
rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
break;
#endif
#ifdef FPE_FLTUND
case FPE_FLTUND:
rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
break;
#endif
#ifdef FPE_FLTRES
case FPE_FLTRES:
rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
break;
#endif
#ifdef FPE_FLTINV
case FPE_FLTINV:
#endif
default:
rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
break;
}
setup_exception( sigcontext, &rec );
}
/**********************************************************************
* int_handler
*
* Handler for SIGINT.
*/
static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
HANDLE handle;
if (!p__wine_ctrl_routine) return;
if (!NtCreateThreadEx( &handle, THREAD_ALL_ACCESS, NULL, NtCurrentProcess(),
p__wine_ctrl_routine, 0 /* CTRL_C_EVENT */, 0, 0, 0, 0, NULL ))
NtClose( handle );
}
/**********************************************************************
* abrt_handler
*
* Handler for SIGABRT.
*/
static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
EXCEPTION_RECORD rec = { EXCEPTION_WINE_ASSERTION, EXCEPTION_NONCONTINUABLE };
setup_exception( sigcontext, &rec );
}
/**********************************************************************
* quit_handler
*
* Handler for SIGQUIT.
*/
static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
if (!is_inside_syscall( sigcontext )) user_mode_abort_thread( 0, arm64_thread_data()->syscall_frame );
abort_thread(0);
}
/**********************************************************************
* usr1_handler
*
* Handler for SIGUSR1, used to signal a thread that it got suspended.
*/
static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
CONTEXT context;
if (is_inside_syscall( sigcontext ))
{
context.ContextFlags = CONTEXT_FULL;
NtGetContextThread( GetCurrentThread(), &context );
wait_suspend( &context );
NtSetContextThread( GetCurrentThread(), &context );
}
else
{
save_context( &context, sigcontext );
wait_suspend( &context );
restore_context( &context, sigcontext );
}
}
/**********************************************************************
* usr2_handler
*
* Handler for SIGUSR2, used to set a thread context.
*/
static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext )
{
struct syscall_frame *frame = arm64_thread_data()->syscall_frame;
ucontext_t *context = sigcontext;
DWORD i;
if (!is_inside_syscall( sigcontext )) return;
FP_sig(context) = frame->fp;
LR_sig(context) = frame->lr;
SP_sig(context) = frame->sp;
PC_sig(context) = frame->pc;
PSTATE_sig(context) = frame->cpsr;
for (i = 0; i <= 28; i++) REGn_sig( i, context ) = frame->x[i];
#ifdef linux
{
struct fpsimd_context *fp = get_fpsimd_context( sigcontext );
if (fp)
{
fp->fpcr = frame->fpcr;
fp->fpsr = frame->fpsr;
memcpy( fp->vregs, frame->v, sizeof(fp->vregs) );
}
}
#elif defined(__APPLE__)
context->uc_mcontext->__ns.__fpcr = frame->fpcr;
context->uc_mcontext->__ns.__fpsr = frame->fpsr;
memcpy( context->uc_mcontext->__ns.__v, frame->v, sizeof(frame->v) );
#endif
}
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}
/******************************************************************************
* NtSetLdtEntries (NTDLL.@)
* ZwSetLdtEntries (NTDLL.@)
*/
NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 )
{
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* signal_init_threading
*/
void signal_init_threading(void)
{
}
/**********************************************************************
* signal_alloc_thread
*/
NTSTATUS signal_alloc_thread( TEB *teb )
{
return STATUS_SUCCESS;
}
/**********************************************************************
* signal_free_thread
*/
void signal_free_thread( TEB *teb )
{
}
/**********************************************************************
* signal_init_process
*/
void signal_init_process(void)
{
struct sigaction sig_act;
void *kernel_stack = (char *)ntdll_get_thread_data()->kernel_stack + kernel_stack_size;
arm64_thread_data()->syscall_frame = (struct syscall_frame *)kernel_stack - 1;
sig_act.sa_mask = server_block_set;
sig_act.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK;
sig_act.sa_sigaction = int_handler;
if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
sig_act.sa_sigaction = fpe_handler;
if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
sig_act.sa_sigaction = abrt_handler;
if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
sig_act.sa_sigaction = quit_handler;
if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
sig_act.sa_sigaction = usr1_handler;
if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
sig_act.sa_sigaction = usr2_handler;
if (sigaction( SIGUSR2, &sig_act, NULL ) == -1) goto error;
sig_act.sa_sigaction = trap_handler;
if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
sig_act.sa_sigaction = segv_handler;
if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
sig_act.sa_sigaction = ill_handler;
if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
sig_act.sa_sigaction = bus_handler;
if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
return;
error:
perror("sigaction");
exit(1);
}
/***********************************************************************
* syscall_dispatcher_return_slowpath
*/
void syscall_dispatcher_return_slowpath(void)
{
raise( SIGUSR2 );
}
/***********************************************************************
* call_init_thunk
*/
void call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb,
struct syscall_frame *frame, void *syscall_cfa )
{
struct arm64_thread_data *thread_data = (struct arm64_thread_data *)&teb->GdiTebBatch;
CONTEXT *ctx, context = { CONTEXT_ALL };
I386_CONTEXT *i386_context;
ARM_CONTEXT *arm_context;
thread_data->syscall_table = KeServiceDescriptorTable;
context.X0 = (DWORD64)entry;
context.X1 = (DWORD64)arg;
context.X18 = (DWORD64)teb;
context.Sp = (DWORD64)teb->Tib.StackBase;
context.Pc = (DWORD64)pRtlUserThreadStart;
if ((i386_context = get_cpu_area( IMAGE_FILE_MACHINE_I386 )))
{
XMM_SAVE_AREA32 *fpu = (XMM_SAVE_AREA32 *)i386_context->ExtendedRegisters;
i386_context->ContextFlags = CONTEXT_I386_ALL;
i386_context->Eax = (ULONG_PTR)entry;
i386_context->Ebx = (arg == peb ? (ULONG_PTR)wow_peb : (ULONG_PTR)arg);
i386_context->Esp = get_wow_teb( teb )->Tib.StackBase - 16;
i386_context->Eip = pLdrSystemDllInitBlock->pRtlUserThreadStart;
i386_context->SegCs = 0x23;
i386_context->SegDs = 0x2b;
i386_context->SegEs = 0x2b;
i386_context->SegFs = 0x53;
i386_context->SegGs = 0x2b;
i386_context->SegSs = 0x2b;
i386_context->EFlags = 0x202;
fpu->ControlWord = 0x27f;
fpu->MxCsr = 0x1f80;
fpux_to_fpu( &i386_context->FloatSave, fpu );
}
else if ((arm_context = get_cpu_area( IMAGE_FILE_MACHINE_ARMNT )))
{
arm_context->ContextFlags = CONTEXT_ARM_ALL;
arm_context->R0 = (ULONG_PTR)entry;
arm_context->R1 = (arg == peb ? (ULONG_PTR)wow_peb : (ULONG_PTR)arg);
arm_context->Sp = get_wow_teb( teb )->Tib.StackBase;
arm_context->Pc = pLdrSystemDllInitBlock->pRtlUserThreadStart;
if (arm_context->Pc & 1) arm_context->Cpsr |= 0x20; /* thumb mode */
}
if (suspend) wait_suspend( &context );
ctx = (CONTEXT *)((ULONG_PTR)context.Sp & ~15) - 1;
*ctx = context;
ctx->ContextFlags = CONTEXT_FULL;
memset( frame, 0, sizeof(*frame) );
NtSetContextThread( GetCurrentThread(), ctx );
frame->sp = (ULONG64)ctx;
frame->pc = (ULONG64)pLdrInitializeThunk;
frame->x[0] = (ULONG64)ctx;
frame->x[18] = (ULONG64)teb;
frame->restore_flags |= CONTEXT_INTEGER;
frame->syscall_cfa = syscall_cfa;
syscall_frame_fixup_for_fastpath( frame );
pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL );
__wine_syscall_dispatcher_return( frame, 0 );
}
/***********************************************************************
* signal_start_thread
*/
__ASM_GLOBAL_FUNC( signal_start_thread,
"stp x29, x30, [sp,#-0xc0]!\n\t"
__ASM_CFI(".cfi_def_cfa_offset 0xc0\n\t")
__ASM_CFI(".cfi_offset 29,-0xc0\n\t")
__ASM_CFI(".cfi_offset 30,-0xb8\n\t")
"mov x29, sp\n\t"
__ASM_CFI(".cfi_def_cfa_register 29\n\t")
"stp x19, x20, [x29, #0x10]\n\t"
__ASM_CFI(".cfi_rel_offset 19,0x10\n\t")
__ASM_CFI(".cfi_rel_offset 20,0x18\n\t")
"stp x21, x22, [x29, #0x20]\n\t"
__ASM_CFI(".cfi_rel_offset 21,0x20\n\t")
__ASM_CFI(".cfi_rel_offset 22,0x28\n\t")
"stp x23, x24, [x29, #0x30]\n\t"
__ASM_CFI(".cfi_rel_offset 23,0x30\n\t")
__ASM_CFI(".cfi_rel_offset 24,0x38\n\t")
"stp x25, x26, [x29, #0x40]\n\t"
__ASM_CFI(".cfi_rel_offset 25,0x40\n\t")
__ASM_CFI(".cfi_rel_offset 26,0x48\n\t")
"stp x27, x28, [x29, #0x50]\n\t"
__ASM_CFI(".cfi_rel_offset 27,0x50\n\t")
__ASM_CFI(".cfi_rel_offset 28,0x58\n\t")
"add x5, x29, #0xc0\n\t" /* syscall_cfa */
/* set syscall frame */
"ldr x4, [x3, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
"cbnz x4, 1f\n\t"
"sub x4, sp, #0x330\n\t" /* sizeof(struct syscall_frame) */
"str x4, [x3, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
/* switch to kernel stack */
"1:\tmov sp, x4\n\t"
"bl " __ASM_NAME("call_init_thunk") )
/***********************************************************************
* __wine_syscall_dispatcher
*/
__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
"ldr x10, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
"stp x18, x19, [x10, #0x90]\n\t"
"stp x20, x21, [x10, #0xa0]\n\t"
"stp x22, x23, [x10, #0xb0]\n\t"
"stp x24, x25, [x10, #0xc0]\n\t"
"stp x26, x27, [x10, #0xd0]\n\t"
"stp x28, x29, [x10, #0xe0]\n\t"
"mov x19, sp\n\t"
"stp x9, x19, [x10, #0xf0]\n\t"
"mrs x9, NZCV\n\t"
"stp x30, x9, [x10, #0x100]\n\t"
"mrs x9, FPCR\n\t"
"str w9, [x10, #0x128]\n\t"
"mrs x9, FPSR\n\t"
"str w9, [x10, #0x12c]\n\t"
"stp q0, q1, [x10, #0x130]\n\t"
"stp q2, q3, [x10, #0x150]\n\t"
"stp q4, q5, [x10, #0x170]\n\t"
"stp q6, q7, [x10, #0x190]\n\t"
"stp q8, q9, [x10, #0x1b0]\n\t"
"stp q10, q11, [x10, #0x1d0]\n\t"
"stp q12, q13, [x10, #0x1f0]\n\t"
"stp q14, q15, [x10, #0x210]\n\t"
"stp q16, q17, [x10, #0x230]\n\t"
"stp q18, q19, [x10, #0x250]\n\t"
"stp q20, q21, [x10, #0x270]\n\t"
"stp q22, q23, [x10, #0x290]\n\t"
"stp q24, q25, [x10, #0x2b0]\n\t"
"stp q26, q27, [x10, #0x2d0]\n\t"
"stp q28, q29, [x10, #0x2f0]\n\t"
"stp q30, q31, [x10, #0x310]\n\t"
"mov x22, x10\n\t"
/* switch to kernel stack */
"mov sp, x10\n\t"
/* we're now on the kernel stack, stitch unwind info with previous frame */
__ASM_CFI_CFA_IS_AT2(x22, 0x98, 0x02) /* frame->syscall_cfa */
__ASM_CFI(".cfi_offset 29, -0xc0\n\t")
__ASM_CFI(".cfi_offset 30, -0xb8\n\t")
__ASM_CFI(".cfi_offset 19, -0xb0\n\t")
__ASM_CFI(".cfi_offset 20, -0xa8\n\t")
__ASM_CFI(".cfi_offset 21, -0xa0\n\t")
__ASM_CFI(".cfi_offset 22, -0x98\n\t")
__ASM_CFI(".cfi_offset 23, -0x90\n\t")
__ASM_CFI(".cfi_offset 24, -0x88\n\t")
__ASM_CFI(".cfi_offset 25, -0x80\n\t")
__ASM_CFI(".cfi_offset 26, -0x78\n\t")
__ASM_CFI(".cfi_offset 27, -0x70\n\t")
__ASM_CFI(".cfi_offset 28, -0x68\n\t")
"and x20, x8, #0xfff\n\t" /* syscall number */
"ubfx x21, x8, #12, #2\n\t" /* syscall table number */
"ldr x16, [x18, #0x2f8]\n\t" /* arm64_thread_data()->syscall_table */
"add x21, x16, x21, lsl #5\n\t"
"ldr x16, [x21, #16]\n\t" /* table->ServiceLimit */
"cmp x20, x16\n\t"
"bcs 4f\n\t"
"ldr x16, [x21, #24]\n\t" /* table->ArgumentTable */
"ldrb w9, [x16, x20]\n\t"
"subs x9, x9, #64\n\t"
"bls 2f\n\t"
"sub sp, sp, x9\n\t"
"tbz x9, #3, 1f\n\t"
"sub sp, sp, #8\n"
"1:\tsub x9, x9, #8\n\t"
"ldr x10, [x19, x9]\n\t"
"str x10, [sp, x9]\n\t"
"cbnz x9, 1b\n"
"2:\tldr x16, [x21]\n\t" /* table->ServiceTable */
"ldr x16, [x16, x20, lsl 3]\n\t"
"blr x16\n\t"
"mov sp, x22\n"
__ASM_CFI_CFA_IS_AT2(sp, 0x98, 0x02) /* frame->syscall_cfa */
__ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") ":\n\t"
"ldr w16, [sp, #0x10c]\n\t" /* frame->restore_flags */
"tbz x16, #1, 2f\n\t" /* CONTEXT_INTEGER */
"ldp x12, x13, [sp, #0x80]\n\t" /* frame->x[16..17] */
"ldp x14, x15, [sp, #0xf8]\n\t" /* frame->sp, frame->pc */
"cmp x12, x15\n\t" /* frame->x16 == frame->pc? */
"ccmp x13, x14, #0, eq\n\t" /* frame->x17 == frame->sp? */
"beq 1f\n\t" /* take slowpath if unequal */
"bl " __ASM_NAME("syscall_dispatcher_return_slowpath") "\n"
"1:\tldp x0, x1, [sp, #0x00]\n\t"
"ldp x2, x3, [sp, #0x10]\n\t"
"ldp x4, x5, [sp, #0x20]\n\t"
"ldp x6, x7, [sp, #0x30]\n\t"
"ldp x8, x9, [sp, #0x40]\n\t"
"ldp x10, x11, [sp, #0x50]\n\t"
"ldp x12, x13, [sp, #0x60]\n\t"
"ldp x14, x15, [sp, #0x70]\n"
"2:\tldp x18, x19, [sp, #0x90]\n\t"
"ldp x20, x21, [sp, #0xa0]\n\t"
"ldp x22, x23, [sp, #0xb0]\n\t"
"ldp x24, x25, [sp, #0xc0]\n\t"
"ldp x26, x27, [sp, #0xd0]\n\t"
"ldp x28, x29, [sp, #0xe0]\n\t"
"tbz x16, #2, 1f\n\t" /* CONTEXT_FLOATING_POINT */
"ldp q0, q1, [sp, #0x130]\n\t"
"ldp q2, q3, [sp, #0x150]\n\t"
"ldp q4, q5, [sp, #0x170]\n\t"
"ldp q6, q7, [sp, #0x190]\n\t"
"ldp q8, q9, [sp, #0x1b0]\n\t"
"ldp q10, q11, [sp, #0x1d0]\n\t"
"ldp q12, q13, [sp, #0x1f0]\n\t"
"ldp q14, q15, [sp, #0x210]\n\t"
"ldp q16, q17, [sp, #0x230]\n\t"
"ldp q18, q19, [sp, #0x250]\n\t"
"ldp q20, q21, [sp, #0x270]\n\t"
"ldp q22, q23, [sp, #0x290]\n\t"
"ldp q24, q25, [sp, #0x2b0]\n\t"
"ldp q26, q27, [sp, #0x2d0]\n\t"
"ldp q28, q29, [sp, #0x2f0]\n\t"
"ldp q30, q31, [sp, #0x310]\n\t"
"ldr w17, [sp, #0x128]\n\t"
"msr FPCR, x17\n\t"
"ldr w17, [sp, #0x12c]\n\t"
"msr FPSR, x17\n"
"1:\tldp x16, x17, [sp, #0x100]\n\t"
"msr NZCV, x17\n\t"
"ldp x30, x17, [sp, #0xf0]\n\t"
/* switch to user stack */
"mov sp, x17\n\t"
"ret x16\n"
"4:\tmov x0, #0xc0000000\n\t" /* STATUS_INVALID_PARAMETER */
"movk x0, #0x000d\n\t"
"b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
__ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
"mov sp, x0\n\t"
"mov x0, x1\n\t"
"b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
/***********************************************************************
* __wine_unix_call_dispatcher
*/
__ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher,
"ldr x10, [x18, #0x2f0]\n\t" /* arm64_thread_data()->syscall_frame */
"stp x18, x19, [x10, #0x90]\n\t"
"stp x20, x21, [x10, #0xa0]\n\t"
"stp x22, x23, [x10, #0xb0]\n\t"
"stp x24, x25, [x10, #0xc0]\n\t"
"stp x26, x27, [x10, #0xd0]\n\t"
"stp x28, x29, [x10, #0xe0]\n\t"
"stp q8, q9, [x10, #0x1b0]\n\t"
"stp q10, q11, [x10, #0x1d0]\n\t"
"stp q12, q13, [x10, #0x1f0]\n\t"
"stp q14, q15, [x10, #0x210]\n\t"
"mov x9, sp\n\t"
"stp x30, x9, [x10, #0xf0]\n\t"
"mrs x9, NZCV\n\t"
"stp x30, x9, [x10, #0x100]\n\t"
"mov x19, x10\n\t"
/* switch to kernel stack */
"mov sp, x10\n\t"
/* we're now on the kernel stack, stitch unwind info with previous frame */
__ASM_CFI_CFA_IS_AT2(x19, 0x98, 0x02) /* frame->syscall_cfa */
__ASM_CFI(".cfi_offset 29, -0xc0\n\t")
__ASM_CFI(".cfi_offset 30, -0xb8\n\t")
__ASM_CFI(".cfi_offset 19, -0xb0\n\t")
__ASM_CFI(".cfi_offset 20, -0xa8\n\t")
__ASM_CFI(".cfi_offset 21, -0xa0\n\t")
__ASM_CFI(".cfi_offset 22, -0x98\n\t")
__ASM_CFI(".cfi_offset 23, -0x90\n\t")
__ASM_CFI(".cfi_offset 24, -0x88\n\t")
__ASM_CFI(".cfi_offset 25, -0x80\n\t")
__ASM_CFI(".cfi_offset 26, -0x78\n\t")
__ASM_CFI(".cfi_offset 27, -0x70\n\t")
__ASM_CFI(".cfi_offset 28, -0x68\n\t")
"ldr x16, [x0, x1, lsl 3]\n\t"
"mov x0, x2\n\t" /* args */
"blr x16\n\t"
"ldr w16, [sp, #0x10c]\n\t" /* frame->restore_flags */
"cbnz w16, " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
__ASM_CFI_CFA_IS_AT2(sp, 0x98, 0x02) /* frame->syscall_cfa */
"ldp x18, x19, [sp, #0x90]\n\t"
"ldp x16, x17, [sp, #0xf8]\n\t"
/* switch to user stack */
"mov sp, x16\n\t"
"ret x17" )
#endif /* __aarch64__ */