From 2333099c52566c6cf3d3f981588a26d4ff408155 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 9 Jun 2020 12:32:41 +0200 Subject: [PATCH] ntdll: Move signal handlers to the Unix library. Signed-off-by: Alexandre Julliard --- dlls/ntdll/exception.c | 71 -- dlls/ntdll/loader.c | 5 +- dlls/ntdll/ntdll_misc.h | 18 - dlls/ntdll/server.c | 153 --- dlls/ntdll/signal_arm.c | 587 ------------ dlls/ntdll/signal_arm64.c | 458 --------- dlls/ntdll/signal_i386.c | 1489 ------------------------------ dlls/ntdll/signal_powerpc.c | 580 +----------- dlls/ntdll/signal_x86_64.c | 718 +------------- dlls/ntdll/thread.c | 12 +- dlls/ntdll/unix/loader.c | 6 - dlls/ntdll/unix/server.c | 33 +- dlls/ntdll/unix/signal_arm.c | 508 ++++++++++ dlls/ntdll/unix/signal_arm64.c | 431 +++++++++ dlls/ntdll/unix/signal_i386.c | 1310 +++++++++++++++++++++++++- dlls/ntdll/unix/signal_powerpc.c | 488 ++++++++++ dlls/ntdll/unix/signal_x86_64.c | 778 +++++++++++++++- dlls/ntdll/unix/thread.c | 11 +- dlls/ntdll/unix/unix_private.h | 15 +- dlls/ntdll/unix/virtual.c | 10 +- dlls/ntdll/unixlib.h | 10 +- dlls/ntdll/virtual.c | 44 +- 22 files changed, 3582 insertions(+), 4153 deletions(-) diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index 4b77f1a5e97..104bb4d5b90 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -104,77 +104,6 @@ static ULONG remove_vectored_handler( struct list *handler_list, VECTORED_HANDLE } -/********************************************************************** - * wait_suspend - * - * Wait until the thread is no longer suspended. - */ -void wait_suspend( CONTEXT *context ) -{ - int saved_errno = errno; - - /* wait with 0 timeout, will only return once the thread is no longer suspended */ - unix_funcs->server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, context, NULL, NULL ); - - errno = saved_errno; -} - - -/********************************************************************** - * send_debug_event - * - * Send an EXCEPTION_DEBUG_EVENT event to the debugger. - */ -NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context ) -{ - NTSTATUS ret; - DWORD i; - obj_handle_t handle = 0; - client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS]; - CONTEXT exception_context = *context; - select_op_t select_op; - sigset_t old_set; - - if (!NtCurrentTeb()->Peb->BeingDebugged) return 0; /* no debugger present */ - - pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); - - for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++) - params[i] = rec->ExceptionInformation[i]; - - SERVER_START_REQ( queue_exception_event ) - { - req->first = first_chance; - req->code = rec->ExceptionCode; - req->flags = rec->ExceptionFlags; - req->record = wine_server_client_ptr( rec->ExceptionRecord ); - req->address = wine_server_client_ptr( rec->ExceptionAddress ); - req->len = i * sizeof(params[0]); - wine_server_add_data( req, params, req->len ); - if (!(ret = wine_server_call( req ))) handle = reply->handle; - } - SERVER_END_REQ; - - if (handle) - { - select_op.wait.op = SELECT_WAIT; - select_op.wait.handles[0] = handle; - unix_funcs->server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE, TIMEOUT_INFINITE, &exception_context, NULL, NULL ); - - SERVER_START_REQ( get_exception_status ) - { - req->handle = handle; - ret = wine_server_call( req ); - } - SERVER_END_REQ; - if (ret >= 0) *context = exception_context; - } - - pthread_sigmask( SIG_SETMASK, &old_set, NULL ); - return ret; -} - - /********************************************************************** * call_vectored_handlers * diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index ffbc9fabb23..3ab2905c709 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -3826,8 +3826,6 @@ void WINAPI LdrInitializeThunk( CONTEXT *context, void **entry, ULONG_PTR unknow WINE_MODREF *wm; LPCWSTR load_path = NtCurrentTeb()->Peb->ProcessParameters->DllPath.Buffer; - pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL ); - if (process_detaching) return; RtlEnterCriticalSection( &loader_section ); @@ -4359,6 +4357,7 @@ void __wine_process_init(void) static const WCHAR kernel32W[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s','\\', 's','y','s','t','e','m','3','2','\\', 'k','e','r','n','e','l','3','2','.','d','l','l',0}; + void (WINAPI *kernel32_start_process)(LPTHREAD_START_ROUTINE,void*) = NULL; RTL_USER_PROCESS_PARAMETERS *params; WINE_MODREF *wm; NTSTATUS status; @@ -4467,7 +4466,7 @@ void __wine_process_init(void) teb->Tib.StackLimit = stack.StackLimit; teb->DeallocationStack = stack.DeallocationStack; - server_init_process_done(); + unix_funcs->server_init_process_done( kernel32_start_process ); } /*********************************************************************** diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 65c65cc02d8..092932e9823 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -58,8 +58,6 @@ extern NTSTATUS close_handle( HANDLE ) DECLSPEC_HIDDEN; extern ULONG_PTR get_system_affinity_mask(void) DECLSPEC_HIDDEN; /* exceptions */ -extern void wait_suspend( CONTEXT *context ) DECLSPEC_HIDDEN; -extern NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context ) DECLSPEC_HIDDEN; extern LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN raise_status( NTSTATUS status, EXCEPTION_RECORD *rec ) DECLSPEC_HIDDEN; extern NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self ) DECLSPEC_HIDDEN; @@ -75,14 +73,10 @@ extern LPCSTR debugstr_us( const UNICODE_STRING *str ) DECLSPEC_HIDDEN; extern LPCSTR debugstr_ObjectAttributes(const OBJECT_ATTRIBUTES *oa) DECLSPEC_HIDDEN; /* init routines */ -extern SIZE_T signal_stack_size DECLSPEC_HIDDEN; -extern SIZE_T signal_stack_mask DECLSPEC_HIDDEN; -extern void signal_init_process(void) DECLSPEC_HIDDEN; extern void version_init(void) DECLSPEC_HIDDEN; extern void debug_init(void) DECLSPEC_HIDDEN; extern TEB *thread_init( SIZE_T *info_size, BOOL *suspend ) DECLSPEC_HIDDEN; extern void actctx_init(void) DECLSPEC_HIDDEN; -extern void virtual_init(void) DECLSPEC_HIDDEN; extern void fill_cpu_info(void) DECLSPEC_HIDDEN; extern void heap_set_debug_flags( HANDLE handle ) DECLSPEC_HIDDEN; extern void init_unix_codepage(void) DECLSPEC_HIDDEN; @@ -102,17 +96,6 @@ extern const char *config_dir DECLSPEC_HIDDEN; extern timeout_t server_start_time DECLSPEC_HIDDEN; extern unsigned int server_cpus DECLSPEC_HIDDEN; extern BOOL is_wow64 DECLSPEC_HIDDEN; -extern NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info ) DECLSPEC_HIDDEN; -extern void server_init_process(void) DECLSPEC_HIDDEN; -extern void server_init_process_done(void) DECLSPEC_HIDDEN; -extern sigset_t server_block_set DECLSPEC_HIDDEN; -extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN; -extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN; -extern unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT flags, - timeout_t abs_timeout, CONTEXT *context, RTL_CRITICAL_SECTION *cs, user_apc_t *user_apc ) DECLSPEC_HIDDEN; -extern unsigned int server_wait( const select_op_t *select_op, data_size_t size, - UINT flags, const LARGE_INTEGER *timeout ) DECLSPEC_HIDDEN; -extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, apc_result_t *result ) DECLSPEC_HIDDEN; extern NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret, data_size_t *ret_len ) DECLSPEC_HIDDEN; extern NTSTATUS validate_open_object_attributes( const OBJECT_ATTRIBUTES *attr ) DECLSPEC_HIDDEN; @@ -130,7 +113,6 @@ extern const WCHAR system_dir[] DECLSPEC_HIDDEN; extern const WCHAR syswow64_dir[] DECLSPEC_HIDDEN; extern const struct unix_funcs *unix_funcs DECLSPEC_HIDDEN; -extern void (WINAPI *kernel32_start_process)(LPTHREAD_START_ROUTINE,void*) DECLSPEC_HIDDEN; /* Device IO */ extern NTSTATUS CDROM_DeviceIoControl(HANDLE hDevice, diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index 6fb86a68d6f..9e1cc85a36e 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -23,87 +23,18 @@ #include #include -#ifdef HAVE_DIRENT_H -# include -#endif -#include -#include -#ifdef HAVE_LWP_H -#include -#endif -#ifdef HAVE_PTHREAD_NP_H -# include -#endif -#ifdef HAVE_PWD_H -# include -#endif -#include #include #include #include #include -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_SYS_WAIT_H -#include -#endif -#ifdef HAVE_SYS_UN_H -#include -#endif -#ifdef HAVE_SYS_MMAN_H -#include -#endif -#ifdef HAVE_SYS_PRCTL_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_SYS_SYSCALL_H -# include -#endif -#ifdef HAVE_SYS_UIO_H -#include -#endif -#ifdef HAVE_SYS_UCONTEXT_H -# include -#endif -#ifdef HAVE_SYS_THR_H -#include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef __APPLE__ -#include -#include -#ifndef _POSIX_SPAWN_DISABLE_ASLR -#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 -#endif -#endif #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" #include "winnt.h" -#include "wine/library.h" #include "wine/server.h" #include "wine/debug.h" #include "ntdll_misc.h" -#include "ddk/wdm.h" - -/* Some versions of glibc don't define this */ -#ifndef SCM_RIGHTS -#define SCM_RIGHTS 1 -#endif - -#ifndef MSG_CMSG_CLOEXEC -#define MSG_CMSG_CLOEXEC 0 -#endif - -#define SOCKETNAME "socket" /* name of the socket file */ -#define LOCKNAME "lock" /* name of the lock file */ const char *build_dir = NULL; const char *data_dir = NULL; @@ -114,8 +45,6 @@ BOOL is_wow64 = FALSE; timeout_t server_start_time = 0; /* time of server startup */ -sigset_t server_block_set; /* signals to block during server calls */ - /*********************************************************************** * wine_server_call (NTDLL.@) * @@ -144,26 +73,6 @@ unsigned int CDECL wine_server_call( void *req_ptr ) } -/*********************************************************************** - * server_enter_uninterrupted_section - */ -void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) -{ - pthread_sigmask( SIG_BLOCK, &server_block_set, sigset ); - RtlEnterCriticalSection( cs ); -} - - -/*********************************************************************** - * server_leave_uninterrupted_section - */ -void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) -{ - RtlLeaveCriticalSection( cs ); - pthread_sigmask( SIG_SETMASK, sigset, NULL ); -} - - /*********************************************************************** * wine_server_send_fd (NTDLL.@) * @@ -238,65 +147,3 @@ void CDECL wine_server_release_fd( HANDLE handle, int unix_fd ) { unix_funcs->server_release_fd( handle, unix_fd ); } - - -/*********************************************************************** - * server_init_process - * - * Start the server and create the initial socket pair. - */ -void server_init_process(void) -{ - /* setup the signal mask */ - sigemptyset( &server_block_set ); - sigaddset( &server_block_set, SIGALRM ); - sigaddset( &server_block_set, SIGIO ); - sigaddset( &server_block_set, SIGINT ); - sigaddset( &server_block_set, SIGHUP ); - sigaddset( &server_block_set, SIGUSR1 ); - sigaddset( &server_block_set, SIGUSR2 ); - sigaddset( &server_block_set, SIGCHLD ); -} - - -/*********************************************************************** - * server_init_process_done - */ -void server_init_process_done(void) -{ -#ifdef __i386__ - extern struct ldt_copy *__wine_ldt_copy; -#endif - PEB *peb = NtCurrentTeb()->Peb; - IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress ); - void *entry = (char *)peb->ImageBaseAddress + nt->OptionalHeader.AddressOfEntryPoint; - NTSTATUS status; - int suspend; - - unix_funcs->server_init_process_done(); - - /* Install signal handlers; this cannot be done earlier, since we cannot - * send exceptions to the debugger before the create process event that - * is sent by REQ_INIT_PROCESS_DONE. - * We do need the handlers in place by the time the request is over, so - * we set them up here. If we segfault between here and the server call - * something is very wrong... */ - signal_init_process(); - - /* Signal the parent process to continue */ - SERVER_START_REQ( init_process_done ) - { - req->module = wine_server_client_ptr( peb->ImageBaseAddress ); -#ifdef __i386__ - req->ldt_copy = wine_server_client_ptr( __wine_ldt_copy ); -#endif - req->entry = wine_server_client_ptr( entry ); - req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI); - status = wine_server_call( req ); - suspend = reply->suspend; - } - SERVER_END_REQ; - - assert( !status ); - unix_funcs->start_process( entry, suspend, kernel32_start_process ); -} diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c index a09848449a6..adac4965255 100644 --- a/dlls/ntdll/signal_arm.c +++ b/dlls/ntdll/signal_arm.c @@ -32,22 +32,6 @@ #ifdef HAVE_UNISTD_H # include #endif -#ifdef HAVE_SYS_PARAM_H -# include -#endif -#ifdef HAVE_SYSCALL_H -# include -#else -# ifdef HAVE_SYS_SYSCALL_H -# include -# endif -#endif -#ifdef HAVE_SYS_SIGNAL_H -# include -#endif -#ifdef HAVE_SYS_UCONTEXT_H -# include -#endif #define NONAMELESSUNION #define NONAMELESSSTRUCT @@ -62,104 +46,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(seh); -/*********************************************************************** - * signal context platform-specific definitions - */ -#ifdef linux - -#if defined(__ANDROID__) && !defined(HAVE_SYS_UCONTEXT_H) -typedef struct ucontext -{ - unsigned long uc_flags; - struct ucontext *uc_link; - stack_t uc_stack; - struct sigcontext uc_mcontext; - sigset_t uc_sigmask; - unsigned long uc_regspace[128] __attribute__((__aligned__(8))); -} ucontext_t; -#endif - -/* 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.arm_r##reg_num) - -/* Special Registers access */ -# define SP_sig(context) REG_sig(arm_sp, context) /* Stack pointer */ -# define LR_sig(context) REG_sig(arm_lr, context) /* Link register */ -# define PC_sig(context) REG_sig(arm_pc, context) /* Program counter */ -# define CPSR_sig(context) REG_sig(arm_cpsr, context) /* Current State Register */ -# define IP_sig(context) REG_sig(arm_ip, context) /* Intra-Procedure-call scratch register */ -# define FP_sig(context) REG_sig(arm_fp, context) /* Frame pointer */ - -/* Exceptions */ -# define ERROR_sig(context) REG_sig(error_code, context) -# define TRAP_sig(context) REG_sig(trap_no, context) - -#elif defined(__FreeBSD__) - -/* All Registers access - only for local access */ -# define REGn_sig(reg_num, context) ((context)->uc_mcontext.__gregs[reg_num]) - -/* Special Registers access */ -# define SP_sig(context) REGn_sig(_REG_SP, context) /* Stack pointer */ -# define LR_sig(context) REGn_sig(_REG_LR, context) /* Link register */ -# define PC_sig(context) REGn_sig(_REG_PC, context) /* Program counter */ -# define CPSR_sig(context) REGn_sig(_REG_CPSR, context) /* Current State Register */ -# define IP_sig(context) REGn_sig(_REG_R12, context) /* Intra-Procedure-call scratch register */ -# define FP_sig(context) REGn_sig(_REG_FP, context) /* Frame pointer */ - -#endif /* linux */ - -enum arm_trap_code -{ - TRAP_ARM_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */ - TRAP_ARM_PRIVINFLT = 6, /* Invalid opcode exception */ - TRAP_ARM_PAGEFLT = 14, /* Page fault */ - TRAP_ARM_ALIGNFLT = 17, /* Alignment check exception */ -}; - -typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context ); - - -/*********************************************************************** - * get_trap_code - * - * Get the trap code for a signal. - */ -static inline enum arm_trap_code get_trap_code( int signal, const ucontext_t *sigcontext ) -{ -#ifdef TRAP_sig - enum arm_trap_code trap = TRAP_sig(sigcontext); - if (trap) - return trap; -#endif - - switch (signal) - { - case SIGILL: - return TRAP_ARM_PRIVINFLT; - case SIGSEGV: - return TRAP_ARM_PAGEFLT; - case SIGBUS: - return TRAP_ARM_ALIGNFLT; - default: - return TRAP_ARM_UNKNOWN; - } -} - -/*********************************************************************** - * get_error_code - * - * Get the error code for a signal. - */ -static inline WORD get_error_code( const ucontext_t *sigcontext ) -{ -#ifdef ERROR_sig - return ERROR_sig(sigcontext); -#else - return 0; -#endif -} /******************************************************************* * is_valid_frame @@ -171,69 +57,6 @@ static inline BOOL is_valid_frame( void *frame ) (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1); } -/*********************************************************************** - * save_context - * - * Set the register values from a sigcontext. - */ -static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) -{ -#define C(x) context->R##x = REGn_sig(x,sigcontext) - /* Save normal registers */ - C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); -#undef C - - context->ContextFlags = CONTEXT_FULL; - context->Sp = SP_sig(sigcontext); /* Stack pointer */ - context->Lr = LR_sig(sigcontext); /* Link register */ - context->Pc = PC_sig(sigcontext); /* Program Counter */ - context->Cpsr = CPSR_sig(sigcontext); /* Current State Register */ - context->R11 = FP_sig(sigcontext); /* Frame pointer */ - context->R12 = IP_sig(sigcontext); /* Intra-Procedure-call scratch register */ -} - - -/*********************************************************************** - * restore_context - * - * Build a sigcontext from the register values. - */ -static void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) -{ -#define C(x) REGn_sig(x,sigcontext) = context->R##x - /* Restore normal registers */ - C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); -#undef C - - SP_sig(sigcontext) = context->Sp; /* Stack pointer */ - LR_sig(sigcontext) = context->Lr ; /* Link register */ - PC_sig(sigcontext) = context->Pc; /* Program Counter */ - CPSR_sig(sigcontext) = context->Cpsr; /* Current State Register */ - FP_sig(sigcontext) = context->R11; /* Frame pointer */ - IP_sig(sigcontext) = context->R12; /* Intra-Procedure-call scratch register */ -} - - -/*********************************************************************** - * save_fpu - * - * Set the FPU context from a sigcontext. - */ -static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext ) -{ - FIXME("not implemented\n"); -} - - -/*********************************************************************** - * restore_fpu - * - * Restore the FPU context to a sigcontext. - */ -static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext ) -{ - FIXME("not implemented\n"); -} /************************************************************************** * __chkstk (NTDLL.@) @@ -283,81 +106,6 @@ __ASM_GLOBAL_FUNC( set_cpu_context, "pop {pc}" ) -extern void raise_func_trampoline_thumb( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func ); -__ASM_GLOBAL_FUNC( raise_func_trampoline_thumb, - ".thumb\n\t" - "blx r2\n\t" - "bkpt") - -extern void raise_func_trampoline_arm( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func ); -__ASM_GLOBAL_FUNC( raise_func_trampoline_arm, - ".arm\n\t" - "blx r2\n\t" - "bkpt") - -/*********************************************************************** - * setup_exception_record - * - * Setup the exception record and context on the thread stack. - */ -static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func func ) -{ - struct stack_layout - { - CONTEXT context; - EXCEPTION_RECORD rec; - } *stack; - DWORD exception_code = 0; - - stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3); - stack--; /* push the stack_layout structure */ - - stack->rec.ExceptionRecord = NULL; - stack->rec.ExceptionCode = exception_code; - stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext); - stack->rec.NumberParameters = 0; - - save_context( &stack->context, sigcontext ); - - /* now modify the sigcontext to return to the raise function */ - SP_sig(sigcontext) = (DWORD)stack; - if (CPSR_sig(sigcontext) & 0x20) - PC_sig(sigcontext) = (DWORD)raise_func_trampoline_thumb; - else - PC_sig(sigcontext) = (DWORD)raise_func_trampoline_arm; - REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for raise_func */ - REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for raise_func */ - REGn_sig(2, sigcontext) = (DWORD)func; /* the raise_func as third arg for the trampoline */ - - - return &stack->rec; -} - -/********************************************************************** - * raise_segv_exception - */ -static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) -{ - NTSTATUS status; - - switch(rec->ExceptionCode) - { - case EXCEPTION_ACCESS_VIOLATION: - if (rec->NumberParameters == 2) - { - if (!(rec->ExceptionCode = unix_funcs->virtual_handle_fault( (void *)rec->ExceptionInformation[1], - rec->ExceptionInformation[0], FALSE ))) - goto done; - } - break; - } - status = NtRaiseException( rec, context, TRUE ); - if (status) raise_status( status, rec ); -done: - set_cpu_context( context ); -} - /********************************************************************** * call_stack_handlers * @@ -412,74 +160,6 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) } -/******************************************************************* - * raise_exception - * - * Implementation of NtRaiseException. - */ -static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) -{ - NTSTATUS status; - - if (first_chance) - { - DWORD c; - - TRACE( "code=%x flags=%x addr=%p pc=%08x tid=%04x\n", - rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, - context->Pc, GetCurrentThreadId() ); - for (c = 0; c < rec->NumberParameters; c++) - TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] ); - if (rec->ExceptionCode == EXCEPTION_WINE_STUB) - { - if (rec->ExceptionInformation[1] >> 16) - MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n", - rec->ExceptionAddress, - (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] ); - else - MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n", - rec->ExceptionAddress, - (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] ); - } - else - { - TRACE( " r0=%08x r1=%08x r2=%08x r3=%08x r4=%08x r5=%08x\n", - context->R0, context->R1, context->R2, context->R3, context->R4, context->R5 ); - TRACE( " r6=%08x r7=%08x r8=%08x r9=%08x r10=%08x r11=%08x\n", - context->R6, context->R7, context->R8, context->R9, context->R10, context->R11 ); - TRACE( " r12=%08x sp=%08x lr=%08x pc=%08x cpsr=%08x\n", - context->R12, context->Sp, context->Lr, context->Pc, context->Cpsr ); - } - - status = send_debug_event( rec, TRUE, context ); - if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) - return STATUS_SUCCESS; - - if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION) - return STATUS_SUCCESS; - - if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION) - return status; - } - - /* last chance exception */ - - status = send_debug_event( rec, FALSE, context ); - if (status != DBG_CONTINUE) - { - if (rec->ExceptionFlags & EH_STACK_INVALID) - ERR("Exception frame is not in stack limits => unable to dispatch exception.\n"); - else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION) - ERR("Process attempted to continue execution after noncontinuable exception.\n"); - else - ERR("Unhandled exception code %x flags %x addr %p\n", - rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); - NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode ); - } - return STATUS_SUCCESS; -} - - /******************************************************************* * KiUserExceptionDispatcher (NTDLL.@) */ @@ -526,273 +206,6 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte } -/********************************************************************** - * segv_handler - * - * Handler for SIGSEGV and related errors. - */ -static void segv_handler( int signal, siginfo_t *info, void *ucontext ) -{ - EXCEPTION_RECORD *rec; - ucontext_t *context = ucontext; - - /* check for page fault inside the thread stack */ - if (get_trap_code(signal, context) == TRAP_ARM_PAGEFLT) - { - switch (unix_funcs->virtual_handle_stack_fault( info->si_addr )) - { - case 1: /* handled */ - return; - case -1: /* overflow */ - rec = setup_exception( context, raise_segv_exception ); - rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW; - return; - } - } - - rec = setup_exception( context, raise_segv_exception ); - if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return; - - switch(get_trap_code(signal, context)) - { - case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */ - rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; - break; - case TRAP_ARM_PAGEFLT: /* Page fault */ - rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION; - rec->NumberParameters = 2; - rec->ExceptionInformation[0] = (get_error_code(context) & 0x800) != 0; - rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr; - break; - case TRAP_ARM_ALIGNFLT: /* Alignment check exception */ - rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; - break; - case TRAP_ARM_UNKNOWN: /* Unknown fault code */ - rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION; - rec->NumberParameters = 2; - rec->ExceptionInformation[0] = 0; - rec->ExceptionInformation[1] = 0xffffffff; - break; - default: - ERR("Got unexpected trap %d\n", get_trap_code(signal, context)); - rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; - break; - } -} - -/********************************************************************** - * trap_handler - * - * Handler for SIGTRAP. - */ -static void trap_handler( int signal, siginfo_t *info, void *ucontext ) -{ - EXCEPTION_RECORD rec; - CONTEXT context; - NTSTATUS status; - - switch ( info->si_code ) - { - case TRAP_TRACE: - rec.ExceptionCode = EXCEPTION_SINGLE_STEP; - break; - case TRAP_BRKPT: - default: - rec.ExceptionCode = EXCEPTION_BREAKPOINT; - break; - } - - save_context( &context, ucontext ); - rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = (LPVOID)context.Pc; - rec.NumberParameters = 0; - status = raise_exception( &rec, &context, TRUE ); - if (status) raise_status( status, &rec ); - restore_context( &context, ucontext ); -} - -/********************************************************************** - * fpe_handler - * - * Handler for SIGFPE. - */ -static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - EXCEPTION_RECORD rec; - CONTEXT context; - NTSTATUS status; - - save_fpu( &context, sigcontext ); - save_context( &context, sigcontext ); - - 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; - } - rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = (LPVOID)context.Pc; - rec.NumberParameters = 0; - status = raise_exception( &rec, &context, TRUE ); - if (status) raise_status( status, &rec ); - - restore_context( &context, sigcontext ); - restore_fpu( &context, sigcontext ); -} - -/********************************************************************** - * int_handler - * - * Handler for SIGINT. - */ -static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - EXCEPTION_RECORD rec; - CONTEXT context; - NTSTATUS status; - - save_context( &context, sigcontext ); - rec.ExceptionCode = CONTROL_C_EXIT; - rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = (LPVOID)context.Pc; - rec.NumberParameters = 0; - status = raise_exception( &rec, &context, TRUE ); - if (status) raise_status( status, &rec ); - restore_context( &context, sigcontext ); -} - - -/********************************************************************** - * abrt_handler - * - * Handler for SIGABRT. - */ -static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - EXCEPTION_RECORD rec; - CONTEXT context; - NTSTATUS status; - - save_context( &context, sigcontext ); - rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; - rec.ExceptionFlags = EH_NONCONTINUABLE; - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = (LPVOID)context.Pc; - rec.NumberParameters = 0; - status = raise_exception( &rec, &context, TRUE ); - if (status) raise_status( status, &rec ); - restore_context( &context, sigcontext ); -} - - -/********************************************************************** - * quit_handler - * - * Handler for SIGQUIT. - */ -static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - unix_funcs->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; - - save_context( &context, sigcontext ); - wait_suspend( &context ); - restore_context( &context, sigcontext ); -} - - -/********************************************************************** - * signal_init_process - */ -void signal_init_process(void) -{ - struct sigaction sig_act; - - sig_act.sa_mask = server_block_set; - sig_act.sa_flags = SA_RESTART | SA_SIGINFO; - - 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 = segv_handler; - if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; -#ifdef SIGBUS - if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; -#endif - -#ifdef SIGTRAP - sig_act.sa_sigaction = trap_handler; - if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error; -#endif - return; - - error: - perror("sigaction"); - exit(1); -} - - /*********************************************************************** * RtlUnwind (NTDLL.@) */ diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c index a9a58a2e7ad..0159888f7ab 100644 --- a/dlls/ntdll/signal_arm64.c +++ b/dlls/ntdll/signal_arm64.c @@ -88,59 +88,6 @@ struct MSVCRT_JUMP_BUFFER double D[8]; }; -/*********************************************************************** - * 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( 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( 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; -} - -#endif /* linux */ - -static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */ - -typedef void (*raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context ); - -/* stack layout when calling an exception raise function */ -struct stack_layout -{ - CONTEXT context; - EXCEPTION_RECORD rec; - void *redzone[2]; -}; - struct arm64_thread_data { void *exit_frame; /* exit frame pointer */ @@ -155,15 +102,6 @@ static inline struct arm64_thread_data *arm64_thread_data(void) return (struct arm64_thread_data *)NtCurrentTeb()->SystemReserved2; } -/*********************************************************************** - * get_signal_stack - * - * Get the base of the signal stack for the current thread. - */ -static inline void *get_signal_stack(void) -{ - return (char *)NtCurrentTeb() + teb_size; -} /******************************************************************* * is_valid_frame @@ -175,85 +113,6 @@ static inline BOOL is_valid_frame( ULONG_PTR frame ) (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1); } -/*********************************************************************** - * is_inside_signal_stack - * - * Check if pointer is inside the signal stack. - */ -static inline BOOL is_inside_signal_stack( void *ptr ) -{ - return ((char *)ptr >= (char *)get_signal_stack() && - (char *)ptr < (char *)get_signal_stack() + signal_stack_size); -} - -/*********************************************************************** - * 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->u.s.Fp = FP_sig(sigcontext); /* Frame pointer */ - context->u.s.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->u.X[i] = REGn_sig( i, 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->u.s.Fp; /* Frame pointer */ - LR_sig(sigcontext) = context->u.s.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->u.X[i]; -} - - -/*********************************************************************** - * save_fpu - * - * Set the FPU context from a sigcontext. - */ -static void save_fpu( CONTEXT *context, ucontext_t *sigcontext ) -{ - 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) ); -} - - -/*********************************************************************** - * restore_fpu - * - * Restore the FPU context to a sigcontext. - */ -static void restore_fpu( CONTEXT *context, ucontext_t *sigcontext ) -{ - 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) ); -} /*********************************************************************** * RtlCaptureContext (NTDLL.@) @@ -779,316 +638,6 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte return NtRaiseException( rec, context, FALSE ); } -/*********************************************************************** - * setup_exception - * - * Setup the exception record and context on the thread stack. - */ -static struct stack_layout *setup_exception( ucontext_t *sigcontext ) -{ - struct stack_layout *stack; - DWORD exception_code = 0; - - /* push the stack_layout structure */ - stack = (struct stack_layout *)((SP_sig(sigcontext) - sizeof(*stack)) & ~15); - - stack->rec.ExceptionRecord = NULL; - stack->rec.ExceptionCode = exception_code; - stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext); - stack->rec.NumberParameters = 0; - - save_context( &stack->context, sigcontext ); - save_fpu( &stack->context, sigcontext ); - return stack; -} - - -extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func, void *sp ); -__ASM_GLOBAL_FUNC( raise_func_trampoline, - __ASM_CFI(".cfi_signal_frame\n\t") - "stp x29, x30, [sp, #-0x20]!\n\t" - __ASM_CFI(".cfi_def_cfa_offset 32\n\t") - __ASM_CFI(".cfi_offset 29, -32\n\t") - __ASM_CFI(".cfi_offset 30, -24\n\t") - "mov x29, sp\n\t" - __ASM_CFI(".cfi_def_cfa_register 29\n\t") - "str x3, [sp, 0x10]\n\t" - __ASM_CFI(".cfi_remember_state\n\t") - __ASM_CFI(".cfi_escape 0x0f,0x03,0x8d,0x10,0x06\n\t") /* CFA */ - __ASM_CFI(".cfi_escape 0x10,0x1d,0x02,0x8d,0x00\n\t") /* x29 */ - __ASM_CFI(".cfi_escape 0x10,0x1e,0x02,0x8d,0x08\n\t") /* x30 */ - "blr x2\n\t" - __ASM_CFI(".cfi_restore_state\n\t") - "brk #1") - -/*********************************************************************** - * setup_raise_exception - * - * Modify the signal context to call the exception raise function. - */ -static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *stack ) -{ - NTSTATUS status = send_debug_event( &stack->rec, TRUE, &stack->context ); - - if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) - { - restore_context( &stack->context, sigcontext ); - return; - } - REGn_sig(3, sigcontext) = SP_sig(sigcontext); /* original stack pointer, fourth arg for raise_func_trampoline */ - SP_sig(sigcontext) = (ULONG_PTR)stack; - LR_sig(sigcontext) = PC_sig(sigcontext); - PC_sig(sigcontext) = (ULONG_PTR)raise_func_trampoline; /* raise_generic_exception; */ - REGn_sig(0, sigcontext) = (ULONG_PTR)&stack->rec; /* first arg for raise_generic_exception */ - REGn_sig(1, sigcontext) = (ULONG_PTR)&stack->context; /* second arg for raise_generic_exception */ - REGn_sig(2, sigcontext) = (ULONG_PTR)KiUserExceptionDispatcher; /* third arg for raise_func_trampoline */ - REGn_sig(18, sigcontext) = (ULONG_PTR)NtCurrentTeb(); -} - -/********************************************************************** - * segv_handler - * - * Handler for SIGSEGV and related errors. - */ -static void segv_handler( int signal, siginfo_t *info, void *ucontext ) -{ - struct stack_layout *stack; - ucontext_t *context = ucontext; - - /* check for page fault inside the thread stack */ - if (signal == SIGSEGV) - { - switch (unix_funcs->virtual_handle_stack_fault( info->si_addr )) - { - case 1: /* handled */ - return; - case -1: /* overflow */ - stack = setup_exception( context ); - stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; - goto done; - } - } - - stack = setup_exception( context ); - if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done; - - switch(signal) - { - case SIGILL: /* Invalid opcode exception */ - stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; - break; - case SIGSEGV: /* Segmentation fault */ - stack->rec.NumberParameters = 2; - stack->rec.ExceptionInformation[0] = (get_fault_esr( context ) & 0x40) != 0; - stack->rec.ExceptionInformation[1] = (ULONG_PTR)info->si_addr; - if (!(stack->rec.ExceptionCode = unix_funcs->virtual_handle_fault( (void *)stack->rec.ExceptionInformation[1], - stack->rec.ExceptionInformation[0], FALSE ))) - return; - break; - case SIGBUS: /* Alignment check exception */ - stack->rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; - break; - default: - ERR("Got unexpected signal %i\n", signal); - stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; - break; - } -done: - setup_raise_exception( context, stack ); -} - -/********************************************************************** - * trap_handler - * - * Handler for SIGTRAP. - */ -static void trap_handler( int signal, siginfo_t *info, void *ucontext ) -{ - ucontext_t *context = ucontext; - struct stack_layout *stack = setup_exception( context ); - - switch (info->si_code) - { - case TRAP_TRACE: - stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP; - break; - case TRAP_BRKPT: - default: - stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; - stack->context.Pc += 4; - break; - } - setup_raise_exception( context, stack ); -} - -/********************************************************************** - * fpe_handler - * - * Handler for SIGFPE. - */ -static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack = setup_exception( sigcontext ); - - switch (siginfo->si_code & 0xffff ) - { -#ifdef FPE_FLTSUB - case FPE_FLTSUB: - stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; - break; -#endif -#ifdef FPE_INTDIV - case FPE_INTDIV: - stack->rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; - break; -#endif -#ifdef FPE_INTOVF - case FPE_INTOVF: - stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; - break; -#endif -#ifdef FPE_FLTDIV - case FPE_FLTDIV: - stack->rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO; - break; -#endif -#ifdef FPE_FLTOVF - case FPE_FLTOVF: - stack->rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW; - break; -#endif -#ifdef FPE_FLTUND - case FPE_FLTUND: - stack->rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW; - break; -#endif -#ifdef FPE_FLTRES - case FPE_FLTRES: - stack->rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT; - break; -#endif -#ifdef FPE_FLTINV - case FPE_FLTINV: -#endif - default: - stack->rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; - break; - } - setup_raise_exception( sigcontext, stack ); -} - -/********************************************************************** - * int_handler - * - * Handler for SIGINT. - */ -static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack = setup_exception( sigcontext ); - - stack->rec.ExceptionCode = CONTROL_C_EXIT; - setup_raise_exception( sigcontext, stack ); -} - - -/********************************************************************** - * abrt_handler - * - * Handler for SIGABRT. - */ -static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack = setup_exception( sigcontext ); - - stack->rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; - stack->rec.ExceptionFlags = EH_NONCONTINUABLE; - setup_raise_exception( sigcontext, stack ); -} - - -/********************************************************************** - * quit_handler - * - * Handler for SIGQUIT. - */ -static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - unix_funcs->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; - - 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 ) -{ - CONTEXT *context = InterlockedExchangePointer( (void **)&arm64_thread_data()->context, NULL ); - if (!context) return; - if ((context->ContextFlags & ~CONTEXT_ARM64) & CONTEXT_FLOATING_POINT) - restore_fpu( context, sigcontext ); - restore_context( context, sigcontext ); -} - - -/********************************************************************** - * signal_init_process - */ -void signal_init_process(void) -{ - struct sigaction sig_act; - - sig_act.sa_mask = server_block_set; - sig_act.sa_flags = SA_RESTART | SA_SIGINFO | 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 = segv_handler; - if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; -#ifdef SIGBUS - if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; -#endif - -#ifdef SIGTRAP - sig_act.sa_sigaction = trap_handler; - if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error; -#endif - return; - - error: - perror("sigaction"); - exit(1); -} - /*********************************************************************** * Definitions for Win32 unwind tables */ @@ -1691,13 +1240,6 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec unwind_done: if (!dispatch.EstablisherFrame) break; - if (is_inside_signal_stack( (void *)dispatch.EstablisherFrame )) - { - TRACE( "frame %lx is inside signal stack (%p-%p)\n", dispatch.EstablisherFrame, - get_signal_stack(), (char *)get_signal_stack() + signal_stack_size ); - *context = new_context; - continue; - } if (!is_valid_frame( dispatch.EstablisherFrame )) { ERR( "invalid frame %lx (%p-%p)\n", dispatch.EstablisherFrame, diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index 83868f25121..21cc1b3ead4 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -35,19 +35,6 @@ #ifdef HAVE_SYS_PARAM_H # include #endif -#ifdef HAVE_SYSCALL_H -# include -#else -# ifdef HAVE_SYS_SYSCALL_H -# include -# endif -#endif -#ifdef HAVE_SYS_SIGNAL_H -# include -#endif -#ifdef HAVE_SYS_UCONTEXT_H -# include -#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -56,12 +43,6 @@ #include "wine/exception.h" #include "wine/debug.h" -#ifdef HAVE_VALGRIND_MEMCHECK_H -#include -#endif - -#undef ERR /* Solaris needs to define this */ - WINE_DEFAULT_DEBUG_CHANNEL(seh); /* not defined for x86, so copy the x86_64 definition */ @@ -91,405 +72,6 @@ typedef struct BYTE Reserved4[96]; } XMM_SAVE_AREA32; -/*********************************************************************** - * signal context platform-specific definitions - */ - -#ifdef __linux__ - -#ifndef HAVE_SYS_UCONTEXT_H - -enum -{ - REG_GS, REG_FS, REG_ES, REG_DS, REG_EDI, REG_ESI, REG_EBP, REG_ESP, - REG_EBX, REG_EDX, REG_ECX, REG_EAX, REG_TRAPNO, REG_ERR, REG_EIP, - REG_CS, REG_EFL, REG_UESP, REG_SS, NGREG -}; - -typedef int greg_t; -typedef greg_t gregset_t[NGREG]; - -struct _libc_fpreg -{ - unsigned short significand[4]; - unsigned short exponent; -}; - -struct _libc_fpstate -{ - unsigned long cw; - unsigned long sw; - unsigned long tag; - unsigned long ipoff; - unsigned long cssel; - unsigned long dataoff; - unsigned long datasel; - struct _libc_fpreg _st[8]; - unsigned long status; -}; - -typedef struct _libc_fpstate* fpregset_t; - -typedef struct -{ - gregset_t gregs; - fpregset_t fpregs; - unsigned long oldmask; - unsigned long cr2; -} mcontext_t; - -typedef struct ucontext -{ - unsigned long uc_flags; - struct ucontext *uc_link; - stack_t uc_stack; - mcontext_t uc_mcontext; - sigset_t uc_sigmask; -} ucontext_t; -#endif /* HAVE_SYS_UCONTEXT_H */ - -#define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX]) -#define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX]) -#define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX]) -#define EDX_sig(context) ((context)->uc_mcontext.gregs[REG_EDX]) -#define ESI_sig(context) ((context)->uc_mcontext.gregs[REG_ESI]) -#define EDI_sig(context) ((context)->uc_mcontext.gregs[REG_EDI]) -#define EBP_sig(context) ((context)->uc_mcontext.gregs[REG_EBP]) -#define ESP_sig(context) ((context)->uc_mcontext.gregs[REG_ESP]) - -#define CS_sig(context) ((context)->uc_mcontext.gregs[REG_CS]) -#define DS_sig(context) ((context)->uc_mcontext.gregs[REG_DS]) -#define ES_sig(context) ((context)->uc_mcontext.gregs[REG_ES]) -#define SS_sig(context) ((context)->uc_mcontext.gregs[REG_SS]) -#define FS_sig(context) ((context)->uc_mcontext.gregs[REG_FS]) -#define GS_sig(context) ((context)->uc_mcontext.gregs[REG_GS]) - -#define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL]) -#define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) -#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) -#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) - -#define FPU_sig(context) ((FLOATING_SAVE_AREA*)((context)->uc_mcontext.fpregs)) -#define FPUX_sig(context) (FPU_sig(context) && !((context)->uc_mcontext.fpregs->status >> 16) ? (XMM_SAVE_AREA32 *)(FPU_sig(context) + 1) : NULL) - -#ifdef __ANDROID__ -/* custom signal restorer since we may have unmapped the one in vdso, and bionic doesn't check for that */ -void rt_sigreturn(void); -__ASM_GLOBAL_FUNC( rt_sigreturn, - "movl $173,%eax\n\t" /* NR_rt_sigreturn */ - "int $0x80" ); -#endif - -#elif defined (__BSDI__) - -#include -typedef struct trapframe ucontext_t; - -#define EAX_sig(context) ((context)->tf_eax) -#define EBX_sig(context) ((context)->tf_ebx) -#define ECX_sig(context) ((context)->tf_ecx) -#define EDX_sig(context) ((context)->tf_edx) -#define ESI_sig(context) ((context)->tf_esi) -#define EDI_sig(context) ((context)->tf_edi) -#define EBP_sig(context) ((context)->tf_ebp) - -#define CS_sig(context) ((context)->tf_cs) -#define DS_sig(context) ((context)->tf_ds) -#define ES_sig(context) ((context)->tf_es) -#define SS_sig(context) ((context)->tf_ss) - -#define EFL_sig(context) ((context)->tf_eflags) - -#define EIP_sig(context) (*((unsigned long*)&(context)->tf_eip)) -#define ESP_sig(context) (*((unsigned long*)&(context)->tf_esp)) - -#define FPU_sig(context) NULL /* FIXME */ -#define FPUX_sig(context) NULL /* FIXME */ - -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) - -#include -#include -#include - -#define EAX_sig(context) ((context)->uc_mcontext.mc_eax) -#define EBX_sig(context) ((context)->uc_mcontext.mc_ebx) -#define ECX_sig(context) ((context)->uc_mcontext.mc_ecx) -#define EDX_sig(context) ((context)->uc_mcontext.mc_edx) -#define ESI_sig(context) ((context)->uc_mcontext.mc_esi) -#define EDI_sig(context) ((context)->uc_mcontext.mc_edi) -#define EBP_sig(context) ((context)->uc_mcontext.mc_ebp) - -#define CS_sig(context) ((context)->uc_mcontext.mc_cs) -#define DS_sig(context) ((context)->uc_mcontext.mc_ds) -#define ES_sig(context) ((context)->uc_mcontext.mc_es) -#define FS_sig(context) ((context)->uc_mcontext.mc_fs) -#define GS_sig(context) ((context)->uc_mcontext.mc_gs) -#define SS_sig(context) ((context)->uc_mcontext.mc_ss) - -#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) -#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) -#define EFL_sig(context) ((context)->uc_mcontext.mc_eflags) - -#define EIP_sig(context) ((context)->uc_mcontext.mc_eip) -#define ESP_sig(context) ((context)->uc_mcontext.mc_esp) - -#define FPU_sig(context) NULL /* FIXME */ -#define FPUX_sig(context) NULL /* FIXME */ - -#elif defined (__OpenBSD__) - -#include -#include - -#define EAX_sig(context) ((context)->sc_eax) -#define EBX_sig(context) ((context)->sc_ebx) -#define ECX_sig(context) ((context)->sc_ecx) -#define EDX_sig(context) ((context)->sc_edx) -#define ESI_sig(context) ((context)->sc_esi) -#define EDI_sig(context) ((context)->sc_edi) -#define EBP_sig(context) ((context)->sc_ebp) - -#define CS_sig(context) ((context)->sc_cs) -#define DS_sig(context) ((context)->sc_ds) -#define ES_sig(context) ((context)->sc_es) -#define FS_sig(context) ((context)->sc_fs) -#define GS_sig(context) ((context)->sc_gs) -#define SS_sig(context) ((context)->sc_ss) - -#define TRAP_sig(context) ((context)->sc_trapno) -#define ERROR_sig(context) ((context)->sc_err) -#define EFL_sig(context) ((context)->sc_eflags) - -#define EIP_sig(context) ((context)->sc_eip) -#define ESP_sig(context) ((context)->sc_esp) - -#define FPU_sig(context) NULL /* FIXME */ -#define FPUX_sig(context) NULL /* FIXME */ - -#define T_MCHK T_MACHK -#define T_XMMFLT T_XFTRAP - -#elif defined(__svr4__) || defined(_SCO_DS) || defined(__sun) - -#if defined(_SCO_DS) || defined(__sun) -#include -#endif - -#ifdef _SCO_DS -#define gregs regs -#endif - -#define EAX_sig(context) ((context)->uc_mcontext.gregs[EAX]) -#define EBX_sig(context) ((context)->uc_mcontext.gregs[EBX]) -#define ECX_sig(context) ((context)->uc_mcontext.gregs[ECX]) -#define EDX_sig(context) ((context)->uc_mcontext.gregs[EDX]) -#define ESI_sig(context) ((context)->uc_mcontext.gregs[ESI]) -#define EDI_sig(context) ((context)->uc_mcontext.gregs[EDI]) -#define EBP_sig(context) ((context)->uc_mcontext.gregs[EBP]) - -#define CS_sig(context) ((context)->uc_mcontext.gregs[CS]) -#define DS_sig(context) ((context)->uc_mcontext.gregs[DS]) -#define ES_sig(context) ((context)->uc_mcontext.gregs[ES]) -#define SS_sig(context) ((context)->uc_mcontext.gregs[SS]) - -#define FS_sig(context) ((context)->uc_mcontext.gregs[FS]) -#define GS_sig(context) ((context)->uc_mcontext.gregs[GS]) - -#define EFL_sig(context) ((context)->uc_mcontext.gregs[EFL]) - -#define EIP_sig(context) ((context)->uc_mcontext.gregs[EIP]) -#ifdef UESP -#define ESP_sig(context) ((context)->uc_mcontext.gregs[UESP]) -#elif defined(R_ESP) -#define ESP_sig(context) ((context)->uc_mcontext.gregs[R_ESP]) -#else -#define ESP_sig(context) ((context)->uc_mcontext.gregs[ESP]) -#endif -#ifdef ERR -#define ERROR_sig(context) ((context)->uc_mcontext.gregs[ERR]) -#endif -#ifdef TRAPNO -#define TRAP_sig(context) ((context)->uc_mcontext.gregs[TRAPNO]) -#endif - -#define FPU_sig(context) NULL /* FIXME */ -#define FPUX_sig(context) NULL /* FIXME */ - -#elif defined (__APPLE__) - -#include - -/* work around silly renaming of struct members in OS X 10.5 */ -#if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) -#define EAX_sig(context) ((context)->uc_mcontext->__ss.__eax) -#define EBX_sig(context) ((context)->uc_mcontext->__ss.__ebx) -#define ECX_sig(context) ((context)->uc_mcontext->__ss.__ecx) -#define EDX_sig(context) ((context)->uc_mcontext->__ss.__edx) -#define ESI_sig(context) ((context)->uc_mcontext->__ss.__esi) -#define EDI_sig(context) ((context)->uc_mcontext->__ss.__edi) -#define EBP_sig(context) ((context)->uc_mcontext->__ss.__ebp) -#define CS_sig(context) ((context)->uc_mcontext->__ss.__cs) -#define DS_sig(context) ((context)->uc_mcontext->__ss.__ds) -#define ES_sig(context) ((context)->uc_mcontext->__ss.__es) -#define FS_sig(context) ((context)->uc_mcontext->__ss.__fs) -#define GS_sig(context) ((context)->uc_mcontext->__ss.__gs) -#define SS_sig(context) ((context)->uc_mcontext->__ss.__ss) -#define EFL_sig(context) ((context)->uc_mcontext->__ss.__eflags) -#define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__eip)) -#define ESP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__esp)) -#define TRAP_sig(context) ((context)->uc_mcontext->__es.__trapno) -#define ERROR_sig(context) ((context)->uc_mcontext->__es.__err) -#define FPU_sig(context) NULL -#define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->__fs.__fpu_fcw) -#else -#define EAX_sig(context) ((context)->uc_mcontext->ss.eax) -#define EBX_sig(context) ((context)->uc_mcontext->ss.ebx) -#define ECX_sig(context) ((context)->uc_mcontext->ss.ecx) -#define EDX_sig(context) ((context)->uc_mcontext->ss.edx) -#define ESI_sig(context) ((context)->uc_mcontext->ss.esi) -#define EDI_sig(context) ((context)->uc_mcontext->ss.edi) -#define EBP_sig(context) ((context)->uc_mcontext->ss.ebp) -#define CS_sig(context) ((context)->uc_mcontext->ss.cs) -#define DS_sig(context) ((context)->uc_mcontext->ss.ds) -#define ES_sig(context) ((context)->uc_mcontext->ss.es) -#define FS_sig(context) ((context)->uc_mcontext->ss.fs) -#define GS_sig(context) ((context)->uc_mcontext->ss.gs) -#define SS_sig(context) ((context)->uc_mcontext->ss.ss) -#define EFL_sig(context) ((context)->uc_mcontext->ss.eflags) -#define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip)) -#define ESP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.esp)) -#define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) -#define ERROR_sig(context) ((context)->uc_mcontext->es.err) -#define FPU_sig(context) NULL -#define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->fs.fpu_fcw) -#endif - -#elif defined(__NetBSD__) - -#include -#include - -#define EAX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EAX]) -#define EBX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EBX]) -#define ECX_sig(context) ((context)->uc_mcontext.__gregs[_REG_ECX]) -#define EDX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EDX]) -#define ESI_sig(context) ((context)->uc_mcontext.__gregs[_REG_ESI]) -#define EDI_sig(context) ((context)->uc_mcontext.__gregs[_REG_EDI]) -#define EBP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EBP]) -#define ESP_sig(context) _UC_MACHINE_SP(context) - -#define CS_sig(context) ((context)->uc_mcontext.__gregs[_REG_CS]) -#define DS_sig(context) ((context)->uc_mcontext.__gregs[_REG_DS]) -#define ES_sig(context) ((context)->uc_mcontext.__gregs[_REG_ES]) -#define SS_sig(context) ((context)->uc_mcontext.__gregs[_REG_SS]) -#define FS_sig(context) ((context)->uc_mcontext.__gregs[_REG_FS]) -#define GS_sig(context) ((context)->uc_mcontext.__gregs[_REG_GS]) - -#define EFL_sig(context) ((context)->uc_mcontext.__gregs[_REG_EFL]) -#define EIP_sig(context) _UC_MACHINE_PC(context) -#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) -#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) - -#define FPU_sig(context) NULL -#define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&((context)->uc_mcontext.__fpregs)) - -#define T_MCHK T_MCA -#define T_XMMFLT T_XMM - -#elif defined(__GNU__) - -#include -#include - -#define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX]) -#define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX]) -#define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX]) -#define EDX_sig(context) ((context)->uc_mcontext.gregs[REG_EDX]) -#define ESI_sig(context) ((context)->uc_mcontext.gregs[REG_ESI]) -#define EDI_sig(context) ((context)->uc_mcontext.gregs[REG_EDI]) -#define EBP_sig(context) ((context)->uc_mcontext.gregs[REG_EBP]) -#define ESP_sig(context) ((context)->uc_mcontext.gregs[REG_ESP]) - -#define CS_sig(context) ((context)->uc_mcontext.gregs[REG_CS]) -#define DS_sig(context) ((context)->uc_mcontext.gregs[REG_DS]) -#define ES_sig(context) ((context)->uc_mcontext.gregs[REG_ES]) -#define SS_sig(context) ((context)->uc_mcontext.gregs[REG_SS]) -#define FS_sig(context) ((context)->uc_mcontext.gregs[REG_FS]) -#define GS_sig(context) ((context)->uc_mcontext.gregs[REG_GS]) - -#define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL]) -#define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) -#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) -#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) - -#define FPU_sig(context) ((FLOATING_SAVE_AREA *)&(context)->uc_mcontext.fpregs.fp_reg_set.fpchip_state) -#define FPUX_sig(context) NULL - -#else -#error You must define the signal context functions for your platform -#endif /* linux */ - -/* stack layout when calling an exception raise function */ -struct stack_layout -{ - void *ret_addr; /* return address from raise_generic_exception */ - EXCEPTION_RECORD *rec_ptr; /* first arg for raise_generic_exception */ - CONTEXT *context_ptr; /* second arg for raise_generic_exception */ - CONTEXT context; - EXCEPTION_RECORD rec; - DWORD ebp; - DWORD eip; -}; - -static ULONG first_ldt_entry = 32; - -enum i386_trap_code -{ - TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */ -#if defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) - TRAP_x86_DIVIDE = T_DIVIDE, /* Division by zero exception */ - TRAP_x86_TRCTRAP = T_TRCTRAP, /* Single-step exception */ - TRAP_x86_NMI = T_NMI, /* NMI interrupt */ - TRAP_x86_BPTFLT = T_BPTFLT, /* Breakpoint exception */ - TRAP_x86_OFLOW = T_OFLOW, /* Overflow exception */ - TRAP_x86_BOUND = T_BOUND, /* Bound range exception */ - TRAP_x86_PRIVINFLT = T_PRIVINFLT, /* Invalid opcode exception */ - TRAP_x86_DNA = T_DNA, /* Device not available exception */ - TRAP_x86_DOUBLEFLT = T_DOUBLEFLT, /* Double fault exception */ - TRAP_x86_FPOPFLT = T_FPOPFLT, /* Coprocessor segment overrun */ - TRAP_x86_TSSFLT = T_TSSFLT, /* Invalid TSS exception */ - TRAP_x86_SEGNPFLT = T_SEGNPFLT, /* Segment not present exception */ - TRAP_x86_STKFLT = T_STKFLT, /* Stack fault */ - TRAP_x86_PROTFLT = T_PROTFLT, /* General protection fault */ - TRAP_x86_PAGEFLT = T_PAGEFLT, /* Page fault */ - TRAP_x86_ARITHTRAP = T_ARITHTRAP, /* Floating point exception */ - TRAP_x86_ALIGNFLT = T_ALIGNFLT, /* Alignment check exception */ - TRAP_x86_MCHK = T_MCHK, /* Machine check exception */ - TRAP_x86_CACHEFLT = T_XMMFLT /* Cache flush exception */ -#else - TRAP_x86_DIVIDE = 0, /* Division by zero exception */ - TRAP_x86_TRCTRAP = 1, /* Single-step exception */ - TRAP_x86_NMI = 2, /* NMI interrupt */ - TRAP_x86_BPTFLT = 3, /* Breakpoint exception */ - TRAP_x86_OFLOW = 4, /* Overflow exception */ - TRAP_x86_BOUND = 5, /* Bound range exception */ - TRAP_x86_PRIVINFLT = 6, /* Invalid opcode exception */ - TRAP_x86_DNA = 7, /* Device not available exception */ - TRAP_x86_DOUBLEFLT = 8, /* Double fault exception */ - TRAP_x86_FPOPFLT = 9, /* Coprocessor segment overrun */ - TRAP_x86_TSSFLT = 10, /* Invalid TSS exception */ - TRAP_x86_SEGNPFLT = 11, /* Segment not present exception */ - TRAP_x86_STKFLT = 12, /* Stack fault */ - TRAP_x86_PROTFLT = 13, /* General protection fault */ - TRAP_x86_PAGEFLT = 14, /* Page fault */ - TRAP_x86_ARITHTRAP = 16, /* Floating point exception */ - TRAP_x86_ALIGNFLT = 17, /* Alignment check exception */ - TRAP_x86_MCHK = 18, /* Machine check exception */ - TRAP_x86_CACHEFLT = 19 /* SIMD exception (via SIGFPE) if CPU is SSE capable - otherwise Cache flush exception (via SIGSEV) */ -#endif -}; struct x86_thread_data { @@ -513,13 +95,6 @@ static inline struct x86_thread_data *x86_thread_data(void) return (struct x86_thread_data *)NtCurrentTeb()->SystemReserved2; } -static inline WORD get_cs(void) { WORD res; __asm__( "movw %%cs,%0" : "=r" (res) ); return res; } -static inline WORD get_ds(void) { WORD res; __asm__( "movw %%ds,%0" : "=r" (res) ); return res; } -static inline WORD get_fs(void) { WORD res; __asm__( "movw %%fs,%0" : "=r" (res) ); return res; } -static inline WORD get_gs(void) { WORD res; __asm__( "movw %%gs,%0" : "=r" (res) ); return res; } -static inline void set_fs( WORD val ) { __asm__( "mov %0,%%fs" :: "r" (val)); } -static inline void set_gs( WORD val ) { __asm__( "mov %0,%%gs" :: "r" (val)); } - /* Exception record for handling exceptions happening inside exception handlers */ typedef struct { @@ -531,61 +106,6 @@ extern DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_R CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher, PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler ); -/*********************************************************************** - * is_gdt_sel - */ -static inline int is_gdt_sel( WORD sel ) -{ - return !(sel & 4); -} - -/*********************************************************************** - * ldt_is_system - */ -static inline int ldt_is_system( WORD sel ) -{ - return is_gdt_sel( sel ) || ((sel >> 3) < first_ldt_entry); -} - -/*********************************************************************** - * get_trap_code - * - * Get the trap code for a signal. - */ -static inline enum i386_trap_code get_trap_code( const ucontext_t *sigcontext ) -{ -#ifdef TRAP_sig - return TRAP_sig(sigcontext); -#else - return TRAP_x86_UNKNOWN; /* unknown trap code */ -#endif -} - -/*********************************************************************** - * get_error_code - * - * Get the error code for a signal. - */ -static inline WORD get_error_code( const ucontext_t *sigcontext ) -{ -#ifdef ERROR_sig - return ERROR_sig(sigcontext); -#else - return 0; -#endif -} - -/*********************************************************************** - * get_signal_stack - * - * Get the base of the signal stack for the current thread. - */ -static inline void *get_signal_stack(void) -{ - return (char *)NtCurrentTeb() + 4096; -} - - /*********************************************************************** * has_fpux */ @@ -595,19 +115,6 @@ static inline int has_fpux(void) } -/*********************************************************************** - * get_current_teb - * - * Get the current teb based on the stack pointer. - */ -static inline TEB *get_current_teb(void) -{ - unsigned long esp; - __asm__("movl %%esp,%0" : "=g" (esp) ); - return (TEB *)(esp & ~signal_stack_mask); -} - - /******************************************************************* * is_valid_frame */ @@ -753,111 +260,6 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte } -#ifdef __sun - -/* We have to workaround two Solaris breakages: - * - Solaris doesn't restore %ds and %es before calling the signal handler so exceptions in 16-bit - * code crash badly. - * - Solaris inserts a libc trampoline to call our handler, but the trampoline expects that registers - * are setup correctly. So we need to insert our own trampoline below the libc trampoline to set %gs. - */ - -extern int sigaction_syscall( int sig, const struct sigaction *new, struct sigaction *old ); -__ASM_GLOBAL_FUNC( sigaction_syscall, - "movl $0x62,%eax\n\t" - "int $0x91\n\t" - "ret" ) - -/* assume the same libc handler is used for all signals */ -static void (*libc_sigacthandler)( int signal, siginfo_t *siginfo, void *context ); - -static void wine_sigacthandler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct x86_thread_data *thread_data; - - __asm__ __volatile__("mov %ss,%ax; mov %ax,%ds; mov %ax,%es"); - - thread_data = (struct x86_thread_data *)get_current_teb()->SystemReserved2; - set_fs( thread_data->fs ); - set_gs( thread_data->gs ); - - libc_sigacthandler( signal, siginfo, sigcontext ); -} - -static int solaris_sigaction( int sig, const struct sigaction *new, struct sigaction *old ) -{ - struct sigaction real_act; - - if (sigaction( sig, new, old ) == -1) return -1; - - /* retrieve the real handler and flags with a direct syscall */ - sigaction_syscall( sig, NULL, &real_act ); - libc_sigacthandler = real_act.sa_sigaction; - real_act.sa_sigaction = wine_sigacthandler; - sigaction_syscall( sig, &real_act, NULL ); - return 0; -} -#define sigaction(sig,new,old) solaris_sigaction(sig,new,old) - -#endif - -extern void clear_alignment_flag(void); -__ASM_GLOBAL_FUNC( clear_alignment_flag, - "pushfl\n\t" - __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") - "andl $~0x40000,(%esp)\n\t" - "popfl\n\t" - __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") - "ret" ) - - -/*********************************************************************** - * init_handler - * - * Handler initialization when the full context is not needed. - * Return the stack pointer to use for pushing the exception data. - */ -static inline void *init_handler( const ucontext_t *sigcontext, WORD *fs, WORD *gs ) -{ - TEB *teb = get_current_teb(); - - clear_alignment_flag(); - - /* get %fs and %gs at time of the fault */ -#ifdef FS_sig - *fs = LOWORD(FS_sig(sigcontext)); -#else - *fs = get_fs(); -#endif -#ifdef GS_sig - *gs = LOWORD(GS_sig(sigcontext)); -#else - *gs = get_gs(); -#endif - -#ifndef __sun /* see above for Solaris handling */ - { - struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2; - set_fs( thread_data->fs ); - set_gs( thread_data->gs ); - } -#endif - - if (!ldt_is_system(CS_sig(sigcontext)) || !ldt_is_system(SS_sig(sigcontext))) /* 16-bit mode */ - { - /* - * Win16 or DOS protected mode. Note that during switch - * from 16-bit mode to linear mode, CS may be set to system - * segment before FS is restored. Fortunately, in this case - * SS is still non-system segment. This is why both CS and SS - * are checked. - */ - return teb->WOW32Reserved; - } - return (void *)(ESP_sig(sigcontext) & ~3); -} - - /*********************************************************************** * save_fpu * @@ -910,165 +312,6 @@ static inline void save_fpux( CONTEXT *context ) } -/*********************************************************************** - * restore_fpu - * - * Restore the FPU context to a sigcontext. - */ -static inline void restore_fpu( const CONTEXT *context ) -{ - FLOATING_SAVE_AREA float_status = context->FloatSave; - /* reset the current interrupt status */ - float_status.StatusWord &= float_status.ControlWord | 0xffffff80; -#ifdef __GNUC__ - __asm__ __volatile__( "frstor %0; fwait" : : "m" (float_status) ); -#endif /* __GNUC__ */ -} - - -/*********************************************************************** - * fpux_to_fpu - * - * Build a standard FPU context from an extended one. - */ -static void fpux_to_fpu( FLOATING_SAVE_AREA *fpu, const XMM_SAVE_AREA32 *fpux ) -{ - unsigned int i, tag, stack_top; - - fpu->ControlWord = fpux->ControlWord | 0xffff0000; - fpu->StatusWord = fpux->StatusWord | 0xffff0000; - fpu->ErrorOffset = fpux->ErrorOffset; - fpu->ErrorSelector = fpux->ErrorSelector | (fpux->ErrorOpcode << 16); - fpu->DataOffset = fpux->DataOffset; - fpu->DataSelector = fpux->DataSelector; - fpu->Cr0NpxState = fpux->StatusWord | 0xffff0000; - - stack_top = (fpux->StatusWord >> 11) & 7; - fpu->TagWord = 0xffff0000; - for (i = 0; i < 8; i++) - { - memcpy( &fpu->RegisterArea[10 * i], &fpux->FloatRegisters[i], 10 ); - if (!(fpux->TagWord & (1 << i))) tag = 3; /* empty */ - else - { - const M128A *reg = &fpux->FloatRegisters[(i - stack_top) & 7]; - if ((reg->High & 0x7fff) == 0x7fff) /* exponent all ones */ - { - tag = 2; /* special */ - } - else if (!(reg->High & 0x7fff)) /* exponent all zeroes */ - { - if (reg->Low) tag = 2; /* special */ - else tag = 1; /* zero */ - } - else - { - if (reg->Low >> 63) tag = 0; /* valid */ - else tag = 2; /* special */ - } - } - fpu->TagWord |= tag << (2 * i); - } -} - - -/*********************************************************************** - * save_context - * - * Build a context structure from the signal info. - */ -static inline void save_context( CONTEXT *context, const ucontext_t *sigcontext, WORD fs, WORD gs ) -{ - FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); - XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext); - - memset(context, 0, sizeof(*context)); - context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; - context->Eax = EAX_sig(sigcontext); - context->Ebx = EBX_sig(sigcontext); - context->Ecx = ECX_sig(sigcontext); - context->Edx = EDX_sig(sigcontext); - context->Esi = ESI_sig(sigcontext); - context->Edi = EDI_sig(sigcontext); - context->Ebp = EBP_sig(sigcontext); - context->EFlags = EFL_sig(sigcontext); - context->Eip = EIP_sig(sigcontext); - context->Esp = ESP_sig(sigcontext); - context->SegCs = LOWORD(CS_sig(sigcontext)); - context->SegDs = LOWORD(DS_sig(sigcontext)); - context->SegEs = LOWORD(ES_sig(sigcontext)); - context->SegFs = fs; - context->SegGs = gs; - context->SegSs = LOWORD(SS_sig(sigcontext)); - context->Dr0 = x86_thread_data()->dr0; - context->Dr1 = x86_thread_data()->dr1; - context->Dr2 = x86_thread_data()->dr2; - context->Dr3 = x86_thread_data()->dr3; - context->Dr6 = x86_thread_data()->dr6; - context->Dr7 = x86_thread_data()->dr7; - - if (fpu) - { - context->ContextFlags |= CONTEXT_FLOATING_POINT; - context->FloatSave = *fpu; - } - if (fpux) - { - context->ContextFlags |= CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; - memcpy( context->ExtendedRegisters, fpux, sizeof(*fpux) ); - if (!fpu) fpux_to_fpu( &context->FloatSave, fpux ); - } - if (!fpu && !fpux) save_fpu( context ); -} - - -/*********************************************************************** - * restore_context - * - * Restore the signal info from the context. - */ -static inline void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) -{ - FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); - XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext); - - x86_thread_data()->dr0 = context->Dr0; - x86_thread_data()->dr1 = context->Dr1; - x86_thread_data()->dr2 = context->Dr2; - x86_thread_data()->dr3 = context->Dr3; - x86_thread_data()->dr6 = context->Dr6; - x86_thread_data()->dr7 = context->Dr7; - EAX_sig(sigcontext) = context->Eax; - EBX_sig(sigcontext) = context->Ebx; - ECX_sig(sigcontext) = context->Ecx; - EDX_sig(sigcontext) = context->Edx; - ESI_sig(sigcontext) = context->Esi; - EDI_sig(sigcontext) = context->Edi; - EBP_sig(sigcontext) = context->Ebp; - EFL_sig(sigcontext) = context->EFlags; - EIP_sig(sigcontext) = context->Eip; - ESP_sig(sigcontext) = context->Esp; - CS_sig(sigcontext) = context->SegCs; - DS_sig(sigcontext) = context->SegDs; - ES_sig(sigcontext) = context->SegEs; - SS_sig(sigcontext) = context->SegSs; -#ifdef GS_sig - GS_sig(sigcontext) = context->SegGs; -#else - set_gs( context->SegGs ); -#endif -#ifdef FS_sig - FS_sig(sigcontext) = context->SegFs; -#else - set_fs( context->SegFs ); -#endif - - if (fpu) *fpu = context->FloatSave; - if (fpux) memcpy( fpux, context->ExtendedRegisters, sizeof(*fpux) ); - if (!fpu && !fpux) restore_fpu( context ); -} - - /*********************************************************************** * RtlCaptureContext (NTDLL.@) */ @@ -1152,738 +395,6 @@ __ASM_STDCALL_FUNC( NtGetContextThread, 8, "ret $8" ) -/*********************************************************************** - * is_privileged_instr - * - * Check if the fault location is a privileged instruction. - * Based on the instruction emulation code in dlls/kernel/instr.c. - */ -static inline DWORD is_privileged_instr( CONTEXT *context ) -{ - BYTE instr[16]; - unsigned int i, len, prefix_count = 0; - - if (!ldt_is_system( context->SegCs )) return 0; - len = unix_funcs->virtual_uninterrupted_read_memory( (BYTE *)context->Eip, instr, sizeof(instr) ); - - for (i = 0; i < len; i++) switch (instr[i]) - { - /* instruction prefixes */ - case 0x2e: /* %cs: */ - case 0x36: /* %ss: */ - case 0x3e: /* %ds: */ - case 0x26: /* %es: */ - case 0x64: /* %fs: */ - case 0x65: /* %gs: */ - case 0x66: /* opcode size */ - case 0x67: /* addr size */ - case 0xf0: /* lock */ - case 0xf2: /* repne */ - case 0xf3: /* repe */ - if (++prefix_count >= 15) return EXCEPTION_ILLEGAL_INSTRUCTION; - continue; - - case 0x0f: /* extended instruction */ - if (i == len - 1) return 0; - switch(instr[i + 1]) - { - case 0x20: /* mov crX, reg */ - case 0x21: /* mov drX, reg */ - case 0x22: /* mov reg, crX */ - case 0x23: /* mov reg drX */ - return EXCEPTION_PRIV_INSTRUCTION; - } - return 0; - case 0x6c: /* insb (%dx) */ - case 0x6d: /* insl (%dx) */ - case 0x6e: /* outsb (%dx) */ - case 0x6f: /* outsl (%dx) */ - case 0xcd: /* int $xx */ - case 0xe4: /* inb al,XX */ - case 0xe5: /* in (e)ax,XX */ - case 0xe6: /* outb XX,al */ - case 0xe7: /* out XX,(e)ax */ - case 0xec: /* inb (%dx),%al */ - case 0xed: /* inl (%dx),%eax */ - case 0xee: /* outb %al,(%dx) */ - case 0xef: /* outl %eax,(%dx) */ - case 0xf4: /* hlt */ - case 0xfa: /* cli */ - case 0xfb: /* sti */ - return EXCEPTION_PRIV_INSTRUCTION; - default: - return 0; - } - return 0; -} - - -/*********************************************************************** - * check_invalid_gs - * - * Check for fault caused by invalid %gs value (some copy protection schemes mess with it). - */ -static inline BOOL check_invalid_gs( ucontext_t *sigcontext, CONTEXT *context ) -{ - unsigned int prefix_count = 0; - const BYTE *instr = (BYTE *)context->Eip; - WORD system_gs = x86_thread_data()->gs; - - if (context->SegGs == system_gs) return FALSE; - if (!ldt_is_system( context->SegCs )) return FALSE; - /* only handle faults in system libraries */ - if (unix_funcs->virtual_is_valid_code_address( instr, 1 )) return FALSE; - - for (;;) switch(*instr) - { - /* instruction prefixes */ - case 0x2e: /* %cs: */ - case 0x36: /* %ss: */ - case 0x3e: /* %ds: */ - case 0x26: /* %es: */ - case 0x64: /* %fs: */ - case 0x66: /* opcode size */ - case 0x67: /* addr size */ - case 0xf0: /* lock */ - case 0xf2: /* repne */ - case 0xf3: /* repe */ - if (++prefix_count >= 15) return FALSE; - instr++; - continue; - case 0x65: /* %gs: */ - TRACE( "%04x/%04x at %p, fixing up\n", context->SegGs, system_gs, instr ); -#ifdef GS_sig - GS_sig(sigcontext) = system_gs; -#endif - return TRUE; - default: - return FALSE; - } -} - - -#include "pshpack1.h" -union atl_thunk -{ - struct - { - DWORD movl; /* movl this,4(%esp) */ - DWORD this; - BYTE jmp; /* jmp func */ - int func; - } t1; - struct - { - BYTE movl; /* movl this,ecx */ - DWORD this; - BYTE jmp; /* jmp func */ - int func; - } t2; - struct - { - BYTE movl1; /* movl this,edx */ - DWORD this; - BYTE movl2; /* movl func,ecx */ - DWORD func; - WORD jmp; /* jmp ecx */ - } t3; - struct - { - BYTE movl1; /* movl this,ecx */ - DWORD this; - BYTE movl2; /* movl func,eax */ - DWORD func; - WORD jmp; /* jmp eax */ - } t4; - struct - { - DWORD inst1; /* pop ecx - * pop eax - * push ecx - * jmp 4(%eax) */ - WORD inst2; - } t5; -}; -#include "poppack.h" - -/********************************************************************** - * check_atl_thunk - * - * Check if code destination is an ATL thunk, and emulate it if so. - */ -static BOOL check_atl_thunk( ucontext_t *sigcontext, struct stack_layout *stack ) -{ - const union atl_thunk *thunk = (const union atl_thunk *)stack->rec.ExceptionInformation[1]; - union atl_thunk thunk_copy; - SIZE_T thunk_len; - - thunk_len = unix_funcs->virtual_uninterrupted_read_memory( thunk, &thunk_copy, sizeof(*thunk) ); - if (!thunk_len) return FALSE; - - if (thunk_len >= sizeof(thunk_copy.t1) && thunk_copy.t1.movl == 0x042444c7 && - thunk_copy.t1.jmp == 0xe9) - { - if (!unix_funcs->virtual_uninterrupted_write_memory( (DWORD *)stack->context.Esp + 1, - &thunk_copy.t1.this, sizeof(DWORD) )) - { - EIP_sig(sigcontext) = (DWORD_PTR)(&thunk->t1.func + 1) + thunk_copy.t1.func; - TRACE( "emulating ATL thunk type 1 at %p, func=%08x arg=%08x\n", - thunk, EIP_sig(sigcontext), thunk_copy.t1.this ); - return TRUE; - } - } - else if (thunk_len >= sizeof(thunk_copy.t2) && thunk_copy.t2.movl == 0xb9 && - thunk_copy.t2.jmp == 0xe9) - { - ECX_sig(sigcontext) = thunk_copy.t2.this; - EIP_sig(sigcontext) = (DWORD_PTR)(&thunk->t2.func + 1) + thunk_copy.t2.func; - TRACE( "emulating ATL thunk type 2 at %p, func=%08x ecx=%08x\n", - thunk, EIP_sig(sigcontext), ECX_sig(sigcontext) ); - return TRUE; - } - else if (thunk_len >= sizeof(thunk_copy.t3) && thunk_copy.t3.movl1 == 0xba && - thunk_copy.t3.movl2 == 0xb9 && - thunk_copy.t3.jmp == 0xe1ff) - { - EDX_sig(sigcontext) = thunk_copy.t3.this; - ECX_sig(sigcontext) = thunk_copy.t3.func; - EIP_sig(sigcontext) = thunk_copy.t3.func; - TRACE( "emulating ATL thunk type 3 at %p, func=%08x ecx=%08x edx=%08x\n", - thunk, EIP_sig(sigcontext), ECX_sig(sigcontext), EDX_sig(sigcontext) ); - return TRUE; - } - else if (thunk_len >= sizeof(thunk_copy.t4) && thunk_copy.t4.movl1 == 0xb9 && - thunk_copy.t4.movl2 == 0xb8 && - thunk_copy.t4.jmp == 0xe0ff) - { - ECX_sig(sigcontext) = thunk_copy.t4.this; - EAX_sig(sigcontext) = thunk_copy.t4.func; - EIP_sig(sigcontext) = thunk_copy.t4.func; - TRACE( "emulating ATL thunk type 4 at %p, func=%08x eax=%08x ecx=%08x\n", - thunk, EIP_sig(sigcontext), EAX_sig(sigcontext), ECX_sig(sigcontext) ); - return TRUE; - } - else if (thunk_len >= sizeof(thunk_copy.t5) && thunk_copy.t5.inst1 == 0xff515859 && - thunk_copy.t5.inst2 == 0x0460) - { - DWORD func, sp[2]; - if (unix_funcs->virtual_uninterrupted_read_memory( (DWORD *)stack->context.Esp, sp, sizeof(sp) ) == sizeof(sp) && - unix_funcs->virtual_uninterrupted_read_memory( (DWORD *)sp[1] + 1, &func, sizeof(DWORD) ) == sizeof(DWORD) && - !unix_funcs->virtual_uninterrupted_write_memory( (DWORD *)stack->context.Esp + 1, &sp[0], sizeof(sp[0]) )) - { - ECX_sig(sigcontext) = sp[0]; - EAX_sig(sigcontext) = sp[1]; - ESP_sig(sigcontext) += sizeof(DWORD); - EIP_sig(sigcontext) = func; - TRACE( "emulating ATL thunk type 5 at %p, func=%08x eax=%08x ecx=%08x esp=%08x\n", - thunk, EIP_sig(sigcontext), EAX_sig(sigcontext), - ECX_sig(sigcontext), ESP_sig(sigcontext) ); - return TRUE; - } - } - - return FALSE; -} - - -/*********************************************************************** - * setup_exception_record - * - * Setup the exception record and context on the thread stack. - */ -static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void *stack_ptr, - WORD fs, WORD gs ) -{ - struct stack_layout *stack = stack_ptr; - DWORD exception_code = 0; - - /* stack sanity checks */ - - if ((char *)stack >= (char *)get_signal_stack() && - (char *)stack < (char *)get_signal_stack() + signal_stack_size) - { - WINE_ERR( "nested exception on signal stack in thread %04x eip %08x esp %08x stack %p-%p\n", - GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), - (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit, - NtCurrentTeb()->Tib.StackBase ); - unix_funcs->abort_thread(1); - } - - if (stack - 1 > stack || /* check for overflow in subtraction */ - (char *)stack <= (char *)NtCurrentTeb()->DeallocationStack || - (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase) - { - WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n", - GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), - (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit, - NtCurrentTeb()->Tib.StackBase ); - } - else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096) - { - /* stack overflow on last page, unrecoverable */ - UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1); - WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n", - diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), - (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, - NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); - unix_funcs->abort_thread(1); - } - else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit) - { - /* stack access below stack limit, may be recoverable */ - switch (unix_funcs->virtual_handle_stack_fault( stack - 1 )) - { - case 0: /* not handled */ - { - UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1); - WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n", - diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), - (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, - NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); - unix_funcs->abort_thread(1); - } - case -1: /* overflow */ - exception_code = EXCEPTION_STACK_OVERFLOW; - break; - } - } - - stack--; /* push the stack_layout structure */ -#if defined(VALGRIND_MAKE_MEM_UNDEFINED) - VALGRIND_MAKE_MEM_UNDEFINED(stack, sizeof(*stack)); -#elif defined(VALGRIND_MAKE_WRITABLE) - VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack)); -#endif - stack->rec.ExceptionRecord = NULL; - stack->rec.ExceptionCode = exception_code; - stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext); - stack->rec.NumberParameters = 0; - - save_context( &stack->context, sigcontext, fs, gs ); - return stack; -} - - -/*********************************************************************** - * setup_exception - * - * Setup a proper stack frame for the raise function, and modify the - * sigcontext so that the return from the signal handler will call - * the raise function. - */ -static struct stack_layout *setup_exception( ucontext_t *sigcontext ) -{ - WORD fs, gs; - void *stack = init_handler( sigcontext, &fs, &gs ); - - return setup_exception_record( sigcontext, stack, fs, gs ); -} - - -/*********************************************************************** - * setup_raise_exception - * - * Change context to setup a call to a raise exception function. - */ -static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *stack ) -{ - NTSTATUS status = send_debug_event( &stack->rec, TRUE, &stack->context ); - - if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) - { - restore_context( &stack->context, sigcontext ); - return; - } - ESP_sig(sigcontext) = (DWORD)stack; - EIP_sig(sigcontext) = (DWORD)KiUserExceptionDispatcher; - /* clear single-step, direction, and align check flag */ - EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000); - CS_sig(sigcontext) = get_cs(); - DS_sig(sigcontext) = get_ds(); - ES_sig(sigcontext) = get_ds(); - FS_sig(sigcontext) = get_fs(); - GS_sig(sigcontext) = get_gs(); - SS_sig(sigcontext) = get_ds(); - stack->ret_addr = (void *)0xdeadbabe; /* KiUserExceptionDispatcher must not return */ - stack->rec_ptr = &stack->rec; /* arguments for KiUserExceptionDispatcher */ - stack->context_ptr = &stack->context; -} - - -/********************************************************************** - * get_fpu_code - * - * Get the FPU exception code from the FPU status. - */ -static inline DWORD get_fpu_code( const CONTEXT *context ) -{ - DWORD status = context->FloatSave.StatusWord & ~(context->FloatSave.ControlWord & 0x3f); - - if (status & 0x01) /* IE */ - { - if (status & 0x40) /* SF */ - return EXCEPTION_FLT_STACK_CHECK; - else - return EXCEPTION_FLT_INVALID_OPERATION; - } - if (status & 0x02) return EXCEPTION_FLT_DENORMAL_OPERAND; /* DE flag */ - if (status & 0x04) return EXCEPTION_FLT_DIVIDE_BY_ZERO; /* ZE flag */ - if (status & 0x08) return EXCEPTION_FLT_OVERFLOW; /* OE flag */ - if (status & 0x10) return EXCEPTION_FLT_UNDERFLOW; /* UE flag */ - if (status & 0x20) return EXCEPTION_FLT_INEXACT_RESULT; /* PE flag */ - return EXCEPTION_FLT_INVALID_OPERATION; /* generic error */ -} - - -/*********************************************************************** - * handle_interrupt - * - * Handle an interrupt. - */ -static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, struct stack_layout *stack ) -{ - switch(interrupt) - { - case 0x2d: - if (!is_wow64) - { - /* On Wow64, the upper DWORD of Rax contains garbage, and the debug - * service is usually not recognized when called from usermode. */ - switch (stack->context.Eax) - { - case 1: /* BREAKPOINT_PRINT */ - case 3: /* BREAKPOINT_LOAD_SYMBOLS */ - case 4: /* BREAKPOINT_UNLOAD_SYMBOLS */ - case 5: /* BREAKPOINT_COMMAND_STRING (>= Win2003) */ - EIP_sig(sigcontext) += 3; - return TRUE; - } - } - stack->context.Eip += 3; - stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; - stack->rec.ExceptionAddress = (void *)stack->context.Eip; - stack->rec.NumberParameters = is_wow64 ? 1 : 3; - stack->rec.ExceptionInformation[0] = stack->context.Eax; - stack->rec.ExceptionInformation[1] = stack->context.Ecx; - stack->rec.ExceptionInformation[2] = stack->context.Edx; - setup_raise_exception( sigcontext, stack ); - return TRUE; - default: - return FALSE; - } -} - - -/********************************************************************** - * segv_handler - * - * Handler for SIGSEGV and related errors. - */ -static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - WORD fs, gs; - struct stack_layout *stack; - ucontext_t *context = sigcontext; - void *stack_ptr = init_handler( sigcontext, &fs, &gs ); - - /* check for exceptions on the signal stack caused by write watches */ - if (get_trap_code(context) == TRAP_x86_PAGEFLT && - (char *)stack_ptr >= (char *)get_signal_stack() && - (char *)stack_ptr < (char *)get_signal_stack() + signal_stack_size && - !unix_funcs->virtual_handle_fault( siginfo->si_addr, (get_error_code(context) >> 1) & 0x09, TRUE )) - { - return; - } - - /* check for page fault inside the thread stack */ - if (get_trap_code(context) == TRAP_x86_PAGEFLT) - { - switch (unix_funcs->virtual_handle_stack_fault( siginfo->si_addr )) - { - case 1: /* handled */ - return; - case -1: /* overflow */ - stack = setup_exception_record( context, stack_ptr, fs, gs ); - stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; - goto done; - } - } - - stack = setup_exception_record( context, stack_ptr, fs, gs ); - if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done; - - switch(get_trap_code(context)) - { - case TRAP_x86_OFLOW: /* Overflow exception */ - stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; - break; - case TRAP_x86_BOUND: /* Bound range exception */ - stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; - break; - case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */ - stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; - break; - case TRAP_x86_STKFLT: /* Stack fault */ - stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; - break; - case TRAP_x86_SEGNPFLT: /* Segment not present exception */ - case TRAP_x86_PROTFLT: /* General protection fault */ - case TRAP_x86_UNKNOWN: /* Unknown fault code */ - { - WORD err = get_error_code(context); - if (!err && (stack->rec.ExceptionCode = is_privileged_instr( &stack->context ))) break; - if ((err & 7) == 2 && handle_interrupt( err >> 3, context, stack )) return; - stack->rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION; - stack->rec.NumberParameters = 2; - stack->rec.ExceptionInformation[0] = 0; - /* if error contains a LDT selector, use that as fault address */ - if ((err & 7) == 4 && !ldt_is_system( err | 7 )) - stack->rec.ExceptionInformation[1] = err & ~7; - else - { - stack->rec.ExceptionInformation[1] = 0xffffffff; - if (check_invalid_gs( context, &stack->context )) return; - } - } - break; - case TRAP_x86_PAGEFLT: /* Page fault */ - stack->rec.NumberParameters = 2; - stack->rec.ExceptionInformation[0] = (get_error_code(context) >> 1) & 0x09; - stack->rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; - stack->rec.ExceptionCode = unix_funcs->virtual_handle_fault( (void *)stack->rec.ExceptionInformation[1], - stack->rec.ExceptionInformation[0], FALSE ); - if (!stack->rec.ExceptionCode) return; - if (stack->rec.ExceptionCode == EXCEPTION_ACCESS_VIOLATION && - stack->rec.ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT) - { - ULONG flags; - NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, - &flags, sizeof(flags), NULL ); - if (!(flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) && check_atl_thunk( context, stack )) - return; - - /* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */ - if (!(flags & MEM_EXECUTE_OPTION_DISABLE)) - stack->rec.ExceptionInformation[0] = EXCEPTION_READ_FAULT; - } - break; - case TRAP_x86_ALIGNFLT: /* Alignment check exception */ - /* FIXME: pass through exception handler first? */ - if (stack->context.EFlags & 0x00040000) - { - EFL_sig(context) &= ~0x00040000; /* disable AC flag */ - return; - } - stack->rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; - break; - default: - WINE_ERR( "Got unexpected trap %d\n", get_trap_code(context) ); - /* fall through */ - case TRAP_x86_NMI: /* NMI interrupt */ - case TRAP_x86_DNA: /* Device not available exception */ - case TRAP_x86_DOUBLEFLT: /* Double fault exception */ - case TRAP_x86_TSSFLT: /* Invalid TSS exception */ - case TRAP_x86_MCHK: /* Machine check exception */ - case TRAP_x86_CACHEFLT: /* Cache flush exception */ - stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; - break; - } -done: - setup_raise_exception( context, stack ); -} - - -/********************************************************************** - * trap_handler - * - * Handler for SIGTRAP. - */ -static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - ucontext_t *context = sigcontext; - struct stack_layout *stack = setup_exception( context ); - - switch(get_trap_code(context)) - { - case TRAP_x86_TRCTRAP: /* Single-step exception */ - stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP; - /* when single stepping can't tell whether this is a hw bp or a - * single step interrupt. try to avoid as much overhead as possible - * and only do a server call if there is any hw bp enabled. */ - if (!(stack->context.EFlags & 0x100) || (stack->context.Dr7 & 0xff)) - { - /* (possible) hardware breakpoint, fetch the debug registers */ - DWORD saved_flags = stack->context.ContextFlags; - stack->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; - NtGetContextThread( GetCurrentThread(), &stack->context ); - stack->context.ContextFlags |= saved_flags; /* restore flags */ - } - stack->context.EFlags &= ~0x100; /* clear single-step flag */ - break; - case TRAP_x86_BPTFLT: /* Breakpoint exception */ - stack->rec.ExceptionAddress = (char *)stack->rec.ExceptionAddress - 1; /* back up over the int3 instruction */ - /* fall through */ - default: - stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; - stack->rec.NumberParameters = is_wow64 ? 1 : 3; - stack->rec.ExceptionInformation[0] = 0; - stack->rec.ExceptionInformation[1] = 0; /* FIXME */ - stack->rec.ExceptionInformation[2] = 0; /* FIXME */ - break; - } - setup_raise_exception( context, stack ); -} - - -/********************************************************************** - * fpe_handler - * - * Handler for SIGFPE. - */ -static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - ucontext_t *context = sigcontext; - struct stack_layout *stack = setup_exception( context ); - - switch(get_trap_code(context)) - { - case TRAP_x86_DIVIDE: /* Division by zero exception */ - stack->rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; - break; - case TRAP_x86_FPOPFLT: /* Coprocessor segment overrun */ - stack->rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; - break; - case TRAP_x86_ARITHTRAP: /* Floating point exception */ - case TRAP_x86_UNKNOWN: /* Unknown fault code */ - stack->rec.ExceptionCode = get_fpu_code( &stack->context ); - stack->rec.ExceptionAddress = (LPVOID)stack->context.FloatSave.ErrorOffset; - break; - case TRAP_x86_CACHEFLT: /* SIMD exception */ - /* TODO: - * Behaviour only tested for divide-by-zero exceptions - * Check for other SIMD exceptions as well */ - if(siginfo->si_code != FPE_FLTDIV && siginfo->si_code != FPE_FLTINV) - FIXME("untested SIMD exception: %#x. Might not work correctly\n", - siginfo->si_code); - - stack->rec.ExceptionCode = STATUS_FLOAT_MULTIPLE_TRAPS; - stack->rec.NumberParameters = 1; - /* no idea what meaning is actually behind this but that's what native does */ - stack->rec.ExceptionInformation[0] = 0; - break; - default: - WINE_ERR( "Got unexpected trap %d\n", get_trap_code(context) ); - stack->rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; - break; - } - - setup_raise_exception( context, stack ); -} - - -/********************************************************************** - * int_handler - * - * Handler for SIGINT. - */ -static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack = setup_exception( sigcontext ); - stack->rec.ExceptionCode = CONTROL_C_EXIT; - setup_raise_exception( sigcontext, stack ); -} - -/********************************************************************** - * abrt_handler - * - * Handler for SIGABRT. - */ -static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack = setup_exception( sigcontext ); - stack->rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; - stack->rec.ExceptionFlags = EH_NONCONTINUABLE; - setup_raise_exception( sigcontext, stack ); -} - - -/********************************************************************** - * quit_handler - * - * Handler for SIGQUIT. - */ -static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - WORD fs, gs; - init_handler( sigcontext, &fs, &gs ); - unix_funcs->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; - WORD fs, gs; - - init_handler( sigcontext, &fs, &gs ); - save_context( &context, sigcontext, fs, gs ); - wait_suspend( &context ); - restore_context( &context, sigcontext ); -} - - -/********************************************************************** - * signal_init_process - */ -void signal_init_process(void) -{ - struct sigaction sig_act; - - sig_act.sa_mask = server_block_set; - sig_act.sa_flags = SA_SIGINFO | SA_RESTART; -#ifdef SA_ONSTACK - sig_act.sa_flags |= SA_ONSTACK; -#endif -#ifdef __ANDROID__ - sig_act.sa_flags |= SA_RESTORER; - sig_act.sa_restorer = rt_sigreturn; -#endif - 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 = segv_handler; - if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; -#ifdef SIGBUS - if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; -#endif - -#ifdef SIGTRAP - sig_act.sa_sigaction = trap_handler; - if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error; -#endif - return; - - error: - perror("sigaction"); - exit(1); -} - - /******************************************************************* * RtlUnwind (NTDLL.@) */ diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c index 879b2b58c49..8d761f48e11 100644 --- a/dlls/ntdll/signal_powerpc.c +++ b/dlls/ntdll/signal_powerpc.c @@ -32,22 +32,6 @@ #ifdef HAVE_UNISTD_H # include #endif -#ifdef HAVE_SYS_PARAM_H -# include -#endif -#ifdef HAVE_SYSCALL_H -# include -#else -# ifdef HAVE_SYS_SYSCALL_H -# include -# endif -#endif -#ifdef HAVE_SYS_SIGNAL_H -# include -#endif -#ifdef HAVE_SYS_UCONTEXT_H -# include -#endif #include "ntstatus.h" #define WIN32_NO_STATUS @@ -59,181 +43,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(seh); -/*********************************************************************** - * signal context platform-specific definitions - */ -#ifdef linux - -/* All Registers access - only for local access */ -# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name) - - -/* Gpr Registers access */ -# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context) - -# define IAR_sig(context) REG_sig(nip, context) /* Program counter */ -# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */ -# define CTR_sig(context) REG_sig(ctr, context) /* Count register */ - -# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */ -# define LR_sig(context) REG_sig(link, context) /* Link register */ -# define CR_sig(context) REG_sig(ccr, context) /* Condition register */ - -/* Float Registers access */ -# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num]) - -# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4))) - -/* Exception Registers access */ -# define DAR_sig(context) REG_sig(dar, context) -# define DSISR_sig(context) REG_sig(dsisr, context) -# define TRAP_sig(context) REG_sig(trap, context) - -#endif /* linux */ - -#ifdef __APPLE__ - -/* All Registers access - only for local access */ -# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name) -# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name) -# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name) -# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name) - -/* Gpr Registers access */ -# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context) - -# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */ -# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */ -# define CTR_sig(context) REG_sig(ctr, context) - -# define XER_sig(context) REG_sig(xer, context) /* Link register */ -# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */ -# define CR_sig(context) REG_sig(cr, context) /* Condition register */ - -/* Float Registers access */ -# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context) - -# define FPSCR_sig(context) FLOATREG_sig(fpscr, context) - -/* Exception Registers access */ -# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */ -# define DSISR_sig(context) EXCEPREG_sig(dsisr, context) -# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */ - -/* Signal defs : Those are undefined on darwin -SIGBUS -#undef BUS_ADRERR -#undef BUS_OBJERR -SIGILL -#undef ILL_ILLOPN -#undef ILL_ILLTRP -#undef ILL_ILLADR -#undef ILL_COPROC -#undef ILL_PRVREG -#undef ILL_BADSTK -SIGTRAP -#undef TRAP_BRKPT -#undef TRAP_TRACE -SIGFPE -*/ - -#endif /* __APPLE__ */ - - -/*********************************************************************** - * save_context - * - * Set the register values from a sigcontext. - */ -static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) -{ - -#define C(x) context->Gpr##x = GPR_sig(x,sigcontext) - /* Save Gpr registers */ - C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); - C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20); - C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30); - C(31); -#undef C - - context->Iar = IAR_sig(sigcontext); /* Program Counter */ - context->Msr = MSR_sig(sigcontext); /* Machine State Register (Supervisor) */ - context->Ctr = CTR_sig(sigcontext); - - context->Xer = XER_sig(sigcontext); - context->Lr = LR_sig(sigcontext); - context->Cr = CR_sig(sigcontext); - - /* Saving Exception regs */ - context->Dar = DAR_sig(sigcontext); - context->Dsisr = DSISR_sig(sigcontext); - context->Trap = TRAP_sig(sigcontext); -} - - -/*********************************************************************** - * restore_context - * - * Build a sigcontext from the register values. - */ -static void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) -{ - -#define C(x) GPR_sig(x,sigcontext) = context->Gpr##x - C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); - C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20); - C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30); - C(31); -#undef C - - IAR_sig(sigcontext) = context->Iar; /* Program Counter */ - MSR_sig(sigcontext) = context->Msr; /* Machine State Register (Supervisor) */ - CTR_sig(sigcontext) = context->Ctr; - - XER_sig(sigcontext) = context->Xer; - LR_sig(sigcontext) = context->Lr; - CR_sig(sigcontext) = context->Cr; - - /* Setting Exception regs */ - DAR_sig(sigcontext) = context->Dar; - DSISR_sig(sigcontext) = context->Dsisr; - TRAP_sig(sigcontext) = context->Trap; -} - - -/*********************************************************************** - * save_fpu - * - * Set the FPU context from a sigcontext. - */ -static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext ) -{ -#define C(x) context->Fpr##x = FLOAT_sig(x,sigcontext) - C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); - C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20); - C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30); - C(31); -#undef C - context->Fpscr = FPSCR_sig(sigcontext); -} - - -/*********************************************************************** - * restore_fpu - * - * Restore the FPU context to a sigcontext. - */ -static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext ) -{ -#define C(x) FLOAT_sig(x,sigcontext) = context->Fpr##x - C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); - C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20); - C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30); - C(31); -#undef C - FPSCR_sig(sigcontext) = context->Fpscr; -} - /*********************************************************************** * RtlCaptureContext (NTDLL.@) @@ -264,69 +73,6 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) } -/******************************************************************* - * raise_exception - * - * Implementation of NtRaiseException. - */ -static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) -{ - NTSTATUS status; - - if (first_chance) - { - DWORD c; - - TRACE( "code=%x flags=%x addr=%p ip=%x tid=%04x\n", - rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, - context->Iar, GetCurrentThreadId() ); - for (c = 0; c < rec->NumberParameters; c++) - TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] ); - if (rec->ExceptionCode == EXCEPTION_WINE_STUB) - { - if (rec->ExceptionInformation[1] >> 16) - MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n", - rec->ExceptionAddress, - (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] ); - else - MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n", - rec->ExceptionAddress, - (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] ); - } - else - { - /* FIXME: dump context */ - } - - status = send_debug_event( rec, TRUE, context ); - if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) - return STATUS_SUCCESS; - - if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION) - return STATUS_SUCCESS; - - if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION) - return status; - } - - /* last chance exception */ - - status = send_debug_event( rec, FALSE, context ); - if (status != DBG_CONTINUE) - { - if (rec->ExceptionFlags & EH_STACK_INVALID) - ERR("Exception frame is not in stack limits => unable to dispatch exception.\n"); - else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION) - ERR("Process attempted to continue execution after noncontinuable exception.\n"); - else - ERR("Unhandled exception code %x flags %x addr %p\n", - rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); - NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode ); - } - return STATUS_SUCCESS; -} - - /******************************************************************* * KiUserExceptionDispatcher (NTDLL.@) */ @@ -368,328 +114,6 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte } -/********************************************************************** - * segv_handler - * - * Handler for SIGSEGV and related errors. - */ -static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - EXCEPTION_RECORD rec; - CONTEXT context; - NTSTATUS status; - - save_context( &context, sigcontext ); - - rec.ExceptionRecord = NULL; - rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - rec.ExceptionAddress = (LPVOID)context.Iar; - rec.NumberParameters = 0; - - switch (signal) - { - case SIGSEGV: - switch (siginfo->si_code & 0xffff) - { - case SEGV_MAPERR: - case SEGV_ACCERR: - rec.NumberParameters = 2; - rec.ExceptionInformation[0] = 0; /* FIXME ? */ - rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; - if (!(rec.ExceptionCode = unix_funcs->virtual_handle_fault(siginfo->si_addr, rec.ExceptionInformation[0], FALSE))) - goto done; - break; - default: - FIXME("Unhandled SIGSEGV/%x\n",siginfo->si_code); - break; - } - break; - case SIGBUS: - switch (siginfo->si_code & 0xffff) - { - case BUS_ADRALN: - rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; - break; -#ifdef BUS_ADRERR - case BUS_ADRERR: -#endif -#ifdef BUS_OBJERR - case BUS_OBJERR: - /* FIXME: correct for all cases ? */ - rec.NumberParameters = 2; - rec.ExceptionInformation[0] = 0; /* FIXME ? */ - rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; - if (!(rec.ExceptionCode = unix_funcs->virtual_handle_fault(siginfo->si_addr, rec.ExceptionInformation[0], FALSE))) - goto done; - break; -#endif - default: - FIXME("Unhandled SIGBUS/%x\n",siginfo->si_code); - break; - } - break; - case SIGILL: - switch (siginfo->si_code & 0xffff) - { - case ILL_ILLOPC: /* illegal opcode */ -#ifdef ILL_ILLOPN - case ILL_ILLOPN: /* illegal operand */ -#endif -#ifdef ILL_ILLADR - case ILL_ILLADR: /* illegal addressing mode */ -#endif -#ifdef ILL_ILLTRP - case ILL_ILLTRP: /* illegal trap */ -#endif -#ifdef ILL_COPROC - case ILL_COPROC: /* coprocessor error */ -#endif - rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; - break; - case ILL_PRVOPC: /* privileged opcode */ -#ifdef ILL_PRVREG - case ILL_PRVREG: /* privileged register */ -#endif - rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION; - break; -#ifdef ILL_BADSTK - case ILL_BADSTK: /* internal stack error */ - rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; - break; -#endif - default: - FIXME("Unhandled SIGILL/%x\n", siginfo->si_code); - break; - } - break; - } - status = raise_exception( &rec, &context, TRUE ); - if (status) raise_status( status, &rec ); -done: - restore_context( &context, sigcontext ); -} - -/********************************************************************** - * trap_handler - * - * Handler for SIGTRAP. - */ -static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - EXCEPTION_RECORD rec; - CONTEXT context; - NTSTATUS status; - - save_context( &context, sigcontext ); - - rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = (LPVOID)context.Iar; - rec.NumberParameters = 0; - - /* FIXME: check if we might need to modify PC */ - switch (siginfo->si_code & 0xffff) - { -#ifdef TRAP_BRKPT - case TRAP_BRKPT: - rec.ExceptionCode = EXCEPTION_BREAKPOINT; - break; -#endif -#ifdef TRAP_TRACE - case TRAP_TRACE: - rec.ExceptionCode = EXCEPTION_SINGLE_STEP; - break; -#endif - default: - FIXME("Unhandled SIGTRAP/%x\n", siginfo->si_code); - break; - } - status = raise_exception( &rec, &context, TRUE ); - if (status) raise_status( status, &rec ); - restore_context( &context, sigcontext ); -} - -/********************************************************************** - * fpe_handler - * - * Handler for SIGFPE. - */ -static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - EXCEPTION_RECORD rec; - CONTEXT context; - NTSTATUS status; - - save_fpu( &context, sigcontext ); - save_context( &context, sigcontext ); - - 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; - } - rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = (LPVOID)context.Iar; - rec.NumberParameters = 0; - status = raise_exception( &rec, &context, TRUE ); - if (status) raise_status( status, &rec ); - - restore_context( &context, sigcontext ); - restore_fpu( &context, sigcontext ); -} - -/********************************************************************** - * int_handler - * - * Handler for SIGINT. - */ -static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - EXCEPTION_RECORD rec; - CONTEXT context; - NTSTATUS status; - - save_context( &context, sigcontext ); - rec.ExceptionCode = CONTROL_C_EXIT; - rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = (LPVOID)context.Iar; - rec.NumberParameters = 0; - status = raise_exception( &rec, &context, TRUE ); - if (status) raise_status( status, &rec ); - restore_context( &context, sigcontext ); -} - - -/********************************************************************** - * abrt_handler - * - * Handler for SIGABRT. - */ -static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - EXCEPTION_RECORD rec; - CONTEXT context; - NTSTATUS status; - - save_context( &context, sigcontext ); - rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; - rec.ExceptionFlags = EH_NONCONTINUABLE; - rec.ExceptionRecord = NULL; - rec.ExceptionAddress = (LPVOID)context.Iar; - rec.NumberParameters = 0; - status = raise_exception( &rec, &context, TRUE ); - if (status) raise_status( status, &rec ); - restore_context( &context, sigcontext ); -} - - -/********************************************************************** - * quit_handler - * - * Handler for SIGQUIT. - */ -static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - unix_funcs->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; - - save_context( &context, sigcontext ); - wait_suspend( &context ); - restore_context( &context, sigcontext ); -} - - -/********************************************************************** - * signal_init_process - */ -void signal_init_process(void) -{ - struct sigaction sig_act; - - sig_act.sa_mask = server_block_set; - sig_act.sa_flags = SA_RESTART | SA_SIGINFO; - - 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 = segv_handler; - if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; -#ifdef SIGBUS - if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; -#endif - -#ifdef SIGTRAP - sig_act.sa_sigaction = trap_handler; - if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error; -#endif - return; - - error: - perror("sigaction"); - exit(1); -} - - /*********************************************************************** * RtlUnwind (NTDLL.@) */ @@ -704,12 +128,10 @@ void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecor void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec ) { CONTEXT context; - NTSTATUS status; RtlCaptureContext( &context ); rec->ExceptionAddress = (void *)context.Iar; - status = raise_exception( rec, &context, TRUE ); - if (status) raise_status( status, rec ); + RtlRaiseStatus( NtRaiseException( rec, &context, TRUE )); } /************************************************************************* diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index c6b0fbf618d..7c477db7890 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -252,46 +252,6 @@ struct MSVCRT_JUMP_BUFFER #error You must define the signal context functions for your platform #endif -enum i386_trap_code -{ - TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */ - TRAP_x86_DIVIDE = 0, /* Division by zero exception */ - TRAP_x86_TRCTRAP = 1, /* Single-step exception */ - TRAP_x86_NMI = 2, /* NMI interrupt */ - TRAP_x86_BPTFLT = 3, /* Breakpoint exception */ - TRAP_x86_OFLOW = 4, /* Overflow exception */ - TRAP_x86_BOUND = 5, /* Bound range exception */ - TRAP_x86_PRIVINFLT = 6, /* Invalid opcode exception */ - TRAP_x86_DNA = 7, /* Device not available exception */ - TRAP_x86_DOUBLEFLT = 8, /* Double fault exception */ - TRAP_x86_FPOPFLT = 9, /* Coprocessor segment overrun */ - TRAP_x86_TSSFLT = 10, /* Invalid TSS exception */ - TRAP_x86_SEGNPFLT = 11, /* Segment not present exception */ - TRAP_x86_STKFLT = 12, /* Stack fault */ - TRAP_x86_PROTFLT = 13, /* General protection fault */ - TRAP_x86_PAGEFLT = 14, /* Page fault */ - TRAP_x86_ARITHTRAP = 16, /* Floating point exception */ - TRAP_x86_ALIGNFLT = 17, /* Alignment check exception */ - TRAP_x86_MCHK = 18, /* Machine check exception */ - TRAP_x86_CACHEFLT = 19 /* Cache flush exception */ -}; - -static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */ - -typedef void (*raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context ); - -/* stack layout when calling an exception raise function */ -struct stack_layout -{ - CONTEXT context; - EXCEPTION_RECORD rec; - ULONG64 rsi; - ULONG64 rdi; - ULONG64 rbp; - ULONG64 rip; - ULONG64 red_zone[16]; -}; - struct amd64_thread_data { DWORD_PTR dr0; /* debug registers */ @@ -311,40 +271,6 @@ static inline struct amd64_thread_data *amd64_thread_data(void) return (struct amd64_thread_data *)NtCurrentTeb()->SystemReserved2; } -static inline void set_sigcontext( const CONTEXT *context, ucontext_t *sigcontext ) -{ - RAX_sig(sigcontext) = context->Rax; - RCX_sig(sigcontext) = context->Rcx; - RDX_sig(sigcontext) = context->Rdx; - RBX_sig(sigcontext) = context->Rbx; - RSP_sig(sigcontext) = context->Rsp; - RBP_sig(sigcontext) = context->Rbp; - RSI_sig(sigcontext) = context->Rsi; - RDI_sig(sigcontext) = context->Rdi; - R8_sig(sigcontext) = context->R8; - R9_sig(sigcontext) = context->R9; - R10_sig(sigcontext) = context->R10; - R11_sig(sigcontext) = context->R11; - R12_sig(sigcontext) = context->R12; - R13_sig(sigcontext) = context->R13; - R14_sig(sigcontext) = context->R14; - R15_sig(sigcontext) = context->R15; - RIP_sig(sigcontext) = context->Rip; - CS_sig(sigcontext) = context->SegCs; - FS_sig(sigcontext) = context->SegFs; - GS_sig(sigcontext) = context->SegGs; - EFL_sig(sigcontext) = context->EFlags; -#ifdef DS_sig - DS_sig(sigcontext) = context->SegDs; -#endif -#ifdef ES_sig - ES_sig(sigcontext) = context->SegEs; -#endif -#ifdef SS_sig - SS_sig(sigcontext) = context->SegSs; -#endif -} - /*********************************************************************** * Definitions for Win32 unwind tables @@ -1489,7 +1415,27 @@ static NTSTATUS libunwind_virtual_unwind( ULONG64 ip, BOOL* got_info, ULONG64 *f unw_set_reg( &cursor, UNW_X86_64_R15, context->R15 ); } #else - set_sigcontext( context, &unw_context ); + RAX_sig(&unw_context) = context->Rax; + RCX_sig(&unw_context) = context->Rcx; + RDX_sig(&unw_context) = context->Rdx; + RBX_sig(&unw_context) = context->Rbx; + RSP_sig(&unw_context) = context->Rsp; + RBP_sig(&unw_context) = context->Rbp; + RSI_sig(&unw_context) = context->Rsi; + RDI_sig(&unw_context) = context->Rdi; + R8_sig(&unw_context) = context->R8; + R9_sig(&unw_context) = context->R9; + R10_sig(&unw_context) = context->R10; + R11_sig(&unw_context) = context->R11; + R12_sig(&unw_context) = context->R12; + R13_sig(&unw_context) = context->R13; + R14_sig(&unw_context) = context->R14; + R15_sig(&unw_context) = context->R15; + RIP_sig(&unw_context) = context->Rip; + CS_sig(&unw_context) = context->SegCs; + FS_sig(&unw_context) = context->SegFs; + GS_sig(&unw_context) = context->SegGs; + EFL_sig(&unw_context) = context->EFlags; rc = unw_init_local( &cursor, &unw_context ); #endif if (rc != UNW_ESUCCESS) @@ -1630,103 +1576,6 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX return STATUS_SUCCESS; } -/*********************************************************************** - * get_signal_stack - * - * Get the base of the signal stack for the current thread. - */ -static inline void *get_signal_stack(void) -{ - return (char *)NtCurrentTeb() + teb_size; -} - -/*********************************************************************** - * is_inside_signal_stack - * - * Check if pointer is inside the signal stack. - */ -static inline BOOL is_inside_signal_stack( void *ptr ) -{ - return ((char *)ptr >= (char *)get_signal_stack() && - (char *)ptr < (char *)get_signal_stack() + signal_stack_size); -} - -/*********************************************************************** - * save_context - * - * Set the register values from a sigcontext. - */ -static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) -{ - context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS; - context->Rax = RAX_sig(sigcontext); - context->Rcx = RCX_sig(sigcontext); - context->Rdx = RDX_sig(sigcontext); - context->Rbx = RBX_sig(sigcontext); - context->Rsp = RSP_sig(sigcontext); - context->Rbp = RBP_sig(sigcontext); - context->Rsi = RSI_sig(sigcontext); - context->Rdi = RDI_sig(sigcontext); - context->R8 = R8_sig(sigcontext); - context->R9 = R9_sig(sigcontext); - context->R10 = R10_sig(sigcontext); - context->R11 = R11_sig(sigcontext); - context->R12 = R12_sig(sigcontext); - context->R13 = R13_sig(sigcontext); - context->R14 = R14_sig(sigcontext); - context->R15 = R15_sig(sigcontext); - context->Rip = RIP_sig(sigcontext); - context->SegCs = CS_sig(sigcontext); - context->SegFs = FS_sig(sigcontext); - context->SegGs = GS_sig(sigcontext); - context->EFlags = EFL_sig(sigcontext); -#ifdef DS_sig - context->SegDs = DS_sig(sigcontext); -#else - __asm__("movw %%ds,%0" : "=m" (context->SegDs)); -#endif -#ifdef ES_sig - context->SegEs = ES_sig(sigcontext); -#else - __asm__("movw %%es,%0" : "=m" (context->SegEs)); -#endif -#ifdef SS_sig - context->SegSs = SS_sig(sigcontext); -#else - __asm__("movw %%ss,%0" : "=m" (context->SegSs)); -#endif - context->Dr0 = amd64_thread_data()->dr0; - context->Dr1 = amd64_thread_data()->dr1; - context->Dr2 = amd64_thread_data()->dr2; - context->Dr3 = amd64_thread_data()->dr3; - context->Dr6 = amd64_thread_data()->dr6; - context->Dr7 = amd64_thread_data()->dr7; - if (FPU_sig(sigcontext)) - { - context->ContextFlags |= CONTEXT_FLOATING_POINT; - context->u.FltSave = *FPU_sig(sigcontext); - context->MxCsr = context->u.FltSave.MxCsr; - } -} - - -/*********************************************************************** - * restore_context - * - * Build a sigcontext from the register values. - */ -static void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) -{ - amd64_thread_data()->dr0 = context->Dr0; - amd64_thread_data()->dr1 = context->Dr1; - amd64_thread_data()->dr2 = context->Dr2; - amd64_thread_data()->dr3 = context->Dr3; - amd64_thread_data()->dr6 = context->Dr6; - amd64_thread_data()->dr7 = context->Dr7; - set_sigcontext( context, sigcontext ); - if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->u.FltSave; -} - /************************************************************************** * __chkstk (NTDLL.@) @@ -2261,523 +2110,6 @@ NTSTATUS WINAPI KiUserExceptionDispatcher( EXCEPTION_RECORD *rec, CONTEXT *conte } -extern void CDECL raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func ); -__ASM_GLOBAL_FUNC( raise_func_trampoline, - __ASM_CFI(".cfi_signal_frame\n\t") - __ASM_CFI(".cfi_def_cfa %rbp,160\n\t") /* red zone + rip + rbp + rdi + rsi */ - __ASM_CFI(".cfi_rel_offset %rip,24\n\t") - __ASM_CFI(".cfi_rel_offset %rbp,16\n\t") - __ASM_CFI(".cfi_rel_offset %rdi,8\n\t") - __ASM_CFI(".cfi_rel_offset %rsi,0\n\t") - "call *%r8\n\t" - "int $3") - -/*********************************************************************** - * setup_exception - * - * Setup a proper stack frame for the raise function, and modify the - * sigcontext so that the return from the signal handler will call - * the raise function. - */ -static struct stack_layout *setup_exception( ucontext_t *sigcontext ) -{ - struct stack_layout *stack; - DWORD exception_code = 0; - - stack = (struct stack_layout *)(RSP_sig(sigcontext) & ~15); - - /* stack sanity checks */ - - if (is_inside_signal_stack( stack )) - { - ERR( "nested exception on signal stack in thread %04x eip %016lx esp %016lx stack %p-%p\n", - GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext), - NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); - unix_funcs->abort_thread(1); - } - - if (stack - 1 > stack || /* check for overflow in subtraction */ - (char *)stack <= (char *)NtCurrentTeb()->DeallocationStack || - (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase) - { - WARN( "exception outside of stack limits in thread %04x eip %016lx esp %016lx stack %p-%p\n", - GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext), - NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); - } - else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096) - { - /* stack overflow on last page, unrecoverable */ - UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1); - ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n", - diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), - (ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, - NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); - unix_funcs->abort_thread(1); - } - else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit) - { - /* stack access below stack limit, may be recoverable */ - switch (unix_funcs->virtual_handle_stack_fault( stack - 1 )) - { - case 0: /* not handled */ - { - UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1); - ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n", - diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), - (ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, - NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); - unix_funcs->abort_thread(1); - } - case -1: /* overflow */ - exception_code = EXCEPTION_STACK_OVERFLOW; - break; - } - } - - stack--; /* push the stack_layout structure */ -#if defined(VALGRIND_MAKE_MEM_UNDEFINED) - VALGRIND_MAKE_MEM_UNDEFINED(stack, sizeof(*stack)); -#elif defined(VALGRIND_MAKE_WRITABLE) - VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack)); -#endif - stack->rec.ExceptionRecord = NULL; - stack->rec.ExceptionCode = exception_code; - stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE; - stack->rec.ExceptionAddress = (void *)RIP_sig(sigcontext); - stack->rec.NumberParameters = 0; - save_context( &stack->context, sigcontext ); - - return stack; -} - -static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *stack ) -{ - ULONG64 *rsp_ptr; - NTSTATUS status; - - if (stack->rec.ExceptionCode == EXCEPTION_SINGLE_STEP) - { - /* when single stepping can't tell whether this is a hw bp or a - * single step interrupt. try to avoid as much overhead as possible - * and only do a server call if there is any hw bp enabled. */ - - if (!(stack->context.EFlags & 0x100) || (stack->context.Dr7 & 0xff)) - { - /* (possible) hardware breakpoint, fetch the debug registers */ - DWORD saved_flags = stack->context.ContextFlags; - stack->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; - NtGetContextThread(GetCurrentThread(), &stack->context); - stack->context.ContextFlags |= saved_flags; /* restore flags */ - } - - stack->context.EFlags &= ~0x100; /* clear single-step flag */ - } - - status = send_debug_event( &stack->rec, TRUE, &stack->context ); - if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) - { - restore_context( &stack->context, sigcontext ); - return; - } - - /* store return address and %rbp without aligning, so that the offset is fixed */ - rsp_ptr = (ULONG64 *)RSP_sig(sigcontext) - 16; - *(--rsp_ptr) = stack->context.Rip; - *(--rsp_ptr) = stack->context.Rbp; - *(--rsp_ptr) = stack->context.Rdi; - *(--rsp_ptr) = stack->context.Rsi; - - /* now modify the sigcontext to return to the raise function */ - RIP_sig(sigcontext) = (ULONG_PTR)raise_func_trampoline; - RCX_sig(sigcontext) = (ULONG_PTR)&stack->rec; - RDX_sig(sigcontext) = (ULONG_PTR)&stack->context; - R8_sig(sigcontext) = (ULONG_PTR)KiUserExceptionDispatcher; - RBP_sig(sigcontext) = (ULONG_PTR)rsp_ptr; - RSP_sig(sigcontext) = (ULONG_PTR)stack; - /* clear single-step, direction, and align check flag */ - EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000); -} - - -/*********************************************************************** - * is_privileged_instr - * - * Check if the fault location is a privileged instruction. - */ -static inline DWORD is_privileged_instr( CONTEXT *context ) -{ - BYTE instr[16]; - unsigned int i, prefix_count = 0; - unsigned int len = unix_funcs->virtual_uninterrupted_read_memory( (BYTE *)context->Rip, instr, sizeof(instr) ); - - for (i = 0; i < len; i++) switch (instr[i]) - { - /* instruction prefixes */ - case 0x2e: /* %cs: */ - case 0x36: /* %ss: */ - case 0x3e: /* %ds: */ - case 0x26: /* %es: */ - case 0x40: /* rex */ - case 0x41: /* rex */ - case 0x42: /* rex */ - case 0x43: /* rex */ - case 0x44: /* rex */ - case 0x45: /* rex */ - case 0x46: /* rex */ - case 0x47: /* rex */ - case 0x48: /* rex */ - case 0x49: /* rex */ - case 0x4a: /* rex */ - case 0x4b: /* rex */ - case 0x4c: /* rex */ - case 0x4d: /* rex */ - case 0x4e: /* rex */ - case 0x4f: /* rex */ - case 0x64: /* %fs: */ - case 0x65: /* %gs: */ - case 0x66: /* opcode size */ - case 0x67: /* addr size */ - case 0xf0: /* lock */ - case 0xf2: /* repne */ - case 0xf3: /* repe */ - if (++prefix_count >= 15) return EXCEPTION_ILLEGAL_INSTRUCTION; - continue; - - case 0x0f: /* extended instruction */ - if (i == len - 1) return 0; - switch (instr[i + 1]) - { - case 0x06: /* clts */ - case 0x08: /* invd */ - case 0x09: /* wbinvd */ - case 0x20: /* mov crX, reg */ - case 0x21: /* mov drX, reg */ - case 0x22: /* mov reg, crX */ - case 0x23: /* mov reg drX */ - return EXCEPTION_PRIV_INSTRUCTION; - } - return 0; - case 0x6c: /* insb (%dx) */ - case 0x6d: /* insl (%dx) */ - case 0x6e: /* outsb (%dx) */ - case 0x6f: /* outsl (%dx) */ - case 0xcd: /* int $xx */ - case 0xe4: /* inb al,XX */ - case 0xe5: /* in (e)ax,XX */ - case 0xe6: /* outb XX,al */ - case 0xe7: /* out XX,(e)ax */ - case 0xec: /* inb (%dx),%al */ - case 0xed: /* inl (%dx),%eax */ - case 0xee: /* outb %al,(%dx) */ - case 0xef: /* outl %eax,(%dx) */ - case 0xf4: /* hlt */ - case 0xfa: /* cli */ - case 0xfb: /* sti */ - return EXCEPTION_PRIV_INSTRUCTION; - default: - return 0; - } - return 0; -} - - -/*********************************************************************** - * handle_interrupt - * - * Handle an interrupt. - */ -static inline BOOL handle_interrupt( ucontext_t *sigcontext, struct stack_layout *stack ) -{ - switch (ERROR_sig(sigcontext) >> 3) - { - case 0x2c: - stack->rec.ExceptionCode = STATUS_ASSERTION_FAILURE; - break; - case 0x2d: - switch (stack->context.Rax) - { - case 1: /* BREAKPOINT_PRINT */ - case 3: /* BREAKPOINT_LOAD_SYMBOLS */ - case 4: /* BREAKPOINT_UNLOAD_SYMBOLS */ - case 5: /* BREAKPOINT_COMMAND_STRING (>= Win2003) */ - RIP_sig(sigcontext) += 3; - return TRUE; - } - stack->context.Rip += 3; - stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; - stack->rec.ExceptionAddress = (void *)stack->context.Rip; - stack->rec.NumberParameters = 1; - stack->rec.ExceptionInformation[0] = stack->context.Rax; - break; - default: - return FALSE; - } - setup_raise_exception( sigcontext, stack ); - return TRUE; -} - - -/********************************************************************** - * segv_handler - * - * Handler for SIGSEGV and related errors. - */ -static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack; - ucontext_t *ucontext = sigcontext; - - stack = (struct stack_layout *)(RSP_sig(ucontext) & ~15); - - /* check for exceptions on the signal stack caused by write watches */ - if (TRAP_sig(ucontext) == TRAP_x86_PAGEFLT && is_inside_signal_stack( stack ) && - !unix_funcs->virtual_handle_fault( siginfo->si_addr, (ERROR_sig(ucontext) >> 1) & 0x09, TRUE )) - { - return; - } - - /* check for page fault inside the thread stack */ - if (TRAP_sig(ucontext) == TRAP_x86_PAGEFLT) - { - switch (unix_funcs->virtual_handle_stack_fault( siginfo->si_addr )) - { - case 1: /* handled */ - return; - case -1: /* overflow */ - stack = setup_exception( sigcontext ); - stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; - goto done; - } - } - - stack = setup_exception( sigcontext ); - if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done; - - switch(TRAP_sig(ucontext)) - { - case TRAP_x86_OFLOW: /* Overflow exception */ - stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; - break; - case TRAP_x86_BOUND: /* Bound range exception */ - stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; - break; - case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */ - stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; - break; - case TRAP_x86_STKFLT: /* Stack fault */ - stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; - break; - case TRAP_x86_SEGNPFLT: /* Segment not present exception */ - case TRAP_x86_PROTFLT: /* General protection fault */ - case TRAP_x86_UNKNOWN: /* Unknown fault code */ - { - WORD err = ERROR_sig(ucontext); - if (!err && (stack->rec.ExceptionCode = is_privileged_instr( &stack->context ))) break; - if ((err & 7) == 2 && handle_interrupt( ucontext, stack )) return; - stack->rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION; - stack->rec.NumberParameters = 2; - stack->rec.ExceptionInformation[0] = 0; - stack->rec.ExceptionInformation[1] = 0xffffffffffffffff; - } - break; - case TRAP_x86_PAGEFLT: /* Page fault */ - stack->rec.NumberParameters = 2; - stack->rec.ExceptionInformation[0] = (ERROR_sig(ucontext) >> 1) & 0x09; - stack->rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; - if (!(stack->rec.ExceptionCode = unix_funcs->virtual_handle_fault((void *)stack->rec.ExceptionInformation[1], - stack->rec.ExceptionInformation[0], FALSE ))) - return; - break; - case TRAP_x86_ALIGNFLT: /* Alignment check exception */ - stack->rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; - break; - default: - ERR( "Got unexpected trap %ld\n", (ULONG_PTR)TRAP_sig(ucontext) ); - /* fall through */ - case TRAP_x86_NMI: /* NMI interrupt */ - case TRAP_x86_DNA: /* Device not available exception */ - case TRAP_x86_DOUBLEFLT: /* Double fault exception */ - case TRAP_x86_TSSFLT: /* Invalid TSS exception */ - case TRAP_x86_MCHK: /* Machine check exception */ - case TRAP_x86_CACHEFLT: /* Cache flush exception */ - stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; - break; - } -done: - setup_raise_exception( sigcontext, stack ); -} - -/********************************************************************** - * trap_handler - * - * Handler for SIGTRAP. - */ -static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack = setup_exception( sigcontext ); - - switch (siginfo->si_code) - { - case TRAP_TRACE: /* Single-step exception */ - case 4 /* TRAP_HWBKPT */: /* Hardware breakpoint exception */ - stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP; - break; - case TRAP_BRKPT: /* Breakpoint exception */ -#ifdef SI_KERNEL - case SI_KERNEL: -#endif - /* Check if this is actually icebp instruction */ - if (((unsigned char *)stack->rec.ExceptionAddress)[-1] == 0xF1) - { - stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP; - break; - } - stack->rec.ExceptionAddress = (char *)stack->rec.ExceptionAddress - 1; /* back up over the int3 instruction */ - /* fall through */ - default: - stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; - stack->rec.NumberParameters = 1; - stack->rec.ExceptionInformation[0] = 0; - break; - } - - setup_raise_exception( sigcontext, stack ); -} - -/********************************************************************** - * fpe_handler - * - * Handler for SIGFPE. - */ -static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack = setup_exception( sigcontext ); - - switch (siginfo->si_code) - { - case FPE_FLTSUB: - stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; - break; - case FPE_INTDIV: - stack->rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; - break; - case FPE_INTOVF: - stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; - break; - case FPE_FLTDIV: - stack->rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO; - break; - case FPE_FLTOVF: - stack->rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW; - break; - case FPE_FLTUND: - stack->rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW; - break; - case FPE_FLTRES: - stack->rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT; - break; - case FPE_FLTINV: - default: - stack->rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; - break; - } - - setup_raise_exception( sigcontext, stack ); -} - -/********************************************************************** - * int_handler - * - * Handler for SIGINT. - */ -static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack = setup_exception( sigcontext ); - stack->rec.ExceptionCode = CONTROL_C_EXIT; - setup_raise_exception( sigcontext, stack ); -} - - -/********************************************************************** - * abrt_handler - * - * Handler for SIGABRT. - */ -static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) -{ - struct stack_layout *stack = setup_exception( sigcontext ); - stack->rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; - stack->rec.ExceptionFlags = EH_NONCONTINUABLE; - setup_raise_exception( sigcontext, stack ); -} - - -/********************************************************************** - * quit_handler - * - * Handler for SIGQUIT. - */ -static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext ) -{ - unix_funcs->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 *ucontext ) -{ - CONTEXT context; - - save_context( &context, ucontext ); - wait_suspend( &context ); - restore_context( &context, ucontext ); -} - - -/********************************************************************** - * signal_init_process - */ -void signal_init_process(void) -{ - struct sigaction sig_act; - - sig_act.sa_mask = server_block_set; - sig_act.sa_flags = SA_RESTART | SA_SIGINFO | 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 = segv_handler; - if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error; - if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; -#ifdef SIGBUS - if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; -#endif - -#ifdef SIGTRAP - sig_act.sa_sigaction = trap_handler; - if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error; -#endif - return; - - error: - perror("sigaction"); - exit(1); -} - - static ULONG64 get_int_reg( CONTEXT *context, int reg ) { return *(&context->Rax + reg); @@ -3325,14 +2657,6 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec unwind_done: if (!dispatch.EstablisherFrame) break; - if (is_inside_signal_stack( (void *)dispatch.EstablisherFrame )) - { - TRACE( "frame %lx is inside signal stack (%p-%p)\n", dispatch.EstablisherFrame, - get_signal_stack(), (char *)get_signal_stack() + signal_stack_size ); - *context = new_context; - continue; - } - if ((dispatch.EstablisherFrame & 7) || dispatch.EstablisherFrame < (ULONG64)NtCurrentTeb()->Tib.StackLimit || dispatch.EstablisherFrame > (ULONG64)NtCurrentTeb()->Tib.StackBase) diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index d045466f6d2..54425471fad 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -39,7 +39,6 @@ #include "ntstatus.h" #define WIN32_NO_STATUS #include "winternl.h" -#include "wine/library.h" #include "wine/server.h" #include "wine/debug.h" #include "ntdll_misc.h" @@ -51,8 +50,6 @@ WINE_DECLARE_DEBUG_CHANNEL(relay); struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; -void (WINAPI *kernel32_start_process)(LPTHREAD_START_ROUTINE,void*) = NULL; - static PEB *peb; static PEB_LDR_DATA ldr; static RTL_BITMAP tls_bitmap; @@ -183,12 +180,8 @@ int __cdecl __wine_dbg_output( const char *str ) */ TEB *thread_init( SIZE_T *info_size, BOOL *suspend ) { - TEB *teb; - - virtual_init(); - - teb = unix_funcs->init_threading( &nb_threads, &__wine_ldt_copy, info_size, suspend, &server_cpus, - &is_wow64, &server_start_time ); + TEB *teb = unix_funcs->init_threading( &nb_threads, &__wine_ldt_copy, info_size, suspend, &server_cpus, + &is_wow64, &server_start_time ); peb = teb->Peb; peb->FastPebLock = &peb_lock; @@ -222,7 +215,6 @@ TEB *thread_init( SIZE_T *info_size, BOOL *suspend ) unix_funcs->get_paths( &build_dir, &data_dir, &config_dir ); fill_cpu_info(); - server_init_process(); return teb; } diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 618e3d6adb3..34c2e8fdaf4 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -1052,22 +1052,16 @@ static struct unix_funcs unix_funcs = virtual_get_system_info, virtual_create_builtin_view, virtual_alloc_thread_stack, - virtual_handle_fault, virtual_locked_server_call, virtual_locked_read, virtual_locked_pread, virtual_locked_recvmsg, - virtual_is_valid_code_address, - virtual_handle_stack_fault, virtual_check_buffer_for_read, virtual_check_buffer_for_write, - virtual_uninterrupted_read_memory, - virtual_uninterrupted_write_memory, virtual_set_force_exec, virtual_release_address_space, virtual_set_large_address_space, init_threading, - start_process, abort_thread, exit_thread, exit_process, diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index fb3f98dd579..777ba848870 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -1473,11 +1473,42 @@ void server_init_process(void) /*********************************************************************** * server_init_process_done */ -void CDECL server_init_process_done(void) +void CDECL server_init_process_done( void *relay ) { +#ifdef __i386__ + extern struct ldt_copy __wine_ldt_copy; +#endif + PEB *peb = NtCurrentTeb()->Peb; + IMAGE_NT_HEADERS *nt = RtlImageNtHeader( peb->ImageBaseAddress ); + void *entry = (char *)peb->ImageBaseAddress + nt->OptionalHeader.AddressOfEntryPoint; + NTSTATUS status; + int suspend; + #ifdef __APPLE__ send_server_task_port(); #endif + + /* Install signal handlers; this cannot be done earlier, since we cannot + * send exceptions to the debugger before the create process event that + * is sent by init_process_done */ + signal_init_process(); + + /* Signal the parent process to continue */ + SERVER_START_REQ( init_process_done ) + { + req->module = wine_server_client_ptr( peb->ImageBaseAddress ); +#ifdef __i386__ + req->ldt_copy = wine_server_client_ptr( &__wine_ldt_copy ); +#endif + req->entry = wine_server_client_ptr( entry ); + req->gui = (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_WINDOWS_CUI); + status = wine_server_call( req ); + suspend = reply->suspend; + } + SERVER_END_REQ; + + assert( !status ); + signal_start_thread( entry, peb, suspend, relay, NtCurrentTeb() ); } diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 378c40aa8b1..1ef3ff6618b 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -66,9 +66,177 @@ #include "unix_private.h" #include "wine/debug.h" +WINE_DEFAULT_DEBUG_CHANNEL(seh); + static pthread_key_t teb_key; +/*********************************************************************** + * signal context platform-specific definitions + */ +#ifdef linux + +#if defined(__ANDROID__) && !defined(HAVE_SYS_UCONTEXT_H) +typedef struct ucontext +{ + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; + unsigned long uc_regspace[128] __attribute__((__aligned__(8))); +} ucontext_t; +#endif + +/* 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.arm_r##reg_num) + +/* Special Registers access */ +# define SP_sig(context) REG_sig(arm_sp, context) /* Stack pointer */ +# define LR_sig(context) REG_sig(arm_lr, context) /* Link register */ +# define PC_sig(context) REG_sig(arm_pc, context) /* Program counter */ +# define CPSR_sig(context) REG_sig(arm_cpsr, context) /* Current State Register */ +# define IP_sig(context) REG_sig(arm_ip, context) /* Intra-Procedure-call scratch register */ +# define FP_sig(context) REG_sig(arm_fp, context) /* Frame pointer */ + +/* Exceptions */ +# define ERROR_sig(context) REG_sig(error_code, context) +# define TRAP_sig(context) REG_sig(trap_no, context) + +#elif defined(__FreeBSD__) + +/* All Registers access - only for local access */ +# define REGn_sig(reg_num, context) ((context)->uc_mcontext.__gregs[reg_num]) + +/* Special Registers access */ +# define SP_sig(context) REGn_sig(_REG_SP, context) /* Stack pointer */ +# define LR_sig(context) REGn_sig(_REG_LR, context) /* Link register */ +# define PC_sig(context) REGn_sig(_REG_PC, context) /* Program counter */ +# define CPSR_sig(context) REGn_sig(_REG_CPSR, context) /* Current State Register */ +# define IP_sig(context) REGn_sig(_REG_R12, context) /* Intra-Procedure-call scratch register */ +# define FP_sig(context) REGn_sig(_REG_FP, context) /* Frame pointer */ + +#endif /* linux */ + +enum arm_trap_code +{ + TRAP_ARM_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */ + TRAP_ARM_PRIVINFLT = 6, /* Invalid opcode exception */ + TRAP_ARM_PAGEFLT = 14, /* Page fault */ + TRAP_ARM_ALIGNFLT = 17, /* Alignment check exception */ +}; + +typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context ); + + +/*********************************************************************** + * get_trap_code + * + * Get the trap code for a signal. + */ +static inline enum arm_trap_code get_trap_code( int signal, const ucontext_t *sigcontext ) +{ +#ifdef TRAP_sig + enum arm_trap_code trap = TRAP_sig(sigcontext); + if (trap) + return trap; +#endif + + switch (signal) + { + case SIGILL: + return TRAP_ARM_PRIVINFLT; + case SIGSEGV: + return TRAP_ARM_PAGEFLT; + case SIGBUS: + return TRAP_ARM_ALIGNFLT; + default: + return TRAP_ARM_UNKNOWN; + } +} + + +/*********************************************************************** + * get_error_code + * + * Get the error code for a signal. + */ +static inline WORD get_error_code( const ucontext_t *sigcontext ) +{ +#ifdef ERROR_sig + return ERROR_sig(sigcontext); +#else + return 0; +#endif +} + + +/*********************************************************************** + * save_context + * + * Set the register values from a sigcontext. + */ +static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) +{ +#define C(x) context->R##x = REGn_sig(x,sigcontext) + /* Save normal registers */ + C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); +#undef C + + context->ContextFlags = CONTEXT_FULL; + context->Sp = SP_sig(sigcontext); /* Stack pointer */ + context->Lr = LR_sig(sigcontext); /* Link register */ + context->Pc = PC_sig(sigcontext); /* Program Counter */ + context->Cpsr = CPSR_sig(sigcontext); /* Current State Register */ + context->R11 = FP_sig(sigcontext); /* Frame pointer */ + context->R12 = IP_sig(sigcontext); /* Intra-Procedure-call scratch register */ +} + + +/*********************************************************************** + * restore_context + * + * Build a sigcontext from the register values. + */ +static void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) +{ +#define C(x) REGn_sig(x,sigcontext) = context->R##x + /* Restore normal registers */ + C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); +#undef C + + SP_sig(sigcontext) = context->Sp; /* Stack pointer */ + LR_sig(sigcontext) = context->Lr ; /* Link register */ + PC_sig(sigcontext) = context->Pc; /* Program Counter */ + CPSR_sig(sigcontext) = context->Cpsr; /* Current State Register */ + FP_sig(sigcontext) = context->R11; /* Frame pointer */ + IP_sig(sigcontext) = context->R12; /* Intra-Procedure-call scratch register */ +} + + +/*********************************************************************** + * save_fpu + * + * Set the FPU context from a sigcontext. + */ +static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext ) +{ + FIXME("not implemented\n"); +} + + +/*********************************************************************** + * restore_fpu + * + * Restore the FPU context to a sigcontext. + */ +static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext ) +{ + FIXME("not implemented\n"); +} + + /*********************************************************************** * set_cpu_context * @@ -305,6 +473,311 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) } +extern void raise_func_trampoline_thumb( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func ); +__ASM_GLOBAL_FUNC( raise_func_trampoline_thumb, + ".thumb\n\t" + "blx r2\n\t" + "bkpt") + +extern void raise_func_trampoline_arm( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func ); +__ASM_GLOBAL_FUNC( raise_func_trampoline_arm, + ".arm\n\t" + "blx r2\n\t" + "bkpt") + +/*********************************************************************** + * setup_exception_record + * + * Setup the exception record and context on the thread stack. + */ +static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func func ) +{ + struct stack_layout + { + CONTEXT context; + EXCEPTION_RECORD rec; + } *stack; + DWORD exception_code = 0; + + stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3); + stack--; /* push the stack_layout structure */ + + stack->rec.ExceptionRecord = NULL; + stack->rec.ExceptionCode = exception_code; + stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext); + stack->rec.NumberParameters = 0; + + save_context( &stack->context, sigcontext ); + + /* now modify the sigcontext to return to the raise function */ + SP_sig(sigcontext) = (DWORD)stack; + if (CPSR_sig(sigcontext) & 0x20) + PC_sig(sigcontext) = (DWORD)raise_func_trampoline_thumb; + else + PC_sig(sigcontext) = (DWORD)raise_func_trampoline_arm; + REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for raise_func */ + REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for raise_func */ + REGn_sig(2, sigcontext) = (DWORD)func; /* the raise_func as third arg for the trampoline */ + return &stack->rec; +} + + +/********************************************************************** + * raise_segv_exception + */ +static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context ) +{ + NTSTATUS status; + + switch(rec->ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + if (rec->NumberParameters == 2) + { + if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1], + rec->ExceptionInformation[0], FALSE ))) + goto done; + } + break; + } + status = NtRaiseException( rec, context, TRUE ); + if (status) RtlRaiseStatus( status ); +done: + set_cpu_context( context ); +} + + +/********************************************************************** + * segv_handler + * + * Handler for SIGSEGV and related errors. + */ +static void segv_handler( int signal, siginfo_t *info, void *ucontext ) +{ + EXCEPTION_RECORD *rec; + ucontext_t *context = ucontext; + + /* check for page fault inside the thread stack */ + if (get_trap_code(signal, context) == TRAP_ARM_PAGEFLT) + { + switch (virtual_handle_stack_fault( info->si_addr )) + { + case 1: /* handled */ + return; + case -1: /* overflow */ + rec = setup_exception( context, raise_segv_exception ); + rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW; + return; + } + } + + rec = setup_exception( context, raise_segv_exception ); + if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return; + + switch(get_trap_code(signal, context)) + { + case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */ + rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + case TRAP_ARM_PAGEFLT: /* Page fault */ + rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION; + rec->NumberParameters = 2; + rec->ExceptionInformation[0] = (get_error_code(context) & 0x800) != 0; + rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr; + break; + case TRAP_ARM_ALIGNFLT: /* Alignment check exception */ + rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; + break; + case TRAP_ARM_UNKNOWN: /* Unknown fault code */ + rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION; + rec->NumberParameters = 2; + rec->ExceptionInformation[0] = 0; + rec->ExceptionInformation[1] = 0xffffffff; + break; + default: + ERR("Got unexpected trap %d\n", get_trap_code(signal, context)); + rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + } +} + + +/********************************************************************** + * trap_handler + * + * Handler for SIGTRAP. + */ +static void trap_handler( int signal, siginfo_t *info, void *ucontext ) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + NTSTATUS status; + + switch ( info->si_code ) + { + case TRAP_TRACE: + rec.ExceptionCode = EXCEPTION_SINGLE_STEP; + break; + case TRAP_BRKPT: + default: + rec.ExceptionCode = EXCEPTION_BREAKPOINT; + break; + } + + save_context( &context, ucontext ); + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Pc; + rec.NumberParameters = 0; + status = NtRaiseException( &rec, &context, TRUE ); + if (status) RtlRaiseStatus( status ); + restore_context( &context, ucontext ); +} + + +/********************************************************************** + * fpe_handler + * + * Handler for SIGFPE. + */ +static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + NTSTATUS status; + + save_fpu( &context, sigcontext ); + save_context( &context, sigcontext ); + + 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; + } + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Pc; + rec.NumberParameters = 0; + status = NtRaiseException( &rec, &context, TRUE ); + if (status) RtlRaiseStatus( status ); + + restore_context( &context, sigcontext ); + restore_fpu( &context, sigcontext ); +} + + +/********************************************************************** + * int_handler + * + * Handler for SIGINT. + */ +static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + NTSTATUS status; + + save_context( &context, sigcontext ); + rec.ExceptionCode = CONTROL_C_EXIT; + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Pc; + rec.NumberParameters = 0; + status = NtRaiseException( &rec, &context, TRUE ); + if (status) RtlRaiseStatus( status ); + restore_context( &context, sigcontext ); +} + + +/********************************************************************** + * abrt_handler + * + * Handler for SIGABRT. + */ +static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + NTSTATUS status; + + save_context( &context, sigcontext ); + rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Pc; + rec.NumberParameters = 0; + status = NtRaiseException( &rec, &context, TRUE ); + if (status) RtlRaiseStatus( status ); + restore_context( &context, sigcontext ); +} + + +/********************************************************************** + * quit_handler + * + * Handler for SIGQUIT. + */ +static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + 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; + + save_context( &context, sigcontext ); + wait_suspend( &context ); + restore_context( &context, sigcontext ); +} + + /********************************************************************** * get_thread_ldt_entry */ @@ -363,6 +836,40 @@ void signal_init_thread( TEB *teb ) } +/********************************************************************** + * signal_init_process + */ +void signal_init_process(void) +{ + struct sigaction sig_act; + + sig_act.sa_mask = server_block_set; + sig_act.sa_flags = SA_RESTART | SA_SIGINFO; + + 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 = 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; + if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; + if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; + return; + + error: + perror("sigaction"); + exit(1); +} + + /*********************************************************************** * init_thread_context */ @@ -397,6 +904,7 @@ PCONTEXT DECLSPEC_HIDDEN attach_thread( LPTHREAD_START_ROUTINE entry, void *arg, ctx = (CONTEXT *)NtCurrentTeb()->Tib.StackBase - 1; init_thread_context( ctx, entry, arg, relay ); } + pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL ); ctx->ContextFlags = CONTEXT_FULL; LdrInitializeThunk( ctx, (void **)&ctx->R0, 0, 0 ); return ctx; diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 1f2839844a6..6c9083664e0 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -69,10 +69,63 @@ #include "unix_private.h" #include "wine/debug.h" +WINE_DEFAULT_DEBUG_CHANNEL(seh); + +/*********************************************************************** + * 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( 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( 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; +} + +#endif /* linux */ + static pthread_key_t teb_key; static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */ +typedef void (*raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context ); + +/* stack layout when calling an exception raise function */ +struct stack_layout +{ + CONTEXT context; + EXCEPTION_RECORD rec; + void *redzone[2]; +}; + struct arm64_thread_data { void *exit_frame; /* exit frame pointer */ @@ -88,6 +141,76 @@ static inline struct arm64_thread_data *arm64_thread_data(void) } +/*********************************************************************** + * 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->u.s.Fp = FP_sig(sigcontext); /* Frame pointer */ + context->u.s.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->u.X[i] = REGn_sig( i, 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->u.s.Fp; /* Frame pointer */ + LR_sig(sigcontext) = context->u.s.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->u.X[i]; +} + + +/*********************************************************************** + * save_fpu + * + * Set the FPU context from a sigcontext. + */ +static void save_fpu( CONTEXT *context, ucontext_t *sigcontext ) +{ + 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) ); +} + + +/*********************************************************************** + * restore_fpu + * + * Restore the FPU context to a sigcontext. + */ +static void restore_fpu( CONTEXT *context, ucontext_t *sigcontext ) +{ + 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) ); +} + + /*********************************************************************** * get_server_context_flags * @@ -297,6 +420,278 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) } +/*********************************************************************** + * setup_exception + * + * Setup the exception record and context on the thread stack. + */ +static struct stack_layout *setup_exception( ucontext_t *sigcontext ) +{ + struct stack_layout *stack; + DWORD exception_code = 0; + + /* push the stack_layout structure */ + stack = (struct stack_layout *)((SP_sig(sigcontext) - sizeof(*stack)) & ~15); + + stack->rec.ExceptionRecord = NULL; + stack->rec.ExceptionCode = exception_code; + stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext); + stack->rec.NumberParameters = 0; + + save_context( &stack->context, sigcontext ); + save_fpu( &stack->context, sigcontext ); + return stack; +} + + +extern void raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func, void *sp ); +__ASM_GLOBAL_FUNC( raise_func_trampoline, + __ASM_CFI(".cfi_signal_frame\n\t") + "stp x29, x30, [sp, #-0x20]!\n\t" + __ASM_CFI(".cfi_def_cfa_offset 32\n\t") + __ASM_CFI(".cfi_offset 29, -32\n\t") + __ASM_CFI(".cfi_offset 30, -24\n\t") + "mov x29, sp\n\t" + __ASM_CFI(".cfi_def_cfa_register 29\n\t") + "str x3, [sp, 0x10]\n\t" + __ASM_CFI(".cfi_remember_state\n\t") + __ASM_CFI(".cfi_escape 0x0f,0x03,0x8d,0x10,0x06\n\t") /* CFA */ + __ASM_CFI(".cfi_escape 0x10,0x1d,0x02,0x8d,0x00\n\t") /* x29 */ + __ASM_CFI(".cfi_escape 0x10,0x1e,0x02,0x8d,0x08\n\t") /* x30 */ + "blr x2\n\t" + __ASM_CFI(".cfi_restore_state\n\t") + "brk #1") + +/*********************************************************************** + * setup_raise_exception + * + * Modify the signal context to call the exception raise function. + */ +static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *stack ) +{ + NTSTATUS status = send_debug_event( &stack->rec, &stack->context, TRUE ); + + if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) + { + restore_context( &stack->context, sigcontext ); + return; + } + REGn_sig(3, sigcontext) = SP_sig(sigcontext); /* original stack pointer, fourth arg for raise_func_trampoline */ + SP_sig(sigcontext) = (ULONG_PTR)stack; + LR_sig(sigcontext) = PC_sig(sigcontext); + PC_sig(sigcontext) = (ULONG_PTR)raise_func_trampoline; /* raise_generic_exception; */ + REGn_sig(0, sigcontext) = (ULONG_PTR)&stack->rec; /* first arg for raise_generic_exception */ + REGn_sig(1, sigcontext) = (ULONG_PTR)&stack->context; /* second arg for raise_generic_exception */ + REGn_sig(2, sigcontext) = (ULONG_PTR)KiUserExceptionDispatcher; /* third arg for raise_func_trampoline */ + REGn_sig(18, sigcontext) = (ULONG_PTR)NtCurrentTeb(); +} + +/********************************************************************** + * segv_handler + * + * Handler for SIGSEGV and related errors. + */ +static void segv_handler( int signal, siginfo_t *info, void *ucontext ) +{ + struct stack_layout *stack; + ucontext_t *context = ucontext; + + /* check for page fault inside the thread stack */ + if (signal == SIGSEGV) + { + switch (virtual_handle_stack_fault( info->si_addr )) + { + case 1: /* handled */ + return; + case -1: /* overflow */ + stack = setup_exception( context ); + stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; + goto done; + } + } + + stack = setup_exception( context ); + if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done; + + switch(signal) + { + case SIGILL: /* Invalid opcode exception */ + stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + case SIGSEGV: /* Segmentation fault */ + stack->rec.NumberParameters = 2; + stack->rec.ExceptionInformation[0] = (get_fault_esr( context ) & 0x40) != 0; + stack->rec.ExceptionInformation[1] = (ULONG_PTR)info->si_addr; + if (!(stack->rec.ExceptionCode = virtual_handle_fault( (void *)stack->rec.ExceptionInformation[1], + stack->rec.ExceptionInformation[0], FALSE ))) + return; + break; + case SIGBUS: /* Alignment check exception */ + stack->rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; + break; + default: + ERR("Got unexpected signal %i\n", signal); + stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + } +done: + setup_raise_exception( context, stack ); +} + + +/********************************************************************** + * trap_handler + * + * Handler for SIGTRAP. + */ +static void trap_handler( int signal, siginfo_t *info, void *ucontext ) +{ + ucontext_t *context = ucontext; + struct stack_layout *stack = setup_exception( context ); + + switch (info->si_code) + { + case TRAP_TRACE: + stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP; + break; + case TRAP_BRKPT: + default: + stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; + stack->context.Pc += 4; + break; + } + setup_raise_exception( context, stack ); +} + + +/********************************************************************** + * fpe_handler + * + * Handler for SIGFPE. + */ +static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack = setup_exception( sigcontext ); + + switch (siginfo->si_code & 0xffff ) + { +#ifdef FPE_FLTSUB + case FPE_FLTSUB: + stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; + break; +#endif +#ifdef FPE_INTDIV + case FPE_INTDIV: + stack->rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; + break; +#endif +#ifdef FPE_INTOVF + case FPE_INTOVF: + stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; + break; +#endif +#ifdef FPE_FLTDIV + case FPE_FLTDIV: + stack->rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO; + break; +#endif +#ifdef FPE_FLTOVF + case FPE_FLTOVF: + stack->rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW; + break; +#endif +#ifdef FPE_FLTUND + case FPE_FLTUND: + stack->rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW; + break; +#endif +#ifdef FPE_FLTRES + case FPE_FLTRES: + stack->rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT; + break; +#endif +#ifdef FPE_FLTINV + case FPE_FLTINV: +#endif + default: + stack->rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; + break; + } + setup_raise_exception( sigcontext, stack ); +} + + +/********************************************************************** + * int_handler + * + * Handler for SIGINT. + */ +static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack = setup_exception( sigcontext ); + + stack->rec.ExceptionCode = CONTROL_C_EXIT; + setup_raise_exception( sigcontext, stack ); +} + + +/********************************************************************** + * abrt_handler + * + * Handler for SIGABRT. + */ +static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack = setup_exception( sigcontext ); + + stack->rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; + stack->rec.ExceptionFlags = EH_NONCONTINUABLE; + setup_raise_exception( sigcontext, stack ); +} + + +/********************************************************************** + * quit_handler + * + * Handler for SIGQUIT. + */ +static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + 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; + + 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 ) +{ + CONTEXT *context = InterlockedExchangePointer( (void **)&arm64_thread_data()->context, NULL ); + if (!context) return; + if ((context->ContextFlags & ~CONTEXT_ARM64) & CONTEXT_FLOATING_POINT) + restore_fpu( context, sigcontext ); + restore_context( context, sigcontext ); +} + + /********************************************************************** * get_thread_ldt_entry */ @@ -361,6 +756,41 @@ void signal_init_thread( TEB *teb ) } +/********************************************************************** + * signal_init_process + */ +void signal_init_process(void) +{ + struct sigaction sig_act; + + 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; + if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; + if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; + return; + + error: + perror("sigaction"); + exit(1); +} + /*********************************************************************** * init_thread_context */ @@ -396,6 +826,7 @@ PCONTEXT DECLSPEC_HIDDEN attach_thread( LPTHREAD_START_ROUTINE entry, void *arg, ctx = (CONTEXT *)NtCurrentTeb()->Tib.StackBase - 1; init_thread_context( ctx, entry, arg, relay ); } + pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL ); ctx->ContextFlags = CONTEXT_FULL; LdrInitializeThunk( ctx, (void **)&ctx->u.s.X0, 0, 0 ); return ctx; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index cbfcdf49db0..7ae4cda33a6 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -63,6 +63,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(seh); +#undef ERR /* Solaris needs to define this */ + /* not defined for x86, so copy the x86_64 definition */ typedef struct DECLSPEC_ALIGN(16) _M128A { @@ -96,6 +98,89 @@ typedef struct #ifdef __linux__ +#ifndef HAVE_SYS_UCONTEXT_H + +enum +{ + REG_GS, REG_FS, REG_ES, REG_DS, REG_EDI, REG_ESI, REG_EBP, REG_ESP, + REG_EBX, REG_EDX, REG_ECX, REG_EAX, REG_TRAPNO, REG_ERR, REG_EIP, + REG_CS, REG_EFL, REG_UESP, REG_SS, NGREG +}; + +typedef int greg_t; +typedef greg_t gregset_t[NGREG]; + +struct _libc_fpreg +{ + unsigned short significand[4]; + unsigned short exponent; +}; + +struct _libc_fpstate +{ + unsigned long cw; + unsigned long sw; + unsigned long tag; + unsigned long ipoff; + unsigned long cssel; + unsigned long dataoff; + unsigned long datasel; + struct _libc_fpreg _st[8]; + unsigned long status; +}; + +typedef struct _libc_fpstate* fpregset_t; + +typedef struct +{ + gregset_t gregs; + fpregset_t fpregs; + unsigned long oldmask; + unsigned long cr2; +} mcontext_t; + +typedef struct ucontext +{ + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + mcontext_t uc_mcontext; + sigset_t uc_sigmask; +} ucontext_t; +#endif /* HAVE_SYS_UCONTEXT_H */ + +#define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX]) +#define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX]) +#define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX]) +#define EDX_sig(context) ((context)->uc_mcontext.gregs[REG_EDX]) +#define ESI_sig(context) ((context)->uc_mcontext.gregs[REG_ESI]) +#define EDI_sig(context) ((context)->uc_mcontext.gregs[REG_EDI]) +#define EBP_sig(context) ((context)->uc_mcontext.gregs[REG_EBP]) +#define ESP_sig(context) ((context)->uc_mcontext.gregs[REG_ESP]) + +#define CS_sig(context) ((context)->uc_mcontext.gregs[REG_CS]) +#define DS_sig(context) ((context)->uc_mcontext.gregs[REG_DS]) +#define ES_sig(context) ((context)->uc_mcontext.gregs[REG_ES]) +#define SS_sig(context) ((context)->uc_mcontext.gregs[REG_SS]) +#define FS_sig(context) ((context)->uc_mcontext.gregs[REG_FS]) +#define GS_sig(context) ((context)->uc_mcontext.gregs[REG_GS]) + +#define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL]) +#define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) +#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) + +#define FPU_sig(context) ((FLOATING_SAVE_AREA*)((context)->uc_mcontext.fpregs)) +#define FPUX_sig(context) (FPU_sig(context) && !((context)->uc_mcontext.fpregs->status >> 16) ? (XMM_SAVE_AREA32 *)(FPU_sig(context) + 1) : NULL) + +#ifdef __ANDROID__ +/* custom signal restorer since we may have unmapped the one in vdso, and bionic doesn't check for that */ +void rt_sigreturn(void); +__ASM_GLOBAL_FUNC( rt_sigreturn, + "movl $173,%eax\n\t" /* NR_rt_sigreturn */ + "int $0x80" ); +#endif + struct modify_ldt_s { unsigned int entry_number; @@ -120,49 +205,287 @@ static inline int set_thread_area( struct modify_ldt_s *ptr ) return syscall( 243 /* SYS_set_thread_area */, ptr ); } -#elif defined (__BSDI__) - -#include - #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) #include #include #include +#define EAX_sig(context) ((context)->uc_mcontext.mc_eax) +#define EBX_sig(context) ((context)->uc_mcontext.mc_ebx) +#define ECX_sig(context) ((context)->uc_mcontext.mc_ecx) +#define EDX_sig(context) ((context)->uc_mcontext.mc_edx) +#define ESI_sig(context) ((context)->uc_mcontext.mc_esi) +#define EDI_sig(context) ((context)->uc_mcontext.mc_edi) +#define EBP_sig(context) ((context)->uc_mcontext.mc_ebp) + +#define CS_sig(context) ((context)->uc_mcontext.mc_cs) +#define DS_sig(context) ((context)->uc_mcontext.mc_ds) +#define ES_sig(context) ((context)->uc_mcontext.mc_es) +#define FS_sig(context) ((context)->uc_mcontext.mc_fs) +#define GS_sig(context) ((context)->uc_mcontext.mc_gs) +#define SS_sig(context) ((context)->uc_mcontext.mc_ss) + +#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +#define EFL_sig(context) ((context)->uc_mcontext.mc_eflags) + +#define EIP_sig(context) ((context)->uc_mcontext.mc_eip) +#define ESP_sig(context) ((context)->uc_mcontext.mc_esp) + +#define FPU_sig(context) NULL /* FIXME */ +#define FPUX_sig(context) NULL /* FIXME */ + #elif defined (__OpenBSD__) #include #include +#define EAX_sig(context) ((context)->sc_eax) +#define EBX_sig(context) ((context)->sc_ebx) +#define ECX_sig(context) ((context)->sc_ecx) +#define EDX_sig(context) ((context)->sc_edx) +#define ESI_sig(context) ((context)->sc_esi) +#define EDI_sig(context) ((context)->sc_edi) +#define EBP_sig(context) ((context)->sc_ebp) + +#define CS_sig(context) ((context)->sc_cs) +#define DS_sig(context) ((context)->sc_ds) +#define ES_sig(context) ((context)->sc_es) +#define FS_sig(context) ((context)->sc_fs) +#define GS_sig(context) ((context)->sc_gs) +#define SS_sig(context) ((context)->sc_ss) + +#define TRAP_sig(context) ((context)->sc_trapno) +#define ERROR_sig(context) ((context)->sc_err) +#define EFL_sig(context) ((context)->sc_eflags) + +#define EIP_sig(context) ((context)->sc_eip) +#define ESP_sig(context) ((context)->sc_esp) + +#define FPU_sig(context) NULL /* FIXME */ +#define FPUX_sig(context) NULL /* FIXME */ + +#define T_MCHK T_MACHK +#define T_XMMFLT T_XFTRAP + #elif defined(__svr4__) || defined(_SCO_DS) || defined(__sun) #if defined(_SCO_DS) || defined(__sun) #include #endif +#ifdef _SCO_DS +#define gregs regs +#endif + +#define EAX_sig(context) ((context)->uc_mcontext.gregs[EAX]) +#define EBX_sig(context) ((context)->uc_mcontext.gregs[EBX]) +#define ECX_sig(context) ((context)->uc_mcontext.gregs[ECX]) +#define EDX_sig(context) ((context)->uc_mcontext.gregs[EDX]) +#define ESI_sig(context) ((context)->uc_mcontext.gregs[ESI]) +#define EDI_sig(context) ((context)->uc_mcontext.gregs[EDI]) +#define EBP_sig(context) ((context)->uc_mcontext.gregs[EBP]) + +#define CS_sig(context) ((context)->uc_mcontext.gregs[CS]) +#define DS_sig(context) ((context)->uc_mcontext.gregs[DS]) +#define ES_sig(context) ((context)->uc_mcontext.gregs[ES]) +#define SS_sig(context) ((context)->uc_mcontext.gregs[SS]) + +#define FS_sig(context) ((context)->uc_mcontext.gregs[FS]) +#define GS_sig(context) ((context)->uc_mcontext.gregs[GS]) + +#define EFL_sig(context) ((context)->uc_mcontext.gregs[EFL]) + +#define EIP_sig(context) ((context)->uc_mcontext.gregs[EIP]) +#ifdef UESP +#define ESP_sig(context) ((context)->uc_mcontext.gregs[UESP]) +#elif defined(R_ESP) +#define ESP_sig(context) ((context)->uc_mcontext.gregs[R_ESP]) +#else +#define ESP_sig(context) ((context)->uc_mcontext.gregs[ESP]) +#endif +#define ERROR_sig(context) ((context)->uc_mcontext.gregs[ERR]) +#define TRAP_sig(context) ((context)->uc_mcontext.gregs[TRAPNO]) + +#define FPU_sig(context) NULL /* FIXME */ +#define FPUX_sig(context) NULL /* FIXME */ + #elif defined (__APPLE__) #include +/* work around silly renaming of struct members in OS X 10.5 */ +#if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) +#define EAX_sig(context) ((context)->uc_mcontext->__ss.__eax) +#define EBX_sig(context) ((context)->uc_mcontext->__ss.__ebx) +#define ECX_sig(context) ((context)->uc_mcontext->__ss.__ecx) +#define EDX_sig(context) ((context)->uc_mcontext->__ss.__edx) +#define ESI_sig(context) ((context)->uc_mcontext->__ss.__esi) +#define EDI_sig(context) ((context)->uc_mcontext->__ss.__edi) +#define EBP_sig(context) ((context)->uc_mcontext->__ss.__ebp) +#define CS_sig(context) ((context)->uc_mcontext->__ss.__cs) +#define DS_sig(context) ((context)->uc_mcontext->__ss.__ds) +#define ES_sig(context) ((context)->uc_mcontext->__ss.__es) +#define FS_sig(context) ((context)->uc_mcontext->__ss.__fs) +#define GS_sig(context) ((context)->uc_mcontext->__ss.__gs) +#define SS_sig(context) ((context)->uc_mcontext->__ss.__ss) +#define EFL_sig(context) ((context)->uc_mcontext->__ss.__eflags) +#define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__eip)) +#define ESP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__esp)) +#define TRAP_sig(context) ((context)->uc_mcontext->__es.__trapno) +#define ERROR_sig(context) ((context)->uc_mcontext->__es.__err) +#define FPU_sig(context) NULL +#define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->__fs.__fpu_fcw) +#else +#define EAX_sig(context) ((context)->uc_mcontext->ss.eax) +#define EBX_sig(context) ((context)->uc_mcontext->ss.ebx) +#define ECX_sig(context) ((context)->uc_mcontext->ss.ecx) +#define EDX_sig(context) ((context)->uc_mcontext->ss.edx) +#define ESI_sig(context) ((context)->uc_mcontext->ss.esi) +#define EDI_sig(context) ((context)->uc_mcontext->ss.edi) +#define EBP_sig(context) ((context)->uc_mcontext->ss.ebp) +#define CS_sig(context) ((context)->uc_mcontext->ss.cs) +#define DS_sig(context) ((context)->uc_mcontext->ss.ds) +#define ES_sig(context) ((context)->uc_mcontext->ss.es) +#define FS_sig(context) ((context)->uc_mcontext->ss.fs) +#define GS_sig(context) ((context)->uc_mcontext->ss.gs) +#define SS_sig(context) ((context)->uc_mcontext->ss.ss) +#define EFL_sig(context) ((context)->uc_mcontext->ss.eflags) +#define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip)) +#define ESP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.esp)) +#define TRAP_sig(context) ((context)->uc_mcontext->es.trapno) +#define ERROR_sig(context) ((context)->uc_mcontext->es.err) +#define FPU_sig(context) NULL +#define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->fs.fpu_fcw) +#endif + #elif defined(__NetBSD__) #include #include +#define EAX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EAX]) +#define EBX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EBX]) +#define ECX_sig(context) ((context)->uc_mcontext.__gregs[_REG_ECX]) +#define EDX_sig(context) ((context)->uc_mcontext.__gregs[_REG_EDX]) +#define ESI_sig(context) ((context)->uc_mcontext.__gregs[_REG_ESI]) +#define EDI_sig(context) ((context)->uc_mcontext.__gregs[_REG_EDI]) +#define EBP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EBP]) +#define ESP_sig(context) _UC_MACHINE_SP(context) + +#define CS_sig(context) ((context)->uc_mcontext.__gregs[_REG_CS]) +#define DS_sig(context) ((context)->uc_mcontext.__gregs[_REG_DS]) +#define ES_sig(context) ((context)->uc_mcontext.__gregs[_REG_ES]) +#define SS_sig(context) ((context)->uc_mcontext.__gregs[_REG_SS]) +#define FS_sig(context) ((context)->uc_mcontext.__gregs[_REG_FS]) +#define GS_sig(context) ((context)->uc_mcontext.__gregs[_REG_GS]) + +#define EFL_sig(context) ((context)->uc_mcontext.__gregs[_REG_EFL]) +#define EIP_sig(context) _UC_MACHINE_PC(context) +#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) + +#define FPU_sig(context) NULL +#define FPUX_sig(context) ((XMM_SAVE_AREA32 *)&((context)->uc_mcontext.__fpregs)) + +#define T_MCHK T_MCA +#define T_XMMFLT T_XMM + #elif defined(__GNU__) #include #include +#define EAX_sig(context) ((context)->uc_mcontext.gregs[REG_EAX]) +#define EBX_sig(context) ((context)->uc_mcontext.gregs[REG_EBX]) +#define ECX_sig(context) ((context)->uc_mcontext.gregs[REG_ECX]) +#define EDX_sig(context) ((context)->uc_mcontext.gregs[REG_EDX]) +#define ESI_sig(context) ((context)->uc_mcontext.gregs[REG_ESI]) +#define EDI_sig(context) ((context)->uc_mcontext.gregs[REG_EDI]) +#define EBP_sig(context) ((context)->uc_mcontext.gregs[REG_EBP]) +#define ESP_sig(context) ((context)->uc_mcontext.gregs[REG_ESP]) + +#define CS_sig(context) ((context)->uc_mcontext.gregs[REG_CS]) +#define DS_sig(context) ((context)->uc_mcontext.gregs[REG_DS]) +#define ES_sig(context) ((context)->uc_mcontext.gregs[REG_ES]) +#define SS_sig(context) ((context)->uc_mcontext.gregs[REG_SS]) +#define FS_sig(context) ((context)->uc_mcontext.gregs[REG_FS]) +#define GS_sig(context) ((context)->uc_mcontext.gregs[REG_GS]) + +#define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL]) +#define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP]) +#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) + +#define FPU_sig(context) ((FLOATING_SAVE_AREA *)&(context)->uc_mcontext.fpregs.fp_reg_set.fpchip_state) +#define FPUX_sig(context) NULL + #else #error You must define the signal context functions for your platform #endif /* linux */ +/* stack layout when calling an exception raise function */ +struct stack_layout +{ + void *ret_addr; /* return address from raise_generic_exception */ + EXCEPTION_RECORD *rec_ptr; /* first arg for raise_generic_exception */ + CONTEXT *context_ptr; /* second arg for raise_generic_exception */ + CONTEXT context; + EXCEPTION_RECORD rec; + DWORD ebp; + DWORD eip; +}; static const size_t teb_size = 4096; /* we reserve one page for the TEB */ static ULONG first_ldt_entry = 32; +enum i386_trap_code +{ +#if defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) + TRAP_x86_DIVIDE = T_DIVIDE, /* Division by zero exception */ + TRAP_x86_TRCTRAP = T_TRCTRAP, /* Single-step exception */ + TRAP_x86_NMI = T_NMI, /* NMI interrupt */ + TRAP_x86_BPTFLT = T_BPTFLT, /* Breakpoint exception */ + TRAP_x86_OFLOW = T_OFLOW, /* Overflow exception */ + TRAP_x86_BOUND = T_BOUND, /* Bound range exception */ + TRAP_x86_PRIVINFLT = T_PRIVINFLT, /* Invalid opcode exception */ + TRAP_x86_DNA = T_DNA, /* Device not available exception */ + TRAP_x86_DOUBLEFLT = T_DOUBLEFLT, /* Double fault exception */ + TRAP_x86_FPOPFLT = T_FPOPFLT, /* Coprocessor segment overrun */ + TRAP_x86_TSSFLT = T_TSSFLT, /* Invalid TSS exception */ + TRAP_x86_SEGNPFLT = T_SEGNPFLT, /* Segment not present exception */ + TRAP_x86_STKFLT = T_STKFLT, /* Stack fault */ + TRAP_x86_PROTFLT = T_PROTFLT, /* General protection fault */ + TRAP_x86_PAGEFLT = T_PAGEFLT, /* Page fault */ + TRAP_x86_ARITHTRAP = T_ARITHTRAP, /* Floating point exception */ + TRAP_x86_ALIGNFLT = T_ALIGNFLT, /* Alignment check exception */ + TRAP_x86_MCHK = T_MCHK, /* Machine check exception */ + TRAP_x86_CACHEFLT = T_XMMFLT /* Cache flush exception */ +#else + TRAP_x86_DIVIDE = 0, /* Division by zero exception */ + TRAP_x86_TRCTRAP = 1, /* Single-step exception */ + TRAP_x86_NMI = 2, /* NMI interrupt */ + TRAP_x86_BPTFLT = 3, /* Breakpoint exception */ + TRAP_x86_OFLOW = 4, /* Overflow exception */ + TRAP_x86_BOUND = 5, /* Bound range exception */ + TRAP_x86_PRIVINFLT = 6, /* Invalid opcode exception */ + TRAP_x86_DNA = 7, /* Device not available exception */ + TRAP_x86_DOUBLEFLT = 8, /* Double fault exception */ + TRAP_x86_FPOPFLT = 9, /* Coprocessor segment overrun */ + TRAP_x86_TSSFLT = 10, /* Invalid TSS exception */ + TRAP_x86_SEGNPFLT = 11, /* Segment not present exception */ + TRAP_x86_STKFLT = 12, /* Stack fault */ + TRAP_x86_PROTFLT = 13, /* General protection fault */ + TRAP_x86_PAGEFLT = 14, /* Page fault */ + TRAP_x86_ARITHTRAP = 16, /* Floating point exception */ + TRAP_x86_ALIGNFLT = 17, /* Alignment check exception */ + TRAP_x86_MCHK = 18, /* Machine check exception */ + TRAP_x86_CACHEFLT = 19 /* SIMD exception (via SIGFPE) if CPU is SSE capable + otherwise Cache flush exception (via SIGSEV) */ +#endif +}; + struct x86_thread_data { DWORD fs; /* 1d4 TEB selector */ @@ -190,6 +513,7 @@ static inline WORD get_ds(void) { WORD res; __asm__( "movw %%ds,%0" : "=r" (res) static inline WORD get_fs(void) { WORD res; __asm__( "movw %%fs,%0" : "=r" (res) ); return res; } static inline WORD get_gs(void) { WORD res; __asm__( "movw %%gs,%0" : "=r" (res) ); return res; } static inline void set_fs( WORD val ) { __asm__( "mov %0,%%fs" :: "r" (val)); } +static inline void set_gs( WORD val ) { __asm__( "mov %0,%%gs" :: "r" (val)); } /*********************************************************************** @@ -201,6 +525,132 @@ static inline int is_gdt_sel( WORD sel ) } +/*********************************************************************** + * ldt_is_system + */ +static inline int ldt_is_system( WORD sel ) +{ + return is_gdt_sel( sel ) || ((sel >> 3) < first_ldt_entry); +} + + +/*********************************************************************** + * get_signal_stack + * + * Get the base of the signal stack for the current thread. + */ +static inline void *get_signal_stack(void) +{ + return (char *)NtCurrentTeb() + 4096; +} + + +/*********************************************************************** + * get_current_teb + * + * Get the current teb based on the stack pointer. + */ +static inline TEB *get_current_teb(void) +{ + unsigned long esp; + __asm__("movl %%esp,%0" : "=g" (esp) ); + return (TEB *)(esp & ~signal_stack_mask); +} + + +#ifdef __sun + +/* We have to workaround two Solaris breakages: + * - Solaris doesn't restore %ds and %es before calling the signal handler so exceptions in 16-bit + * code crash badly. + * - Solaris inserts a libc trampoline to call our handler, but the trampoline expects that registers + * are setup correctly. So we need to insert our own trampoline below the libc trampoline to set %gs. + */ + +extern int sigaction_syscall( int sig, const struct sigaction *new, struct sigaction *old ); +__ASM_GLOBAL_FUNC( sigaction_syscall, + "movl $0x62,%eax\n\t" + "int $0x91\n\t" + "ret" ) + +/* assume the same libc handler is used for all signals */ +static void (*libc_sigacthandler)( int signal, siginfo_t *siginfo, void *context ); + +static void wine_sigacthandler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct x86_thread_data *thread_data; + + __asm__ __volatile__("mov %ss,%ax; mov %ax,%ds; mov %ax,%es"); + + thread_data = (struct x86_thread_data *)get_current_teb()->SystemReserved2; + set_fs( thread_data->fs ); + set_gs( thread_data->gs ); + + libc_sigacthandler( signal, siginfo, sigcontext ); +} + +static int solaris_sigaction( int sig, const struct sigaction *new, struct sigaction *old ) +{ + struct sigaction real_act; + + if (sigaction( sig, new, old ) == -1) return -1; + + /* retrieve the real handler and flags with a direct syscall */ + sigaction_syscall( sig, NULL, &real_act ); + libc_sigacthandler = real_act.sa_sigaction; + real_act.sa_sigaction = wine_sigacthandler; + sigaction_syscall( sig, &real_act, NULL ); + return 0; +} +#define sigaction(sig,new,old) solaris_sigaction(sig,new,old) + +#endif + +extern void clear_alignment_flag(void); +__ASM_GLOBAL_FUNC( clear_alignment_flag, + "pushfl\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") + "andl $~0x40000,(%esp)\n\t" + "popfl\n\t" + __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") + "ret" ) + + +/*********************************************************************** + * init_handler + * + * Handler initialization when the full context is not needed. + * Return the stack pointer to use for pushing the exception data. + */ +static inline void *init_handler( const ucontext_t *sigcontext ) +{ + TEB *teb = get_current_teb(); + + clear_alignment_flag(); + +#ifndef __sun /* see above for Solaris handling */ + { + struct x86_thread_data *thread_data = (struct x86_thread_data *)teb->SystemReserved2; + set_fs( thread_data->fs ); + set_gs( thread_data->gs ); + } +#endif + + if (!ldt_is_system(CS_sig(sigcontext)) || !ldt_is_system(SS_sig(sigcontext))) /* 16-bit mode */ + { + /* + * Win16 or DOS protected mode. Note that during switch + * from 16-bit mode to linear mode, CS may be set to system + * segment before FS is restored. Fortunately, in this case + * SS is still non-system segment. This is why both CS and SS + * are checked. + */ + return teb->WOW32Reserved; + } + return (void *)(ESP_sig(sigcontext) & ~3); +} + + /*********************************************************************** * save_fpu * @@ -280,6 +730,141 @@ static inline void restore_fpux( const CONTEXT *context ) } +/*********************************************************************** + * fpux_to_fpu + * + * Build a standard FPU context from an extended one. + */ +static void fpux_to_fpu( FLOATING_SAVE_AREA *fpu, const XMM_SAVE_AREA32 *fpux ) +{ + unsigned int i, tag, stack_top; + + fpu->ControlWord = fpux->ControlWord | 0xffff0000; + fpu->StatusWord = fpux->StatusWord | 0xffff0000; + fpu->ErrorOffset = fpux->ErrorOffset; + fpu->ErrorSelector = fpux->ErrorSelector | (fpux->ErrorOpcode << 16); + fpu->DataOffset = fpux->DataOffset; + fpu->DataSelector = fpux->DataSelector; + fpu->Cr0NpxState = fpux->StatusWord | 0xffff0000; + + stack_top = (fpux->StatusWord >> 11) & 7; + fpu->TagWord = 0xffff0000; + for (i = 0; i < 8; i++) + { + memcpy( &fpu->RegisterArea[10 * i], &fpux->FloatRegisters[i], 10 ); + if (!(fpux->TagWord & (1 << i))) tag = 3; /* empty */ + else + { + const M128A *reg = &fpux->FloatRegisters[(i - stack_top) & 7]; + if ((reg->High & 0x7fff) == 0x7fff) /* exponent all ones */ + { + tag = 2; /* special */ + } + else if (!(reg->High & 0x7fff)) /* exponent all zeroes */ + { + if (reg->Low) tag = 2; /* special */ + else tag = 1; /* zero */ + } + else + { + if (reg->Low >> 63) tag = 0; /* valid */ + else tag = 2; /* special */ + } + } + fpu->TagWord |= tag << (2 * i); + } +} + + +/*********************************************************************** + * save_context + * + * Build a context structure from the signal info. + */ +static inline void save_context( CONTEXT *context, const ucontext_t *sigcontext ) +{ + FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); + XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext); + + memset(context, 0, sizeof(*context)); + context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; + context->Eax = EAX_sig(sigcontext); + context->Ebx = EBX_sig(sigcontext); + context->Ecx = ECX_sig(sigcontext); + context->Edx = EDX_sig(sigcontext); + context->Esi = ESI_sig(sigcontext); + context->Edi = EDI_sig(sigcontext); + context->Ebp = EBP_sig(sigcontext); + context->EFlags = EFL_sig(sigcontext); + context->Eip = EIP_sig(sigcontext); + context->Esp = ESP_sig(sigcontext); + context->SegCs = LOWORD(CS_sig(sigcontext)); + context->SegDs = LOWORD(DS_sig(sigcontext)); + context->SegEs = LOWORD(ES_sig(sigcontext)); + context->SegFs = LOWORD(FS_sig(sigcontext)); + context->SegGs = LOWORD(GS_sig(sigcontext)); + context->SegSs = LOWORD(SS_sig(sigcontext)); + context->Dr0 = x86_thread_data()->dr0; + context->Dr1 = x86_thread_data()->dr1; + context->Dr2 = x86_thread_data()->dr2; + context->Dr3 = x86_thread_data()->dr3; + context->Dr6 = x86_thread_data()->dr6; + context->Dr7 = x86_thread_data()->dr7; + + if (fpu) + { + context->ContextFlags |= CONTEXT_FLOATING_POINT; + context->FloatSave = *fpu; + } + if (fpux) + { + context->ContextFlags |= CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; + memcpy( context->ExtendedRegisters, fpux, sizeof(*fpux) ); + if (!fpu) fpux_to_fpu( &context->FloatSave, fpux ); + } + if (!fpu && !fpux) save_fpu( context ); +} + + +/*********************************************************************** + * restore_context + * + * Restore the signal info from the context. + */ +static inline void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) +{ + FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); + XMM_SAVE_AREA32 *fpux = FPUX_sig(sigcontext); + + x86_thread_data()->dr0 = context->Dr0; + x86_thread_data()->dr1 = context->Dr1; + x86_thread_data()->dr2 = context->Dr2; + x86_thread_data()->dr3 = context->Dr3; + x86_thread_data()->dr6 = context->Dr6; + x86_thread_data()->dr7 = context->Dr7; + EAX_sig(sigcontext) = context->Eax; + EBX_sig(sigcontext) = context->Ebx; + ECX_sig(sigcontext) = context->Ecx; + EDX_sig(sigcontext) = context->Edx; + ESI_sig(sigcontext) = context->Esi; + EDI_sig(sigcontext) = context->Edi; + EBP_sig(sigcontext) = context->Ebp; + EFL_sig(sigcontext) = context->EFlags; + EIP_sig(sigcontext) = context->Eip; + ESP_sig(sigcontext) = context->Esp; + CS_sig(sigcontext) = context->SegCs; + DS_sig(sigcontext) = context->SegDs; + ES_sig(sigcontext) = context->SegEs; + FS_sig(sigcontext) = context->SegFs; + GS_sig(sigcontext) = context->SegGs; + SS_sig(sigcontext) = context->SegSs; + + if (fpu) *fpu = context->FloatSave; + if (fpux) memcpy( fpux, context->ExtendedRegisters, sizeof(*fpux) ); + if (!fpu && !fpux) restore_fpu( context ); +} + + /*********************************************************************** * set_full_cpu_context * @@ -640,6 +1225,683 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) } +/*********************************************************************** + * is_privileged_instr + * + * Check if the fault location is a privileged instruction. + * Based on the instruction emulation code in dlls/kernel/instr.c. + */ +static inline DWORD is_privileged_instr( CONTEXT *context ) +{ + BYTE instr[16]; + unsigned int i, len, prefix_count = 0; + + if (!ldt_is_system( context->SegCs )) return 0; + len = virtual_uninterrupted_read_memory( (BYTE *)context->Eip, instr, sizeof(instr) ); + + for (i = 0; i < len; i++) switch (instr[i]) + { + /* instruction prefixes */ + case 0x2e: /* %cs: */ + case 0x36: /* %ss: */ + case 0x3e: /* %ds: */ + case 0x26: /* %es: */ + case 0x64: /* %fs: */ + case 0x65: /* %gs: */ + case 0x66: /* opcode size */ + case 0x67: /* addr size */ + case 0xf0: /* lock */ + case 0xf2: /* repne */ + case 0xf3: /* repe */ + if (++prefix_count >= 15) return EXCEPTION_ILLEGAL_INSTRUCTION; + continue; + + case 0x0f: /* extended instruction */ + if (i == len - 1) return 0; + switch(instr[i + 1]) + { + case 0x20: /* mov crX, reg */ + case 0x21: /* mov drX, reg */ + case 0x22: /* mov reg, crX */ + case 0x23: /* mov reg drX */ + return EXCEPTION_PRIV_INSTRUCTION; + } + return 0; + case 0x6c: /* insb (%dx) */ + case 0x6d: /* insl (%dx) */ + case 0x6e: /* outsb (%dx) */ + case 0x6f: /* outsl (%dx) */ + case 0xcd: /* int $xx */ + case 0xe4: /* inb al,XX */ + case 0xe5: /* in (e)ax,XX */ + case 0xe6: /* outb XX,al */ + case 0xe7: /* out XX,(e)ax */ + case 0xec: /* inb (%dx),%al */ + case 0xed: /* inl (%dx),%eax */ + case 0xee: /* outb %al,(%dx) */ + case 0xef: /* outl %eax,(%dx) */ + case 0xf4: /* hlt */ + case 0xfa: /* cli */ + case 0xfb: /* sti */ + return EXCEPTION_PRIV_INSTRUCTION; + default: + return 0; + } + return 0; +} + + +/*********************************************************************** + * check_invalid_gs + * + * Check for fault caused by invalid %gs value (some copy protection schemes mess with it). + */ +static inline BOOL check_invalid_gs( ucontext_t *sigcontext, CONTEXT *context ) +{ + unsigned int prefix_count = 0; + const BYTE *instr = (BYTE *)context->Eip; + WORD system_gs = x86_thread_data()->gs; + + if (context->SegGs == system_gs) return FALSE; + if (!ldt_is_system( context->SegCs )) return FALSE; + /* only handle faults in system libraries */ + if (virtual_is_valid_code_address( instr, 1 )) return FALSE; + + for (;;) switch(*instr) + { + /* instruction prefixes */ + case 0x2e: /* %cs: */ + case 0x36: /* %ss: */ + case 0x3e: /* %ds: */ + case 0x26: /* %es: */ + case 0x64: /* %fs: */ + case 0x66: /* opcode size */ + case 0x67: /* addr size */ + case 0xf0: /* lock */ + case 0xf2: /* repne */ + case 0xf3: /* repe */ + if (++prefix_count >= 15) return FALSE; + instr++; + continue; + case 0x65: /* %gs: */ + TRACE( "%04x/%04x at %p, fixing up\n", context->SegGs, system_gs, instr ); + GS_sig(sigcontext) = system_gs; + return TRUE; + default: + return FALSE; + } +} + + +#include "pshpack1.h" +union atl_thunk +{ + struct + { + DWORD movl; /* movl this,4(%esp) */ + DWORD this; + BYTE jmp; /* jmp func */ + int func; + } t1; + struct + { + BYTE movl; /* movl this,ecx */ + DWORD this; + BYTE jmp; /* jmp func */ + int func; + } t2; + struct + { + BYTE movl1; /* movl this,edx */ + DWORD this; + BYTE movl2; /* movl func,ecx */ + DWORD func; + WORD jmp; /* jmp ecx */ + } t3; + struct + { + BYTE movl1; /* movl this,ecx */ + DWORD this; + BYTE movl2; /* movl func,eax */ + DWORD func; + WORD jmp; /* jmp eax */ + } t4; + struct + { + DWORD inst1; /* pop ecx + * pop eax + * push ecx + * jmp 4(%eax) */ + WORD inst2; + } t5; +}; +#include "poppack.h" + +/********************************************************************** + * check_atl_thunk + * + * Check if code destination is an ATL thunk, and emulate it if so. + */ +static BOOL check_atl_thunk( ucontext_t *sigcontext, struct stack_layout *stack ) +{ + const union atl_thunk *thunk = (const union atl_thunk *)stack->rec.ExceptionInformation[1]; + union atl_thunk thunk_copy; + SIZE_T thunk_len; + + thunk_len = virtual_uninterrupted_read_memory( thunk, &thunk_copy, sizeof(*thunk) ); + if (!thunk_len) return FALSE; + + if (thunk_len >= sizeof(thunk_copy.t1) && thunk_copy.t1.movl == 0x042444c7 && + thunk_copy.t1.jmp == 0xe9) + { + if (!virtual_uninterrupted_write_memory( (DWORD *)stack->context.Esp + 1, + &thunk_copy.t1.this, sizeof(DWORD) )) + { + EIP_sig(sigcontext) = (DWORD_PTR)(&thunk->t1.func + 1) + thunk_copy.t1.func; + TRACE( "emulating ATL thunk type 1 at %p, func=%08x arg=%08x\n", + thunk, EIP_sig(sigcontext), thunk_copy.t1.this ); + return TRUE; + } + } + else if (thunk_len >= sizeof(thunk_copy.t2) && thunk_copy.t2.movl == 0xb9 && + thunk_copy.t2.jmp == 0xe9) + { + ECX_sig(sigcontext) = thunk_copy.t2.this; + EIP_sig(sigcontext) = (DWORD_PTR)(&thunk->t2.func + 1) + thunk_copy.t2.func; + TRACE( "emulating ATL thunk type 2 at %p, func=%08x ecx=%08x\n", + thunk, EIP_sig(sigcontext), ECX_sig(sigcontext) ); + return TRUE; + } + else if (thunk_len >= sizeof(thunk_copy.t3) && thunk_copy.t3.movl1 == 0xba && + thunk_copy.t3.movl2 == 0xb9 && + thunk_copy.t3.jmp == 0xe1ff) + { + EDX_sig(sigcontext) = thunk_copy.t3.this; + ECX_sig(sigcontext) = thunk_copy.t3.func; + EIP_sig(sigcontext) = thunk_copy.t3.func; + TRACE( "emulating ATL thunk type 3 at %p, func=%08x ecx=%08x edx=%08x\n", + thunk, EIP_sig(sigcontext), ECX_sig(sigcontext), EDX_sig(sigcontext) ); + return TRUE; + } + else if (thunk_len >= sizeof(thunk_copy.t4) && thunk_copy.t4.movl1 == 0xb9 && + thunk_copy.t4.movl2 == 0xb8 && + thunk_copy.t4.jmp == 0xe0ff) + { + ECX_sig(sigcontext) = thunk_copy.t4.this; + EAX_sig(sigcontext) = thunk_copy.t4.func; + EIP_sig(sigcontext) = thunk_copy.t4.func; + TRACE( "emulating ATL thunk type 4 at %p, func=%08x eax=%08x ecx=%08x\n", + thunk, EIP_sig(sigcontext), EAX_sig(sigcontext), ECX_sig(sigcontext) ); + return TRUE; + } + else if (thunk_len >= sizeof(thunk_copy.t5) && thunk_copy.t5.inst1 == 0xff515859 && + thunk_copy.t5.inst2 == 0x0460) + { + DWORD func, sp[2]; + if (virtual_uninterrupted_read_memory( (DWORD *)stack->context.Esp, sp, sizeof(sp) ) == sizeof(sp) && + virtual_uninterrupted_read_memory( (DWORD *)sp[1] + 1, &func, sizeof(DWORD) ) == sizeof(DWORD) && + !virtual_uninterrupted_write_memory( (DWORD *)stack->context.Esp + 1, &sp[0], sizeof(sp[0]) )) + { + ECX_sig(sigcontext) = sp[0]; + EAX_sig(sigcontext) = sp[1]; + ESP_sig(sigcontext) += sizeof(DWORD); + EIP_sig(sigcontext) = func; + TRACE( "emulating ATL thunk type 5 at %p, func=%08x eax=%08x ecx=%08x esp=%08x\n", + thunk, EIP_sig(sigcontext), EAX_sig(sigcontext), + ECX_sig(sigcontext), ESP_sig(sigcontext) ); + return TRUE; + } + } + + return FALSE; +} + + +/*********************************************************************** + * setup_exception_record + * + * Setup the exception record and context on the thread stack. + */ +static struct stack_layout *setup_exception_record( ucontext_t *sigcontext, void *stack_ptr ) +{ + struct stack_layout *stack = stack_ptr; + DWORD exception_code = 0; + + /* stack sanity checks */ + + if ((char *)stack >= (char *)get_signal_stack() && + (char *)stack < (char *)get_signal_stack() + signal_stack_size) + { + WINE_ERR( "nested exception on signal stack in thread %04x eip %08x esp %08x stack %p-%p\n", + GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), + (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit, + NtCurrentTeb()->Tib.StackBase ); + abort_thread(1); + } + + if (stack - 1 > stack || /* check for overflow in subtraction */ + (char *)stack <= (char *)NtCurrentTeb()->DeallocationStack || + (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase) + { + WARN( "exception outside of stack limits in thread %04x eip %08x esp %08x stack %p-%p\n", + GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), + (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->Tib.StackLimit, + NtCurrentTeb()->Tib.StackBase ); + } + else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096) + { + /* stack overflow on last page, unrecoverable */ + UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1); + WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n", + diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), + (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, + NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); + abort_thread(1); + } + else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit) + { + /* stack access below stack limit, may be recoverable */ + switch (virtual_handle_stack_fault( stack - 1 )) + { + case 0: /* not handled */ + { + UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1); + WINE_ERR( "stack overflow %u bytes in thread %04x eip %08x esp %08x stack %p-%p-%p\n", + diff, GetCurrentThreadId(), (unsigned int) EIP_sig(sigcontext), + (unsigned int) ESP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, + NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); + abort_thread(1); + } + case -1: /* overflow */ + exception_code = EXCEPTION_STACK_OVERFLOW; + break; + } + } + + stack--; /* push the stack_layout structure */ +#if defined(VALGRIND_MAKE_MEM_UNDEFINED) + VALGRIND_MAKE_MEM_UNDEFINED(stack, sizeof(*stack)); +#elif defined(VALGRIND_MAKE_WRITABLE) + VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack)); +#endif + stack->rec.ExceptionRecord = NULL; + stack->rec.ExceptionCode = exception_code; + stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + stack->rec.ExceptionAddress = (LPVOID)EIP_sig(sigcontext); + stack->rec.NumberParameters = 0; + + save_context( &stack->context, sigcontext ); + return stack; +} + + +/*********************************************************************** + * setup_exception + * + * Setup a proper stack frame for the raise function, and modify the + * sigcontext so that the return from the signal handler will call + * the raise function. + */ +static struct stack_layout *setup_exception( ucontext_t *sigcontext ) +{ + void *stack = init_handler( sigcontext ); + + return setup_exception_record( sigcontext, stack ); +} + + +/*********************************************************************** + * setup_raise_exception + * + * Change context to setup a call to a raise exception function. + */ +static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *stack ) +{ + NTSTATUS status = send_debug_event( &stack->rec, &stack->context, TRUE ); + + if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) + { + restore_context( &stack->context, sigcontext ); + return; + } + ESP_sig(sigcontext) = (DWORD)stack; + EIP_sig(sigcontext) = (DWORD)KiUserExceptionDispatcher; + /* clear single-step, direction, and align check flag */ + EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000); + CS_sig(sigcontext) = get_cs(); + DS_sig(sigcontext) = get_ds(); + ES_sig(sigcontext) = get_ds(); + FS_sig(sigcontext) = get_fs(); + GS_sig(sigcontext) = get_gs(); + SS_sig(sigcontext) = get_ds(); + stack->ret_addr = (void *)0xdeadbabe; /* KiUserExceptionDispatcher must not return */ + stack->rec_ptr = &stack->rec; /* arguments for KiUserExceptionDispatcher */ + stack->context_ptr = &stack->context; +} + + +/********************************************************************** + * get_fpu_code + * + * Get the FPU exception code from the FPU status. + */ +static inline DWORD get_fpu_code( const CONTEXT *context ) +{ + DWORD status = context->FloatSave.StatusWord & ~(context->FloatSave.ControlWord & 0x3f); + + if (status & 0x01) /* IE */ + { + if (status & 0x40) /* SF */ + return EXCEPTION_FLT_STACK_CHECK; + else + return EXCEPTION_FLT_INVALID_OPERATION; + } + if (status & 0x02) return EXCEPTION_FLT_DENORMAL_OPERAND; /* DE flag */ + if (status & 0x04) return EXCEPTION_FLT_DIVIDE_BY_ZERO; /* ZE flag */ + if (status & 0x08) return EXCEPTION_FLT_OVERFLOW; /* OE flag */ + if (status & 0x10) return EXCEPTION_FLT_UNDERFLOW; /* UE flag */ + if (status & 0x20) return EXCEPTION_FLT_INEXACT_RESULT; /* PE flag */ + return EXCEPTION_FLT_INVALID_OPERATION; /* generic error */ +} + + +/*********************************************************************** + * handle_interrupt + * + * Handle an interrupt. + */ +static BOOL handle_interrupt( unsigned int interrupt, ucontext_t *sigcontext, struct stack_layout *stack ) +{ + switch(interrupt) + { + case 0x2d: + if (!is_wow64) + { + /* On Wow64, the upper DWORD of Rax contains garbage, and the debug + * service is usually not recognized when called from usermode. */ + switch (stack->context.Eax) + { + case 1: /* BREAKPOINT_PRINT */ + case 3: /* BREAKPOINT_LOAD_SYMBOLS */ + case 4: /* BREAKPOINT_UNLOAD_SYMBOLS */ + case 5: /* BREAKPOINT_COMMAND_STRING (>= Win2003) */ + EIP_sig(sigcontext) += 3; + return TRUE; + } + } + stack->context.Eip += 3; + stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; + stack->rec.ExceptionAddress = (void *)stack->context.Eip; + stack->rec.NumberParameters = is_wow64 ? 1 : 3; + stack->rec.ExceptionInformation[0] = stack->context.Eax; + stack->rec.ExceptionInformation[1] = stack->context.Ecx; + stack->rec.ExceptionInformation[2] = stack->context.Edx; + setup_raise_exception( sigcontext, stack ); + return TRUE; + default: + return FALSE; + } +} + + +/********************************************************************** + * segv_handler + * + * Handler for SIGSEGV and related errors. + */ +static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack; + ucontext_t *context = sigcontext; + void *stack_ptr = init_handler( sigcontext ); + + /* check for exceptions on the signal stack caused by write watches */ + if (TRAP_sig(context) == TRAP_x86_PAGEFLT && + (char *)stack_ptr >= (char *)get_signal_stack() && + (char *)stack_ptr < (char *)get_signal_stack() + signal_stack_size && + !virtual_handle_fault( siginfo->si_addr, (ERROR_sig(context) >> 1) & 0x09, TRUE )) + { + return; + } + + /* check for page fault inside the thread stack */ + if (TRAP_sig(context) == TRAP_x86_PAGEFLT) + { + switch (virtual_handle_stack_fault( siginfo->si_addr )) + { + case 1: /* handled */ + return; + case -1: /* overflow */ + stack = setup_exception_record( context, stack_ptr ); + stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; + goto done; + } + } + + stack = setup_exception_record( context, stack_ptr ); + if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done; + + switch (TRAP_sig(context)) + { + case TRAP_x86_OFLOW: /* Overflow exception */ + stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; + break; + case TRAP_x86_BOUND: /* Bound range exception */ + stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; + break; + case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */ + stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + case TRAP_x86_STKFLT: /* Stack fault */ + stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; + break; + case TRAP_x86_SEGNPFLT: /* Segment not present exception */ + case TRAP_x86_PROTFLT: /* General protection fault */ + { + WORD err = ERROR_sig(context); + if (!err && (stack->rec.ExceptionCode = is_privileged_instr( &stack->context ))) break; + if ((err & 7) == 2 && handle_interrupt( err >> 3, context, stack )) return; + stack->rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION; + stack->rec.NumberParameters = 2; + stack->rec.ExceptionInformation[0] = 0; + /* if error contains a LDT selector, use that as fault address */ + if ((err & 7) == 4 && !ldt_is_system( err | 7 )) + stack->rec.ExceptionInformation[1] = err & ~7; + else + { + stack->rec.ExceptionInformation[1] = 0xffffffff; + if (check_invalid_gs( context, &stack->context )) return; + } + } + break; + case TRAP_x86_PAGEFLT: /* Page fault */ + stack->rec.NumberParameters = 2; + stack->rec.ExceptionInformation[0] = (ERROR_sig(context) >> 1) & 0x09; + stack->rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; + stack->rec.ExceptionCode = virtual_handle_fault( (void *)stack->rec.ExceptionInformation[1], + stack->rec.ExceptionInformation[0], FALSE ); + if (!stack->rec.ExceptionCode) return; + if (stack->rec.ExceptionCode == EXCEPTION_ACCESS_VIOLATION && + stack->rec.ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT) + { + ULONG flags; + NtQueryInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, + &flags, sizeof(flags), NULL ); + if (!(flags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) && check_atl_thunk( context, stack )) + return; + + /* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */ + if (!(flags & MEM_EXECUTE_OPTION_DISABLE)) + stack->rec.ExceptionInformation[0] = EXCEPTION_READ_FAULT; + } + break; + case TRAP_x86_ALIGNFLT: /* Alignment check exception */ + /* FIXME: pass through exception handler first? */ + if (stack->context.EFlags & 0x00040000) + { + EFL_sig(context) &= ~0x00040000; /* disable AC flag */ + return; + } + stack->rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; + break; + default: + WINE_ERR( "Got unexpected trap %d\n", TRAP_sig(context) ); + /* fall through */ + case TRAP_x86_NMI: /* NMI interrupt */ + case TRAP_x86_DNA: /* Device not available exception */ + case TRAP_x86_DOUBLEFLT: /* Double fault exception */ + case TRAP_x86_TSSFLT: /* Invalid TSS exception */ + case TRAP_x86_MCHK: /* Machine check exception */ + case TRAP_x86_CACHEFLT: /* Cache flush exception */ + stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + } +done: + setup_raise_exception( context, stack ); +} + + +/********************************************************************** + * trap_handler + * + * Handler for SIGTRAP. + */ +static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + ucontext_t *context = sigcontext; + struct stack_layout *stack = setup_exception( context ); + + switch (TRAP_sig(context)) + { + case TRAP_x86_TRCTRAP: /* Single-step exception */ + stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP; + /* when single stepping can't tell whether this is a hw bp or a + * single step interrupt. try to avoid as much overhead as possible + * and only do a server call if there is any hw bp enabled. */ + if (!(stack->context.EFlags & 0x100) || (stack->context.Dr7 & 0xff)) + { + /* (possible) hardware breakpoint, fetch the debug registers */ + DWORD saved_flags = stack->context.ContextFlags; + stack->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; + NtGetContextThread( GetCurrentThread(), &stack->context ); + stack->context.ContextFlags |= saved_flags; /* restore flags */ + } + stack->context.EFlags &= ~0x100; /* clear single-step flag */ + break; + case TRAP_x86_BPTFLT: /* Breakpoint exception */ + stack->rec.ExceptionAddress = (char *)stack->rec.ExceptionAddress - 1; /* back up over the int3 instruction */ + /* fall through */ + default: + stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; + stack->rec.NumberParameters = is_wow64 ? 1 : 3; + stack->rec.ExceptionInformation[0] = 0; + stack->rec.ExceptionInformation[1] = 0; /* FIXME */ + stack->rec.ExceptionInformation[2] = 0; /* FIXME */ + break; + } + setup_raise_exception( context, stack ); +} + + +/********************************************************************** + * fpe_handler + * + * Handler for SIGFPE. + */ +static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + ucontext_t *context = sigcontext; + struct stack_layout *stack = setup_exception( context ); + + switch (TRAP_sig(context)) + { + case TRAP_x86_DIVIDE: /* Division by zero exception */ + stack->rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; + break; + case TRAP_x86_FPOPFLT: /* Coprocessor segment overrun */ + stack->rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; + break; + case TRAP_x86_ARITHTRAP: /* Floating point exception */ + stack->rec.ExceptionCode = get_fpu_code( &stack->context ); + stack->rec.ExceptionAddress = (LPVOID)stack->context.FloatSave.ErrorOffset; + break; + case TRAP_x86_CACHEFLT: /* SIMD exception */ + /* TODO: + * Behaviour only tested for divide-by-zero exceptions + * Check for other SIMD exceptions as well */ + if(siginfo->si_code != FPE_FLTDIV && siginfo->si_code != FPE_FLTINV) + FIXME("untested SIMD exception: %#x. Might not work correctly\n", + siginfo->si_code); + + stack->rec.ExceptionCode = STATUS_FLOAT_MULTIPLE_TRAPS; + stack->rec.NumberParameters = 1; + /* no idea what meaning is actually behind this but that's what native does */ + stack->rec.ExceptionInformation[0] = 0; + break; + default: + WINE_ERR( "Got unexpected trap %d\n", TRAP_sig(context) ); + stack->rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; + break; + } + + setup_raise_exception( context, stack ); +} + + +/********************************************************************** + * int_handler + * + * Handler for SIGINT. + */ +static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack = setup_exception( sigcontext ); + stack->rec.ExceptionCode = CONTROL_C_EXIT; + setup_raise_exception( sigcontext, stack ); +} + +/********************************************************************** + * abrt_handler + * + * Handler for SIGABRT. + */ +static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack = setup_exception( sigcontext ); + stack->rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; + stack->rec.ExceptionFlags = EH_NONCONTINUABLE; + setup_raise_exception( sigcontext, stack ); +} + + +/********************************************************************** + * quit_handler + * + * Handler for SIGQUIT. + */ +static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + init_handler( sigcontext ); + 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; + + init_handler( sigcontext ); + save_context( &context, sigcontext ); + wait_suspend( &context ); + restore_context( &context, sigcontext ); +} + + /*********************************************************************** * LDT support */ @@ -941,11 +2203,44 @@ void signal_init_thread( TEB *teb ) ldt_set_fs( thread_data->fs, teb ); thread_data->gs = get_gs(); -#ifdef __GNUC__ __asm__ volatile ("fninit; fldcw %0" : : "m" (fpu_cw)); -#else - FIXME("FPU setup not implemented for this platform.\n"); +} + + +/********************************************************************** + * signal_init_process + */ +void signal_init_process(void) +{ + struct sigaction sig_act; + + sig_act.sa_mask = server_block_set; + sig_act.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK; +#ifdef __ANDROID__ + sig_act.sa_flags |= SA_RESTORER; + sig_act.sa_restorer = rt_sigreturn; #endif + 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 = 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; + if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; + if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; + return; + + error: + perror("sigaction"); + exit(1); } @@ -993,6 +2288,7 @@ PCONTEXT DECLSPEC_HIDDEN attach_thread( LPTHREAD_START_ROUTINE entry, void *arg, ctx = (CONTEXT *)((char *)NtCurrentTeb()->Tib.StackBase - 16) - 1; init_thread_context( ctx, entry, arg, relay ); } + pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL ); ctx->ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; LdrInitializeThunk( ctx, (void **)&ctx->Eax, 0, 0 ); return ctx; diff --git a/dlls/ntdll/unix/signal_powerpc.c b/dlls/ntdll/unix/signal_powerpc.c index fefb3a99135..f98d6fc9713 100644 --- a/dlls/ntdll/unix/signal_powerpc.c +++ b/dlls/ntdll/unix/signal_powerpc.c @@ -63,9 +63,181 @@ #include "unix_private.h" #include "wine/debug.h" +/*********************************************************************** + * signal context platform-specific definitions + */ +#ifdef linux + +/* All Registers access - only for local access */ +# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name) + + +/* Gpr Registers access */ +# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context) + +# define IAR_sig(context) REG_sig(nip, context) /* Program counter */ +# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */ +# define CTR_sig(context) REG_sig(ctr, context) /* Count register */ + +# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */ +# define LR_sig(context) REG_sig(link, context) /* Link register */ +# define CR_sig(context) REG_sig(ccr, context) /* Condition register */ + +/* Float Registers access */ +# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num]) + +# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4))) + +/* Exception Registers access */ +# define DAR_sig(context) REG_sig(dar, context) +# define DSISR_sig(context) REG_sig(dsisr, context) +# define TRAP_sig(context) REG_sig(trap, context) + +#endif /* linux */ + +#ifdef __APPLE__ + +/* All Registers access - only for local access */ +# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name) +# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name) +# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name) +# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name) + +/* Gpr Registers access */ +# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context) + +# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */ +# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */ +# define CTR_sig(context) REG_sig(ctr, context) + +# define XER_sig(context) REG_sig(xer, context) /* Link register */ +# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */ +# define CR_sig(context) REG_sig(cr, context) /* Condition register */ + +/* Float Registers access */ +# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context) + +# define FPSCR_sig(context) FLOATREG_sig(fpscr, context) + +/* Exception Registers access */ +# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */ +# define DSISR_sig(context) EXCEPREG_sig(dsisr, context) +# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */ + +/* Signal defs : Those are undefined on darwin +SIGBUS +#undef BUS_ADRERR +#undef BUS_OBJERR +SIGILL +#undef ILL_ILLOPN +#undef ILL_ILLTRP +#undef ILL_ILLADR +#undef ILL_COPROC +#undef ILL_PRVREG +#undef ILL_BADSTK +SIGTRAP +#undef TRAP_BRKPT +#undef TRAP_TRACE +SIGFPE +*/ + +#endif /* __APPLE__ */ + + static pthread_key_t teb_key; +/*********************************************************************** + * save_context + * + * Set the register values from a sigcontext. + */ +static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) +{ + +#define C(x) context->Gpr##x = GPR_sig(x,sigcontext) + /* Save Gpr registers */ + C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); + C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20); + C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30); + C(31); +#undef C + + context->Iar = IAR_sig(sigcontext); /* Program Counter */ + context->Msr = MSR_sig(sigcontext); /* Machine State Register (Supervisor) */ + context->Ctr = CTR_sig(sigcontext); + context->Xer = XER_sig(sigcontext); + context->Lr = LR_sig(sigcontext); + context->Cr = CR_sig(sigcontext); + /* Saving Exception regs */ + context->Dar = DAR_sig(sigcontext); + context->Dsisr = DSISR_sig(sigcontext); + context->Trap = TRAP_sig(sigcontext); +} + + +/*********************************************************************** + * restore_context + * + * Build a sigcontext from the register values. + */ +static void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) +{ + +#define C(x) GPR_sig(x,sigcontext) = context->Gpr##x + C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); + C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20); + C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30); + C(31); +#undef C + + IAR_sig(sigcontext) = context->Iar; /* Program Counter */ + MSR_sig(sigcontext) = context->Msr; /* Machine State Register (Supervisor) */ + CTR_sig(sigcontext) = context->Ctr; + XER_sig(sigcontext) = context->Xer; + LR_sig(sigcontext) = context->Lr; + CR_sig(sigcontext) = context->Cr; + /* Setting Exception regs */ + DAR_sig(sigcontext) = context->Dar; + DSISR_sig(sigcontext) = context->Dsisr; + TRAP_sig(sigcontext) = context->Trap; +} + + +/*********************************************************************** + * save_fpu + * + * Set the FPU context from a sigcontext. + */ +static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext ) +{ +#define C(x) context->Fpr##x = FLOAT_sig(x,sigcontext) + C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); + C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20); + C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30); + C(31); +#undef C + context->Fpscr = FPSCR_sig(sigcontext); +} + + +/*********************************************************************** + * restore_fpu + * + * Restore the FPU context to a sigcontext. + */ +static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext ) +{ +#define C(x) FLOAT_sig(x,sigcontext) = context->Fpr##x + C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10); + C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20); + C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30); + C(31); +#undef C + FPSCR_sig(sigcontext) = context->Fpscr; +} + + /*********************************************************************** * set_cpu_context * @@ -437,6 +609,288 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) } +/********************************************************************** + * segv_handler + * + * Handler for SIGSEGV and related errors. + */ +static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + NTSTATUS status; + + save_context( &context, sigcontext ); + + rec.ExceptionRecord = NULL; + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionAddress = (LPVOID)context.Iar; + rec.NumberParameters = 0; + + switch (signal) + { + case SIGSEGV: + switch (siginfo->si_code & 0xffff) + { + case SEGV_MAPERR: + case SEGV_ACCERR: + rec.NumberParameters = 2; + rec.ExceptionInformation[0] = 0; /* FIXME ? */ + rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; + if (!(rec.ExceptionCode = unix_funcs->virtual_handle_fault(siginfo->si_addr, rec.ExceptionInformation[0], FALSE))) + goto done; + break; + default: + FIXME("Unhandled SIGSEGV/%x\n",siginfo->si_code); + break; + } + break; + case SIGBUS: + switch (siginfo->si_code & 0xffff) + { + case BUS_ADRALN: + rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; + break; +#ifdef BUS_ADRERR + case BUS_ADRERR: +#endif +#ifdef BUS_OBJERR + case BUS_OBJERR: + /* FIXME: correct for all cases ? */ + rec.NumberParameters = 2; + rec.ExceptionInformation[0] = 0; /* FIXME ? */ + rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; + if (!(rec.ExceptionCode = unix_funcs->virtual_handle_fault(siginfo->si_addr, rec.ExceptionInformation[0], FALSE))) + goto done; + break; +#endif + default: + FIXME("Unhandled SIGBUS/%x\n",siginfo->si_code); + break; + } + break; + case SIGILL: + switch (siginfo->si_code & 0xffff) + { + case ILL_ILLOPC: /* illegal opcode */ +#ifdef ILL_ILLOPN + case ILL_ILLOPN: /* illegal operand */ +#endif +#ifdef ILL_ILLADR + case ILL_ILLADR: /* illegal addressing mode */ +#endif +#ifdef ILL_ILLTRP + case ILL_ILLTRP: /* illegal trap */ +#endif +#ifdef ILL_COPROC + case ILL_COPROC: /* coprocessor error */ +#endif + rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + case ILL_PRVOPC: /* privileged opcode */ +#ifdef ILL_PRVREG + case ILL_PRVREG: /* privileged register */ +#endif + rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION; + break; +#ifdef ILL_BADSTK + case ILL_BADSTK: /* internal stack error */ + rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; + break; +#endif + default: + FIXME("Unhandled SIGILL/%x\n", siginfo->si_code); + break; + } + break; + } + status = NtRaiseException( &rec, &context, TRUE ); + if (status) RtlRaiseStatus( status ); +done: + restore_context( &context, sigcontext ); +} + +/********************************************************************** + * trap_handler + * + * Handler for SIGTRAP. + */ +static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + NTSTATUS status; + + save_context( &context, sigcontext ); + + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Iar; + rec.NumberParameters = 0; + + /* FIXME: check if we might need to modify PC */ + switch (siginfo->si_code & 0xffff) + { +#ifdef TRAP_BRKPT + case TRAP_BRKPT: + rec.ExceptionCode = EXCEPTION_BREAKPOINT; + break; +#endif +#ifdef TRAP_TRACE + case TRAP_TRACE: + rec.ExceptionCode = EXCEPTION_SINGLE_STEP; + break; +#endif + default: + FIXME("Unhandled SIGTRAP/%x\n", siginfo->si_code); + break; + } + status = NtRaiseException( &rec, &context, TRUE ); + if (status) RtlRaiseStatus( status ); + restore_context( &context, sigcontext ); +} + +/********************************************************************** + * fpe_handler + * + * Handler for SIGFPE. + */ +static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + NTSTATUS status; + + save_fpu( &context, sigcontext ); + save_context( &context, sigcontext ); + + 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; + } + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Iar; + rec.NumberParameters = 0; + status = NtRaiseException( &rec, &context, TRUE ); + if (status) RtlRaiseStatus( status ); + + restore_context( &context, sigcontext ); + restore_fpu( &context, sigcontext ); +} + +/********************************************************************** + * int_handler + * + * Handler for SIGINT. + */ +static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + NTSTATUS status; + + save_context( &context, sigcontext ); + rec.ExceptionCode = CONTROL_C_EXIT; + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Iar; + rec.NumberParameters = 0; + status = NtRaiseException( &rec, &context, TRUE ); + if (status) RtlRaiseStatus( status ); + restore_context( &context, sigcontext ); +} + + +/********************************************************************** + * abrt_handler + * + * Handler for SIGABRT. + */ +static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + NTSTATUS status; + + save_context( &context, sigcontext ); + rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Iar; + rec.NumberParameters = 0; + status = NtRaiseException( &rec, &context, TRUE ); + if (status) RtlRaiseStatus( status ); + restore_context( &context, sigcontext ); +} + + +/********************************************************************** + * quit_handler + * + * Handler for SIGQUIT. + */ +static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + unix_funcs->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; + + save_context( &context, sigcontext ); + wait_suspend( &context ); + restore_context( &context, sigcontext ); +} + + /********************************************************************** * get_thread_ldt_entry */ @@ -491,6 +945,40 @@ void signal_init_thread( TEB *teb ) } +/********************************************************************** + * signal_init_process + */ +void signal_init_process(void) +{ + struct sigaction sig_act; + + sig_act.sa_mask = server_block_set; + sig_act.sa_flags = SA_RESTART | SA_SIGINFO; + + 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 = 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; + if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; + if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; + return; + + error: + perror("sigaction"); + exit(1); +} + + /*********************************************************************** * signal_exit_thread */ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 301968f78de..d4a6e821a4c 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -86,11 +86,124 @@ WINE_DEFAULT_DEBUG_CHANNEL(seh); #include static inline int arch_prctl( int func, void *ptr ) { return syscall( __NR_arch_prctl, func, ptr ); } +#define RAX_sig(context) ((context)->uc_mcontext.gregs[REG_RAX]) +#define RBX_sig(context) ((context)->uc_mcontext.gregs[REG_RBX]) +#define RCX_sig(context) ((context)->uc_mcontext.gregs[REG_RCX]) +#define RDX_sig(context) ((context)->uc_mcontext.gregs[REG_RDX]) +#define RSI_sig(context) ((context)->uc_mcontext.gregs[REG_RSI]) +#define RDI_sig(context) ((context)->uc_mcontext.gregs[REG_RDI]) +#define RBP_sig(context) ((context)->uc_mcontext.gregs[REG_RBP]) +#define R8_sig(context) ((context)->uc_mcontext.gregs[REG_R8]) +#define R9_sig(context) ((context)->uc_mcontext.gregs[REG_R9]) +#define R10_sig(context) ((context)->uc_mcontext.gregs[REG_R10]) +#define R11_sig(context) ((context)->uc_mcontext.gregs[REG_R11]) +#define R12_sig(context) ((context)->uc_mcontext.gregs[REG_R12]) +#define R13_sig(context) ((context)->uc_mcontext.gregs[REG_R13]) +#define R14_sig(context) ((context)->uc_mcontext.gregs[REG_R14]) +#define R15_sig(context) ((context)->uc_mcontext.gregs[REG_R15]) +#define CS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 0)) +#define GS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 1)) +#define FS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 2)) +#define RSP_sig(context) ((context)->uc_mcontext.gregs[REG_RSP]) +#define RIP_sig(context) ((context)->uc_mcontext.gregs[REG_RIP]) +#define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL]) +#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR]) +#define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.fpregs)) + +#elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) + +#define RAX_sig(context) ((context)->uc_mcontext.mc_rax) +#define RBX_sig(context) ((context)->uc_mcontext.mc_rbx) +#define RCX_sig(context) ((context)->uc_mcontext.mc_rcx) +#define RDX_sig(context) ((context)->uc_mcontext.mc_rdx) +#define RSI_sig(context) ((context)->uc_mcontext.mc_rsi) +#define RDI_sig(context) ((context)->uc_mcontext.mc_rdi) +#define RBP_sig(context) ((context)->uc_mcontext.mc_rbp) +#define R8_sig(context) ((context)->uc_mcontext.mc_r8) +#define R9_sig(context) ((context)->uc_mcontext.mc_r9) +#define R10_sig(context) ((context)->uc_mcontext.mc_r10) +#define R11_sig(context) ((context)->uc_mcontext.mc_r11) +#define R12_sig(context) ((context)->uc_mcontext.mc_r12) +#define R13_sig(context) ((context)->uc_mcontext.mc_r13) +#define R14_sig(context) ((context)->uc_mcontext.mc_r14) +#define R15_sig(context) ((context)->uc_mcontext.mc_r15) +#define CS_sig(context) ((context)->uc_mcontext.mc_cs) +#define DS_sig(context) ((context)->uc_mcontext.mc_ds) +#define ES_sig(context) ((context)->uc_mcontext.mc_es) +#define FS_sig(context) ((context)->uc_mcontext.mc_fs) +#define GS_sig(context) ((context)->uc_mcontext.mc_gs) +#define SS_sig(context) ((context)->uc_mcontext.mc_ss) +#define EFL_sig(context) ((context)->uc_mcontext.mc_rflags) +#define RIP_sig(context) ((context)->uc_mcontext.mc_rip) +#define RSP_sig(context) ((context)->uc_mcontext.mc_rsp) +#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno) +#define ERROR_sig(context) ((context)->uc_mcontext.mc_err) +#define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.mc_fpstate)) + +#elif defined(__NetBSD__) + +#define RAX_sig(context) ((context)->uc_mcontext.__gregs[_REG_RAX]) +#define RBX_sig(context) ((context)->uc_mcontext.__gregs[_REG_RBX]) +#define RCX_sig(context) ((context)->uc_mcontext.__gregs[_REG_RCX]) +#define RDX_sig(context) ((context)->uc_mcontext.__gregs[_REG_RDX]) +#define RSI_sig(context) ((context)->uc_mcontext.__gregs[_REG_RSI]) +#define RDI_sig(context) ((context)->uc_mcontext.__gregs[_REG_RDI]) +#define RBP_sig(context) ((context)->uc_mcontext.__gregs[_REG_RBP]) +#define R8_sig(context) ((context)->uc_mcontext.__gregs[_REG_R8]) +#define R9_sig(context) ((context)->uc_mcontext.__gregs[_REG_R9]) +#define R10_sig(context) ((context)->uc_mcontext.__gregs[_REG_R10]) +#define R11_sig(context) ((context)->uc_mcontext.__gregs[_REG_R11]) +#define R12_sig(context) ((context)->uc_mcontext.__gregs[_REG_R12]) +#define R13_sig(context) ((context)->uc_mcontext.__gregs[_REG_R13]) +#define R14_sig(context) ((context)->uc_mcontext.__gregs[_REG_R14]) +#define R15_sig(context) ((context)->uc_mcontext.__gregs[_REG_R15]) +#define CS_sig(context) ((context)->uc_mcontext.__gregs[_REG_CS]) +#define DS_sig(context) ((context)->uc_mcontext.__gregs[_REG_DS]) +#define ES_sig(context) ((context)->uc_mcontext.__gregs[_REG_ES]) +#define FS_sig(context) ((context)->uc_mcontext.__gregs[_REG_FS]) +#define GS_sig(context) ((context)->uc_mcontext.__gregs[_REG_GS]) +#define SS_sig(context) ((context)->uc_mcontext.__gregs[_REG_SS]) +#define EFL_sig(context) ((context)->uc_mcontext.__gregs[_REG_RFL]) +#define RIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.__gregs[_REG_RIP])) +#define RSP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.__gregs[_REG_URSP])) +#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO]) +#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR]) +#define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.__fpregs)) + +#elif defined (__APPLE__) + +#define RAX_sig(context) ((context)->uc_mcontext->__ss.__rax) +#define RBX_sig(context) ((context)->uc_mcontext->__ss.__rbx) +#define RCX_sig(context) ((context)->uc_mcontext->__ss.__rcx) +#define RDX_sig(context) ((context)->uc_mcontext->__ss.__rdx) +#define RSI_sig(context) ((context)->uc_mcontext->__ss.__rsi) +#define RDI_sig(context) ((context)->uc_mcontext->__ss.__rdi) +#define RBP_sig(context) ((context)->uc_mcontext->__ss.__rbp) +#define R8_sig(context) ((context)->uc_mcontext->__ss.__r8) +#define R9_sig(context) ((context)->uc_mcontext->__ss.__r9) +#define R10_sig(context) ((context)->uc_mcontext->__ss.__r10) +#define R11_sig(context) ((context)->uc_mcontext->__ss.__r11) +#define R12_sig(context) ((context)->uc_mcontext->__ss.__r12) +#define R13_sig(context) ((context)->uc_mcontext->__ss.__r13) +#define R14_sig(context) ((context)->uc_mcontext->__ss.__r14) +#define R15_sig(context) ((context)->uc_mcontext->__ss.__r15) +#define CS_sig(context) ((context)->uc_mcontext->__ss.__cs) +#define FS_sig(context) ((context)->uc_mcontext->__ss.__fs) +#define GS_sig(context) ((context)->uc_mcontext->__ss.__gs) +#define EFL_sig(context) ((context)->uc_mcontext->__ss.__rflags) +#define RIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__rip)) +#define RSP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->__ss.__rsp)) +#define TRAP_sig(context) ((context)->uc_mcontext->__es.__trapno) +#define ERROR_sig(context) ((context)->uc_mcontext->__es.__err) +#define FPU_sig(context) ((XMM_SAVE_AREA32 *)&(context)->uc_mcontext->__fs.__fpu_fcw) + +#else +#error You must define the signal context functions for your platform #endif enum i386_trap_code { - TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */ TRAP_x86_DIVIDE = 0, /* Division by zero exception */ TRAP_x86_TRCTRAP = 1, /* Single-step exception */ TRAP_x86_NMI = 2, /* NMI interrupt */ @@ -114,6 +227,20 @@ enum i386_trap_code static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */ +typedef void (*raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context ); + +/* stack layout when calling an exception raise function */ +struct stack_layout +{ + CONTEXT context; + EXCEPTION_RECORD rec; + ULONG64 rsi; + ULONG64 rdi; + ULONG64 rbp; + ULONG64 rip; + ULONG64 red_zone[16]; +}; + struct amd64_thread_data { DWORD_PTR dr0; /* debug registers */ @@ -134,6 +261,141 @@ static inline struct amd64_thread_data *amd64_thread_data(void) } +static inline void set_sigcontext( const CONTEXT *context, ucontext_t *sigcontext ) +{ + RAX_sig(sigcontext) = context->Rax; + RCX_sig(sigcontext) = context->Rcx; + RDX_sig(sigcontext) = context->Rdx; + RBX_sig(sigcontext) = context->Rbx; + RSP_sig(sigcontext) = context->Rsp; + RBP_sig(sigcontext) = context->Rbp; + RSI_sig(sigcontext) = context->Rsi; + RDI_sig(sigcontext) = context->Rdi; + R8_sig(sigcontext) = context->R8; + R9_sig(sigcontext) = context->R9; + R10_sig(sigcontext) = context->R10; + R11_sig(sigcontext) = context->R11; + R12_sig(sigcontext) = context->R12; + R13_sig(sigcontext) = context->R13; + R14_sig(sigcontext) = context->R14; + R15_sig(sigcontext) = context->R15; + RIP_sig(sigcontext) = context->Rip; + CS_sig(sigcontext) = context->SegCs; + FS_sig(sigcontext) = context->SegFs; + GS_sig(sigcontext) = context->SegGs; + EFL_sig(sigcontext) = context->EFlags; +#ifdef DS_sig + DS_sig(sigcontext) = context->SegDs; +#endif +#ifdef ES_sig + ES_sig(sigcontext) = context->SegEs; +#endif +#ifdef SS_sig + SS_sig(sigcontext) = context->SegSs; +#endif +} + + +/*********************************************************************** + * get_signal_stack + * + * Get the base of the signal stack for the current thread. + */ +static inline void *get_signal_stack(void) +{ + return (char *)NtCurrentTeb() + teb_size; +} + + +/*********************************************************************** + * is_inside_signal_stack + * + * Check if pointer is inside the signal stack. + */ +static inline BOOL is_inside_signal_stack( void *ptr ) +{ + return ((char *)ptr >= (char *)get_signal_stack() && + (char *)ptr < (char *)get_signal_stack() + signal_stack_size); +} + + +/*********************************************************************** + * save_context + * + * Set the register values from a sigcontext. + */ +static void save_context( CONTEXT *context, const ucontext_t *sigcontext ) +{ + context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS; + context->Rax = RAX_sig(sigcontext); + context->Rcx = RCX_sig(sigcontext); + context->Rdx = RDX_sig(sigcontext); + context->Rbx = RBX_sig(sigcontext); + context->Rsp = RSP_sig(sigcontext); + context->Rbp = RBP_sig(sigcontext); + context->Rsi = RSI_sig(sigcontext); + context->Rdi = RDI_sig(sigcontext); + context->R8 = R8_sig(sigcontext); + context->R9 = R9_sig(sigcontext); + context->R10 = R10_sig(sigcontext); + context->R11 = R11_sig(sigcontext); + context->R12 = R12_sig(sigcontext); + context->R13 = R13_sig(sigcontext); + context->R14 = R14_sig(sigcontext); + context->R15 = R15_sig(sigcontext); + context->Rip = RIP_sig(sigcontext); + context->SegCs = CS_sig(sigcontext); + context->SegFs = FS_sig(sigcontext); + context->SegGs = GS_sig(sigcontext); + context->EFlags = EFL_sig(sigcontext); +#ifdef DS_sig + context->SegDs = DS_sig(sigcontext); +#else + __asm__("movw %%ds,%0" : "=m" (context->SegDs)); +#endif +#ifdef ES_sig + context->SegEs = ES_sig(sigcontext); +#else + __asm__("movw %%es,%0" : "=m" (context->SegEs)); +#endif +#ifdef SS_sig + context->SegSs = SS_sig(sigcontext); +#else + __asm__("movw %%ss,%0" : "=m" (context->SegSs)); +#endif + context->Dr0 = amd64_thread_data()->dr0; + context->Dr1 = amd64_thread_data()->dr1; + context->Dr2 = amd64_thread_data()->dr2; + context->Dr3 = amd64_thread_data()->dr3; + context->Dr6 = amd64_thread_data()->dr6; + context->Dr7 = amd64_thread_data()->dr7; + if (FPU_sig(sigcontext)) + { + context->ContextFlags |= CONTEXT_FLOATING_POINT; + context->u.FltSave = *FPU_sig(sigcontext); + context->MxCsr = context->u.FltSave.MxCsr; + } +} + + +/*********************************************************************** + * restore_context + * + * Build a sigcontext from the register values. + */ +static void restore_context( const CONTEXT *context, ucontext_t *sigcontext ) +{ + amd64_thread_data()->dr0 = context->Dr0; + amd64_thread_data()->dr1 = context->Dr1; + amd64_thread_data()->dr2 = context->Dr2; + amd64_thread_data()->dr3 = context->Dr3; + amd64_thread_data()->dr6 = context->Dr6; + amd64_thread_data()->dr7 = context->Dr7; + set_sigcontext( context, sigcontext ); + if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->u.FltSave; +} + + /*********************************************************************** * set_full_cpu_context * @@ -501,6 +763,485 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) } +extern void CDECL raise_func_trampoline( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func ); +__ASM_GLOBAL_FUNC( raise_func_trampoline, + __ASM_CFI(".cfi_signal_frame\n\t") + __ASM_CFI(".cfi_def_cfa %rbp,160\n\t") /* red zone + rip + rbp + rdi + rsi */ + __ASM_CFI(".cfi_rel_offset %rip,24\n\t") + __ASM_CFI(".cfi_rel_offset %rbp,16\n\t") + __ASM_CFI(".cfi_rel_offset %rdi,8\n\t") + __ASM_CFI(".cfi_rel_offset %rsi,0\n\t") + "call *%r8\n\t" + "int $3") + +/*********************************************************************** + * setup_exception + * + * Setup a proper stack frame for the raise function, and modify the + * sigcontext so that the return from the signal handler will call + * the raise function. + */ +static struct stack_layout *setup_exception( ucontext_t *sigcontext ) +{ + struct stack_layout *stack; + DWORD exception_code = 0; + + stack = (struct stack_layout *)(RSP_sig(sigcontext) & ~15); + + /* stack sanity checks */ + + if (is_inside_signal_stack( stack )) + { + ERR( "nested exception on signal stack in thread %04x eip %016lx esp %016lx stack %p-%p\n", + GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext), + NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); + abort_thread(1); + } + + if (stack - 1 > stack || /* check for overflow in subtraction */ + (char *)stack <= (char *)NtCurrentTeb()->DeallocationStack || + (char *)stack > (char *)NtCurrentTeb()->Tib.StackBase) + { + WARN( "exception outside of stack limits in thread %04x eip %016lx esp %016lx stack %p-%p\n", + GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), (ULONG_PTR)RSP_sig(sigcontext), + NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); + } + else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->DeallocationStack + 4096) + { + /* stack overflow on last page, unrecoverable */ + UINT diff = (char *)NtCurrentTeb()->DeallocationStack + 4096 - (char *)(stack - 1); + ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n", + diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), + (ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, + NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); + abort_thread(1); + } + else if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit) + { + /* stack access below stack limit, may be recoverable */ + switch (virtual_handle_stack_fault( stack - 1 )) + { + case 0: /* not handled */ + { + UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit - (char *)(stack - 1); + ERR( "stack overflow %u bytes in thread %04x eip %016lx esp %016lx stack %p-%p-%p\n", + diff, GetCurrentThreadId(), (ULONG_PTR)RIP_sig(sigcontext), + (ULONG_PTR)RSP_sig(sigcontext), NtCurrentTeb()->DeallocationStack, + NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase ); + abort_thread(1); + } + case -1: /* overflow */ + exception_code = EXCEPTION_STACK_OVERFLOW; + break; + } + } + + stack--; /* push the stack_layout structure */ +#if defined(VALGRIND_MAKE_MEM_UNDEFINED) + VALGRIND_MAKE_MEM_UNDEFINED(stack, sizeof(*stack)); +#elif defined(VALGRIND_MAKE_WRITABLE) + VALGRIND_MAKE_WRITABLE(stack, sizeof(*stack)); +#endif + stack->rec.ExceptionRecord = NULL; + stack->rec.ExceptionCode = exception_code; + stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + stack->rec.ExceptionAddress = (void *)RIP_sig(sigcontext); + stack->rec.NumberParameters = 0; + save_context( &stack->context, sigcontext ); + + return stack; +} + +static void setup_raise_exception( ucontext_t *sigcontext, struct stack_layout *stack ) +{ + ULONG64 *rsp_ptr; + NTSTATUS status; + + if (stack->rec.ExceptionCode == EXCEPTION_SINGLE_STEP) + { + /* when single stepping can't tell whether this is a hw bp or a + * single step interrupt. try to avoid as much overhead as possible + * and only do a server call if there is any hw bp enabled. */ + + if (!(stack->context.EFlags & 0x100) || (stack->context.Dr7 & 0xff)) + { + /* (possible) hardware breakpoint, fetch the debug registers */ + DWORD saved_flags = stack->context.ContextFlags; + stack->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; + NtGetContextThread(GetCurrentThread(), &stack->context); + stack->context.ContextFlags |= saved_flags; /* restore flags */ + } + + stack->context.EFlags &= ~0x100; /* clear single-step flag */ + } + + status = send_debug_event( &stack->rec, &stack->context, TRUE ); + if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED) + { + restore_context( &stack->context, sigcontext ); + return; + } + + /* store return address and %rbp without aligning, so that the offset is fixed */ + rsp_ptr = (ULONG64 *)RSP_sig(sigcontext) - 16; + *(--rsp_ptr) = stack->context.Rip; + *(--rsp_ptr) = stack->context.Rbp; + *(--rsp_ptr) = stack->context.Rdi; + *(--rsp_ptr) = stack->context.Rsi; + + /* now modify the sigcontext to return to the raise function */ + RIP_sig(sigcontext) = (ULONG_PTR)raise_func_trampoline; + RCX_sig(sigcontext) = (ULONG_PTR)&stack->rec; + RDX_sig(sigcontext) = (ULONG_PTR)&stack->context; + R8_sig(sigcontext) = (ULONG_PTR)KiUserExceptionDispatcher; + RBP_sig(sigcontext) = (ULONG_PTR)rsp_ptr; + RSP_sig(sigcontext) = (ULONG_PTR)stack; + /* clear single-step, direction, and align check flag */ + EFL_sig(sigcontext) &= ~(0x100|0x400|0x40000); +} + + +/*********************************************************************** + * is_privileged_instr + * + * Check if the fault location is a privileged instruction. + */ +static inline DWORD is_privileged_instr( CONTEXT *context ) +{ + BYTE instr[16]; + unsigned int i, prefix_count = 0; + unsigned int len = virtual_uninterrupted_read_memory( (BYTE *)context->Rip, instr, sizeof(instr) ); + + for (i = 0; i < len; i++) switch (instr[i]) + { + /* instruction prefixes */ + case 0x2e: /* %cs: */ + case 0x36: /* %ss: */ + case 0x3e: /* %ds: */ + case 0x26: /* %es: */ + case 0x40: /* rex */ + case 0x41: /* rex */ + case 0x42: /* rex */ + case 0x43: /* rex */ + case 0x44: /* rex */ + case 0x45: /* rex */ + case 0x46: /* rex */ + case 0x47: /* rex */ + case 0x48: /* rex */ + case 0x49: /* rex */ + case 0x4a: /* rex */ + case 0x4b: /* rex */ + case 0x4c: /* rex */ + case 0x4d: /* rex */ + case 0x4e: /* rex */ + case 0x4f: /* rex */ + case 0x64: /* %fs: */ + case 0x65: /* %gs: */ + case 0x66: /* opcode size */ + case 0x67: /* addr size */ + case 0xf0: /* lock */ + case 0xf2: /* repne */ + case 0xf3: /* repe */ + if (++prefix_count >= 15) return EXCEPTION_ILLEGAL_INSTRUCTION; + continue; + + case 0x0f: /* extended instruction */ + if (i == len - 1) return 0; + switch (instr[i + 1]) + { + case 0x06: /* clts */ + case 0x08: /* invd */ + case 0x09: /* wbinvd */ + case 0x20: /* mov crX, reg */ + case 0x21: /* mov drX, reg */ + case 0x22: /* mov reg, crX */ + case 0x23: /* mov reg drX */ + return EXCEPTION_PRIV_INSTRUCTION; + } + return 0; + case 0x6c: /* insb (%dx) */ + case 0x6d: /* insl (%dx) */ + case 0x6e: /* outsb (%dx) */ + case 0x6f: /* outsl (%dx) */ + case 0xcd: /* int $xx */ + case 0xe4: /* inb al,XX */ + case 0xe5: /* in (e)ax,XX */ + case 0xe6: /* outb XX,al */ + case 0xe7: /* out XX,(e)ax */ + case 0xec: /* inb (%dx),%al */ + case 0xed: /* inl (%dx),%eax */ + case 0xee: /* outb %al,(%dx) */ + case 0xef: /* outl %eax,(%dx) */ + case 0xf4: /* hlt */ + case 0xfa: /* cli */ + case 0xfb: /* sti */ + return EXCEPTION_PRIV_INSTRUCTION; + default: + return 0; + } + return 0; +} + + +/*********************************************************************** + * handle_interrupt + * + * Handle an interrupt. + */ +static inline BOOL handle_interrupt( ucontext_t *sigcontext, struct stack_layout *stack ) +{ + switch (ERROR_sig(sigcontext) >> 3) + { + case 0x2c: + stack->rec.ExceptionCode = STATUS_ASSERTION_FAILURE; + break; + case 0x2d: + switch (stack->context.Rax) + { + case 1: /* BREAKPOINT_PRINT */ + case 3: /* BREAKPOINT_LOAD_SYMBOLS */ + case 4: /* BREAKPOINT_UNLOAD_SYMBOLS */ + case 5: /* BREAKPOINT_COMMAND_STRING (>= Win2003) */ + RIP_sig(sigcontext) += 3; + return TRUE; + } + stack->context.Rip += 3; + stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; + stack->rec.ExceptionAddress = (void *)stack->context.Rip; + stack->rec.NumberParameters = 1; + stack->rec.ExceptionInformation[0] = stack->context.Rax; + break; + default: + return FALSE; + } + setup_raise_exception( sigcontext, stack ); + return TRUE; +} + + +/********************************************************************** + * segv_handler + * + * Handler for SIGSEGV and related errors. + */ +static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack; + ucontext_t *ucontext = sigcontext; + + stack = (struct stack_layout *)(RSP_sig(ucontext) & ~15); + + /* check for exceptions on the signal stack caused by write watches */ + if (TRAP_sig(ucontext) == TRAP_x86_PAGEFLT && is_inside_signal_stack( stack ) && + !virtual_handle_fault( siginfo->si_addr, (ERROR_sig(ucontext) >> 1) & 0x09, TRUE )) + { + return; + } + + /* check for page fault inside the thread stack */ + if (TRAP_sig(ucontext) == TRAP_x86_PAGEFLT) + { + switch (virtual_handle_stack_fault( siginfo->si_addr )) + { + case 1: /* handled */ + return; + case -1: /* overflow */ + stack = setup_exception( sigcontext ); + stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; + goto done; + } + } + + stack = setup_exception( sigcontext ); + if (stack->rec.ExceptionCode == EXCEPTION_STACK_OVERFLOW) goto done; + + switch(TRAP_sig(ucontext)) + { + case TRAP_x86_OFLOW: /* Overflow exception */ + stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; + break; + case TRAP_x86_BOUND: /* Bound range exception */ + stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; + break; + case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */ + stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + case TRAP_x86_STKFLT: /* Stack fault */ + stack->rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; + break; + case TRAP_x86_SEGNPFLT: /* Segment not present exception */ + case TRAP_x86_PROTFLT: /* General protection fault */ + { + WORD err = ERROR_sig(ucontext); + if (!err && (stack->rec.ExceptionCode = is_privileged_instr( &stack->context ))) break; + if ((err & 7) == 2 && handle_interrupt( ucontext, stack )) return; + stack->rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION; + stack->rec.NumberParameters = 2; + stack->rec.ExceptionInformation[0] = 0; + stack->rec.ExceptionInformation[1] = 0xffffffffffffffff; + } + break; + case TRAP_x86_PAGEFLT: /* Page fault */ + stack->rec.NumberParameters = 2; + stack->rec.ExceptionInformation[0] = (ERROR_sig(ucontext) >> 1) & 0x09; + stack->rec.ExceptionInformation[1] = (ULONG_PTR)siginfo->si_addr; + if (!(stack->rec.ExceptionCode = virtual_handle_fault((void *)stack->rec.ExceptionInformation[1], + stack->rec.ExceptionInformation[0], FALSE ))) + return; + break; + case TRAP_x86_ALIGNFLT: /* Alignment check exception */ + stack->rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; + break; + default: + ERR( "Got unexpected trap %ld\n", (ULONG_PTR)TRAP_sig(ucontext) ); + /* fall through */ + case TRAP_x86_NMI: /* NMI interrupt */ + case TRAP_x86_DNA: /* Device not available exception */ + case TRAP_x86_DOUBLEFLT: /* Double fault exception */ + case TRAP_x86_TSSFLT: /* Invalid TSS exception */ + case TRAP_x86_MCHK: /* Machine check exception */ + case TRAP_x86_CACHEFLT: /* Cache flush exception */ + stack->rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + } +done: + setup_raise_exception( sigcontext, stack ); +} + + +/********************************************************************** + * trap_handler + * + * Handler for SIGTRAP. + */ +static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack = setup_exception( sigcontext ); + + switch (siginfo->si_code) + { + case TRAP_TRACE: /* Single-step exception */ + case 4 /* TRAP_HWBKPT */: /* Hardware breakpoint exception */ + stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP; + break; + case TRAP_BRKPT: /* Breakpoint exception */ +#ifdef SI_KERNEL + case SI_KERNEL: +#endif + /* Check if this is actually icebp instruction */ + if (((unsigned char *)stack->rec.ExceptionAddress)[-1] == 0xF1) + { + stack->rec.ExceptionCode = EXCEPTION_SINGLE_STEP; + break; + } + stack->rec.ExceptionAddress = (char *)stack->rec.ExceptionAddress - 1; /* back up over the int3 instruction */ + /* fall through */ + default: + stack->rec.ExceptionCode = EXCEPTION_BREAKPOINT; + stack->rec.NumberParameters = 1; + stack->rec.ExceptionInformation[0] = 0; + break; + } + + setup_raise_exception( sigcontext, stack ); +} + + +/********************************************************************** + * fpe_handler + * + * Handler for SIGFPE. + */ +static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack = setup_exception( sigcontext ); + + switch (siginfo->si_code) + { + case FPE_FLTSUB: + stack->rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; + break; + case FPE_INTDIV: + stack->rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; + break; + case FPE_INTOVF: + stack->rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; + break; + case FPE_FLTDIV: + stack->rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO; + break; + case FPE_FLTOVF: + stack->rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW; + break; + case FPE_FLTUND: + stack->rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW; + break; + case FPE_FLTRES: + stack->rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT; + break; + case FPE_FLTINV: + default: + stack->rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; + break; + } + + setup_raise_exception( sigcontext, stack ); +} + + +/********************************************************************** + * int_handler + * + * Handler for SIGINT. + */ +static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack = setup_exception( sigcontext ); + stack->rec.ExceptionCode = CONTROL_C_EXIT; + setup_raise_exception( sigcontext, stack ); +} + + +/********************************************************************** + * abrt_handler + * + * Handler for SIGABRT. + */ +static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +{ + struct stack_layout *stack = setup_exception( sigcontext ); + stack->rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; + stack->rec.ExceptionFlags = EH_NONCONTINUABLE; + setup_raise_exception( sigcontext, stack ); +} + + +/********************************************************************** + * quit_handler + * + * Handler for SIGQUIT. + */ +static void quit_handler( int signal, siginfo_t *siginfo, void *ucontext ) +{ + 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 *ucontext ) +{ + CONTEXT context; + + save_context( &context, ucontext ); + wait_suspend( &context ); + restore_context( &context, ucontext ); +} + + /********************************************************************** * get_thread_ldt_entry */ @@ -641,6 +1382,40 @@ void signal_init_thread( TEB *teb ) } +/********************************************************************** + * signal_init_process + */ +void signal_init_process(void) +{ + struct sigaction sig_act; + + 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 = 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; + if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error; + if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error; + return; + + error: + perror("sigaction"); + exit(1); +} + + /*********************************************************************** * init_thread_context */ @@ -681,6 +1456,7 @@ PCONTEXT DECLSPEC_HIDDEN attach_thread( LPTHREAD_START_ROUTINE entry, void *arg, ctx = (CONTEXT *)((char *)NtCurrentTeb()->Tib.StackBase - 0x30) - 1; init_thread_context( ctx, entry, arg, relay ); } + pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL ); ctx->ContextFlags = CONTEXT_FULL; LdrInitializeThunk( ctx, (void **)&ctx->Rcx, 0, 0 ); return ctx; diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index d4b7a51a627..9e7a15e5dca 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -320,15 +320,6 @@ done: } -/*********************************************************************** - * start_process - */ -void CDECL start_process( PRTL_THREAD_START_ROUTINE entry, BOOL suspend, void *relay ) -{ - signal_start_thread( entry, NtCurrentTeb()->Peb, suspend, relay, NtCurrentTeb() ); -} - - /*********************************************************************** * abort_thread */ @@ -394,7 +385,7 @@ void wait_suspend( CONTEXT *context ) * * Send an EXCEPTION_DEBUG_EVENT event to the debugger. */ -static NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) +NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) { NTSTATUS ret; DWORD i; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 03b92f9e912..b8f7ddc8f32 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -68,17 +68,12 @@ extern NTSTATUS CDECL virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsig extern void CDECL virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL virtual_create_builtin_view( void *module ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL virtual_alloc_thread_stack( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size ) DECLSPEC_HIDDEN; -extern NTSTATUS CDECL virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) DECLSPEC_HIDDEN; extern unsigned int CDECL virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN; extern ssize_t CDECL virtual_locked_read( int fd, void *addr, size_t size ) DECLSPEC_HIDDEN; extern ssize_t CDECL virtual_locked_pread( int fd, void *addr, size_t size, off_t offset ) DECLSPEC_HIDDEN; extern ssize_t CDECL virtual_locked_recvmsg( int fd, struct msghdr *hdr, int flags ) DECLSPEC_HIDDEN; -extern BOOL CDECL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLSPEC_HIDDEN; -extern int CDECL virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN; extern BOOL CDECL virtual_check_buffer_for_read( const void *ptr, SIZE_T size ) DECLSPEC_HIDDEN; extern BOOL CDECL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) DECLSPEC_HIDDEN; -extern SIZE_T CDECL virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) DECLSPEC_HIDDEN; -extern NTSTATUS CDECL virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size ) DECLSPEC_HIDDEN; extern void CDECL virtual_set_force_exec( BOOL enable ) DECLSPEC_HIDDEN; extern void CDECL virtual_release_address_space(void) DECLSPEC_HIDDEN; extern void CDECL virtual_set_large_address_space(void) DECLSPEC_HIDDEN; @@ -97,11 +92,10 @@ extern NTSTATUS CDECL server_fd_to_handle( int fd, unsigned int access, unsigned extern NTSTATUS CDECL server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd, unsigned int *options ) DECLSPEC_HIDDEN; extern void CDECL server_release_fd( HANDLE handle, int unix_fd ) DECLSPEC_HIDDEN; -extern void CDECL server_init_process_done(void) DECLSPEC_HIDDEN; +extern void CDECL server_init_process_done( void *relay ) DECLSPEC_HIDDEN; extern TEB * CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZE_T *size, BOOL *suspend, unsigned int *cpus, BOOL *wow64, timeout_t *start_time ) DECLSPEC_HIDDEN; -extern void CDECL DECLSPEC_NORETURN start_process( PRTL_THREAD_START_ROUTINE entry, BOOL suspend, void *relay ) DECLSPEC_HIDDEN; extern void CDECL DECLSPEC_NORETURN abort_thread( int status ) DECLSPEC_HIDDEN; extern void CDECL DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN; extern void CDECL DECLSPEC_NORETURN exit_process( int status ) DECLSPEC_HIDDEN; @@ -129,6 +123,7 @@ extern int server_pipe( int fd[2] ) DECLSPEC_HIDDEN; extern NTSTATUS context_to_server( context_t *to, const CONTEXT *from ) DECLSPEC_HIDDEN; extern NTSTATUS context_from_server( CONTEXT *to, const context_t *from ) DECLSPEC_HIDDEN; extern void wait_suspend( CONTEXT *context ) DECLSPEC_HIDDEN; +extern NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) DECLSPEC_HIDDEN; extern NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self ) DECLSPEC_HIDDEN; extern NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self ) DECLSPEC_HIDDEN; extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, @@ -141,11 +136,17 @@ extern TEB *virtual_alloc_first_teb(void) DECLSPEC_HIDDEN; extern NTSTATUS virtual_alloc_teb( TEB **ret_teb ) DECLSPEC_HIDDEN; extern void virtual_free_teb( TEB *teb ) DECLSPEC_HIDDEN; extern void virtual_map_user_shared_data(void) DECLSPEC_HIDDEN; +extern NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) DECLSPEC_HIDDEN; +extern BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) DECLSPEC_HIDDEN; +extern int virtual_handle_stack_fault( void *addr ) DECLSPEC_HIDDEN; +extern SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) DECLSPEC_HIDDEN; +extern NTSTATUS virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size ) DECLSPEC_HIDDEN; extern void signal_init_threading(void) DECLSPEC_HIDDEN; extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN; extern void signal_init_thread( TEB *teb ) DECLSPEC_HIDDEN; +extern void signal_init_process(void) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN signal_start_thread( PRTL_THREAD_START_ROUTINE entry, void *arg, BOOL suspend, void *relay, TEB *teb ) DECLSPEC_HIDDEN; extern void DECLSPEC_NORETURN signal_exit_thread( int status, void (*func)(int) ) DECLSPEC_HIDDEN; diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 7c5b5d5cf15..512cf12a742 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2780,7 +2780,7 @@ void virtual_map_user_shared_data(void) /*********************************************************************** * virtual_handle_fault */ -NTSTATUS CDECL virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) +NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) { NTSTATUS ret = STATUS_ACCESS_VIOLATION; void *page = ROUND_ADDR( addr, page_mask ); @@ -2947,7 +2947,7 @@ ssize_t CDECL virtual_locked_recvmsg( int fd, struct msghdr *hdr, int flags ) /*********************************************************************** * virtual_is_valid_code_address */ -BOOL CDECL virtual_is_valid_code_address( const void *addr, SIZE_T size ) +BOOL virtual_is_valid_code_address( const void *addr, SIZE_T size ) { struct file_view *view; BOOL ret = FALSE; @@ -2968,7 +2968,7 @@ BOOL CDECL virtual_is_valid_code_address( const void *addr, SIZE_T size ) * Return 1 if safely handled, -1 if handled into the overflow space. * Called from inside a signal handler. */ -int CDECL virtual_handle_stack_fault( void *addr ) +int virtual_handle_stack_fault( void *addr ) { int ret = 0; @@ -3076,7 +3076,7 @@ BOOL CDECL virtual_check_buffer_for_write( void *ptr, SIZE_T size ) * permissions are checked before accessing each page, to ensure that no * exceptions can happen. */ -SIZE_T CDECL virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) +SIZE_T virtual_uninterrupted_read_memory( const void *addr, void *buffer, SIZE_T size ) { struct file_view *view; sigset_t sigset; @@ -3112,7 +3112,7 @@ SIZE_T CDECL virtual_uninterrupted_read_memory( const void *addr, void *buffer, * permissions are checked before accessing each page, to ensure that no * exceptions can happen. */ -NTSTATUS CDECL virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size ) +NTSTATUS virtual_uninterrupted_write_memory( void *addr, const void *buffer, SIZE_T size ) { BOOL has_write_watch = FALSE; sigset_t sigset; diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 017a0a71b3f..ffc4373ee21 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -28,7 +28,7 @@ struct ldt_copy; struct msghdr; /* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 32 +#define NTDLL_UNIXLIB_VERSION 33 struct unix_funcs { @@ -157,17 +157,12 @@ struct unix_funcs void (CDECL *virtual_get_system_info)( SYSTEM_BASIC_INFORMATION *info ); NTSTATUS (CDECL *virtual_create_builtin_view)( void *module ); NTSTATUS (CDECL *virtual_alloc_thread_stack)( INITIAL_TEB *stack, SIZE_T reserve_size, SIZE_T commit_size, SIZE_T *pthread_size ); - NTSTATUS (CDECL *virtual_handle_fault)( LPCVOID addr, DWORD err, BOOL on_signal_stack ); unsigned int (CDECL *virtual_locked_server_call)( void *req_ptr ); ssize_t (CDECL *virtual_locked_read)( int fd, void *addr, size_t size ); ssize_t (CDECL *virtual_locked_pread)( int fd, void *addr, size_t size, off_t offset ); ssize_t (CDECL *virtual_locked_recvmsg)( int fd, struct msghdr *hdr, int flags ); - BOOL (CDECL *virtual_is_valid_code_address)( const void *addr, SIZE_T size ); - int (CDECL *virtual_handle_stack_fault)( void *addr ); BOOL (CDECL *virtual_check_buffer_for_read)( const void *ptr, SIZE_T size ); BOOL (CDECL *virtual_check_buffer_for_write)( void *ptr, SIZE_T size ); - SIZE_T (CDECL *virtual_uninterrupted_read_memory)( const void *addr, void *buffer, SIZE_T size ); - NTSTATUS (CDECL *virtual_uninterrupted_write_memory)( void *addr, const void *buffer, SIZE_T size ); void (CDECL *virtual_set_force_exec)( BOOL enable ); void (CDECL *virtual_release_address_space)(void); void (CDECL *virtual_set_large_address_space)(void); @@ -175,7 +170,6 @@ struct unix_funcs /* thread/process functions */ TEB * (CDECL *init_threading)( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZE_T *size, BOOL *suspend, unsigned int *cpus, BOOL *wow64, timeout_t *start_time ); - void (CDECL *start_process)( PRTL_THREAD_START_ROUTINE entry, BOOL suspend, void *relay ); void (CDECL *abort_thread)( int status ); void (CDECL *exit_thread)( int status ); void (CDECL *exit_process)( int status ); @@ -196,7 +190,7 @@ struct unix_funcs NTSTATUS (CDECL *server_handle_to_fd)( HANDLE handle, unsigned int access, int *unix_fd, unsigned int *options ); void (CDECL *server_release_fd)( HANDLE handle, int unix_fd ); - void (CDECL *server_init_process_done)(void); + void (CDECL *server_init_process_done)( void *relay ); /* debugging functions */ unsigned char (CDECL *dbg_get_channel_flags)( struct __wine_debug_channel *channel ); diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index 6d5c98b58e1..9556761840b 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -31,47 +31,19 @@ #include #include #include -#include #include -#ifdef HAVE_SYS_SOCKET_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef HAVE_SYS_MMAN_H -# include -#endif -#ifdef HAVE_SYS_SYSINFO_H -# include -#endif -#ifdef HAVE_VALGRIND_VALGRIND_H -# include -#endif #include "ntstatus.h" #define WIN32_NO_STATUS #define NONAMELESSUNION #include "windef.h" #include "winternl.h" -#include "wine/library.h" #include "wine/server.h" -#include "wine/exception.h" -#include "wine/rbtree.h" #include "wine/debug.h" #include "ntdll_misc.h" WINE_DEFAULT_DEBUG_CHANNEL(virtual); -static const UINT page_shift = 12; -static const UINT_PTR page_mask = 0xfff; - -SIZE_T signal_stack_size = 0; -SIZE_T signal_stack_mask = 0; -static SIZE_T signal_stack_align; - -#define ROUND_SIZE(addr,size) \ - (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask) /********************************************************************** * RtlCreateUserStack (NTDLL.@) @@ -111,20 +83,6 @@ void WINAPI RtlFreeUserStack( void *stack ) NtFreeVirtualMemory( NtCurrentProcess(), &stack, &size, MEM_RELEASE ); } -/*********************************************************************** - * virtual_init - */ -void virtual_init(void) -{ - size_t size = ROUND_SIZE( 0, sizeof(TEB) ) + max( MINSIGSTKSZ, 8192 ); - /* find the first power of two not smaller than size */ - signal_stack_align = page_shift; - while ((1u << signal_stack_align) < size) signal_stack_align++; - signal_stack_mask = (1 << signal_stack_align) - 1; - signal_stack_size = (1 << signal_stack_align) - ROUND_SIZE( 0, sizeof(TEB) ); -} - - /*********************************************************************** * __wine_locked_recvmsg */ @@ -162,7 +120,7 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *si NTSTATUS WINAPI DECLSPEC_HOTPATCH NtProtectVirtualMemory( HANDLE process, PVOID *addr_ptr, SIZE_T *size_ptr, ULONG new_prot, ULONG *old_prot ) { - return unix_funcs-> NtProtectVirtualMemory( process, addr_ptr, size_ptr, new_prot, old_prot ); + return unix_funcs->NtProtectVirtualMemory( process, addr_ptr, size_ptr, new_prot, old_prot ); }