diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index c22476075b2..7c79bf9ad62 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -40,6 +40,7 @@ C_SRCS = \ signal_i386.c \ signal_powerpc.c \ signal_sparc.c \ + signal_x86_64.c \ string.c \ sync.c \ version.c \ diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c new file mode 100644 index 00000000000..5a83a530b6f --- /dev/null +++ b/dlls/ntdll/signal_x86_64.c @@ -0,0 +1,507 @@ +/* + * x86-64 signal handling routines + * + * Copyright 1999, 2005 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef __x86_64__ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_SYS_PARAM_H +# include +#endif +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif + +#define NONAMELESSUNION +#include "windef.h" +#include "winternl.h" +#include "wine/library.h" +#include "wine/exception.h" +#include "ntdll_misc.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(seh); + + +/*********************************************************************** + * signal context platform-specific definitions + */ +#ifdef linux + +typedef struct ucontext SIGCONTEXT; + +# define HANDLER_DEF(name) void name( int __signal, struct siginfo *__siginfo, SIGCONTEXT *__context ) +# define HANDLER_CONTEXT (__context) + +#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)) + +#define FAULT_CODE (__siginfo->si_code) +#define FAULT_ADDRESS (__siginfo->si_addr) + +#endif /* linux */ + +#define T_UNKNOWN (-1) /* Unknown fault (TRAP_sig not defined) */ +#define T_DIVIDE 0 /* Division by zero exception */ +#define T_TRCTRAP 1 /* Single-step exception */ +#define T_NMI 2 /* NMI interrupt */ +#define T_BPTFLT 3 /* Breakpoint exception */ +#define T_OFLOW 4 /* Overflow exception */ +#define T_BOUND 5 /* Bound range exception */ +#define T_PRIVINFLT 6 /* Invalid opcode exception */ +#define T_DNA 7 /* Device not available exception */ +#define T_DOUBLEFLT 8 /* Double fault exception */ +#define T_FPOPFLT 9 /* Coprocessor segment overrun */ +#define T_TSSFLT 10 /* Invalid TSS exception */ +#define T_SEGNPFLT 11 /* Segment not present exception */ +#define T_STKFLT 12 /* Stack fault */ +#define T_PROTFLT 13 /* General protection fault */ +#define T_PAGEFLT 14 /* Page fault */ +#define T_RESERVED 15 /* Unknown exception */ +#define T_ARITHTRAP 16 /* Floating point exception */ +#define T_ALIGNFLT 17 /* Alignment check exception */ +#define T_MCHK 18 /* Machine check exception */ +#define T_CACHEFLT 19 /* Cache flush exception */ + +typedef int (*wine_signal_handler)(unsigned int sig); + +static wine_signal_handler handlers[256]; + +/*********************************************************************** + * dispatch_signal + */ +inline static int dispatch_signal(unsigned int sig) +{ + if (handlers[sig] == NULL) return 0; + return handlers[sig](sig); +} + +/*********************************************************************** + * save_context + * + * Set the register values from a sigcontext. + */ +static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext ) +{ + 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); + context->SegDs = 0; /* FIXME */ + context->SegEs = 0; /* FIXME */ + context->SegSs = 0; /* FIXME */ + context->MxCsr = 0; /* FIXME */ + if (FPU_sig(sigcontext)) context->u.FltSave = *FPU_sig(sigcontext); +} + + +/*********************************************************************** + * restore_context + * + * Build a sigcontext from the register values. + */ +static void restore_context( const CONTEXT *context, SIGCONTEXT *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; + if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->u.FltSave; +} + + +/********************************************************************** + * segv_handler + * + * Handler for SIGSEGV and related errors. + */ +static HANDLER_DEF(segv_handler) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + + save_context( &context, HANDLER_CONTEXT ); + + rec.ExceptionRecord = NULL; + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionAddress = (LPVOID)context.Rip; + rec.NumberParameters = 0; + + switch(TRAP_sig(HANDLER_CONTEXT)) + { + case T_OFLOW: /* Overflow exception */ + rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; + break; + case T_BOUND: /* Bound range exception */ + rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; + break; + case T_PRIVINFLT: /* Invalid opcode exception */ + rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + case T_STKFLT: /* Stack fault */ + rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW; + break; + case T_SEGNPFLT: /* Segment not present exception */ + case T_PROTFLT: /* General protection fault */ + case T_UNKNOWN: /* Unknown fault code */ + rec.ExceptionCode = ERROR_sig(HANDLER_CONTEXT) ? EXCEPTION_ACCESS_VIOLATION + : EXCEPTION_PRIV_INSTRUCTION; + break; + case T_PAGEFLT: /* Page fault */ + rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION; +#ifdef FAULT_ADDRESS + rec.NumberParameters = 2; + rec.ExceptionInformation[0] = (ERROR_sig(HANDLER_CONTEXT) & 2) != 0; + rec.ExceptionInformation[1] = (ULONG_PTR)FAULT_ADDRESS; +#endif + break; + case T_ALIGNFLT: /* Alignment check exception */ + rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT; + break; + default: + ERR( "Got unexpected trap %ld\n", TRAP_sig(HANDLER_CONTEXT) ); + /* fall through */ + case T_NMI: /* NMI interrupt */ + case T_DNA: /* Device not available exception */ + case T_DOUBLEFLT: /* Double fault exception */ + case T_TSSFLT: /* Invalid TSS exception */ + case T_RESERVED: /* Unknown exception */ + case T_MCHK: /* Machine check exception */ + case T_CACHEFLT: /* Cache flush exception */ + rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION; + break; + } + + __regs_RtlRaiseException( &rec, &context ); + restore_context( &context, HANDLER_CONTEXT ); +} + +/********************************************************************** + * trap_handler + * + * Handler for SIGTRAP. + */ +static HANDLER_DEF(trap_handler) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + + save_context( &context, HANDLER_CONTEXT ); + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Rip; + rec.NumberParameters = 0; + + switch(FAULT_CODE) + { + case TRAP_TRACE: /* Single-step exception */ + rec.ExceptionCode = EXCEPTION_SINGLE_STEP; + EFL_sig(HANDLER_CONTEXT) &= ~0x100; /* clear single-step flag */ + break; + case TRAP_BRKPT: /* Breakpoint exception */ + rec.ExceptionAddress = (char *)rec.ExceptionAddress - 1; /* back up over the int3 instruction */ + /* fall through */ + default: + rec.ExceptionCode = EXCEPTION_BREAKPOINT; + break; + } + + __regs_RtlRaiseException( &rec, &context ); + restore_context( &context, HANDLER_CONTEXT ); +} + +/********************************************************************** + * fpe_handler + * + * Handler for SIGFPE. + */ +static HANDLER_DEF(fpe_handler) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + + save_context( &context, HANDLER_CONTEXT ); + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Rip; + rec.NumberParameters = 0; + + switch (FAULT_CODE) + { + case FPE_FLTSUB: + rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED; + break; + case FPE_INTDIV: + rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO; + break; + case FPE_INTOVF: + rec.ExceptionCode = EXCEPTION_INT_OVERFLOW; + break; + case FPE_FLTDIV: + rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO; + break; + case FPE_FLTOVF: + rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW; + break; + case FPE_FLTUND: + rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW; + break; + case FPE_FLTRES: + rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT; + break; + case FPE_FLTINV: + default: + rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION; + break; + } + + __regs_RtlRaiseException( &rec, &context ); + restore_context( &context, HANDLER_CONTEXT ); +} + +/********************************************************************** + * int_handler + * + * Handler for SIGINT. + */ +static HANDLER_DEF(int_handler) +{ + if (!dispatch_signal(SIGINT)) + { + EXCEPTION_RECORD rec; + CONTEXT context; + + save_context( &context, HANDLER_CONTEXT ); + rec.ExceptionCode = CONTROL_C_EXIT; + rec.ExceptionFlags = EXCEPTION_CONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Rip; + rec.NumberParameters = 0; + __regs_RtlRaiseException( &rec, &context ); + restore_context( &context, HANDLER_CONTEXT ); + } +} + + +/********************************************************************** + * abrt_handler + * + * Handler for SIGABRT. + */ +static HANDLER_DEF(abrt_handler) +{ + EXCEPTION_RECORD rec; + CONTEXT context; + + save_context( &context, HANDLER_CONTEXT ); + rec.ExceptionCode = EXCEPTION_WINE_ASSERTION; + rec.ExceptionFlags = EH_NONCONTINUABLE; + rec.ExceptionRecord = NULL; + rec.ExceptionAddress = (LPVOID)context.Rip; + rec.NumberParameters = 0; + __regs_RtlRaiseException( &rec, &context ); /* Should never return.. */ + restore_context( &context, HANDLER_CONTEXT ); +} + + +/********************************************************************** + * term_handler + * + * Handler for SIGTERM. + */ +static HANDLER_DEF(term_handler) +{ + server_abort_thread(0); +} + + +/********************************************************************** + * usr1_handler + * + * Handler for SIGUSR1, used to signal a thread that it got suspended. + */ +static HANDLER_DEF(usr1_handler) +{ + LARGE_INTEGER timeout; + + /* wait with 0 timeout, will only return once the thread is no longer suspended */ + timeout.QuadPart = 0; + NTDLL_wait_for_multiple_objects( 0, NULL, 0, &timeout, 0 ); +} + + +/********************************************************************** + * get_signal_stack_total_size + * + * Retrieve the size to allocate for the signal stack, including the TEB at the bottom. + * Must be a power of two. + */ +size_t get_signal_stack_total_size(void) +{ + assert( sizeof(TEB) <= 2*getpagesize() ); + return 2*getpagesize(); /* this is just for the TEB, we don't need a signal stack */ +} + + +/*********************************************************************** + * set_handler + * + * Set a signal handler + */ +static int set_handler( int sig, void (*func)() ) +{ + struct sigaction sig_act; + + sig_act.sa_sigaction = func; + sigemptyset( &sig_act.sa_mask ); + sigaddset( &sig_act.sa_mask, SIGINT ); + sigaddset( &sig_act.sa_mask, SIGUSR2 ); + + sig_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; + return sigaction( sig, &sig_act, NULL ); +} + + +/*********************************************************************** + * __wine_set_signal_handler (NTDLL.@) + */ +int __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh) +{ + if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1; + if (handlers[sig] != NULL) return -2; + handlers[sig] = wsh; + return 0; +} + + +/********************************************************************** + * SIGNAL_Init + */ +BOOL SIGNAL_Init(void) +{ + if (set_handler( SIGINT, (void (*)())int_handler ) == -1) goto error; + if (set_handler( SIGFPE, (void (*)())fpe_handler ) == -1) goto error; + if (set_handler( SIGSEGV, (void (*)())segv_handler ) == -1) goto error; + if (set_handler( SIGILL, (void (*)())segv_handler ) == -1) goto error; + if (set_handler( SIGABRT, (void (*)())abrt_handler ) == -1) goto error; + if (set_handler( SIGTERM, (void (*)())term_handler ) == -1) goto error; + if (set_handler( SIGUSR1, (void (*)())usr1_handler ) == -1) goto error; +#ifdef SIGBUS + if (set_handler( SIGBUS, (void (*)())segv_handler ) == -1) goto error; +#endif +#ifdef SIGTRAP + if (set_handler( SIGTRAP, (void (*)())trap_handler ) == -1) goto error; +#endif + return TRUE; + + error: + perror("sigaction"); + return FALSE; +} + + +/********************************************************************** + * __wine_enter_vm86 (NTDLL.@) + */ +void __wine_enter_vm86( CONTEXT *context ) +{ + MESSAGE("vm86 mode not supported on this platform\n"); +} + +/********************************************************************** + * DbgBreakPoint (NTDLL.@) + */ +__ASM_GLOBAL_FUNC( DbgBreakPoint, "int $3; ret"); + +/********************************************************************** + * DbgUserBreakPoint (NTDLL.@) + */ +__ASM_GLOBAL_FUNC( DbgUserBreakPoint, "int $3; ret"); + +#endif /* __x86_64__ */