mshtml: Added IHTMLWindow2::focus implementation.
[wine] / dlls / ntdll / signal_arm.c
1 /*
2  * ARM signal handling routines
3  *
4  * Copyright 2002 Marcus Meissner, SuSE Linux AG
5  * Copyright 2010 AndrĂ© Hentschel
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #ifdef __arm__
23
24 #include "config.h"
25 #include "wine/port.h"
26
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
35
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
49
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"
59
60 WINE_DEFAULT_DEBUG_CHANNEL(seh);
61
62 static pthread_key_t teb_key;
63
64 /***********************************************************************
65  * signal context platform-specific definitions
66  */
67 #ifdef linux
68
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)
72
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 */
80
81 #endif /* linux */
82
83 typedef int (*wine_signal_handler)(unsigned int sig);
84
85 static wine_signal_handler handlers[256];
86
87 /***********************************************************************
88  *           dispatch_signal
89  */
90 static inline int dispatch_signal(unsigned int sig)
91 {
92     if (handlers[sig] == NULL) return 0;
93     return handlers[sig](sig);
94 }
95
96 /***********************************************************************
97  *           save_context
98  *
99  * Set the register values from a sigcontext.
100  */
101 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
102 {
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
107
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 */
114 }
115
116
117 /***********************************************************************
118  *           restore_context
119  *
120  * Build a sigcontext from the register values.
121  */
122 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
123 {
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
128
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 */
135 }
136
137
138 /***********************************************************************
139  *           save_fpu
140  *
141  * Set the FPU context from a sigcontext.
142  */
143 static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
144 {
145     FIXME("not implemented\n");
146 }
147
148
149 /***********************************************************************
150  *           restore_fpu
151  *
152  * Restore the FPU context to a sigcontext.
153  */
154 static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext )
155 {
156     FIXME("not implemented\n");
157 }
158
159
160 /***********************************************************************
161  *              RtlCaptureContext (NTDLL.@)
162  */
163 void WINAPI RtlCaptureContext( CONTEXT *context )
164 {
165     FIXME("not implemented\n");
166     memset( context, 0, sizeof(*context) );
167 }
168
169
170 /***********************************************************************
171  *           set_cpu_context
172  *
173  * Set the new CPU context.
174  */
175 void set_cpu_context( const CONTEXT *context )
176 {
177     FIXME("not implemented\n");
178     return;
179 }
180
181
182 /***********************************************************************
183  *           copy_context
184  *
185  * Copy a register context according to the flags.
186  */
187 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
188 {
189     if (flags & CONTEXT_CONTROL)
190     {
191         to->Sp      = from->Sp;
192         to->Lr      = from->Lr;
193         to->Pc      = from->Pc;
194         to->Cpsr    = from->Cpsr;
195     }
196     if (flags & CONTEXT_INTEGER)
197     {
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;
211     }
212 }
213
214
215 /***********************************************************************
216  *           context_to_server
217  *
218  * Convert a register context to the server format.
219  */
220 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
221 {
222     DWORD flags = from->ContextFlags;  /* no CPU id? */
223
224     memset( to, 0, sizeof(*to) );
225     to->cpu = CPU_ARM;
226
227     if (flags & CONTEXT_CONTROL)
228     {
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;
234     }
235     if (flags & CONTEXT_INTEGER)
236     {
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;
251     }
252     return STATUS_SUCCESS;
253 }
254
255
256 /***********************************************************************
257  *           context_from_server
258  *
259  * Convert a register context from the server format.
260  */
261 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
262 {
263     if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
264
265     to->ContextFlags = 0;  /* no CPU id? */
266     if (from->flags & SERVER_CTX_CONTROL)
267     {
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;
273     }
274     if (from->flags & SERVER_CTX_INTEGER)
275     {
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];
290      }
291     return STATUS_SUCCESS;
292 }
293
294
295 /**********************************************************************
296  *           call_stack_handlers
297  *
298  * Call the stack handlers chain.
299  */
300 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
301 {
302     EXCEPTION_POINTERS ptrs;
303
304     FIXME( "not implemented on ARM, exceptioncode: %x\n", rec->ExceptionCode );
305
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;
311 }
312
313
314 /*******************************************************************
315  *              raise_exception
316  *
317  * Implementation of NtRaiseException.
318  */
319 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
320 {
321     NTSTATUS status;
322
323     if (first_chance)
324     {
325         DWORD c;
326
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)
330         {
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] );
339         }
340         else
341         {
342             /* FIXME: dump context */
343         }
344
345         status = send_debug_event( rec, TRUE, context );
346         if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
347             return STATUS_SUCCESS;
348
349         if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
350             return STATUS_SUCCESS;
351
352         if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
353             return status;
354     }
355
356     /* last chance exception */
357
358     status = send_debug_event( rec, FALSE, context );
359     if (status != DBG_CONTINUE)
360     {
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 );
369     }
370     return STATUS_SUCCESS;
371 }
372
373
374 /**********************************************************************
375  *              segv_handler
376  *
377  * Handler for SIGSEGV and related errors.
378  */
379 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
380 {
381     EXCEPTION_RECORD rec;
382     CONTEXT context;
383     NTSTATUS status;
384
385     rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
386
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;
390
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;
398
399     status = raise_exception( &rec, &context, TRUE );
400     if (status) raise_status( status, &rec );
401     restore_context( &context, ucontext );
402 }
403
404 /**********************************************************************
405  *              trap_handler
406  *
407  * Handler for SIGTRAP.
408  */
409 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
410 {
411     EXCEPTION_RECORD rec;
412     CONTEXT context;
413     NTSTATUS status;
414
415     switch ( info->si_code )
416     {
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;
424     }
425
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 );
434 }
435
436 /**********************************************************************
437  *              fpe_handler
438  *
439  * Handler for SIGFPE.
440  */
441 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
442 {
443     EXCEPTION_RECORD rec;
444     CONTEXT context;
445     NTSTATUS status;
446
447     save_fpu( &context, sigcontext );
448     save_context( &context, sigcontext );
449
450     switch (siginfo->si_code & 0xffff )
451     {
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;
493     }
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 );
500
501     restore_context( &context, sigcontext );
502     restore_fpu( &context, sigcontext );
503 }
504
505 /**********************************************************************
506  *              int_handler
507  *
508  * Handler for SIGINT.
509  */
510 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
511 {
512     if (!dispatch_signal(SIGINT))
513     {
514         EXCEPTION_RECORD rec;
515         CONTEXT context;
516         NTSTATUS status;
517
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 );
527     }
528 }
529
530
531 /**********************************************************************
532  *              abrt_handler
533  *
534  * Handler for SIGABRT.
535  */
536 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
537 {
538     EXCEPTION_RECORD rec;
539     CONTEXT context;
540     NTSTATUS status;
541
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 );
551 }
552
553
554 /**********************************************************************
555  *              quit_handler
556  *
557  * Handler for SIGQUIT.
558  */
559 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
560 {
561     abort_thread(0);
562 }
563
564
565 /**********************************************************************
566  *              usr1_handler
567  *
568  * Handler for SIGUSR1, used to signal a thread that it got suspended.
569  */
570 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
571 {
572     CONTEXT context;
573
574     save_context( &context, sigcontext );
575     wait_suspend( &context );
576     restore_context( &context, sigcontext );
577 }
578
579
580 /***********************************************************************
581  *           __wine_set_signal_handler   (NTDLL.@)
582  */
583 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
584 {
585     if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
586     if (handlers[sig] != NULL) return -2;
587     handlers[sig] = wsh;
588     return 0;
589 }
590
591
592 /**********************************************************************
593  *             signal_alloc_thread
594  */
595 NTSTATUS signal_alloc_thread( TEB **teb )
596 {
597     static size_t sigstack_zero_bits;
598     SIZE_T size;
599     NTSTATUS status;
600
601     if (!sigstack_zero_bits)
602     {
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 );
607     }
608
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 )))
613     {
614         (*teb)->Tib.Self = &(*teb)->Tib;
615         (*teb)->Tib.ExceptionList = (void *)~0UL;
616     }
617     return status;
618 }
619
620
621 /**********************************************************************
622  *             signal_free_thread
623  */
624 void signal_free_thread( TEB *teb )
625 {
626     SIZE_T size;
627
628     if (teb->DeallocationStack)
629     {
630         size = 0;
631         NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
632     }
633     size = 0;
634     NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
635 }
636
637
638 /**********************************************************************
639  *              signal_init_thread
640  */
641 void signal_init_thread( TEB *teb )
642 {
643     static int init_done;
644
645     if (!init_done)
646     {
647         pthread_key_create( &teb_key, NULL );
648         init_done = 1;
649     }
650     pthread_setspecific( teb_key, teb );
651 }
652
653
654 /**********************************************************************
655  *              signal_init_process
656  */
657 void signal_init_process(void)
658 {
659     struct sigaction sig_act;
660
661     sig_act.sa_mask = server_block_set;
662     sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
663
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;
674
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
681
682 #ifdef SIGTRAP
683     sig_act.sa_sigaction = trap_handler;
684     if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
685 #endif
686     return;
687
688  error:
689     perror("sigaction");
690     exit(1);
691 }
692
693
694 /**********************************************************************
695  *              __wine_enter_vm86   (NTDLL.@)
696  */
697 void __wine_enter_vm86( CONTEXT *context )
698 {
699     MESSAGE("vm86 mode not supported on this platform\n");
700 }
701
702 /***********************************************************************
703  *            RtlUnwind  (NTDLL.@)
704  */
705 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
706 {
707     FIXME( "Not implemented on ARM\n" );
708 }
709
710 /*******************************************************************
711  *              NtRaiseException (NTDLL.@)
712  */
713 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
714 {
715     NTSTATUS status = raise_exception( rec, context, first_chance );
716     if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
717     return status;
718 }
719
720 /***********************************************************************
721  *              RtlRaiseException (NTDLL.@)
722  */
723 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
724 {
725     CONTEXT context;
726     NTSTATUS status;
727
728     RtlCaptureContext( &context );
729     /*rec->ExceptionAddress = (void *)context.Iar;*/
730     status = raise_exception( rec, &context, TRUE );
731     if (status) raise_status( status, rec );
732 }
733
734 /*************************************************************************
735  *             RtlCaptureStackBackTrace (NTDLL.@)
736  */
737 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
738 {
739     FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
740     return 0;
741 }
742
743 /***********************************************************************
744  *           call_thread_entry_point
745  */
746 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
747 {
748     __TRY
749     {
750         exit_thread( entry( arg ));
751     }
752     __EXCEPT(unhandled_exception_filter)
753     {
754         NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
755     }
756     __ENDTRY
757     abort();  /* should not be reached */
758 }
759
760 /***********************************************************************
761  *           RtlExitUserThread  (NTDLL.@)
762  */
763 void WINAPI RtlExitUserThread( ULONG status )
764 {
765     exit_thread( status );
766 }
767
768 /***********************************************************************
769  *           abort_thread
770  */
771 void abort_thread( int status )
772 {
773     terminate_thread( status );
774 }
775
776 /**********************************************************************
777  *              DbgBreakPoint   (NTDLL.@)
778  */
779 void WINAPI DbgBreakPoint(void)
780 {
781      kill(getpid(), SIGTRAP);
782 }
783
784 /**********************************************************************
785  *              DbgUserBreakPoint   (NTDLL.@)
786  */
787 void WINAPI DbgUserBreakPoint(void)
788 {
789      kill(getpid(), SIGTRAP);
790 }
791
792 /**********************************************************************
793  *           NtCurrentTeb   (NTDLL.@)
794  */
795 TEB * WINAPI NtCurrentTeb(void)
796 {
797     return pthread_getspecific( teb_key );
798 }
799
800 #endif  /* __arm__ */