Fixed signal stack handling on Linux when sigaltstack is available.
[wine] / dlls / ntdll / signal_i386.c
1 /*
2  * i386 signal handling routines
3  * 
4  * Copyright 1999 Alexandre Julliard
5  */
6
7 #ifdef __i386__
8
9 #include "config.h"
10
11 #include <errno.h>
12 #include <signal.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <unistd.h>
16
17 #ifdef HAVE_SYS_PARAM_H
18 # include <sys/param.h>
19 #endif
20 #ifdef HAVE_SYSCALL_H
21 # include <syscall.h>
22 #else
23 # ifdef HAVE_SYS_SYSCALL_H
24 #  include <sys/syscall.h>
25 # endif
26 #endif
27
28 #include "selectors.h"
29
30 /***********************************************************************
31  * signal context platform-specific definitions
32  */
33
34 #ifdef linux
35 typedef struct
36 {
37     unsigned short sc_gs, __gsh;
38     unsigned short sc_fs, __fsh;
39     unsigned short sc_es, __esh;
40     unsigned short sc_ds, __dsh;
41     unsigned long sc_edi;
42     unsigned long sc_esi;
43     unsigned long sc_ebp;
44     unsigned long sc_esp;
45     unsigned long sc_ebx;
46     unsigned long sc_edx;
47     unsigned long sc_ecx;
48     unsigned long sc_eax;
49     unsigned long sc_trapno;
50     unsigned long sc_err;
51     unsigned long sc_eip;
52     unsigned short sc_cs, __csh;
53     unsigned long sc_eflags;
54     unsigned long esp_at_signal;
55     unsigned short sc_ss, __ssh;
56     unsigned long i387;
57     unsigned long oldmask;
58     unsigned long cr2;
59 } SIGCONTEXT;
60
61 #define HANDLER_DEF(name) void name( int __signal, SIGCONTEXT __context )
62 #define HANDLER_CONTEXT (&__context)
63
64 /* this is the sigaction structure from the Linux 2.1.20 kernel.  */
65 struct kernel_sigaction
66 {
67     void (*ksa_handler)();
68     unsigned long ksa_mask;
69     unsigned long ksa_flags;
70     void *ksa_restorer;
71 };
72
73 /* Similar to the sigaction function in libc, except it leaves alone the
74    restorer field, which is used to specify the signal stack address */
75 static inline int wine_sigaction( int sig, struct kernel_sigaction *new,
76                                   struct kernel_sigaction *old )
77 {
78     __asm__ __volatile__( "pushl %%ebx\n\t"
79                           "movl %2,%%ebx\n\t"
80                           "int $0x80\n\t"
81                           "popl %%ebx"
82                           : "=a" (sig)
83                           : "0" (SYS_sigaction), "r" (sig), "c" (new), "d" (old) );
84     if (sig>=0) return 0;
85     errno = -sig;
86     return -1;
87 }
88
89 #ifdef HAVE_SIGALTSTACK
90 /* direct syscall for sigaltstack to work around glibc 2.0 brain-damage */
91 static inline int wine_sigaltstack( const struct sigaltstack *new,
92                                     struct sigaltstack *old )
93 {
94     int ret;
95     __asm__ __volatile__( "pushl %%ebx\n\t"
96                           "movl %2,%%ebx\n\t"
97                           "int $0x80\n\t"
98                           "popl %%ebx"
99                           : "=a" (ret)
100                           : "0" (SYS_sigaltstack), "r" (new), "c" (old) );
101     if (ret >= 0) return 0;
102     errno = -ret;
103     return -1;
104 }
105 #endif
106
107 #endif  /* linux */
108
109 #ifdef BSDI
110
111 #define EAX_sig(context)     ((context)->tf_eax)
112 #define EBX_sig(context)     ((context)->tf_ebx)
113 #define ECX_sig(context)     ((context)->tf_ecx)
114 #define EDX_sig(context)     ((context)->tf_edx)
115 #define ESI_sig(context)     ((context)->tf_esi)
116 #define EDI_sig(context)     ((context)->tf_edi)
117 #define EBP_sig(context)     ((context)->tf_ebp)
118                             
119 #define CS_sig(context)      ((context)->tf_cs)
120 #define DS_sig(context)      ((context)->tf_ds)
121 #define ES_sig(context)      ((context)->tf_es)
122 #define SS_sig(context)      ((context)->tf_ss)
123
124 #include <machine/frame.h>
125 typedef struct trapframe SIGCONTEXT;
126
127 #define HANDLER_DEF(name) void name( int __signal, int code, SIGCONTEXT *__context )
128 #define HANDLER_CONTEXT __context
129
130 #define EFL_sig(context)     ((context)->tf_eflags)
131
132 #define EIP_sig(context)     (*((unsigned long*)&(context)->tf_eip))
133 #define ESP_sig(context)     (*((unsigned long*)&(context)->tf_esp))
134
135 #endif /* bsdi */
136
137 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
138
139 typedef struct sigcontext SIGCONTEXT;
140
141 #define HANDLER_DEF(name) void name( int __signal, int code, SIGCONTEXT *__context )
142 #define HANDLER_CONTEXT __context
143
144 #endif  /* FreeBSD */
145
146 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
147
148 #ifdef _SCO_DS
149 #include <sys/regset.h>
150 #endif
151 /* Solaris kludge */
152 #undef ERR
153 #include <sys/ucontext.h>
154 #undef ERR
155 typedef struct ucontext SIGCONTEXT;
156
157 #define HANDLER_DEF(name) void name( int __signal, void *__siginfo, SIGCONTEXT *__context )
158 #define HANDLER_CONTEXT __context
159
160 #endif  /* svr4 || SCO_DS */
161
162 #ifdef __EMX__
163
164 typedef struct
165 {
166     unsigned long ContextFlags;
167     FLOATING_SAVE_AREA sc_float;
168     unsigned long sc_gs;
169     unsigned long sc_fs;
170     unsigned long sc_es;
171     unsigned long sc_ds;
172     unsigned long sc_edi;
173     unsigned long sc_esi;
174     unsigned long sc_eax;
175     unsigned long sc_ebx;
176     unsigned long sc_ecx;
177     unsigned long sc_edx;
178     unsigned long sc_ebp;
179     unsigned long sc_eip;
180     unsigned long sc_cs;
181     unsigned long sc_eflags;
182     unsigned long sc_esp;
183     unsigned long sc_ss;
184 } SIGCONTEXT;
185
186 #endif  /* __EMX__ */
187
188
189 #if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMX__)
190
191 #define EAX_sig(context)     ((context)->sc_eax)
192 #define EBX_sig(context)     ((context)->sc_ebx)
193 #define ECX_sig(context)     ((context)->sc_ecx)
194 #define EDX_sig(context)     ((context)->sc_edx)
195 #define ESI_sig(context)     ((context)->sc_esi)
196 #define EDI_sig(context)     ((context)->sc_edi)
197 #define EBP_sig(context)     ((context)->sc_ebp)
198                             
199 #define CS_sig(context)      ((context)->sc_cs)
200 #define DS_sig(context)      ((context)->sc_ds)
201 #define ES_sig(context)      ((context)->sc_es)
202 #define SS_sig(context)      ((context)->sc_ss)
203                             
204 /* FS and GS are now in the sigcontext struct of FreeBSD, but not 
205  * saved by the exception handling. duh.
206  * Actually they are in -current (have been for a while), and that
207  * patch now finally has been MFC'd to -stable too (Nov 15 1999).
208  * If you're running a system from the -stable branch older than that,
209  * like a 3.3-RELEASE, grab the patch from the ports tree:
210  * ftp://ftp.freebsd.org/pub/FreeBSD/FreeBSD-current/ports/emulators/wine/files/patch-3.3-sys-fsgs
211  * (If its not yet there when you look, go here:
212  * http://www.jelal.kn-bremen.de/freebsd/ports/emulators/wine/files/ )
213  */
214 #ifdef __FreeBSD__
215 #define FS_sig(context)      ((context)->sc_fs)
216 #define GS_sig(context)      ((context)->sc_gs)
217 #endif
218
219 #ifdef linux
220 #define FS_sig(context)      ((context)->sc_fs)
221 #define GS_sig(context)      ((context)->sc_gs)
222 #define CR2_sig(context)     ((context)->cr2)
223 #define TRAP_sig(context)    ((context)->sc_trapno)
224 #define ERROR_sig(context)   ((context)->sc_err)
225 #define FPU_sig(context)     ((FLOATING_SAVE_AREA*)((context)->i387))
226 #endif
227
228 #ifndef __FreeBSD__
229 #define EFL_sig(context)     ((context)->sc_eflags)
230 #else                       
231 #define EFL_sig(context)     ((context)->sc_efl)
232 /* FreeBSD, see i386/i386/traps.c::trap_pfault va->err kludge  */
233 #define CR2_sig(context)     ((context)->sc_err)
234 #define TRAP_sig(context)    ((context)->sc_trapno)
235 #endif                      
236
237 #define EIP_sig(context)     (*((unsigned long*)&(context)->sc_eip))
238 #define ESP_sig(context)     (*((unsigned long*)&(context)->sc_esp))
239
240 #endif  /* linux || __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
241
242 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
243
244 #ifdef _SCO_DS
245 #define gregs regs
246 #endif
247
248 #define EAX_sig(context)     ((context)->uc_mcontext.gregs[EAX])
249 #define EBX_sig(context)     ((context)->uc_mcontext.gregs[EBX])
250 #define ECX_sig(context)     ((context)->uc_mcontext.gregs[ECX])
251 #define EDX_sig(context)     ((context)->uc_mcontext.gregs[EDX])
252 #define ESI_sig(context)     ((context)->uc_mcontext.gregs[ESI])
253 #define EDI_sig(context)     ((context)->uc_mcontext.gregs[EDI])
254 #define EBP_sig(context)     ((context)->uc_mcontext.gregs[EBP])
255                             
256 #define CS_sig(context)      ((context)->uc_mcontext.gregs[CS])
257 #define DS_sig(context)      ((context)->uc_mcontext.gregs[DS])
258 #define ES_sig(context)      ((context)->uc_mcontext.gregs[ES])
259 #define SS_sig(context)      ((context)->uc_mcontext.gregs[SS])
260                             
261 #define FS_sig(context)      ((context)->uc_mcontext.gregs[FS])
262 #define GS_sig(context)      ((context)->uc_mcontext.gregs[GS])
263
264 #define EFL_sig(context)     ((context)->uc_mcontext.gregs[EFL])
265                             
266 #define EIP_sig(context)     ((context)->uc_mcontext.gregs[EIP])
267 #ifdef R_ESP
268 #define ESP_sig(context)     ((context)->uc_mcontext.gregs[R_ESP])
269 #else
270 #define ESP_sig(context)     ((context)->uc_mcontext.gregs[ESP])
271 #endif
272 #ifdef TRAPNO
273 #define TRAP_sig(context)     ((context)->uc_mcontext.gregs[TRAPNO])
274 #endif
275
276 #endif  /* svr4 || SCO_DS */
277
278
279 /* exception code definitions (already defined by FreeBSD) */
280 #ifndef __FreeBSD__  /* FIXME: other BSDs? */
281 #define T_DIVIDE        0   /* Division by zero exception */
282 #define T_TRCTRAP       1   /* Single-step exception */
283 #define T_NMI           2   /* NMI interrupt */
284 #define T_BPTFLT        3   /* Breakpoint exception */
285 #define T_OFLOW         4   /* Overflow exception */
286 #define T_BOUND         5   /* Bound range exception */
287 #define T_PRIVINFLT     6   /* Invalid opcode exception */
288 #define T_DNA           7   /* Device not available exception */
289 #define T_DOUBLEFLT     8   /* Double fault exception */
290 #define T_FPOPFLT       9   /* Coprocessor segment overrun */
291 #define T_TSSFLT        10  /* Invalid TSS exception */
292 #define T_SEGNPFLT      11  /* Segment not present exception */
293 #define T_STKFLT        12  /* Stack fault */
294 #define T_PROTFLT       13  /* General protection fault */
295 #define T_PAGEFLT       14  /* Page fault */
296 #define T_RESERVED      15  /* Unknown exception */
297 #define T_ARITHTRAP     16  /* Floating point exception */
298 #define T_ALIGNFLT      17  /* Alignment check exception */
299 #define T_MCHK          18  /* Machine check exception */
300 #define T_CACHEFLT      19  /* Cache flush exception */
301 #endif
302
303 #define T_UNKNOWN     (-1)  /* Unknown fault (TRAP_sig not defined) */
304
305 #include "wine/exception.h"
306 #include "winnt.h"
307 #include "stackframe.h"
308 #include "global.h"
309 #include "miscemu.h"
310 #include "ntddk.h"
311 #include "syslevel.h"
312 #include "debugtools.h"
313
314 DEFAULT_DEBUG_CHANNEL(seh)
315
316
317
318 /***********************************************************************
319  *           handler_init
320  *
321  * Initialization code for a signal handler.
322  * Restores the proper %fs value for the current thread.
323  */
324 static inline void handler_init( CONTEXT *context, const SIGCONTEXT *sigcontext )
325 {
326     WORD fs;
327     /* get %fs at time of the fault */
328 #ifdef FS_sig
329     fs = FS_sig(sigcontext);
330 #else
331     fs = __get_fs();
332 #endif
333     context->SegFs = fs;
334     /* now restore a proper %fs for the fault handler */
335     if (!IS_SELECTOR_SYSTEM(CS_sig(sigcontext))) fs = SYSLEVEL_Win16CurrentTeb;
336     if (!fs) fs = SYSLEVEL_EmergencyTeb;
337     __set_fs(fs);
338 }
339
340 /***********************************************************************
341  *           get_trap_code
342  *
343  * Get the trap code for a signal.
344  */
345 static inline int get_trap_code( const SIGCONTEXT *sigcontext )
346 {
347 #ifdef TRAP_sig
348     return TRAP_sig(sigcontext);
349 #else
350     return T_UNKNOWN;  /* unknown trap code */
351 #endif
352 }
353
354 /***********************************************************************
355  *           save_context
356  *
357  * Set the register values from a sigcontext. 
358  */
359 static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext )
360 {
361     context->Eax    = EAX_sig(sigcontext);
362     context->Ebx    = EBX_sig(sigcontext);
363     context->Ecx    = ECX_sig(sigcontext);
364     context->Edx    = EDX_sig(sigcontext);
365     context->Esi    = ESI_sig(sigcontext);
366     context->Edi    = EDI_sig(sigcontext);
367     context->Ebp    = EBP_sig(sigcontext);
368     context->EFlags = EFL_sig(sigcontext);
369     context->Eip    = EIP_sig(sigcontext);
370     context->Esp    = ESP_sig(sigcontext);
371     context->SegCs  = LOWORD(CS_sig(sigcontext));
372     context->SegDs  = LOWORD(DS_sig(sigcontext));
373     context->SegEs  = LOWORD(ES_sig(sigcontext));
374     context->SegSs  = LOWORD(SS_sig(sigcontext));
375     /* %fs already handled in handler_init */
376 #ifdef GS_sig
377     context->SegGs  = LOWORD(GS_sig(sigcontext));
378 #else
379     context->SegGs  = __get_gs();
380 #endif
381     if (ISV86(context)) V86BASE(context) = (DWORD)DOSMEM_MemoryBase(0);
382 }
383
384
385 /***********************************************************************
386  *           restore_context
387  *
388  * Build a sigcontext from the register values.
389  */
390 static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
391 {
392     EAX_sig(sigcontext) = context->Eax;
393     EBX_sig(sigcontext) = context->Ebx;
394     ECX_sig(sigcontext) = context->Ecx;
395     EDX_sig(sigcontext) = context->Edx;
396     ESI_sig(sigcontext) = context->Esi;
397     EDI_sig(sigcontext) = context->Edi;
398     EBP_sig(sigcontext) = context->Ebp;
399     EFL_sig(sigcontext) = context->EFlags;
400     EIP_sig(sigcontext) = context->Eip;
401     ESP_sig(sigcontext) = context->Esp;
402     CS_sig(sigcontext)  = context->SegCs;
403     DS_sig(sigcontext)  = context->SegDs;
404     ES_sig(sigcontext)  = context->SegEs;
405     SS_sig(sigcontext)  = context->SegSs;
406 #ifdef FS_sig
407     FS_sig(sigcontext)  = context->SegFs;
408 #else
409     __set_fs( context->SegFs );
410 #endif
411 #ifdef GS_sig
412     GS_sig(sigcontext)  = context->SegGs;
413 #else
414     __set_gs( context->SegGs );
415 #endif
416 }
417
418
419 /***********************************************************************
420  *           save_fpu
421  *
422  * Set the FPU context from a sigcontext. 
423  */
424 static void inline save_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
425 {
426 #ifdef FPU_sig
427     if (FPU_sig(sigcontext))
428     {
429         context->FloatSave = *FPU_sig(sigcontext);
430         return;
431     }
432 #endif  /* FPU_sig */
433 #ifdef __GNUC__
434     __asm__ __volatile__( "fnsave %0; fwait" : "=m" (context->FloatSave) );
435 #endif  /* __GNUC__ */
436 }
437
438
439 /***********************************************************************
440  *           restore_fpu
441  *
442  * Restore the FPU context to a sigcontext. 
443  */
444 static void inline restore_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
445 {
446 #ifdef FPU_sig
447     if (FPU_sig(sigcontext))
448     {
449         *FPU_sig(sigcontext) = context->FloatSave;
450         return;
451     }
452 #endif  /* FPU_sig */
453 #ifdef __GNUC__
454     /* avoid nested exceptions */
455     context->FloatSave.StatusWord &= context->FloatSave.ControlWord | 0xffffff80;
456     __asm__ __volatile__( "frstor %0; fwait" : : "m" (context->FloatSave) );
457 #endif  /* __GNUC__ */
458 }
459
460
461 /**********************************************************************
462  *              get_fpu_code
463  *
464  * Get the FPU exception code from the FPU status.
465  */
466 static inline DWORD get_fpu_code( const CONTEXT *context )
467 {
468     DWORD status = context->FloatSave.StatusWord;
469
470     if (status & 0x01)  /* IE */
471     {
472         if (status & 0x40)  /* SF */
473             return EXCEPTION_FLT_STACK_CHECK;
474         else
475             return EXCEPTION_FLT_INVALID_OPERATION;
476     }
477     if (status & 0x02) return EXCEPTION_FLT_DENORMAL_OPERAND;  /* DE flag */
478     if (status & 0x04) return EXCEPTION_FLT_DIVIDE_BY_ZERO;    /* ZE flag */
479     if (status & 0x08) return EXCEPTION_FLT_OVERFLOW;          /* OE flag */
480     if (status & 0x10) return EXCEPTION_FLT_UNDERFLOW;         /* UE flag */
481     if (status & 0x20) return EXCEPTION_FLT_INEXACT_RESULT;    /* PE flag */
482     return EXCEPTION_FLT_INVALID_OPERATION;  /* generic error */
483 }
484
485
486 /**********************************************************************
487  *              segv_handler
488  *
489  * Handler for SIGSEGV and related errors.
490  */
491 static HANDLER_DEF(segv_handler)
492 {
493     EXCEPTION_RECORD rec;
494     CONTEXT context;
495     DWORD page_fault_code = EXCEPTION_ACCESS_VIOLATION;
496
497     handler_init( &context, HANDLER_CONTEXT );
498
499 #ifdef CR2_sig
500     /* we want the page-fault case to be fast */
501     if (get_trap_code(HANDLER_CONTEXT) == T_PAGEFLT)
502         if (!(page_fault_code = VIRTUAL_HandleFault( (LPVOID)CR2_sig(HANDLER_CONTEXT) ))) return;
503 #endif
504
505     save_context( &context, HANDLER_CONTEXT );
506     rec.ExceptionRecord  = NULL;
507     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
508     rec.ExceptionAddress = (LPVOID)context.Eip;
509     rec.NumberParameters = 0;
510
511     switch(get_trap_code(HANDLER_CONTEXT))
512     {
513     case T_OFLOW:   /* Overflow exception */
514         rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
515         break;
516     case T_BOUND:   /* Bound range exception */
517         rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
518         break;
519     case T_PRIVINFLT:   /* Invalid opcode exception */
520         rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
521         break;
522     case T_STKFLT:  /* Stack fault */
523         rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
524         break;
525     case T_SEGNPFLT:  /* Segment not present exception */
526     case T_PROTFLT:   /* General protection fault */
527     case T_UNKNOWN:   /* Unknown fault code */
528         if (INSTR_EmulateInstruction( &context )) goto restore;
529         rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
530         break;
531     case T_PAGEFLT:  /* Page fault */
532 #ifdef CR2_sig
533         rec.NumberParameters = 2;
534 #ifdef ERROR_sig
535         rec.ExceptionInformation[0] = (ERROR_sig(HANDLER_CONTEXT) & 2) != 0;
536 #else
537         rec.ExceptionInformation[0] = 0;
538 #endif /* ERROR_sig */
539         rec.ExceptionInformation[1] = CR2_sig(HANDLER_CONTEXT);
540 #endif /* CR2_sig */
541         rec.ExceptionCode = page_fault_code;
542         break;
543     case T_ALIGNFLT:  /* Alignment check exception */
544         /* FIXME: pass through exception handler first? */
545         if (context.EFlags & 0x00040000)
546         {
547             /* Disable AC flag, return */
548             context.EFlags &= ~0x00040000;
549             goto restore;
550         }
551         rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
552         break;
553     default:
554         ERR( "Got unexpected trap %d\n", get_trap_code(HANDLER_CONTEXT) );
555         /* fall through */
556     case T_NMI:       /* NMI interrupt */
557     case T_DNA:       /* Device not available exception */
558     case T_DOUBLEFLT: /* Double fault exception */
559     case T_TSSFLT:    /* Invalid TSS exception */
560     case T_RESERVED:  /* Unknown exception */
561     case T_MCHK:      /* Machine check exception */
562 #ifdef T_CACHEFLT
563     case T_CACHEFLT:  /* Cache flush exception */
564 #endif
565         rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
566         break;
567     }
568
569     EXC_RtlRaiseException( &rec, &context );
570  restore:
571     restore_context( &context, HANDLER_CONTEXT );
572 }
573
574
575 /**********************************************************************
576  *              trap_handler
577  *
578  * Handler for SIGTRAP.
579  */
580 static HANDLER_DEF(trap_handler)
581 {
582     EXCEPTION_RECORD rec;
583     CONTEXT context;
584
585     handler_init( &context, HANDLER_CONTEXT );
586
587     save_context( &context, HANDLER_CONTEXT );
588     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
589     rec.ExceptionRecord  = NULL;
590     rec.ExceptionAddress = (LPVOID)context.Eip;
591     rec.NumberParameters = 0;
592
593     switch(get_trap_code(HANDLER_CONTEXT))
594     {
595     case T_TRCTRAP:  /* Single-step exception */
596         rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
597         context.EFlags &= ~0x100;  /* clear single-step flag */
598         break;
599     case T_BPTFLT:   /* Breakpoint exception */
600         rec.ExceptionAddress = (char *) rec.ExceptionAddress - 1;  /* back up over the int3 instruction */
601         /* fall through */
602     default:
603         rec.ExceptionCode = EXCEPTION_BREAKPOINT;
604         break;
605     }
606     EXC_RtlRaiseException( &rec, &context );
607     restore_context( &context, HANDLER_CONTEXT );
608 }
609
610
611 /**********************************************************************
612  *              fpe_handler
613  *
614  * Handler for SIGFPE.
615  */
616 static HANDLER_DEF(fpe_handler)
617 {
618     EXCEPTION_RECORD rec;
619     CONTEXT context;
620
621     handler_init( &context, HANDLER_CONTEXT );
622
623     save_fpu( &context, HANDLER_CONTEXT );
624
625     switch(get_trap_code(HANDLER_CONTEXT))
626     {
627     case T_DIVIDE:   /* Division by zero exception */
628         rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
629         break;
630     case T_FPOPFLT:   /* Coprocessor segment overrun */
631         rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
632         break;
633     case T_ARITHTRAP:  /* Floating point exception */
634     case T_UNKNOWN:    /* Unknown fault code */
635         rec.ExceptionCode = get_fpu_code( &context );
636         break;
637     default:
638         ERR( "Got unexpected trap %d\n", get_trap_code(HANDLER_CONTEXT) );
639         rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
640         break;
641     }
642     save_context( &context, HANDLER_CONTEXT );
643     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
644     rec.ExceptionRecord  = NULL;
645     rec.ExceptionAddress = (LPVOID)context.Eip;
646     rec.NumberParameters = 0;
647     EXC_RtlRaiseException( &rec, &context );
648     restore_context( &context, HANDLER_CONTEXT );
649     restore_fpu( &context, HANDLER_CONTEXT );
650 }
651
652
653 /**********************************************************************
654  *              int_handler
655  *
656  * Handler for SIGINT.
657  */
658 static HANDLER_DEF(int_handler)
659 {
660     EXCEPTION_RECORD rec;
661     CONTEXT context;
662
663     handler_init( &context, HANDLER_CONTEXT );
664     save_context( &context, HANDLER_CONTEXT );
665     rec.ExceptionCode    = CONTROL_C_EXIT;
666     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
667     rec.ExceptionRecord  = NULL;
668     rec.ExceptionAddress = (LPVOID)context.Eip;
669     rec.NumberParameters = 0;
670     EXC_RtlRaiseException( &rec, &context );
671     restore_context( &context, HANDLER_CONTEXT );
672 }
673
674
675 /***********************************************************************
676  *           set_handler
677  *
678  * Set a signal handler
679  */
680 static int set_handler( int sig, int have_sigaltstack, void (*func)() )
681 {
682     struct sigaction sig_act;
683
684 #ifdef linux
685     if (!have_sigaltstack && NtCurrentTeb()->signal_stack)
686     {
687         struct kernel_sigaction sig_act;
688         sig_act.ksa_handler = func;
689         sig_act.ksa_flags   = SA_RESTART | SA_NOMASK;
690         sig_act.ksa_mask    = 0;
691         /* point to the top of the stack */
692         sig_act.ksa_restorer = (char *)NtCurrentTeb()->signal_stack + SIGNAL_STACK_SIZE;
693         return wine_sigaction( sig, &sig_act, NULL );
694     }
695 #endif  /* linux */
696     sig_act.sa_handler = func;
697     sigemptyset( &sig_act.sa_mask );
698
699 #ifdef linux
700     sig_act.sa_flags = SA_RESTART | SA_NOMASK;
701 #elif defined (__svr4__) || defined(_SCO_DS)
702     sig_act.sa_flags = SA_SIGINFO | SA_RESTART;
703 #else
704     sig_act.sa_flags = 0;
705 #endif
706
707 #ifdef SA_ONSTACK
708     if (have_sigaltstack) sig_act.sa_flags |= SA_ONSTACK;
709 #endif
710     return sigaction( sig, &sig_act, NULL );
711 }
712
713
714 /**********************************************************************
715  *              SIGNAL_Init
716  */
717 BOOL SIGNAL_Init(void)
718 {
719     int have_sigaltstack = 0;
720
721 #ifdef HAVE_SIGALTSTACK
722     struct sigaltstack ss;
723     if ((ss.ss_sp = NtCurrentTeb()->signal_stack))
724     {
725         ss.ss_size  = SIGNAL_STACK_SIZE;
726         ss.ss_flags = 0;
727         if (!sigaltstack(&ss, NULL)) have_sigaltstack = 1;
728 #ifdef linux
729         /* sigaltstack may fail because the kernel is too old, or
730            because glibc is brain-dead. In the latter case a
731            direct system call should succeed. */
732         else if (!wine_sigaltstack(&ss, NULL)) have_sigaltstack = 1;
733 #endif  /* linux */
734     }
735 #endif  /* HAVE_SIGALTSTACK */
736     
737     /* ignore SIGPIPE so that WINSOCK can get a EPIPE error instead  */
738     signal( SIGPIPE, SIG_IGN );
739     /* automatic child reaping to avoid zombies */
740     signal( SIGCHLD, SIG_IGN );
741
742     if (set_handler( SIGINT,  have_sigaltstack, (void (*)())int_handler ) == -1) goto error;
743     if (set_handler( SIGFPE,  have_sigaltstack, (void (*)())fpe_handler ) == -1) goto error;
744     if (set_handler( SIGSEGV, have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
745     if (set_handler( SIGILL,  have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
746 #ifdef SIGBUS
747     if (set_handler( SIGBUS,  have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
748 #endif
749 #ifdef SIGTRAP
750     if (set_handler( SIGTRAP, have_sigaltstack, (void (*)())trap_handler ) == -1) goto error;
751 #endif
752     return TRUE;
753
754  error:
755     perror("sigaction");
756     return FALSE;
757 }
758
759 /**********************************************************************
760  *              DbgBreakPoint   (NTDLL)
761  */
762 void WINAPI DbgBreakPoint(void);
763 __ASM_GLOBAL_FUNC( DbgBreakPoint, "int $3; ret");
764
765 /**********************************************************************
766  *              DbgUserBreakPoint   (NTDLL)
767  */
768 void WINAPI DbgUserBreakPoint(void);
769 __ASM_GLOBAL_FUNC( DbgUserBreakPoint, "int $3; ret");
770
771 #endif  /* __i386__ */