ntdll: Add ARM support.
[wine/multimedia.git] / dlls / ntdll / signal_arm.c
blob992b63c6db26392590f41fcd7061947454bf8122
1 /*
2 * ARM signal handling routines
4 * Copyright 2002 Marcus Meissner, SuSE Linux AG
5 * Copyright 2010 André Hentschel
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #ifdef __arm__
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 #ifdef HAVE_SYSCALL_H
40 # include <syscall.h>
41 #else
42 # ifdef HAVE_SYS_SYSCALL_H
43 # include <sys/syscall.h>
44 # endif
45 #endif
46 #ifdef HAVE_SYS_SIGNAL_H
47 # include <sys/signal.h>
48 #endif
50 #include "ntstatus.h"
51 #define WIN32_NO_STATUS
52 #include "windef.h"
53 #include "winternl.h"
54 #include "wine/library.h"
55 #include "wine/exception.h"
56 #include "ntdll_misc.h"
57 #include "wine/debug.h"
58 #include "winnt.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(seh);
62 static pthread_key_t teb_key;
64 /***********************************************************************
65 * signal context platform-specific definitions
67 #ifdef linux
69 /* All Registers access - only for local access */
70 # define REG_sig(reg_name, context) ((context)->uc_mcontext.reg_name)
71 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.arm_r##reg_num)
73 /* Special Registers access */
74 # define SP_sig(context) REG_sig(arm_sp, context) /* Stack pointer */
75 # define LR_sig(context) REG_sig(arm_lr, context) /* Link register */
76 # define PC_sig(context) REG_sig(arm_pc, context) /* Program counter */
77 # define CPSR_sig(context) REG_sig(arm_cpsr, context) /* Current State Register */
78 # define IP_sig(context) REG_sig(arm_ip, context) /* Program counter (2?) */
79 # define FP_sig(context) REG_sig(arm_fp, context) /* Frame pointer */
81 #endif /* linux */
83 typedef int (*wine_signal_handler)(unsigned int sig);
85 static wine_signal_handler handlers[256];
87 /***********************************************************************
88 * dispatch_signal
90 static inline int dispatch_signal(unsigned int sig)
92 if (handlers[sig] == NULL) return 0;
93 return handlers[sig](sig);
96 /***********************************************************************
97 * save_context
99 * Set the register values from a sigcontext.
101 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
103 #define C(x) context->R##x = REGn_sig(x,sigcontext)
104 /* Save normal registers */
105 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
106 #undef C
108 context->Sp = SP_sig(sigcontext); /* Stack pointer */
109 context->Lr = LR_sig(sigcontext); /* Link register */
110 context->Pc = PC_sig(sigcontext); /* Program Counter */
111 context->Cpsr = CPSR_sig(sigcontext); /* Current State Register */
112 context->Ip = IP_sig(sigcontext); /* Intra-Procedure-call scratch register */
113 context->Fp = FP_sig(sigcontext); /* Frame pointer */
117 /***********************************************************************
118 * restore_context
120 * Build a sigcontext from the register values.
122 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
124 #define C(x) REGn_sig(x,sigcontext) = context->R##x
125 /* Restore normal registers */
126 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
127 #undef C
129 SP_sig(sigcontext) = context->Sp; /* Stack pointer */
130 LR_sig(sigcontext) = context->Lr ; /* Link register */
131 PC_sig(sigcontext) = context->Pc; /* Program Counter */
132 CPSR_sig(sigcontext) = context->Cpsr; /* Current State Register */
133 IP_sig(sigcontext) = context->Ip; /* Intra-Procedure-call scratch register */
134 FP_sig(sigcontext) = context->Fp; /* Frame pointer */
138 /***********************************************************************
139 * save_fpu
141 * Set the FPU context from a sigcontext.
143 static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
145 FIXME("not implemented\n");
149 /***********************************************************************
150 * restore_fpu
152 * Restore the FPU context to a sigcontext.
154 static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext )
156 FIXME("not implemented\n");
160 /***********************************************************************
161 * RtlCaptureContext (NTDLL.@)
163 void WINAPI RtlCaptureContext( CONTEXT *context )
165 FIXME("not implemented\n");
166 memset( context, 0, sizeof(*context) );
170 /***********************************************************************
171 * set_cpu_context
173 * Set the new CPU context.
175 void set_cpu_context( const CONTEXT *context )
177 FIXME("not implemented\n");
178 return;
182 /***********************************************************************
183 * copy_context
185 * Copy a register context according to the flags.
187 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
189 if (flags & CONTEXT_CONTROL)
191 to->Sp = from->Sp;
192 to->Lr = from->Lr;
193 to->Pc = from->Pc;
194 to->Cpsr = from->Cpsr;
196 if (flags & CONTEXT_INTEGER)
198 to->R0 = from->R0;
199 to->R1 = from->R1;
200 to->R2 = from->R2;
201 to->R3 = from->R3;
202 to->R4 = from->R4;
203 to->R5 = from->R5;
204 to->R6 = from->R6;
205 to->R7 = from->R7;
206 to->R8 = from->R8;
207 to->R9 = from->R9;
208 to->R10 = from->R10;
209 to->Ip = from->Ip;
210 to->Fp = from->Fp;
215 /***********************************************************************
216 * context_to_server
218 * Convert a register context to the server format.
220 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
222 DWORD flags = from->ContextFlags; /* no CPU id? */
224 memset( to, 0, sizeof(*to) );
225 to->cpu = CPU_ARM;
227 if (flags & CONTEXT_CONTROL)
229 to->flags |= SERVER_CTX_CONTROL;
230 to->ctl.arm_regs.sp = from->Sp;
231 to->ctl.arm_regs.lr = from->Lr;
232 to->ctl.arm_regs.pc = from->Pc;
233 to->ctl.arm_regs.cpsr = from->Cpsr;
235 if (flags & CONTEXT_INTEGER)
237 to->flags |= SERVER_CTX_INTEGER;
238 to->integer.arm_regs.r[0] = from->R0;
239 to->integer.arm_regs.r[1] = from->R1;
240 to->integer.arm_regs.r[2] = from->R2;
241 to->integer.arm_regs.r[3] = from->R3;
242 to->integer.arm_regs.r[4] = from->R4;
243 to->integer.arm_regs.r[5] = from->R5;
244 to->integer.arm_regs.r[6] = from->R6;
245 to->integer.arm_regs.r[7] = from->R7;
246 to->integer.arm_regs.r[8] = from->R8;
247 to->integer.arm_regs.r[9] = from->R9;
248 to->integer.arm_regs.r[10] = from->R10;
249 to->integer.arm_regs.r[11] = from->Fp;
250 to->integer.arm_regs.r[12] = from->Ip;
252 return STATUS_SUCCESS;
256 /***********************************************************************
257 * context_from_server
259 * Convert a register context from the server format.
261 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
263 if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
265 to->ContextFlags = 0; /* no CPU id? */
266 if (from->flags & SERVER_CTX_CONTROL)
268 to->ContextFlags |= CONTEXT_CONTROL;
269 to->Sp = from->ctl.arm_regs.sp;
270 to->Lr = from->ctl.arm_regs.lr;
271 to->Pc = from->ctl.arm_regs.pc;
272 to->Cpsr = from->ctl.arm_regs.cpsr;
274 if (from->flags & SERVER_CTX_INTEGER)
276 to->ContextFlags |= CONTEXT_INTEGER;
277 to->R0 = from->integer.arm_regs.r[0];
278 to->R1 = from->integer.arm_regs.r[1];
279 to->R2 = from->integer.arm_regs.r[2];
280 to->R3 = from->integer.arm_regs.r[3];
281 to->R4 = from->integer.arm_regs.r[4];
282 to->R5 = from->integer.arm_regs.r[5];
283 to->R6 = from->integer.arm_regs.r[6];
284 to->R7 = from->integer.arm_regs.r[7];
285 to->R8 = from->integer.arm_regs.r[8];
286 to->R9 = from->integer.arm_regs.r[9];
287 to->R10 = from->integer.arm_regs.r[10];
288 to->Fp = from->integer.arm_regs.r[11];
289 to->Ip = from->integer.arm_regs.r[12];
291 return STATUS_SUCCESS;
295 /**********************************************************************
296 * call_stack_handlers
298 * Call the stack handlers chain.
300 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
302 EXCEPTION_POINTERS ptrs;
304 FIXME( "not implemented on ARM, exceptioncode: %x\n", rec->ExceptionCode );
306 /* hack: call unhandled exception filter directly */
307 ptrs.ExceptionRecord = rec;
308 ptrs.ContextRecord = context;
309 unhandled_exception_filter( &ptrs );
310 return STATUS_UNHANDLED_EXCEPTION;
314 /*******************************************************************
315 * raise_exception
317 * Implementation of NtRaiseException.
319 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
321 NTSTATUS status;
323 if (first_chance)
325 DWORD c;
327 for (c = 0; c < rec->NumberParameters; c++)
328 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
329 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
331 if (rec->ExceptionInformation[1] >> 16)
332 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
333 rec->ExceptionAddress,
334 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
335 else
336 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
337 rec->ExceptionAddress,
338 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
340 else
342 /* FIXME: dump context */
345 status = send_debug_event( rec, TRUE, context );
346 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
347 return STATUS_SUCCESS;
349 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
350 return STATUS_SUCCESS;
352 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
353 return status;
356 /* last chance exception */
358 status = send_debug_event( rec, FALSE, context );
359 if (status != DBG_CONTINUE)
361 if (rec->ExceptionFlags & EH_STACK_INVALID)
362 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
363 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
364 ERR("Process attempted to continue execution after noncontinuable exception.\n");
365 else
366 ERR("Unhandled exception code %x flags %x addr %p\n",
367 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
368 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
370 return STATUS_SUCCESS;
374 /**********************************************************************
375 * segv_handler
377 * Handler for SIGSEGV and related errors.
379 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
381 EXCEPTION_RECORD rec;
382 CONTEXT context;
383 NTSTATUS status;
385 rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
387 /* we want the page-fault case to be fast */
388 if ( info->si_code == SEGV_ACCERR )
389 if (!(rec.ExceptionCode = virtual_handle_fault( info->si_addr, 0 ))) return;
391 save_context( &context, ucontext );
392 rec.ExceptionRecord = NULL;
393 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
394 rec.ExceptionAddress = (LPVOID)context.Pc;
395 rec.NumberParameters = 2;
396 rec.ExceptionInformation[0] = 0; /* FIXME: read/write access ? */
397 rec.ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
399 status = raise_exception( &rec, &context, TRUE );
400 if (status) raise_status( status, &rec );
401 restore_context( &context, ucontext );
404 /**********************************************************************
405 * trap_handler
407 * Handler for SIGTRAP.
409 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
411 EXCEPTION_RECORD rec;
412 CONTEXT context;
413 NTSTATUS status;
415 switch ( info->si_code )
417 case TRAP_TRACE:
418 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
419 break;
420 case TRAP_BRKPT:
421 default:
422 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
423 break;
426 save_context( &context, ucontext );
427 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
428 rec.ExceptionRecord = NULL;
429 rec.ExceptionAddress = (LPVOID)context.Pc;
430 rec.NumberParameters = 0;
431 status = raise_exception( &rec, &context, TRUE );
432 if (status) raise_status( status, &rec );
433 restore_context( &context, ucontext );
436 /**********************************************************************
437 * fpe_handler
439 * Handler for SIGFPE.
441 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
443 EXCEPTION_RECORD rec;
444 CONTEXT context;
445 NTSTATUS status;
447 save_fpu( &context, sigcontext );
448 save_context( &context, sigcontext );
450 switch (siginfo->si_code & 0xffff )
452 #ifdef FPE_FLTSUB
453 case FPE_FLTSUB:
454 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
455 break;
456 #endif
457 #ifdef FPE_INTDIV
458 case FPE_INTDIV:
459 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
460 break;
461 #endif
462 #ifdef FPE_INTOVF
463 case FPE_INTOVF:
464 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
465 break;
466 #endif
467 #ifdef FPE_FLTDIV
468 case FPE_FLTDIV:
469 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
470 break;
471 #endif
472 #ifdef FPE_FLTOVF
473 case FPE_FLTOVF:
474 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
475 break;
476 #endif
477 #ifdef FPE_FLTUND
478 case FPE_FLTUND:
479 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
480 break;
481 #endif
482 #ifdef FPE_FLTRES
483 case FPE_FLTRES:
484 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
485 break;
486 #endif
487 #ifdef FPE_FLTINV
488 case FPE_FLTINV:
489 #endif
490 default:
491 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
492 break;
494 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
495 rec.ExceptionRecord = NULL;
496 /*rec.ExceptionAddress = (LPVOID)context.Iar;*/
497 rec.NumberParameters = 0;
498 status = raise_exception( &rec, &context, TRUE );
499 if (status) raise_status( status, &rec );
501 restore_context( &context, sigcontext );
502 restore_fpu( &context, sigcontext );
505 /**********************************************************************
506 * int_handler
508 * Handler for SIGINT.
510 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
512 if (!dispatch_signal(SIGINT))
514 EXCEPTION_RECORD rec;
515 CONTEXT context;
516 NTSTATUS status;
518 save_context( &context, sigcontext );
519 rec.ExceptionCode = CONTROL_C_EXIT;
520 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
521 rec.ExceptionRecord = NULL;
522 /*rec.ExceptionAddress = (LPVOID)context.Iar;*/
523 rec.NumberParameters = 0;
524 status = raise_exception( &rec, &context, TRUE );
525 if (status) raise_status( status, &rec );
526 restore_context( &context, sigcontext );
531 /**********************************************************************
532 * abrt_handler
534 * Handler for SIGABRT.
536 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
538 EXCEPTION_RECORD rec;
539 CONTEXT context;
540 NTSTATUS status;
542 save_context( &context, sigcontext );
543 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
544 rec.ExceptionFlags = EH_NONCONTINUABLE;
545 rec.ExceptionRecord = NULL;
546 /*rec.ExceptionAddress = (LPVOID)context.Iar;*/
547 rec.NumberParameters = 0;
548 status = raise_exception( &rec, &context, TRUE );
549 if (status) raise_status( status, &rec );
550 restore_context( &context, sigcontext );
554 /**********************************************************************
555 * quit_handler
557 * Handler for SIGQUIT.
559 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
561 abort_thread(0);
565 /**********************************************************************
566 * usr1_handler
568 * Handler for SIGUSR1, used to signal a thread that it got suspended.
570 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
572 CONTEXT context;
574 save_context( &context, sigcontext );
575 wait_suspend( &context );
576 restore_context( &context, sigcontext );
580 /***********************************************************************
581 * __wine_set_signal_handler (NTDLL.@)
583 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
585 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
586 if (handlers[sig] != NULL) return -2;
587 handlers[sig] = wsh;
588 return 0;
592 /**********************************************************************
593 * signal_alloc_thread
595 NTSTATUS signal_alloc_thread( TEB **teb )
597 static size_t sigstack_zero_bits;
598 SIZE_T size;
599 NTSTATUS status;
601 if (!sigstack_zero_bits)
603 size_t min_size = getpagesize(); /* this is just for the TEB, we don't use a signal stack yet */
604 /* find the first power of two not smaller than min_size */
605 while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
606 assert( sizeof(TEB) <= min_size );
609 size = 1 << sigstack_zero_bits;
610 *teb = NULL;
611 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
612 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
614 (*teb)->Tib.Self = &(*teb)->Tib;
615 (*teb)->Tib.ExceptionList = (void *)~0UL;
617 return status;
621 /**********************************************************************
622 * signal_free_thread
624 void signal_free_thread( TEB *teb )
626 SIZE_T size;
628 if (teb->DeallocationStack)
630 size = 0;
631 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
633 size = 0;
634 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
638 /**********************************************************************
639 * signal_init_thread
641 void signal_init_thread( TEB *teb )
643 static int init_done;
645 if (!init_done)
647 pthread_key_create( &teb_key, NULL );
648 init_done = 1;
650 pthread_setspecific( teb_key, teb );
654 /**********************************************************************
655 * signal_init_process
657 void signal_init_process(void)
659 struct sigaction sig_act;
661 sig_act.sa_mask = server_block_set;
662 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
664 sig_act.sa_sigaction = int_handler;
665 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
666 sig_act.sa_sigaction = fpe_handler;
667 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
668 sig_act.sa_sigaction = abrt_handler;
669 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
670 sig_act.sa_sigaction = quit_handler;
671 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
672 sig_act.sa_sigaction = usr1_handler;
673 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
675 sig_act.sa_sigaction = segv_handler;
676 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
677 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
678 #ifdef SIGBUS
679 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
680 #endif
682 #ifdef SIGTRAP
683 sig_act.sa_sigaction = trap_handler;
684 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
685 #endif
686 return;
688 error:
689 perror("sigaction");
690 exit(1);
694 /**********************************************************************
695 * __wine_enter_vm86 (NTDLL.@)
697 void __wine_enter_vm86( CONTEXT *context )
699 MESSAGE("vm86 mode not supported on this platform\n");
702 /***********************************************************************
703 * RtlUnwind (NTDLL.@)
705 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
707 FIXME( "Not implemented on ARM\n" );
710 /*******************************************************************
711 * NtRaiseException (NTDLL.@)
713 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
715 NTSTATUS status = raise_exception( rec, context, first_chance );
716 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
717 return status;
720 /***********************************************************************
721 * RtlRaiseException (NTDLL.@)
723 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
725 CONTEXT context;
726 NTSTATUS status;
728 RtlCaptureContext( &context );
729 /*rec->ExceptionAddress = (void *)context.Iar;*/
730 status = raise_exception( rec, &context, TRUE );
731 if (status) raise_status( status, rec );
734 /*************************************************************************
735 * RtlCaptureStackBackTrace (NTDLL.@)
737 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
739 FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
740 return 0;
743 /***********************************************************************
744 * call_thread_entry_point
746 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
748 __TRY
750 exit_thread( entry( arg ));
752 __EXCEPT(unhandled_exception_filter)
754 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
756 __ENDTRY
757 abort(); /* should not be reached */
760 /***********************************************************************
761 * RtlExitUserThread (NTDLL.@)
763 void WINAPI RtlExitUserThread( ULONG status )
765 exit_thread( status );
768 /***********************************************************************
769 * abort_thread
771 void abort_thread( int status )
773 terminate_thread( status );
776 /**********************************************************************
777 * DbgBreakPoint (NTDLL.@)
779 void WINAPI DbgBreakPoint(void)
781 kill(getpid(), SIGTRAP);
784 /**********************************************************************
785 * DbgUserBreakPoint (NTDLL.@)
787 void WINAPI DbgUserBreakPoint(void)
789 kill(getpid(), SIGTRAP);
792 /**********************************************************************
793 * NtCurrentTeb (NTDLL.@)
795 TEB * WINAPI NtCurrentTeb(void)
797 return pthread_getspecific( teb_key );
800 #endif /* __arm__ */