2 * ARM64 signal handling routines
4 * Copyright 2010-2013 André Hentschel
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"
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
41 # ifdef HAVE_SYS_SYSCALL_H
42 # include <sys/syscall.h>
45 #ifdef HAVE_SYS_SIGNAL_H
46 # include <sys/signal.h>
50 #define WIN32_NO_STATUS
53 #include "wine/library.h"
54 #include "wine/exception.h"
55 #include "ntdll_misc.h"
56 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(seh);
61 static pthread_key_t teb_key;
63 /***********************************************************************
64 * signal context platform-specific definitions
68 typedef ucontext_t SIGCONTEXT;
70 /* All Registers access - only for local access */
71 # define REG_sig(reg_name, context) ((context)->uc_mcontext.reg_name)
72 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.regs[reg_num])
74 /* Special Registers access */
75 # define SP_sig(context) REG_sig(sp, context) /* Stack pointer */
76 # define PC_sig(context) REG_sig(pc, context) /* Program counter */
77 # define PSTATE_sig(context) REG_sig(pstate, context) /* Current State Register */
78 # define FP_sig(context) REGn_sig(29, context) /* Frame pointer */
79 # define LR_sig(context) REGn_sig(30, context) /* Link Register */
82 # define FAULT_sig(context) REG_sig(fault_address, context)
86 static const size_t teb_size = 0x2000; /* we reserve two pages for the TEB */
87 static size_t signal_stack_size;
89 typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
90 typedef int (*wine_signal_handler)(unsigned int sig);
92 static wine_signal_handler handlers[256];
94 /***********************************************************************
97 static inline int dispatch_signal(unsigned int sig)
99 if (handlers[sig] == NULL) return 0;
100 return handlers[sig](sig);
103 /*******************************************************************
106 static inline BOOL is_valid_frame( void *frame )
108 if ((ULONG_PTR)frame & 3) return FALSE;
109 return (frame >= NtCurrentTeb()->Tib.StackLimit &&
110 (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1);
113 /***********************************************************************
116 * Set the register values from a sigcontext.
118 static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext )
120 #define C(n) context->X##n = REGn_sig(n,sigcontext)
121 /* Save normal registers */
122 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9);
123 C(10); C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19);
124 C(20); C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
127 context->ContextFlags = CONTEXT_FULL;
128 context->Sp = SP_sig(sigcontext); /* Stack pointer */
129 context->Pc = PC_sig(sigcontext); /* Program Counter */
130 context->PState = PSTATE_sig(sigcontext); /* Current State Register */
134 /***********************************************************************
137 * Build a sigcontext from the register values.
139 static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
141 #define C(n) REGn_sig(n,sigcontext) = context->X##n
142 /* Restore normal registers */
143 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9);
144 C(10); C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19);
145 C(20); C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
148 SP_sig(sigcontext) = context->Sp; /* Stack pointer */
149 PC_sig(sigcontext) = context->Pc; /* Program Counter */
150 PSTATE_sig(sigcontext) = context->PState; /* Current State Register */
154 /***********************************************************************
157 * Set the FPU context from a sigcontext.
159 static inline void save_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
161 FIXME( "Not implemented on ARM64\n" );
165 /***********************************************************************
168 * Restore the FPU context to a sigcontext.
170 static inline void restore_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
172 FIXME( "Not implemented on ARM64\n" );
175 /***********************************************************************
176 * RtlCaptureContext (NTDLL.@)
178 void WINAPI RtlCaptureContext( CONTEXT *context )
180 FIXME( "Not implemented on ARM64\n" );
181 memset( context, 0, sizeof(*context) );
184 /***********************************************************************
187 * Set the new CPU context.
189 void set_cpu_context( const CONTEXT *context )
191 FIXME( "Not implemented on ARM64\n" );
194 /***********************************************************************
197 * Copy a register context according to the flags.
199 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
201 flags &= ~CONTEXT_ARM64; /* get rid of CPU id */
202 if (flags & CONTEXT_CONTROL)
206 to->PState = from->PState;
208 if (flags & CONTEXT_INTEGER)
210 #define C(n) to->X##n = from->X##n
211 /* Restore normal registers */
212 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9);
213 C(10); C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19);
214 C(20); C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
219 /***********************************************************************
222 * Convert a register context to the server format.
224 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
226 DWORD flags = from->ContextFlags & ~CONTEXT_ARM64; /* get rid of CPU id */
228 memset( to, 0, sizeof(*to) );
231 if (flags & CONTEXT_CONTROL)
233 to->flags |= SERVER_CTX_CONTROL;
234 to->ctl.arm64_regs.sp = from->Sp;
235 to->ctl.arm64_regs.pc = from->Pc;
236 to->ctl.arm64_regs.pstate = from->PState;
238 if (flags & CONTEXT_INTEGER)
240 to->flags |= SERVER_CTX_INTEGER;
241 #define C(n) to->integer.arm64_regs.x[n] = from->X##n
242 /* Restore normal registers */
243 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9);
244 C(10); C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19);
245 C(20); C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
248 return STATUS_SUCCESS;
252 /***********************************************************************
253 * context_from_server
255 * Convert a register context from the server format.
257 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
259 if (from->cpu != CPU_ARM64) return STATUS_INVALID_PARAMETER;
261 to->ContextFlags = CONTEXT_ARM64;
262 if (from->flags & SERVER_CTX_CONTROL)
264 to->ContextFlags |= CONTEXT_CONTROL;
265 to->Sp = from->ctl.arm64_regs.sp;
266 to->Pc = from->ctl.arm64_regs.pc;
267 to->PState = from->ctl.arm64_regs.pstate;
269 if (from->flags & SERVER_CTX_INTEGER)
271 to->ContextFlags |= CONTEXT_INTEGER;
272 #define C(n) to->X##n = from->integer.arm64_regs.x[n]
273 /* Restore normal registers */
274 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9);
275 C(10); C(11); C(12); C(13); C(14); C(15); C(16); C(17); C(18); C(19);
276 C(20); C(21); C(22); C(23); C(24); C(25); C(26); C(27); C(28); C(29); C(30);
279 return STATUS_SUCCESS;
282 /***********************************************************************
283 * setup_exception_record
285 * Setup the exception record and context on the thread stack.
287 static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func )
292 EXCEPTION_RECORD rec;
294 DWORD exception_code = 0;
296 stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
297 stack--; /* push the stack_layout structure */
299 stack->rec.ExceptionRecord = NULL;
300 stack->rec.ExceptionCode = exception_code;
301 stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
302 stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
303 stack->rec.NumberParameters = 0;
305 save_context( &stack->context, sigcontext );
307 /* now modify the sigcontext to return to the raise function */
308 SP_sig(sigcontext) = (ULONG_PTR)stack;
309 PC_sig(sigcontext) = (ULONG_PTR)func;
310 REGn_sig(0, sigcontext) = (ULONG_PTR)&stack->rec; /* first arg for raise_func */
311 REGn_sig(1, sigcontext) = (ULONG_PTR)&stack->context; /* second arg for raise_func */
316 /**********************************************************************
317 * raise_segv_exception
319 static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
323 switch(rec->ExceptionCode)
325 case EXCEPTION_ACCESS_VIOLATION:
326 if (rec->NumberParameters == 2)
328 if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
329 rec->ExceptionInformation[0] )))
334 status = NtRaiseException( rec, context, TRUE );
335 if (status) raise_status( status, rec );
337 set_cpu_context( context );
340 /**********************************************************************
341 * call_stack_handlers
343 * Call the stack handlers chain.
345 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
347 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
350 frame = NtCurrentTeb()->Tib.ExceptionList;
352 while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
354 /* Check frame address */
355 if (!is_valid_frame( frame ))
357 rec->ExceptionFlags |= EH_STACK_INVALID;
362 TRACE( "calling handler at %p code=%x flags=%x\n",
363 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
364 res = frame->Handler( rec, frame, context, &dispatch );
365 TRACE( "handler at %p returned %x\n", frame->Handler, res );
367 if (frame == nested_frame)
369 /* no longer nested */
371 rec->ExceptionFlags &= ~EH_NESTED_CALL;
376 case ExceptionContinueExecution:
377 if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
378 return STATUS_NONCONTINUABLE_EXCEPTION;
379 case ExceptionContinueSearch:
381 case ExceptionNestedException:
382 if (nested_frame < dispatch) nested_frame = dispatch;
383 rec->ExceptionFlags |= EH_NESTED_CALL;
386 return STATUS_INVALID_DISPOSITION;
390 return STATUS_UNHANDLED_EXCEPTION;
394 /*******************************************************************
397 * Implementation of NtRaiseException.
399 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
407 for (c = 0; c < rec->NumberParameters; c++)
408 TRACE( " info[%d]=%016lx\n", c, rec->ExceptionInformation[c] );
409 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
411 if (rec->ExceptionInformation[1] >> 16)
412 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
413 rec->ExceptionAddress,
414 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
416 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
417 rec->ExceptionAddress,
418 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
422 /* FIXME: dump context */
425 status = send_debug_event( rec, TRUE, context );
426 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
427 return STATUS_SUCCESS;
429 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
430 return STATUS_SUCCESS;
432 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
436 /* last chance exception */
438 status = send_debug_event( rec, FALSE, context );
439 if (status != DBG_CONTINUE)
441 if (rec->ExceptionFlags & EH_STACK_INVALID)
442 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
443 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
444 ERR("Process attempted to continue execution after noncontinuable exception.\n");
446 ERR("Unhandled exception code %x flags %x addr %p\n",
447 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
448 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
450 return STATUS_SUCCESS;
453 /**********************************************************************
456 * Handler for SIGSEGV and related errors.
458 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
460 EXCEPTION_RECORD *rec;
461 SIGCONTEXT *context = ucontext;
463 /* check for page fault inside the thread stack */
464 if (signal == SIGSEGV &&
465 (char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
466 (char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
467 virtual_handle_stack_fault( info->si_addr ))
469 /* check if this was the last guard page */
470 if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
472 rec = setup_exception( context, raise_segv_exception );
473 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
478 rec = setup_exception( context, raise_segv_exception );
479 if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
483 case SIGILL: /* Invalid opcode exception */
484 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
486 case SIGSEGV: /* Segmentation fault */
487 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
488 rec->NumberParameters = 2;
489 /* FIXME: Currently the kernel provides no way to determine if it's read or write */
490 rec->ExceptionInformation[0] = 0;
491 rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
493 case SIGBUS: /* Alignment check exception */
494 rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
497 ERR("Got unexpected signal %i\n", signal);
498 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
503 /**********************************************************************
506 * Handler for SIGTRAP.
508 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
510 EXCEPTION_RECORD rec;
514 switch ( info->si_code )
517 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
521 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
525 save_context( &context, ucontext );
526 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
527 rec.ExceptionRecord = NULL;
528 rec.ExceptionAddress = (LPVOID)context.Pc;
529 rec.NumberParameters = 0;
530 status = raise_exception( &rec, &context, TRUE );
531 if (status) raise_status( status, &rec );
532 restore_context( &context, ucontext );
535 /**********************************************************************
538 * Handler for SIGFPE.
540 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
542 EXCEPTION_RECORD rec;
546 save_fpu( &context, sigcontext );
547 save_context( &context, sigcontext );
549 switch (siginfo->si_code & 0xffff )
553 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
558 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
563 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
568 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
573 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
578 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
583 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
590 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
593 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
594 rec.ExceptionRecord = NULL;
595 rec.ExceptionAddress = (LPVOID)context.Pc;
596 rec.NumberParameters = 0;
597 status = raise_exception( &rec, &context, TRUE );
598 if (status) raise_status( status, &rec );
600 restore_context( &context, sigcontext );
601 restore_fpu( &context, sigcontext );
604 /**********************************************************************
607 * Handler for SIGINT.
609 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
611 if (!dispatch_signal(SIGINT))
613 EXCEPTION_RECORD rec;
617 save_context( &context, sigcontext );
618 rec.ExceptionCode = CONTROL_C_EXIT;
619 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
620 rec.ExceptionRecord = NULL;
621 rec.ExceptionAddress = (LPVOID)context.Pc;
622 rec.NumberParameters = 0;
623 status = raise_exception( &rec, &context, TRUE );
624 if (status) raise_status( status, &rec );
625 restore_context( &context, sigcontext );
630 /**********************************************************************
633 * Handler for SIGABRT.
635 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
637 EXCEPTION_RECORD rec;
641 save_context( &context, sigcontext );
642 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
643 rec.ExceptionFlags = EH_NONCONTINUABLE;
644 rec.ExceptionRecord = NULL;
645 rec.ExceptionAddress = (LPVOID)context.Pc;
646 rec.NumberParameters = 0;
647 status = raise_exception( &rec, &context, TRUE );
648 if (status) raise_status( status, &rec );
649 restore_context( &context, sigcontext );
653 /**********************************************************************
656 * Handler for SIGQUIT.
658 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
664 /**********************************************************************
667 * Handler for SIGUSR1, used to signal a thread that it got suspended.
669 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
673 save_context( &context, sigcontext );
674 wait_suspend( &context );
675 restore_context( &context, sigcontext );
679 /***********************************************************************
680 * __wine_set_signal_handler (NTDLL.@)
682 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
684 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
685 if (handlers[sig] != NULL) return -2;
691 /**********************************************************************
692 * signal_alloc_thread
694 NTSTATUS signal_alloc_thread( TEB **teb )
696 static size_t sigstack_zero_bits;
700 if (!sigstack_zero_bits)
702 size_t min_size = teb_size + max( MINSIGSTKSZ, 8192 );
703 /* find the first power of two not smaller than min_size */
704 sigstack_zero_bits = 12;
705 while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
706 signal_stack_size = (1 << sigstack_zero_bits) - teb_size;
707 assert( sizeof(TEB) <= teb_size );
710 size = 1 << sigstack_zero_bits;
712 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
713 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
715 (*teb)->Tib.Self = &(*teb)->Tib;
716 (*teb)->Tib.ExceptionList = (void *)~0UL;
722 /**********************************************************************
725 void signal_free_thread( TEB *teb )
729 if (teb->DeallocationStack)
732 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
735 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
739 /**********************************************************************
742 void signal_init_thread( TEB *teb )
744 static int init_done;
748 pthread_key_create( &teb_key, NULL );
751 pthread_setspecific( teb_key, teb );
755 /**********************************************************************
756 * signal_init_process
758 void signal_init_process(void)
760 struct sigaction sig_act;
762 sig_act.sa_mask = server_block_set;
763 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
765 sig_act.sa_sigaction = int_handler;
766 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
767 sig_act.sa_sigaction = fpe_handler;
768 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
769 sig_act.sa_sigaction = abrt_handler;
770 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
771 sig_act.sa_sigaction = quit_handler;
772 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
773 sig_act.sa_sigaction = usr1_handler;
774 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
776 sig_act.sa_sigaction = segv_handler;
777 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
778 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
780 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
784 sig_act.sa_sigaction = trap_handler;
785 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
795 /**********************************************************************
796 * __wine_enter_vm86 (NTDLL.@)
798 void __wine_enter_vm86( CONTEXT *context )
800 MESSAGE("vm86 mode not supported on this platform\n");
803 /***********************************************************************
804 * RtlUnwind (NTDLL.@)
806 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
808 FIXME( "Not implemented on ARM64\n" );
811 /*******************************************************************
812 * NtRaiseException (NTDLL.@)
814 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
816 NTSTATUS status = raise_exception( rec, context, first_chance );
817 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
821 /***********************************************************************
822 * RtlRaiseException (NTDLL.@)
824 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
829 RtlCaptureContext( &context );
830 rec->ExceptionAddress = (LPVOID)context.Pc;
831 status = raise_exception( rec, &context, TRUE );
832 if (status) raise_status( status, rec );
835 /*************************************************************************
836 * RtlCaptureStackBackTrace (NTDLL.@)
838 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
840 FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
844 /***********************************************************************
845 * call_thread_entry_point
847 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
851 exit_thread( entry( arg ));
853 __EXCEPT(unhandled_exception_filter)
855 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
858 abort(); /* should not be reached */
861 /***********************************************************************
862 * RtlExitUserThread (NTDLL.@)
864 void WINAPI RtlExitUserThread( ULONG status )
866 exit_thread( status );
869 /***********************************************************************
872 void abort_thread( int status )
874 terminate_thread( status );
877 /**********************************************************************
878 * DbgBreakPoint (NTDLL.@)
880 void WINAPI DbgBreakPoint(void)
882 kill(getpid(), SIGTRAP);
885 /**********************************************************************
886 * DbgUserBreakPoint (NTDLL.@)
888 void WINAPI DbgUserBreakPoint(void)
890 kill(getpid(), SIGTRAP);
893 /**********************************************************************
894 * NtCurrentTeb (NTDLL.@)
896 TEB * WINAPI NtCurrentTeb(void)
898 return pthread_getspecific( teb_key );
901 #endif /* __aarch64__ */