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