push bf834a7eef2241618d351018da1587a7ae2466d1
[wine/hacks.git] / dlls / ntdll / signal_x86_64.c
blob8e9dd7c1e2332054baee483b6a40cc9fa7790da9
1 /*
2 * x86-64 signal handling routines
4 * Copyright 1999, 2005 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #ifdef __x86_64__
23 #include "config.h"
24 #include "wine/port.h"
26 #include <assert.h>
27 #include <signal.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #endif
38 #ifdef HAVE_SYS_SIGNAL_H
39 # include <sys/signal.h>
40 #endif
42 #define NONAMELESSUNION
43 #include "windef.h"
44 #include "winternl.h"
45 #include "wine/library.h"
46 #include "wine/exception.h"
47 #include "ntdll_misc.h"
48 #include "wine/debug.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(seh);
53 /***********************************************************************
54 * signal context platform-specific definitions
56 #ifdef linux
58 typedef struct ucontext SIGCONTEXT;
60 # define HANDLER_DEF(name) void name( int __signal, struct siginfo *__siginfo, SIGCONTEXT *__context )
61 # define HANDLER_CONTEXT (__context)
63 #define RAX_sig(context) ((context)->uc_mcontext.gregs[REG_RAX])
64 #define RBX_sig(context) ((context)->uc_mcontext.gregs[REG_RBX])
65 #define RCX_sig(context) ((context)->uc_mcontext.gregs[REG_RCX])
66 #define RDX_sig(context) ((context)->uc_mcontext.gregs[REG_RDX])
67 #define RSI_sig(context) ((context)->uc_mcontext.gregs[REG_RSI])
68 #define RDI_sig(context) ((context)->uc_mcontext.gregs[REG_RDI])
69 #define RBP_sig(context) ((context)->uc_mcontext.gregs[REG_RBP])
70 #define R8_sig(context) ((context)->uc_mcontext.gregs[REG_R8])
71 #define R9_sig(context) ((context)->uc_mcontext.gregs[REG_R9])
72 #define R10_sig(context) ((context)->uc_mcontext.gregs[REG_R10])
73 #define R11_sig(context) ((context)->uc_mcontext.gregs[REG_R11])
74 #define R12_sig(context) ((context)->uc_mcontext.gregs[REG_R12])
75 #define R13_sig(context) ((context)->uc_mcontext.gregs[REG_R13])
76 #define R14_sig(context) ((context)->uc_mcontext.gregs[REG_R14])
77 #define R15_sig(context) ((context)->uc_mcontext.gregs[REG_R15])
79 #define CS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 0))
80 #define GS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 1))
81 #define FS_sig(context) (*((WORD *)&(context)->uc_mcontext.gregs[REG_CSGSFS] + 2))
83 #define RSP_sig(context) ((context)->uc_mcontext.gregs[REG_RSP])
84 #define RIP_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
85 #define EFL_sig(context) ((context)->uc_mcontext.gregs[REG_EFL])
86 #define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
87 #define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
89 #define FPU_sig(context) ((XMM_SAVE_AREA32 *)((context)->uc_mcontext.fpregs))
91 #define FAULT_CODE (__siginfo->si_code)
92 #define FAULT_ADDRESS (__siginfo->si_addr)
94 #endif /* linux */
96 enum i386_trap_code
98 TRAP_x86_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
99 TRAP_x86_DIVIDE = 0, /* Division by zero exception */
100 TRAP_x86_TRCTRAP = 1, /* Single-step exception */
101 TRAP_x86_NMI = 2, /* NMI interrupt */
102 TRAP_x86_BPTFLT = 3, /* Breakpoint exception */
103 TRAP_x86_OFLOW = 4, /* Overflow exception */
104 TRAP_x86_BOUND = 5, /* Bound range exception */
105 TRAP_x86_PRIVINFLT = 6, /* Invalid opcode exception */
106 TRAP_x86_DNA = 7, /* Device not available exception */
107 TRAP_x86_DOUBLEFLT = 8, /* Double fault exception */
108 TRAP_x86_FPOPFLT = 9, /* Coprocessor segment overrun */
109 TRAP_x86_TSSFLT = 10, /* Invalid TSS exception */
110 TRAP_x86_SEGNPFLT = 11, /* Segment not present exception */
111 TRAP_x86_STKFLT = 12, /* Stack fault */
112 TRAP_x86_PROTFLT = 13, /* General protection fault */
113 TRAP_x86_PAGEFLT = 14, /* Page fault */
114 TRAP_x86_ARITHTRAP = 16, /* Floating point exception */
115 TRAP_x86_ALIGNFLT = 17, /* Alignment check exception */
116 TRAP_x86_MCHK = 18, /* Machine check exception */
117 TRAP_x86_CACHEFLT = 19 /* Cache flush exception */
120 typedef int (*wine_signal_handler)(unsigned int sig);
122 static wine_signal_handler handlers[256];
124 /***********************************************************************
125 * dispatch_signal
127 static inline int dispatch_signal(unsigned int sig)
129 if (handlers[sig] == NULL) return 0;
130 return handlers[sig](sig);
133 /***********************************************************************
134 * save_context
136 * Set the register values from a sigcontext.
138 static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext )
140 context->Rax = RAX_sig(sigcontext);
141 context->Rcx = RCX_sig(sigcontext);
142 context->Rdx = RDX_sig(sigcontext);
143 context->Rbx = RBX_sig(sigcontext);
144 context->Rsp = RSP_sig(sigcontext);
145 context->Rbp = RBP_sig(sigcontext);
146 context->Rsi = RSI_sig(sigcontext);
147 context->Rdi = RDI_sig(sigcontext);
148 context->R8 = R8_sig(sigcontext);
149 context->R9 = R9_sig(sigcontext);
150 context->R10 = R10_sig(sigcontext);
151 context->R11 = R11_sig(sigcontext);
152 context->R12 = R12_sig(sigcontext);
153 context->R13 = R13_sig(sigcontext);
154 context->R14 = R14_sig(sigcontext);
155 context->R15 = R15_sig(sigcontext);
156 context->Rip = RIP_sig(sigcontext);
157 context->SegCs = CS_sig(sigcontext);
158 context->SegFs = FS_sig(sigcontext);
159 context->SegGs = GS_sig(sigcontext);
160 context->EFlags = EFL_sig(sigcontext);
161 context->SegDs = 0; /* FIXME */
162 context->SegEs = 0; /* FIXME */
163 context->SegSs = 0; /* FIXME */
164 context->MxCsr = 0; /* FIXME */
165 if (FPU_sig(sigcontext)) context->u.FltSave = *FPU_sig(sigcontext);
169 /***********************************************************************
170 * restore_context
172 * Build a sigcontext from the register values.
174 static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
176 RAX_sig(sigcontext) = context->Rax;
177 RCX_sig(sigcontext) = context->Rcx;
178 RDX_sig(sigcontext) = context->Rdx;
179 RBX_sig(sigcontext) = context->Rbx;
180 RSP_sig(sigcontext) = context->Rsp;
181 RBP_sig(sigcontext) = context->Rbp;
182 RSI_sig(sigcontext) = context->Rsi;
183 RDI_sig(sigcontext) = context->Rdi;
184 R8_sig(sigcontext) = context->R8;
185 R9_sig(sigcontext) = context->R9;
186 R10_sig(sigcontext) = context->R10;
187 R11_sig(sigcontext) = context->R11;
188 R12_sig(sigcontext) = context->R12;
189 R13_sig(sigcontext) = context->R13;
190 R14_sig(sigcontext) = context->R14;
191 R15_sig(sigcontext) = context->R15;
192 RIP_sig(sigcontext) = context->Rip;
193 CS_sig(sigcontext) = context->SegCs;
194 FS_sig(sigcontext) = context->SegFs;
195 GS_sig(sigcontext) = context->SegGs;
196 EFL_sig(sigcontext) = context->EFlags;
197 if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->u.FltSave;
201 /***********************************************************************
202 * RtlCaptureContext (NTDLL.@)
204 void WINAPI __regs_RtlCaptureContext( CONTEXT *context, CONTEXT *regs )
206 *context = *regs;
208 DEFINE_REGS_ENTRYPOINT( RtlCaptureContext, 1 )
211 /***********************************************************************
212 * set_cpu_context
214 * Set the new CPU context.
216 void set_cpu_context( const CONTEXT *context )
218 FIXME("not implemented\n");
222 /**********************************************************************
223 * segv_handler
225 * Handler for SIGSEGV and related errors.
227 static HANDLER_DEF(segv_handler)
229 EXCEPTION_RECORD rec;
230 CONTEXT context;
232 save_context( &context, HANDLER_CONTEXT );
234 rec.ExceptionRecord = NULL;
235 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
236 rec.ExceptionAddress = (LPVOID)context.Rip;
237 rec.NumberParameters = 0;
239 switch(TRAP_sig(HANDLER_CONTEXT))
241 case TRAP_x86_OFLOW: /* Overflow exception */
242 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
243 break;
244 case TRAP_x86_BOUND: /* Bound range exception */
245 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
246 break;
247 case TRAP_x86_PRIVINFLT: /* Invalid opcode exception */
248 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
249 break;
250 case TRAP_x86_STKFLT: /* Stack fault */
251 rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
252 break;
253 case TRAP_x86_SEGNPFLT: /* Segment not present exception */
254 case TRAP_x86_PROTFLT: /* General protection fault */
255 case TRAP_x86_UNKNOWN: /* Unknown fault code */
256 rec.ExceptionCode = ERROR_sig(HANDLER_CONTEXT) ? EXCEPTION_ACCESS_VIOLATION
257 : EXCEPTION_PRIV_INSTRUCTION;
258 break;
259 case TRAP_x86_PAGEFLT: /* Page fault */
260 rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
261 #ifdef FAULT_ADDRESS
262 rec.NumberParameters = 2;
263 rec.ExceptionInformation[0] = (ERROR_sig(HANDLER_CONTEXT) & 2) != 0;
264 rec.ExceptionInformation[1] = (ULONG_PTR)FAULT_ADDRESS;
265 if (!(rec.ExceptionCode = virtual_handle_fault( FAULT_ADDRESS, rec.ExceptionInformation[0] )))
266 goto done;
267 #endif
268 break;
269 case TRAP_x86_ALIGNFLT: /* Alignment check exception */
270 rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
271 break;
272 default:
273 ERR( "Got unexpected trap %ld\n", TRAP_sig(HANDLER_CONTEXT) );
274 /* fall through */
275 case TRAP_x86_NMI: /* NMI interrupt */
276 case TRAP_x86_DNA: /* Device not available exception */
277 case TRAP_x86_DOUBLEFLT: /* Double fault exception */
278 case TRAP_x86_TSSFLT: /* Invalid TSS exception */
279 case TRAP_x86_MCHK: /* Machine check exception */
280 case TRAP_x86_CACHEFLT: /* Cache flush exception */
281 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
282 break;
285 __regs_RtlRaiseException( &rec, &context );
286 done:
287 restore_context( &context, HANDLER_CONTEXT );
290 /**********************************************************************
291 * trap_handler
293 * Handler for SIGTRAP.
295 static HANDLER_DEF(trap_handler)
297 EXCEPTION_RECORD rec;
298 CONTEXT context;
300 save_context( &context, HANDLER_CONTEXT );
301 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
302 rec.ExceptionRecord = NULL;
303 rec.ExceptionAddress = (LPVOID)context.Rip;
304 rec.NumberParameters = 0;
306 switch(FAULT_CODE)
308 case TRAP_TRACE: /* Single-step exception */
309 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
310 EFL_sig(HANDLER_CONTEXT) &= ~0x100; /* clear single-step flag */
311 break;
312 case TRAP_BRKPT: /* Breakpoint exception */
313 rec.ExceptionAddress = (char *)rec.ExceptionAddress - 1; /* back up over the int3 instruction */
314 /* fall through */
315 default:
316 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
317 break;
320 __regs_RtlRaiseException( &rec, &context );
321 restore_context( &context, HANDLER_CONTEXT );
324 /**********************************************************************
325 * fpe_handler
327 * Handler for SIGFPE.
329 static HANDLER_DEF(fpe_handler)
331 EXCEPTION_RECORD rec;
332 CONTEXT context;
334 save_context( &context, HANDLER_CONTEXT );
335 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
336 rec.ExceptionRecord = NULL;
337 rec.ExceptionAddress = (LPVOID)context.Rip;
338 rec.NumberParameters = 0;
340 switch (FAULT_CODE)
342 case FPE_FLTSUB:
343 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
344 break;
345 case FPE_INTDIV:
346 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
347 break;
348 case FPE_INTOVF:
349 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
350 break;
351 case FPE_FLTDIV:
352 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
353 break;
354 case FPE_FLTOVF:
355 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
356 break;
357 case FPE_FLTUND:
358 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
359 break;
360 case FPE_FLTRES:
361 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
362 break;
363 case FPE_FLTINV:
364 default:
365 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
366 break;
369 __regs_RtlRaiseException( &rec, &context );
370 restore_context( &context, HANDLER_CONTEXT );
373 /**********************************************************************
374 * int_handler
376 * Handler for SIGINT.
378 static HANDLER_DEF(int_handler)
380 if (!dispatch_signal(SIGINT))
382 EXCEPTION_RECORD rec;
383 CONTEXT context;
385 save_context( &context, HANDLER_CONTEXT );
386 rec.ExceptionCode = CONTROL_C_EXIT;
387 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
388 rec.ExceptionRecord = NULL;
389 rec.ExceptionAddress = (LPVOID)context.Rip;
390 rec.NumberParameters = 0;
391 __regs_RtlRaiseException( &rec, &context );
392 restore_context( &context, HANDLER_CONTEXT );
397 /**********************************************************************
398 * abrt_handler
400 * Handler for SIGABRT.
402 static HANDLER_DEF(abrt_handler)
404 EXCEPTION_RECORD rec;
405 CONTEXT context;
407 save_context( &context, HANDLER_CONTEXT );
408 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
409 rec.ExceptionFlags = EH_NONCONTINUABLE;
410 rec.ExceptionRecord = NULL;
411 rec.ExceptionAddress = (LPVOID)context.Rip;
412 rec.NumberParameters = 0;
413 __regs_RtlRaiseException( &rec, &context ); /* Should never return.. */
414 restore_context( &context, HANDLER_CONTEXT );
418 /**********************************************************************
419 * quit_handler
421 * Handler for SIGQUIT.
423 static HANDLER_DEF(quit_handler)
425 server_abort_thread(0);
429 /**********************************************************************
430 * usr1_handler
432 * Handler for SIGUSR1, used to signal a thread that it got suspended.
434 static HANDLER_DEF(usr1_handler)
436 CONTEXT context;
438 save_context( &context, HANDLER_CONTEXT );
439 wait_suspend( &context );
440 restore_context( &context, HANDLER_CONTEXT );
444 /**********************************************************************
445 * get_signal_stack_total_size
447 * Retrieve the size to allocate for the signal stack, including the TEB at the bottom.
448 * Must be a power of two.
450 size_t get_signal_stack_total_size(void)
452 assert( sizeof(TEB) <= 2*getpagesize() );
453 return 2*getpagesize(); /* this is just for the TEB, we don't need a signal stack */
457 /***********************************************************************
458 * set_handler
460 * Set a signal handler
462 static int set_handler( int sig, void (*func)() )
464 struct sigaction sig_act;
466 sig_act.sa_sigaction = func;
467 sig_act.sa_mask = server_block_set;
468 sig_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
469 return sigaction( sig, &sig_act, NULL );
473 /***********************************************************************
474 * __wine_set_signal_handler (NTDLL.@)
476 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
478 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
479 if (handlers[sig] != NULL) return -2;
480 handlers[sig] = wsh;
481 return 0;
485 /**********************************************************************
486 * signal_init_thread
488 void signal_init_thread(void)
492 /**********************************************************************
493 * signal_init_process
495 void signal_init_process(void)
497 if (set_handler( SIGINT, (void (*)())int_handler ) == -1) goto error;
498 if (set_handler( SIGFPE, (void (*)())fpe_handler ) == -1) goto error;
499 if (set_handler( SIGSEGV, (void (*)())segv_handler ) == -1) goto error;
500 if (set_handler( SIGILL, (void (*)())segv_handler ) == -1) goto error;
501 if (set_handler( SIGABRT, (void (*)())abrt_handler ) == -1) goto error;
502 if (set_handler( SIGQUIT, (void (*)())quit_handler ) == -1) goto error;
503 if (set_handler( SIGUSR1, (void (*)())usr1_handler ) == -1) goto error;
504 #ifdef SIGBUS
505 if (set_handler( SIGBUS, (void (*)())segv_handler ) == -1) goto error;
506 #endif
507 #ifdef SIGTRAP
508 if (set_handler( SIGTRAP, (void (*)())trap_handler ) == -1) goto error;
509 #endif
510 signal_init_thread();
511 return;
513 error:
514 perror("sigaction");
515 exit(1);
519 /**********************************************************************
520 * RtlLookupFunctionEntry (NTDLL.@)
522 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG64 pc, ULONG64 *base,
523 UNWIND_HISTORY_TABLE *table )
525 FIXME("stub\n");
526 return NULL;
530 /**********************************************************************
531 * RtlVirtualUnwind (NTDLL.@)
533 PVOID WINAPI RtlVirtualUnwind ( ULONG type, ULONG64 base, ULONG64 pc,
534 RUNTIME_FUNCTION *function, CONTEXT *context,
535 PVOID *data, ULONG64 *frame,
536 KNONVOLATILE_CONTEXT_POINTERS *ctx_ptr )
538 FIXME("stub\n");
539 return NULL;
543 /**********************************************************************
544 * __wine_enter_vm86 (NTDLL.@)
546 void __wine_enter_vm86( CONTEXT *context )
548 MESSAGE("vm86 mode not supported on this platform\n");
551 /**********************************************************************
552 * DbgBreakPoint (NTDLL.@)
554 __ASM_GLOBAL_FUNC( DbgBreakPoint, "int $3; ret")
556 /**********************************************************************
557 * DbgUserBreakPoint (NTDLL.@)
559 __ASM_GLOBAL_FUNC( DbgUserBreakPoint, "int $3; ret")
561 #endif /* __x86_64__ */