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 /* 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 */
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];
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];
102 /* FIXME: what if the current register window isn't saved? */
103 if ( ucontext->uc_mcontext.gwins && ucontext->uc_mcontext.gwins->wbcnt > 0 )
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];
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];
127 /**********************************************************************
130 static void restore_context( CONTEXT *context, ucontext_t *ucontext )
135 /**********************************************************************
138 static void save_fpu( CONTEXT *context, ucontext_t *ucontext )
143 /**********************************************************************
146 static void restore_fpu( CONTEXT *context, ucontext_t *ucontext )
152 /**********************************************************************
153 * call_stack_handlers
155 * Call the stack handlers chain.
157 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
159 EXCEPTION_POINTERS ptrs;
161 FIXME( "not implemented on Sparc\n" );
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;
171 /*******************************************************************
174 * Implementation of NtRaiseException.
176 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
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)
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] );
196 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
197 rec->ExceptionAddress,
198 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
202 /* FIXME: dump context */
205 status = send_debug_event( rec, TRUE, context );
206 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
207 return STATUS_SUCCESS;
209 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
210 return STATUS_SUCCESS;
212 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
216 /* last chance exception */
218 status = send_debug_event( rec, FALSE, context );
219 if (status != DBG_CONTINUE)
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");
226 ERR("Unhandled exception code %x flags %x addr %p\n",
227 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
228 NtTerminateProcess( NtCurrentProcess(), 1 );
230 return STATUS_SUCCESS;
234 /***********************************************************************
235 * RtlCaptureContext (NTDLL.@)
237 void WINAPI RtlCaptureContext( CONTEXT *context )
239 FIXME("not implemented\n");
240 memset( context, 0, sizeof(*context) );
244 /***********************************************************************
247 * Set the new CPU context.
249 void set_cpu_context( const CONTEXT *context )
251 FIXME("not implemented\n");
255 /***********************************************************************
258 * Copy a register context according to the flags.
260 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
262 flags &= ~CONTEXT_SPARC; /* get rid of CPU id */
263 if (flags & CONTEXT_CONTROL)
272 if (flags & CONTEXT_INTEGER)
307 if (flags & CONTEXT_FLOATING_POINT)
314 /***********************************************************************
317 * Convert a register context to the server format.
319 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
321 DWORD flags = from->ContextFlags & ~CONTEXT_SPARC; /* get rid of CPU id */
323 memset( to, 0, sizeof(*to) );
326 if (flags & CONTEXT_CONTROL)
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;
336 if (flags & CONTEXT_INTEGER)
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;
372 if (flags & CONTEXT_FLOATING_POINT)
376 return STATUS_SUCCESS;
380 /***********************************************************************
381 * context_from_server
383 * Convert a register context from the server format.
385 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
387 if (from->cpu != CPU_SPARC) return STATUS_INVALID_PARAMETER;
389 to->ContextFlags = CONTEXT_SPARC;
390 if (from->flags & SERVER_CTX_CONTROL)
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;
400 if (from->flags & SERVER_CTX_INTEGER)
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];
436 if (from->flags & SERVER_CTX_FLOATING_POINT)
440 return STATUS_SUCCESS;
444 /**********************************************************************
447 * Handler for SIGSEGV.
449 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
451 EXCEPTION_RECORD rec;
455 rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
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;
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;
469 status = raise_exception( &rec, &context, TRUE );
470 if (status) raise_status( status, &rec );
471 restore_context( &context, ucontext );
474 /**********************************************************************
477 * Handler for SIGBUS.
479 static void bus_handler( int signal, siginfo_t *info, void *ucontext )
481 EXCEPTION_RECORD rec;
485 save_context( &context, ucontext );
486 rec.ExceptionRecord = NULL;
487 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
488 rec.ExceptionAddress = (LPVOID)context.pc;
489 rec.NumberParameters = 0;
491 if ( info->si_code == BUS_ADRALN )
492 rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
494 rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
496 status = raise_exception( &rec, &context, TRUE );
497 if (status) raise_status( status, &rec );
498 restore_context( &context, ucontext );
501 /**********************************************************************
504 * Handler for SIGILL.
506 static void ill_handler( int signal, siginfo_t *info, void *ucontext )
508 EXCEPTION_RECORD rec;
512 switch ( info->si_code )
519 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
524 rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
528 rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
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 );
543 /**********************************************************************
546 * Handler for SIGTRAP.
548 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
550 EXCEPTION_RECORD rec;
554 switch ( info->si_code )
557 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
561 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
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 );
576 /**********************************************************************
579 * Handler for SIGFPE.
581 static void fpe_handler( int signal, siginfo_t *info, void *ucontext )
583 EXCEPTION_RECORD rec;
587 switch ( info->si_code )
590 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
593 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
596 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
599 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
602 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
605 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
608 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
612 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
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 );
629 /**********************************************************************
632 * Handler for SIGINT.
634 static void int_handler( int signal, siginfo_t *info, void *ucontext )
636 if (!dispatch_signal(SIGINT))
638 EXCEPTION_RECORD rec;
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 );
654 /**********************************************************************
657 * Handler for SIGABRT.
659 static void abrt_handler( int signal, struct siginfo *info, void *ucontext )
661 EXCEPTION_RECORD rec;
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 );
677 /**********************************************************************
680 * Handler for SIGQUIT.
682 static void quit_handler( int signal, struct siginfo *info, void *ucontext )
688 /**********************************************************************
691 * Handler for SIGUSR1, used to signal a thread that it got suspended.
693 static void usr1_handler( int signal, struct siginfo *info, void *ucontext )
697 save_context( &context, ucontext );
698 wait_suspend( &context );
699 restore_context( &context, ucontext );
703 /**********************************************************************
704 * get_signal_stack_total_size
706 * Retrieve the size to allocate for the signal stack, including the TEB at the bottom.
707 * Must be a power of two.
709 size_t get_signal_stack_total_size(void)
711 assert( sizeof(TEB) <= getpagesize() );
712 return getpagesize(); /* this is just for the TEB, we don't need a signal stack */
716 /***********************************************************************
717 * __wine_set_signal_handler (NTDLL.@)
719 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
721 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
722 if (handlers[sig] != NULL) return -2;
728 /**********************************************************************
731 void signal_init_thread( TEB *teb )
733 static int init_done;
737 pthread_key_create( &teb_key, NULL );
740 pthread_setspecific( teb_key, teb );
744 /**********************************************************************
745 * signal_init_process
747 void signal_init_process(void)
749 struct sigaction sig_act;
751 sig_act.sa_mask = server_block_set;
752 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
754 sig_act.sa_sigaction = int_handler;
755 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
756 sig_act.sa_sigaction = fpe_handler;
757 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
758 sig_act.sa_sigaction = abrt_handler;
759 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
760 sig_act.sa_sigaction = quit_handler;
761 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
762 sig_act.sa_sigaction = usr1_handler;
763 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
765 sig_act.sa_sigaction = segv_handler;
766 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
767 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
769 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
773 sig_act.sa_sigaction = trap_handler;
774 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
777 /* 'ta 6' tells the kernel to synthesize any unaligned accesses this
778 process makes, instead of just signalling an error and terminating
779 the process. wine-devel did not reach a conclusion on whether
780 this is correct, because that is what x86 does, or it is harmful
781 because it could obscure problems in user code */
782 asm("ta 6"); /* 6 == ST_FIX_ALIGN defined in sys/trap.h */
791 /**********************************************************************
794 void __wine_enter_vm86( CONTEXT *context )
796 MESSAGE("vm86 mode not supported on this platform\n");
799 /***********************************************************************
800 * RtlUnwind (NTDLL.@)
802 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
804 FIXME( "Not implemented on Sparc\n" );
807 /*******************************************************************
808 * NtRaiseException (NTDLL.@)
810 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
812 NTSTATUS status = raise_exception( rec, context, first_chance );
813 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
817 /***********************************************************************
818 * RtlRaiseException (NTDLL.@)
820 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
825 RtlCaptureContext( &context );
826 rec->ExceptionAddress = (void *)context.pc;
827 status = raise_exception( rec, &context, TRUE );
828 if (status) raise_status( status, rec );
831 /***********************************************************************
832 * call_thread_entry_point
834 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
838 exit_thread( entry( arg ));
840 __EXCEPT(unhandled_exception_filter)
842 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
845 abort(); /* should not be reached */
848 /***********************************************************************
849 * RtlExitUserThread (NTDLL.@)
851 void WINAPI RtlExitUserThread( ULONG status )
853 exit_thread( status );
856 /**********************************************************************
857 * DbgBreakPoint (NTDLL.@)
859 void WINAPI DbgBreakPoint(void)
861 kill(getpid(), SIGTRAP);
864 /**********************************************************************
865 * DbgUserBreakPoint (NTDLL.@)
867 void WINAPI DbgUserBreakPoint(void)
869 kill(getpid(), SIGTRAP);
872 /**********************************************************************
873 * NtCurrentTeb (NTDLL.@)
875 TEB * WINAPI NtCurrentTeb(void)
877 return pthread_getspecific( teb_key );
880 #endif /* __sparc__ */