ntdll: Always enable tail checking when running under Valgrind.
[wine] / dlls / ntdll / signal_sparc.c
1 /*
2  * Sparc signal handling routines
3  *
4  * Copyright 1999 Ulrich Weigand
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #ifdef __sparc__
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <signal.h>
28 #include <stdlib.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <sys/ucontext.h>
35
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
38 #include "windef.h"
39 #include "winternl.h"
40 #include "winnt.h"
41
42 #include "wine/exception.h"
43 #include "ntdll_misc.h"
44
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(seh);
48
49 static pthread_key_t teb_key;
50
51 typedef int (*wine_signal_handler)(unsigned int sig);
52
53 static wine_signal_handler handlers[256];
54
55 /***********************************************************************
56  *           dispatch_signal
57  */
58 static inline int dispatch_signal(unsigned int sig)
59 {
60     if (handlers[sig] == NULL) return 0;
61     return handlers[sig](sig);
62 }
63
64
65 /*
66  * FIXME:  All this works only on Solaris for now
67  */
68
69 /**********************************************************************
70  *              save_context
71  */
72 static void save_context( CONTEXT *context, ucontext_t *ucontext )
73 {
74     /* Special registers */
75     context->psr = ucontext->uc_mcontext.gregs[REG_PSR];
76     context->pc  = ucontext->uc_mcontext.gregs[REG_PC];
77     context->npc = ucontext->uc_mcontext.gregs[REG_nPC];
78     context->y   = ucontext->uc_mcontext.gregs[REG_Y];
79     context->wim = 0;  /* FIXME */
80     context->tbr = 0;  /* FIXME */
81
82     /* Global registers */
83     context->g0 = 0;  /* always */
84     context->g1 = ucontext->uc_mcontext.gregs[REG_G1];
85     context->g2 = ucontext->uc_mcontext.gregs[REG_G2];
86     context->g3 = ucontext->uc_mcontext.gregs[REG_G3];
87     context->g4 = ucontext->uc_mcontext.gregs[REG_G4];
88     context->g5 = ucontext->uc_mcontext.gregs[REG_G5];
89     context->g6 = ucontext->uc_mcontext.gregs[REG_G6];
90     context->g7 = ucontext->uc_mcontext.gregs[REG_G7];
91
92     /* Current 'out' registers */
93     context->o0 = ucontext->uc_mcontext.gregs[REG_O0];
94     context->o1 = ucontext->uc_mcontext.gregs[REG_O1];
95     context->o2 = ucontext->uc_mcontext.gregs[REG_O2];
96     context->o3 = ucontext->uc_mcontext.gregs[REG_O3];
97     context->o4 = ucontext->uc_mcontext.gregs[REG_O4];
98     context->o5 = ucontext->uc_mcontext.gregs[REG_O5];
99     context->o6 = ucontext->uc_mcontext.gregs[REG_O6];
100     context->o7 = ucontext->uc_mcontext.gregs[REG_O7];
101
102     /* FIXME: what if the current register window isn't saved? */
103     if ( ucontext->uc_mcontext.gwins && ucontext->uc_mcontext.gwins->wbcnt > 0 )
104     {
105         /* Current 'local' registers from first register window */
106         context->l0 = ucontext->uc_mcontext.gwins->wbuf[0].rw_local[0];
107         context->l1 = ucontext->uc_mcontext.gwins->wbuf[0].rw_local[1];
108         context->l2 = ucontext->uc_mcontext.gwins->wbuf[0].rw_local[2];
109         context->l3 = ucontext->uc_mcontext.gwins->wbuf[0].rw_local[3];
110         context->l4 = ucontext->uc_mcontext.gwins->wbuf[0].rw_local[4];
111         context->l5 = ucontext->uc_mcontext.gwins->wbuf[0].rw_local[5];
112         context->l6 = ucontext->uc_mcontext.gwins->wbuf[0].rw_local[6];
113         context->l7 = ucontext->uc_mcontext.gwins->wbuf[0].rw_local[7];
114
115         /* Current 'in' registers from first register window */
116         context->i0 = ucontext->uc_mcontext.gwins->wbuf[0].rw_in[0];
117         context->i1 = ucontext->uc_mcontext.gwins->wbuf[0].rw_in[1];
118         context->i2 = ucontext->uc_mcontext.gwins->wbuf[0].rw_in[2];
119         context->i3 = ucontext->uc_mcontext.gwins->wbuf[0].rw_in[3];
120         context->i4 = ucontext->uc_mcontext.gwins->wbuf[0].rw_in[4];
121         context->i5 = ucontext->uc_mcontext.gwins->wbuf[0].rw_in[5];
122         context->i6 = ucontext->uc_mcontext.gwins->wbuf[0].rw_in[6];
123         context->i7 = ucontext->uc_mcontext.gwins->wbuf[0].rw_in[7];
124     }
125 }
126
127 /**********************************************************************
128  *              restore_context
129  */
130 static void restore_context( CONTEXT *context, ucontext_t *ucontext )
131 {
132    /* FIXME */
133 }
134
135 /**********************************************************************
136  *              save_fpu
137  */
138 static void save_fpu( CONTEXT *context, ucontext_t *ucontext )
139 {
140    /* FIXME */
141 }
142
143 /**********************************************************************
144  *              restore_fpu
145  */
146 static void restore_fpu( CONTEXT *context, ucontext_t *ucontext )
147 {
148    /* FIXME */
149 }
150
151
152 /**********************************************************************
153  *           call_stack_handlers
154  *
155  * Call the stack handlers chain.
156  */
157 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
158 {
159     EXCEPTION_POINTERS ptrs;
160
161     FIXME( "not implemented on Sparc\n" );
162
163     /* hack: call unhandled exception filter directly */
164     ptrs.ExceptionRecord = rec;
165     ptrs.ContextRecord = context;
166     unhandled_exception_filter( &ptrs );
167     return STATUS_UNHANDLED_EXCEPTION;
168 }
169
170
171 /*******************************************************************
172  *              raise_exception
173  *
174  * Implementation of NtRaiseException.
175  */
176 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
177 {
178     NTSTATUS status;
179
180     if (first_chance)
181     {
182         DWORD c;
183
184         TRACE( "code=%x flags=%x addr=%p ip=%x tid=%04x\n",
185                rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
186                context->pc, GetCurrentThreadId() );
187         for (c = 0; c < rec->NumberParameters; c++)
188             TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
189         if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
190         {
191             if (rec->ExceptionInformation[1] >> 16)
192                 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
193                          rec->ExceptionAddress,
194                          (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
195             else
196                 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
197                          rec->ExceptionAddress,
198                          (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
199         }
200         else
201         {
202             /* FIXME: dump context */
203         }
204
205         status = send_debug_event( rec, TRUE, context );
206         if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
207             return STATUS_SUCCESS;
208
209         if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
210             return STATUS_SUCCESS;
211
212         if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
213             return status;
214     }
215
216     /* last chance exception */
217
218     status = send_debug_event( rec, FALSE, context );
219     if (status != DBG_CONTINUE)
220     {
221         if (rec->ExceptionFlags & EH_STACK_INVALID)
222             ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
223         else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
224             ERR("Process attempted to continue execution after noncontinuable exception.\n");
225         else
226             ERR("Unhandled exception code %x flags %x addr %p\n",
227                 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
228         NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
229     }
230     return STATUS_SUCCESS;
231 }
232
233
234 /***********************************************************************
235  *              RtlCaptureContext (NTDLL.@)
236  */
237 void WINAPI RtlCaptureContext( CONTEXT *context )
238 {
239     FIXME("not implemented\n");
240     memset( context, 0, sizeof(*context) );
241 }
242
243
244 /***********************************************************************
245  *           set_cpu_context
246  *
247  * Set the new CPU context.
248  */
249 void set_cpu_context( const CONTEXT *context )
250 {
251     FIXME("not implemented\n");
252 }
253
254
255 /***********************************************************************
256  *           copy_context
257  *
258  * Copy a register context according to the flags.
259  */
260 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
261 {
262     flags &= ~CONTEXT_SPARC;  /* get rid of CPU id */
263     if (flags & CONTEXT_CONTROL)
264     {
265         to->psr = from->psr;
266         to->pc  = from->pc;
267         to->npc = from->npc;
268         to->y   = from->y;
269         to->wim = from->wim;
270         to->tbr = from->tbr;
271     }
272     if (flags & CONTEXT_INTEGER)
273     {
274         to->g0 = from->g0;
275         to->g1 = from->g1;
276         to->g2 = from->g2;
277         to->g3 = from->g3;
278         to->g4 = from->g4;
279         to->g5 = from->g5;
280         to->g6 = from->g6;
281         to->g7 = from->g7;
282         to->o0 = from->o0;
283         to->o1 = from->o1;
284         to->o2 = from->o2;
285         to->o3 = from->o3;
286         to->o4 = from->o4;
287         to->o5 = from->o5;
288         to->o6 = from->o6;
289         to->o7 = from->o7;
290         to->l0 = from->l0;
291         to->l1 = from->l1;
292         to->l2 = from->l2;
293         to->l3 = from->l3;
294         to->l4 = from->l4;
295         to->l5 = from->l5;
296         to->l6 = from->l6;
297         to->l7 = from->l7;
298         to->i0 = from->i0;
299         to->i1 = from->i1;
300         to->i2 = from->i2;
301         to->i3 = from->i3;
302         to->i4 = from->i4;
303         to->i5 = from->i5;
304         to->i6 = from->i6;
305         to->i7 = from->i7;
306     }
307     if (flags & CONTEXT_FLOATING_POINT)
308     {
309         /* FIXME */
310     }
311 }
312
313
314 /***********************************************************************
315  *           context_to_server
316  *
317  * Convert a register context to the server format.
318  */
319 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
320 {
321     DWORD flags = from->ContextFlags & ~CONTEXT_SPARC;  /* get rid of CPU id */
322
323     memset( to, 0, sizeof(*to) );
324     to->cpu = CPU_SPARC;
325
326     if (flags & CONTEXT_CONTROL)
327     {
328         to->flags |= SERVER_CTX_CONTROL;
329         to->ctl.sparc_regs.psr = from->psr;
330         to->ctl.sparc_regs.pc  = from->pc;
331         to->ctl.sparc_regs.npc = from->npc;
332         to->ctl.sparc_regs.y   = from->y;
333         to->ctl.sparc_regs.wim = from->wim;
334         to->ctl.sparc_regs.tbr = from->tbr;
335     }
336     if (flags & CONTEXT_INTEGER)
337     {
338         to->flags |= SERVER_CTX_INTEGER;
339         to->integer.sparc_regs.g[0] = from->g0;
340         to->integer.sparc_regs.g[1] = from->g1;
341         to->integer.sparc_regs.g[2] = from->g2;
342         to->integer.sparc_regs.g[3] = from->g3;
343         to->integer.sparc_regs.g[4] = from->g4;
344         to->integer.sparc_regs.g[5] = from->g5;
345         to->integer.sparc_regs.g[6] = from->g6;
346         to->integer.sparc_regs.g[7] = from->g7;
347         to->integer.sparc_regs.o[0] = from->o0;
348         to->integer.sparc_regs.o[1] = from->o1;
349         to->integer.sparc_regs.o[2] = from->o2;
350         to->integer.sparc_regs.o[3] = from->o3;
351         to->integer.sparc_regs.o[4] = from->o4;
352         to->integer.sparc_regs.o[5] = from->o5;
353         to->integer.sparc_regs.o[6] = from->o6;
354         to->integer.sparc_regs.o[7] = from->o7;
355         to->integer.sparc_regs.l[0] = from->l0;
356         to->integer.sparc_regs.l[1] = from->l1;
357         to->integer.sparc_regs.l[2] = from->l2;
358         to->integer.sparc_regs.l[3] = from->l3;
359         to->integer.sparc_regs.l[4] = from->l4;
360         to->integer.sparc_regs.l[5] = from->l5;
361         to->integer.sparc_regs.l[6] = from->l6;
362         to->integer.sparc_regs.l[7] = from->l7;
363         to->integer.sparc_regs.i[0] = from->i0;
364         to->integer.sparc_regs.i[1] = from->i1;
365         to->integer.sparc_regs.i[2] = from->i2;
366         to->integer.sparc_regs.i[3] = from->i3;
367         to->integer.sparc_regs.i[4] = from->i4;
368         to->integer.sparc_regs.i[5] = from->i5;
369         to->integer.sparc_regs.i[6] = from->i6;
370         to->integer.sparc_regs.i[7] = from->i7;
371     }
372     if (flags & CONTEXT_FLOATING_POINT)
373     {
374         /* FIXME */
375     }
376     return STATUS_SUCCESS;
377 }
378
379
380 /***********************************************************************
381  *           context_from_server
382  *
383  * Convert a register context from the server format.
384  */
385 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
386 {
387     if (from->cpu != CPU_SPARC) return STATUS_INVALID_PARAMETER;
388
389     to->ContextFlags = CONTEXT_SPARC;
390     if (from->flags & SERVER_CTX_CONTROL)
391     {
392         to->ContextFlags |= CONTEXT_CONTROL;
393         to->psr = from->ctl.sparc_regs.psr;
394         to->pc  = from->ctl.sparc_regs.pc;
395         to->npc = from->ctl.sparc_regs.npc;
396         to->y   = from->ctl.sparc_regs.y;
397         to->wim = from->ctl.sparc_regs.wim;
398         to->tbr = from->ctl.sparc_regs.tbr;
399     }
400     if (from->flags & SERVER_CTX_INTEGER)
401     {
402         to->ContextFlags |= CONTEXT_INTEGER;
403         to->g0 = from->integer.sparc_regs.g[0];
404         to->g1 = from->integer.sparc_regs.g[1];
405         to->g2 = from->integer.sparc_regs.g[2];
406         to->g3 = from->integer.sparc_regs.g[3];
407         to->g4 = from->integer.sparc_regs.g[4];
408         to->g5 = from->integer.sparc_regs.g[5];
409         to->g6 = from->integer.sparc_regs.g[6];
410         to->g7 = from->integer.sparc_regs.g[7];
411         to->o0 = from->integer.sparc_regs.o[0];
412         to->o1 = from->integer.sparc_regs.o[1];
413         to->o2 = from->integer.sparc_regs.o[2];
414         to->o3 = from->integer.sparc_regs.o[3];
415         to->o4 = from->integer.sparc_regs.o[4];
416         to->o5 = from->integer.sparc_regs.o[5];
417         to->o6 = from->integer.sparc_regs.o[6];
418         to->o7 = from->integer.sparc_regs.o[7];
419         to->l0 = from->integer.sparc_regs.l[0];
420         to->l1 = from->integer.sparc_regs.l[1];
421         to->l2 = from->integer.sparc_regs.l[2];
422         to->l3 = from->integer.sparc_regs.l[3];
423         to->l4 = from->integer.sparc_regs.l[4];
424         to->l5 = from->integer.sparc_regs.l[5];
425         to->l6 = from->integer.sparc_regs.l[6];
426         to->l7 = from->integer.sparc_regs.l[7];
427         to->i0 = from->integer.sparc_regs.i[0];
428         to->i1 = from->integer.sparc_regs.i[1];
429         to->i2 = from->integer.sparc_regs.i[2];
430         to->i3 = from->integer.sparc_regs.i[3];
431         to->i4 = from->integer.sparc_regs.i[4];
432         to->i5 = from->integer.sparc_regs.i[5];
433         to->i6 = from->integer.sparc_regs.i[6];
434         to->i7 = from->integer.sparc_regs.i[7];
435     }
436     if (from->flags & SERVER_CTX_FLOATING_POINT)
437     {
438         /* FIXME */
439     }
440     return STATUS_SUCCESS;
441 }
442
443
444 /**********************************************************************
445  *              segv_handler
446  *
447  * Handler for SIGSEGV.
448  */
449 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
450 {
451     EXCEPTION_RECORD rec;
452     CONTEXT context;
453     NTSTATUS status;
454
455     rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
456
457     /* we want the page-fault case to be fast */
458     if ( info->si_code == SEGV_ACCERR )
459         if (!(rec.ExceptionCode = virtual_handle_fault( info->si_addr, 0 ))) return;
460
461     save_context( &context, ucontext );
462     rec.ExceptionRecord  = NULL;
463     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
464     rec.ExceptionAddress = (LPVOID)context.pc;
465     rec.NumberParameters = 2;
466     rec.ExceptionInformation[0] = 0;  /* FIXME: read/write access ? */
467     rec.ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
468
469     status = raise_exception( &rec, &context, TRUE );
470     if (status) raise_status( status, &rec );
471     restore_context( &context, ucontext );
472 }
473
474 /**********************************************************************
475  *              bus_handler
476  *
477  * Handler for SIGBUS.
478  */
479 static void bus_handler( int signal, siginfo_t *info, void *ucontext )
480 {
481     EXCEPTION_RECORD rec;
482     CONTEXT context;
483     NTSTATUS status;
484
485     save_context( &context, ucontext );
486     rec.ExceptionRecord  = NULL;
487     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
488     rec.ExceptionAddress = (LPVOID)context.pc;
489     rec.NumberParameters = 0;
490
491     if ( info->si_code == BUS_ADRALN )
492         rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
493     else
494         rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
495
496     status = raise_exception( &rec, &context, TRUE );
497     if (status) raise_status( status, &rec );
498     restore_context( &context, ucontext );
499 }
500
501 /**********************************************************************
502  *              ill_handler
503  *
504  * Handler for SIGILL.
505  */
506 static void ill_handler( int signal, siginfo_t *info, void *ucontext )
507 {
508     EXCEPTION_RECORD rec;
509     CONTEXT context;
510     NTSTATUS status;
511
512     switch ( info->si_code )
513     {
514     default:
515     case ILL_ILLOPC:
516     case ILL_ILLOPN:
517     case ILL_ILLADR:
518     case ILL_ILLTRP:
519         rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
520         break;
521
522     case ILL_PRVOPC:
523     case ILL_PRVREG:
524         rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
525         break;
526
527     case ILL_BADSTK:
528         rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
529         break;
530     }
531
532     save_context( &context, ucontext );
533     rec.ExceptionRecord  = NULL;
534     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
535     rec.ExceptionAddress = (LPVOID)context.pc;
536     rec.NumberParameters = 0;
537     status = raise_exception( &rec, &context, TRUE );
538     if (status) raise_status( status, &rec );
539     restore_context( &context, ucontext );
540 }
541
542
543 /**********************************************************************
544  *              trap_handler
545  *
546  * Handler for SIGTRAP.
547  */
548 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
549 {
550     EXCEPTION_RECORD rec;
551     CONTEXT context;
552     NTSTATUS status;
553
554     switch ( info->si_code )
555     {
556     case TRAP_TRACE:
557         rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
558         break;
559     case TRAP_BRKPT:
560     default:
561         rec.ExceptionCode = EXCEPTION_BREAKPOINT;
562         break;
563     }
564
565     save_context( &context, ucontext );
566     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
567     rec.ExceptionRecord  = NULL;
568     rec.ExceptionAddress = (LPVOID)context.pc;
569     rec.NumberParameters = 0;
570     status = raise_exception( &rec, &context, TRUE );
571     if (status) raise_status( status, &rec );
572     restore_context( &context, ucontext );
573 }
574
575
576 /**********************************************************************
577  *              fpe_handler
578  *
579  * Handler for SIGFPE.
580  */
581 static void fpe_handler( int signal, siginfo_t *info, void *ucontext )
582 {
583     EXCEPTION_RECORD rec;
584     CONTEXT context;
585     NTSTATUS status;
586
587     switch ( info->si_code )
588     {
589     case FPE_FLTSUB:
590         rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
591         break;
592     case FPE_INTDIV:
593         rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
594         break;
595     case FPE_INTOVF:
596         rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
597         break;
598     case FPE_FLTDIV:
599         rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
600         break;
601     case FPE_FLTOVF:
602         rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
603         break;
604     case FPE_FLTUND:
605         rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
606         break;
607     case FPE_FLTRES:
608         rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
609         break;
610     case FPE_FLTINV:
611     default:
612         rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
613         break;
614     }
615
616     save_context( &context, ucontext );
617     save_fpu( &context, ucontext );
618     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
619     rec.ExceptionRecord  = NULL;
620     rec.ExceptionAddress = (LPVOID)context.pc;
621     rec.NumberParameters = 0;
622     status = raise_exception( &rec, &context, TRUE );
623     if (status) raise_status( status, &rec );
624     restore_context( &context, ucontext );
625     restore_fpu( &context, ucontext );
626 }
627
628
629 /**********************************************************************
630  *              int_handler
631  *
632  * Handler for SIGINT.
633  */
634 static void int_handler( int signal, siginfo_t *info, void *ucontext )
635 {
636     if (!dispatch_signal(SIGINT))
637     {
638         EXCEPTION_RECORD rec;
639         CONTEXT context;
640         NTSTATUS status;
641
642         save_context( &context, ucontext );
643         rec.ExceptionCode    = CONTROL_C_EXIT;
644         rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
645         rec.ExceptionRecord  = NULL;
646         rec.ExceptionAddress = (LPVOID)context.pc;
647         rec.NumberParameters = 0;
648         status = raise_exception( &rec, &context, TRUE );
649         if (status) raise_status( status, &rec );
650         restore_context( &context, ucontext );
651     }
652 }
653
654 /**********************************************************************
655  *              abrt_handler
656  *
657  * Handler for SIGABRT.
658  */
659 static void abrt_handler( int signal, struct siginfo *info, void *ucontext )
660 {
661     EXCEPTION_RECORD rec;
662     CONTEXT context;
663     NTSTATUS status;
664
665     save_context( &context, ucontext );
666     rec.ExceptionCode    = EXCEPTION_WINE_ASSERTION;
667     rec.ExceptionFlags   = EH_NONCONTINUABLE;
668     rec.ExceptionRecord  = NULL;
669     rec.ExceptionAddress = (LPVOID)context.pc;
670     rec.NumberParameters = 0;
671     status = raise_exception( &rec, &context, TRUE );
672     if (status) raise_status( status, &rec );
673     restore_context( &context, ucontext );
674 }
675
676
677 /**********************************************************************
678  *              quit_handler
679  *
680  * Handler for SIGQUIT.
681  */
682 static void quit_handler( int signal, struct siginfo *info, void *ucontext )
683 {
684     abort_thread(0);
685 }
686
687
688 /**********************************************************************
689  *              usr1_handler
690  *
691  * Handler for SIGUSR1, used to signal a thread that it got suspended.
692  */
693 static void usr1_handler( int signal, struct siginfo *info, void *ucontext )
694 {
695     CONTEXT context;
696
697     save_context( &context, ucontext );
698     wait_suspend( &context );
699     restore_context( &context, ucontext );
700 }
701
702
703 /***********************************************************************
704  *           __wine_set_signal_handler   (NTDLL.@)
705  */
706 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
707 {
708     if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
709     if (handlers[sig] != NULL) return -2;
710     handlers[sig] = wsh;
711     return 0;
712 }
713
714
715 /**********************************************************************
716  *              signal_alloc_thread
717  */
718 NTSTATUS signal_alloc_thread( TEB **teb )
719 {
720     static size_t sigstack_zero_bits;
721     SIZE_T size;
722     NTSTATUS status;
723
724     if (!sigstack_zero_bits)
725     {
726         size_t min_size = getpagesize();  /* this is just for the TEB, we don't use a signal stack yet */
727         /* find the first power of two not smaller than min_size */
728         while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
729         assert( sizeof(TEB) <= min_size );
730     }
731
732     size = 1 << sigstack_zero_bits;
733     *teb = NULL;
734     if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
735                                             &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
736     {
737         (*teb)->Tib.Self = &(*teb)->Tib;
738         (*teb)->Tib.ExceptionList = (void *)~0UL;
739     }
740     return status;
741 }
742
743
744 /**********************************************************************
745  *              signal_free_thread
746  */
747 void signal_free_thread( TEB *teb )
748 {
749     SIZE_T size;
750
751     if (teb->DeallocationStack)
752     {
753         size = 0;
754         NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
755     }
756     size = 0;
757     NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
758 }
759
760
761 /**********************************************************************
762  *              signal_init_thread
763  */
764 void signal_init_thread( TEB *teb )
765 {
766     static int init_done;
767
768     if (!init_done)
769     {
770         pthread_key_create( &teb_key, NULL );
771         init_done = 1;
772     }
773     pthread_setspecific( teb_key, teb );
774 }
775
776
777 /**********************************************************************
778  *              signal_init_process
779  */
780 void signal_init_process(void)
781 {
782     struct sigaction sig_act;
783
784     sig_act.sa_mask = server_block_set;
785     sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
786
787     sig_act.sa_sigaction = int_handler;
788     if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
789     sig_act.sa_sigaction = fpe_handler;
790     if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
791     sig_act.sa_sigaction = abrt_handler;
792     if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
793     sig_act.sa_sigaction = quit_handler;
794     if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
795     sig_act.sa_sigaction = usr1_handler;
796     if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
797
798     sig_act.sa_sigaction = segv_handler;
799     if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
800     if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
801 #ifdef SIGBUS
802     if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
803 #endif
804
805 #ifdef SIGTRAP
806     sig_act.sa_sigaction = trap_handler;
807     if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
808 #endif
809
810     /* 'ta 6' tells the kernel to synthesize any unaligned accesses this 
811        process makes, instead of just signalling an error and terminating
812        the process.  wine-devel did not reach a conclusion on whether
813        this is correct, because that is what x86 does, or it is harmful 
814        because it could obscure problems in user code */
815     __asm__("ta 6"); /* 6 == ST_FIX_ALIGN defined in sys/trap.h */
816     return;
817
818  error:
819     perror("sigaction");
820     exit(1);
821 }
822
823
824 /**********************************************************************
825  *              __wine_enter_vm86
826  */
827 void __wine_enter_vm86( CONTEXT *context )
828 {
829     MESSAGE("vm86 mode not supported on this platform\n");
830 }
831
832 /***********************************************************************
833  *            RtlUnwind  (NTDLL.@)
834  */
835 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
836 {
837     FIXME( "Not implemented on Sparc\n" );
838 }
839
840 /*******************************************************************
841  *              NtRaiseException (NTDLL.@)
842  */
843 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
844 {
845     NTSTATUS status = raise_exception( rec, context, first_chance );
846     if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
847     return status;
848 }
849
850 /***********************************************************************
851  *              RtlRaiseException (NTDLL.@)
852  */
853 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
854 {
855     CONTEXT context;
856     NTSTATUS status;
857
858     RtlCaptureContext( &context );
859     rec->ExceptionAddress = (void *)context.pc;
860     status = raise_exception( rec, &context, TRUE );
861     if (status) raise_status( status, rec );
862 }
863
864 /*************************************************************************
865  *              RtlCaptureStackBackTrace (NTDLL.@)
866  */
867 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
868 {
869     FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
870     return 0;
871 }
872
873 /***********************************************************************
874  *           call_thread_entry_point
875  */
876 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
877 {
878     __TRY
879     {
880         exit_thread( entry( arg ));
881     }
882     __EXCEPT(unhandled_exception_filter)
883     {
884         NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
885     }
886     __ENDTRY
887     abort();  /* should not be reached */
888 }
889
890 /***********************************************************************
891  *           RtlExitUserThread  (NTDLL.@)
892  */
893 void WINAPI RtlExitUserThread( ULONG status )
894 {
895     exit_thread( status );
896 }
897
898 /***********************************************************************
899  *           abort_thread
900  */
901 void abort_thread( int status )
902 {
903     terminate_thread( status );
904 }
905
906 /**********************************************************************
907  *              DbgBreakPoint   (NTDLL.@)
908  */
909 void WINAPI DbgBreakPoint(void)
910 {
911      kill(getpid(), SIGTRAP);
912 }
913
914 /**********************************************************************
915  *              DbgUserBreakPoint   (NTDLL.@)
916  */
917 void WINAPI DbgUserBreakPoint(void)
918 {
919      kill(getpid(), SIGTRAP);
920 }
921
922 /**********************************************************************
923  *           NtCurrentTeb   (NTDLL.@)
924  */
925 TEB * WINAPI NtCurrentTeb(void)
926 {
927     return pthread_getspecific( teb_key );
928 }
929
930 #endif  /* __sparc__ */