2 * Sparc signal handling routines
4 * Copyright 1999 Ulrich Weigand
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
34 #include <sys/ucontext.h>
37 #define WIN32_NO_STATUS
42 #include "wine/exception.h"
43 #include "ntdll_misc.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(seh);
49 static pthread_key_t teb_key;
51 typedef int (*wine_signal_handler)(unsigned int sig);
53 static wine_signal_handler handlers[256];
55 /***********************************************************************
58 static inline int dispatch_signal(unsigned int sig)
60 if (handlers[sig] == NULL) return 0;
61 return handlers[sig](sig);
66 * FIXME: All this works only on Solaris for now
69 /**********************************************************************
72 static void save_context( CONTEXT *context, ucontext_t *ucontext )
74 context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
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 */
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];
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];
104 /* FIXME: what if the current register window isn't saved? */
105 if ( ucontext->uc_mcontext.gwins && ucontext->uc_mcontext.gwins->wbcnt > 0 )
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];
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];
129 /**********************************************************************
132 static void restore_context( CONTEXT *context, ucontext_t *ucontext )
137 /**********************************************************************
140 static void save_fpu( CONTEXT *context, ucontext_t *ucontext )
145 /**********************************************************************
148 static void restore_fpu( CONTEXT *context, ucontext_t *ucontext )
154 /**********************************************************************
155 * call_stack_handlers
157 * Call the stack handlers chain.
159 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
161 EXCEPTION_POINTERS ptrs;
163 FIXME( "not implemented on Sparc\n" );
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;
173 /*******************************************************************
176 * Implementation of NtRaiseException.
178 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
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)
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] );
198 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
199 rec->ExceptionAddress,
200 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
204 /* FIXME: dump context */
207 status = send_debug_event( rec, TRUE, context );
208 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
209 return STATUS_SUCCESS;
211 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
212 return STATUS_SUCCESS;
214 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
218 /* last chance exception */
220 status = send_debug_event( rec, FALSE, context );
221 if (status != DBG_CONTINUE)
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");
228 ERR("Unhandled exception code %x flags %x addr %p\n",
229 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
230 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
232 return STATUS_SUCCESS;
236 /***********************************************************************
237 * RtlCaptureContext (NTDLL.@)
239 void WINAPI RtlCaptureContext( CONTEXT *context )
241 FIXME("not implemented\n");
242 memset( context, 0, sizeof(*context) );
246 /***********************************************************************
249 * Set the new CPU context.
251 void set_cpu_context( const CONTEXT *context )
253 FIXME("not implemented\n");
257 /***********************************************************************
260 * Copy a register context according to the flags.
262 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
264 flags &= ~CONTEXT_SPARC; /* get rid of CPU id */
265 if (flags & CONTEXT_CONTROL)
274 if (flags & CONTEXT_INTEGER)
309 if (flags & CONTEXT_FLOATING_POINT)
316 /***********************************************************************
319 * Convert a register context to the server format.
321 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
323 DWORD flags = from->ContextFlags & ~CONTEXT_SPARC; /* get rid of CPU id */
325 memset( to, 0, sizeof(*to) );
328 if (flags & CONTEXT_CONTROL)
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;
338 if (flags & CONTEXT_INTEGER)
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;
374 if (flags & CONTEXT_FLOATING_POINT)
378 return STATUS_SUCCESS;
382 /***********************************************************************
383 * context_from_server
385 * Convert a register context from the server format.
387 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
389 if (from->cpu != CPU_SPARC) return STATUS_INVALID_PARAMETER;
391 to->ContextFlags = CONTEXT_SPARC;
392 if (from->flags & SERVER_CTX_CONTROL)
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;
402 if (from->flags & SERVER_CTX_INTEGER)
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];
438 if (from->flags & SERVER_CTX_FLOATING_POINT)
442 return STATUS_SUCCESS;
446 /**********************************************************************
449 * Handler for SIGSEGV.
451 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
453 EXCEPTION_RECORD rec;
457 rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
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;
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;
471 status = raise_exception( &rec, &context, TRUE );
472 if (status) raise_status( status, &rec );
473 restore_context( &context, ucontext );
476 /**********************************************************************
479 * Handler for SIGBUS.
481 static void bus_handler( int signal, siginfo_t *info, void *ucontext )
483 EXCEPTION_RECORD rec;
487 save_context( &context, ucontext );
488 rec.ExceptionRecord = NULL;
489 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
490 rec.ExceptionAddress = (LPVOID)context.pc;
491 rec.NumberParameters = 0;
493 if ( info->si_code == BUS_ADRALN )
494 rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
496 rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
498 status = raise_exception( &rec, &context, TRUE );
499 if (status) raise_status( status, &rec );
500 restore_context( &context, ucontext );
503 /**********************************************************************
506 * Handler for SIGILL.
508 static void ill_handler( int signal, siginfo_t *info, void *ucontext )
510 EXCEPTION_RECORD rec;
514 switch ( info->si_code )
521 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
526 rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
530 rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
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 );
545 /**********************************************************************
548 * Handler for SIGTRAP.
550 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
552 EXCEPTION_RECORD rec;
556 switch ( info->si_code )
559 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
563 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
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 );
578 /**********************************************************************
581 * Handler for SIGFPE.
583 static void fpe_handler( int signal, siginfo_t *info, void *ucontext )
585 EXCEPTION_RECORD rec;
589 switch ( info->si_code )
592 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
595 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
598 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
601 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
604 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
607 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
610 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
614 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
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 );
631 /**********************************************************************
634 * Handler for SIGINT.
636 static void int_handler( int signal, siginfo_t *info, void *ucontext )
638 if (!dispatch_signal(SIGINT))
640 EXCEPTION_RECORD rec;
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 );
656 /**********************************************************************
659 * Handler for SIGABRT.
661 static void abrt_handler( int signal, struct siginfo *info, void *ucontext )
663 EXCEPTION_RECORD rec;
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 );
679 /**********************************************************************
682 * Handler for SIGQUIT.
684 static void quit_handler( int signal, struct siginfo *info, void *ucontext )
690 /**********************************************************************
693 * Handler for SIGUSR1, used to signal a thread that it got suspended.
695 static void usr1_handler( int signal, struct siginfo *info, void *ucontext )
699 save_context( &context, ucontext );
700 wait_suspend( &context );
701 restore_context( &context, ucontext );
705 /***********************************************************************
706 * __wine_set_signal_handler (NTDLL.@)
708 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
710 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
711 if (handlers[sig] != NULL) return -2;
717 /**********************************************************************
718 * signal_alloc_thread
720 NTSTATUS signal_alloc_thread( TEB **teb )
722 static size_t sigstack_zero_bits;
726 if (!sigstack_zero_bits)
728 size_t min_size = page_size;
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 );
734 size = 1 << sigstack_zero_bits;
736 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
737 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
739 (*teb)->Tib.Self = &(*teb)->Tib;
740 (*teb)->Tib.ExceptionList = (void *)~0UL;
746 /**********************************************************************
749 void signal_free_thread( TEB *teb )
753 if (teb->DeallocationStack)
756 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
759 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
763 /**********************************************************************
766 void signal_init_thread( TEB *teb )
768 static int init_done;
772 pthread_key_create( &teb_key, NULL );
775 pthread_setspecific( teb_key, teb );
779 /**********************************************************************
780 * signal_init_process
782 void signal_init_process(void)
784 struct sigaction sig_act;
786 sig_act.sa_mask = server_block_set;
787 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
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;
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;
805 sig_act.sa_sigaction = bus_handler;
806 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
810 sig_act.sa_sigaction = trap_handler;
811 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
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 */
830 /**********************************************************************
833 void __wine_enter_vm86( CONTEXT *context )
835 MESSAGE("vm86 mode not supported on this platform\n");
838 /***********************************************************************
839 * RtlUnwind (NTDLL.@)
841 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
843 FIXME( "Not implemented on Sparc\n" );
846 /*******************************************************************
847 * NtRaiseException (NTDLL.@)
849 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
851 NTSTATUS status = raise_exception( rec, context, first_chance );
852 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
856 /***********************************************************************
857 * RtlRaiseException (NTDLL.@)
859 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
864 RtlCaptureContext( &context );
865 rec->ExceptionAddress = (void *)context.pc;
866 status = raise_exception( rec, &context, TRUE );
867 if (status) raise_status( status, rec );
870 /*************************************************************************
871 * RtlCaptureStackBackTrace (NTDLL.@)
873 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
875 FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
879 /***********************************************************************
880 * call_thread_entry_point
882 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
886 exit_thread( entry( arg ));
888 __EXCEPT(unhandled_exception_filter)
890 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
893 abort(); /* should not be reached */
896 /***********************************************************************
897 * RtlExitUserThread (NTDLL.@)
899 void WINAPI RtlExitUserThread( ULONG status )
901 exit_thread( status );
904 /***********************************************************************
907 void abort_thread( int status )
909 terminate_thread( status );
912 /**********************************************************************
913 * DbgBreakPoint (NTDLL.@)
915 void WINAPI DbgBreakPoint(void)
917 kill(getpid(), SIGTRAP);
920 /**********************************************************************
921 * DbgUserBreakPoint (NTDLL.@)
923 void WINAPI DbgUserBreakPoint(void)
925 kill(getpid(), SIGTRAP);
928 /**********************************************************************
929 * NtCurrentTeb (NTDLL.@)
931 TEB * WINAPI NtCurrentTeb(void)
933 return pthread_getspecific( teb_key );
936 #endif /* __sparc__ */