MSVC compatibility fixes.
[wine] / dlls / ntdll / signal_powerpc.c
1 /*
2  * PowerPC signal handling routines
3  *
4  * Copyright 2002 Marcus Meissner, SuSE Linux AG
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #ifdef __powerpc__
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <errno.h>
27 #include <signal.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33
34 #ifdef HAVE_SYS_PARAM_H
35 # include <sys/param.h>
36 #endif
37 #ifdef HAVE_SYSCALL_H
38 # include <syscall.h>
39 #else
40 # ifdef HAVE_SYS_SYSCALL_H
41 #  include <sys/syscall.h>
42 # endif
43 #endif
44
45 #ifdef HAVE_SYS_VM86_H
46 # include <sys/vm86.h>
47 #endif
48
49 #ifdef HAVE_SYS_SIGNAL_H
50 # include <sys/signal.h>
51 #endif
52
53 #include "ntddk.h"
54 #include "winnt.h"
55 #include "wine/library.h"
56
57 #include "selectors.h"
58
59 /***********************************************************************
60  * signal context platform-specific definitions
61  */
62
63 typedef struct ucontext SIGCONTEXT;
64
65 #define HANDLER_DEF(name) void name( int __signal, struct siginfo *__siginfo, SIGCONTEXT *__context )
66 #define HANDLER_CONTEXT (__context)
67
68 #include "wine/exception.h"
69 #include "winnt.h"
70 #include "stackframe.h"
71 #include "global.h"
72 #include "miscemu.h"
73 #include "ntddk.h"
74 #include "syslevel.h"
75 #include "wine/debug.h"
76
77 WINE_DEFAULT_DEBUG_CHANNEL(seh);
78
79 typedef int (*wine_signal_handler)(unsigned sig);
80
81 static wine_signal_handler handlers[256];
82
83 static sigset_t all_sigs;
84
85
86 /***********************************************************************
87  *           dispatch_signal
88  */
89 inline static int dispatch_signal(unsigned sig)
90 {
91     if (handlers[sig] == NULL) return 0;
92     return handlers[sig](sig);
93 }
94
95 /***********************************************************************
96  *           save_context
97  *
98  * Set the register values from a sigcontext.
99  */
100 static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext )
101 {
102 #define CX(x,y) context->x = sigcontext->uc_mcontext.regs->y
103 #define C(x) CX(Gpr##x,gpr[x])
104         C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
105         C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20);
106         C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
107         C(31);
108
109         CX(Fill[0],nip);
110         CX(Msr,msr);
111         CX(Ctr,ctr);
112 #undef CX
113         /* FIXME: fp regs? */
114
115         /* FIXME: missing pt_regs ...
116         unsigned long link;
117         unsigned long xer;
118         unsigned long ccr;
119         unsigned long mq;
120
121         unsigned long trap;
122         unsigned long dar;
123         unsigned long dsisr;
124
125         */
126 }
127
128
129 /***********************************************************************
130  *           restore_context
131  *
132  * Build a sigcontext from the register values.
133  */
134 static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
135 {
136 #define CX(x,y) sigcontext->uc_mcontext.regs->y = context->x
137         C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
138         C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19); C(20);
139         C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
140         C(31);
141
142         CX(Fill[0],nip);
143         CX(Msr,msr);
144         CX(Ctr,ctr);
145 #undef CX
146 }
147
148
149 /***********************************************************************
150  *           save_fpu
151  *
152  * Set the FPU context from a sigcontext.
153  */
154 inline static void save_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
155 {
156         /* FIXME? */
157 }
158
159
160 /***********************************************************************
161  *           restore_fpu
162  *
163  * Restore the FPU context to a sigcontext.
164  */
165 inline static void restore_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
166 {
167         /* FIXME? */
168 }
169
170
171 /**********************************************************************
172  *              get_fpu_code
173  *
174  * Get the FPU exception code from the FPU status.
175  */
176 static inline DWORD get_fpu_code( const CONTEXT *context )
177 {
178     DWORD status  = 0 /* FIXME */;
179
180     if (status & 0x01)  /* IE */
181     {
182         if (status & 0x40)  /* SF */
183             return EXCEPTION_FLT_STACK_CHECK;
184         else
185             return EXCEPTION_FLT_INVALID_OPERATION;
186     }
187     if (status & 0x02) return EXCEPTION_FLT_DENORMAL_OPERAND;  /* DE flag */
188     if (status & 0x04) return EXCEPTION_FLT_DIVIDE_BY_ZERO;    /* ZE flag */
189     if (status & 0x08) return EXCEPTION_FLT_OVERFLOW;          /* OE flag */
190     if (status & 0x10) return EXCEPTION_FLT_UNDERFLOW;         /* UE flag */
191     if (status & 0x20) return EXCEPTION_FLT_INEXACT_RESULT;    /* PE flag */
192     return EXCEPTION_FLT_INVALID_OPERATION;  /* generic error */
193 }
194
195
196 /***********************************************************************
197  *           SIGNAL_Unblock
198  *
199  * Unblock signals. Called from EXC_RtlRaiseException.
200  */
201 void SIGNAL_Unblock( void )
202 {
203     sigprocmask( SIG_UNBLOCK, &all_sigs, NULL );
204 }
205
206 /**********************************************************************
207  *              segv_handler
208  *
209  * Handler for SIGSEGV and related errors.
210  */
211 static HANDLER_DEF(segv_handler)
212 {
213     CONTEXT context;
214     EXCEPTION_RECORD rec;
215     DWORD page_fault_code = EXCEPTION_ACCESS_VIOLATION;
216
217     save_context( &context, HANDLER_CONTEXT );
218
219     rec.ExceptionRecord  = NULL;
220     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
221     rec.ExceptionAddress = (LPVOID)HANDLER_CONTEXT->uc_mcontext.regs->nip;
222     rec.NumberParameters = 0;
223     switch (__siginfo->si_signo) {
224     case SIGSEGV:
225         switch (__siginfo->si_code) {
226         case SEGV_MAPERR:
227         case SEGV_ACCERR:
228                 rec.NumberParameters = 2;
229                 rec.ExceptionInformation[0] = 0; /* FIXME ? */
230                 rec.ExceptionInformation[1] = (DWORD)__siginfo->si_addr;
231                 if (!(page_fault_code=VIRTUAL_HandleFault(__siginfo->si_addr)))
232                         return;
233                 rec.ExceptionCode = page_fault_code;
234                 break;
235         default:FIXME("Unhandled SIGSEGV/%x\n",__siginfo->si_code);
236                 break;
237         }
238         break;
239     case SIGBUS:
240         switch (__siginfo->si_code) {
241         case BUS_ADRALN:
242                 rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
243                 break;
244         case BUS_ADRERR:
245         case BUS_OBJERR:
246                 /* FIXME: correct for all cases ? */
247                 rec.NumberParameters = 2;
248                 rec.ExceptionInformation[0] = 0; /* FIXME ? */
249                 rec.ExceptionInformation[1] = (DWORD)__siginfo->si_addr;
250                 if (!(page_fault_code=VIRTUAL_HandleFault(__siginfo->si_addr)))
251                         return;
252                 rec.ExceptionCode = page_fault_code;
253                 break;
254         default:FIXME("Unhandled SIGBUS/%x\n",__siginfo->si_code);
255                 break;
256         }
257         break;
258     case SIGILL:
259         switch (__siginfo->si_code) {
260         case ILL_ILLOPC: /* illegal opcode */
261         case ILL_ILLOPN: /* illegal operand */
262         case ILL_ILLADR: /* illegal addressing mode */
263         case ILL_ILLTRP: /* illegal trap */
264         case ILL_COPROC: /* coprocessor error */
265                 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
266                 break;
267         case ILL_PRVOPC: /* privileged opcode */
268         case ILL_PRVREG: /* privileged register */
269                 rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
270                 break;
271         case ILL_BADSTK: /* internal stack error */
272                 rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
273                 break;
274         default:FIXME("Unhandled SIGILL/%x\n",__siginfo->si_code);
275                 break;
276         }
277         break;
278     }
279     EXC_RtlRaiseException( &rec, &context );
280     restore_context( &context, HANDLER_CONTEXT );
281 }
282
283 /**********************************************************************
284  *              trap_handler
285  *
286  * Handler for SIGTRAP.
287  */
288 static HANDLER_DEF(trap_handler)
289 {
290     CONTEXT context;
291     EXCEPTION_RECORD rec;
292
293     save_context( &context, HANDLER_CONTEXT );
294
295     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
296     rec.ExceptionRecord  = NULL;
297     rec.ExceptionAddress = (LPVOID)__context->uc_mcontext.regs->nip;
298     rec.NumberParameters = 0;
299
300     /* FIXME: check if we might need to modify PC */
301     switch (__siginfo->si_code) {
302     case TRAP_BRKPT:
303         rec.ExceptionCode = EXCEPTION_BREAKPOINT;
304         break;
305     case TRAP_TRACE:
306         rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
307         break;
308     }
309     EXC_RtlRaiseException( &rec, &context );
310     restore_context( &context, HANDLER_CONTEXT );
311 }
312
313
314 /**********************************************************************
315  *              fpe_handler
316  *
317  * Handler for SIGFPE.
318  */
319 static HANDLER_DEF(fpe_handler)
320 {
321     CONTEXT context;
322     EXCEPTION_RECORD rec;
323
324     /*save_fpu( &context, HANDLER_CONTEXT );*/
325     save_context( &context, HANDLER_CONTEXT );
326
327     switch ( __siginfo->si_code ) {
328     case FPE_FLTSUB:
329         rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
330         break;
331     case FPE_INTDIV:
332         rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
333         break;
334     case FPE_INTOVF:
335         rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
336         break;
337     case FPE_FLTDIV:
338         rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
339         break;
340     case FPE_FLTOVF:
341         rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
342         break;
343     case FPE_FLTUND:
344         rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
345         break;
346     case FPE_FLTRES:
347         rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
348         break;
349     case FPE_FLTINV:
350     default:
351         rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
352         break;
353     }
354     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
355     rec.ExceptionRecord  = NULL;
356     rec.ExceptionAddress = (LPVOID)__context->uc_mcontext.regs->nip;
357     rec.NumberParameters = 0;
358     EXC_RtlRaiseException( &rec, &context );
359     restore_context( &context, HANDLER_CONTEXT );
360     /*restore_fpu( &context, HANDLER_CONTEXT );*/
361 }
362
363
364 /**********************************************************************
365  *              int_handler
366  *
367  * Handler for SIGINT.
368  */
369 static HANDLER_DEF(int_handler)
370 {
371     if (!dispatch_signal(SIGINT))
372     {
373         EXCEPTION_RECORD rec;
374         CONTEXT context;
375
376         save_context( &context, HANDLER_CONTEXT );
377         rec.ExceptionCode    = CONTROL_C_EXIT;
378         rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
379         rec.ExceptionRecord  = NULL;
380         rec.ExceptionAddress = (LPVOID)context.Fill[0];
381         rec.NumberParameters = 0;
382         EXC_RtlRaiseException( &rec, &context );
383         restore_context( &context, HANDLER_CONTEXT );
384     }
385 }
386
387
388 /***********************************************************************
389  *           set_handler
390  *
391  * Set a signal handler
392  */
393 static int set_handler( int sig, int have_sigaltstack, void (*func)() )
394 {
395     struct sigaction sig_act;
396
397     sig_act.sa_sigaction = func;
398     sigemptyset( &sig_act.sa_mask );
399     sigaddset( &sig_act.sa_mask, SIGINT );
400     sigaddset( &sig_act.sa_mask, SIGALRM );
401
402     sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
403
404 #ifdef SA_ONSTACK
405     if (have_sigaltstack) sig_act.sa_flags |= SA_ONSTACK;
406 #endif
407     return sigaction( sig, &sig_act, NULL );
408 }
409
410
411 /***********************************************************************
412  *           __wine_set_signal_handler   (NTDLL.@)
413  */
414 int __wine_set_signal_handler(unsigned sig, wine_signal_handler wsh)
415 {
416     if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
417     if (handlers[sig] != NULL) return -2;
418     handlers[sig] = wsh;
419     return 0;
420 }
421
422
423 /**********************************************************************
424  *              SIGNAL_Init
425  */
426 BOOL SIGNAL_Init(void)
427 {
428     int have_sigaltstack = 0;
429
430 #ifdef HAVE_SIGALTSTACK
431     struct sigaltstack ss;
432     if ((ss.ss_sp = NtCurrentTeb()->signal_stack))
433     {
434         ss.ss_size  = SIGNAL_STACK_SIZE;
435         ss.ss_flags = 0;
436         if (!sigaltstack(&ss, NULL)) have_sigaltstack = 1;
437     }
438 #endif  /* HAVE_SIGALTSTACK */
439
440     sigfillset( &all_sigs );
441
442     if (set_handler( SIGINT,  have_sigaltstack, (void (*)())int_handler ) == -1) goto error;
443     if (set_handler( SIGFPE,  have_sigaltstack, (void (*)())fpe_handler ) == -1) goto error;
444     if (set_handler( SIGSEGV, have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
445     if (set_handler( SIGILL,  have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
446 #ifdef SIGBUS
447     if (set_handler( SIGBUS,  have_sigaltstack, (void (*)())segv_handler ) == -1) goto error;
448 #endif
449 #ifdef SIGTRAP
450     if (set_handler( SIGTRAP, have_sigaltstack, (void (*)())trap_handler ) == -1) goto error;
451 #endif
452
453     return TRUE;
454
455  error:
456     perror("sigaction");
457     return FALSE;
458 }
459
460
461 /**********************************************************************
462  *              SIGNAL_Reset
463  */
464 void SIGNAL_Reset(void)
465 {
466     sigset_t block_set;
467
468     /* block the async signals */
469     sigemptyset( &block_set );
470     sigaddset( &block_set, SIGALRM );
471     sigaddset( &block_set, SIGIO );
472     sigaddset( &block_set, SIGHUP );
473     sigaddset( &block_set, SIGUSR2 );
474     sigprocmask( SIG_BLOCK, &block_set, NULL );
475
476     /* restore default handlers */
477     signal( SIGINT, SIG_DFL );
478     signal( SIGFPE, SIG_DFL );
479     signal( SIGSEGV, SIG_DFL );
480     signal( SIGILL, SIG_DFL );
481 #ifdef SIGBUS
482     signal( SIGBUS, SIG_DFL );
483 #endif
484 #ifdef SIGTRAP
485     signal( SIGTRAP, SIG_DFL );
486 #endif
487 }
488
489 /**********************************************************************
490  *              __wine_enter_vm86   (NTDLL.@)
491  */
492 void __wine_enter_vm86( CONTEXT *context )
493 {
494     MESSAGE("vm86 mode not supported on this platform\n");
495 }
496
497 /**********************************************************************
498  *              DbgBreakPoint   (NTDLL.@)
499  */
500 void WINAPI DbgBreakPoint(void)
501 {
502      kill(getpid(), SIGTRAP);
503 }
504
505 /**********************************************************************
506  *              DbgUserBreakPoint   (NTDLL.@)
507  */
508 void WINAPI DbgUserBreakPoint(void)
509 {
510      kill(getpid(), SIGTRAP);
511 }
512
513 #endif  /* __powerpc__ */