d3d9: Finish the COM cleanup of the IDirect3DDevice9Ex iface.
[wine] / dlls / ntdll / signal_arm.c
1 /*
2  * ARM signal handling routines
3  *
4  * Copyright 2002 Marcus Meissner, SuSE Linux AG
5  * Copyright 2010, 2011 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  *         is_valid_frame
98  */
99 static inline BOOL is_valid_frame( void *frame )
100 {
101     if ((ULONG_PTR)frame & 3) return FALSE;
102     return (frame >= NtCurrentTeb()->Tib.StackLimit &&
103             (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1);
104 }
105
106 /***********************************************************************
107  *           save_context
108  *
109  * Set the register values from a sigcontext.
110  */
111 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
112 {
113 #define C(x) context->R##x = REGn_sig(x,sigcontext)
114     /* Save normal registers */
115     C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
116 #undef C
117
118     context->ContextFlags = CONTEXT_FULL;
119     context->Sp   = SP_sig(sigcontext);   /* Stack pointer */
120     context->Lr   = LR_sig(sigcontext);   /* Link register */
121     context->Pc   = PC_sig(sigcontext);   /* Program Counter */
122     context->Cpsr = CPSR_sig(sigcontext); /* Current State Register */
123     context->Ip   = IP_sig(sigcontext);   /* Intra-Procedure-call scratch register */
124     context->Fp   = FP_sig(sigcontext);   /* Frame pointer */
125 }
126
127
128 /***********************************************************************
129  *           restore_context
130  *
131  * Build a sigcontext from the register values.
132  */
133 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
134 {
135 #define C(x)  REGn_sig(x,sigcontext) = context->R##x
136     /* Restore normal registers */
137     C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
138 #undef C
139
140     SP_sig(sigcontext)   = context->Sp;   /* Stack pointer */
141     LR_sig(sigcontext)   = context->Lr ;  /* Link register */
142     PC_sig(sigcontext)   = context->Pc;   /* Program Counter */
143     CPSR_sig(sigcontext) = context->Cpsr; /* Current State Register */
144     IP_sig(sigcontext)   = context->Ip;   /* Intra-Procedure-call scratch register */
145     FP_sig(sigcontext)   = context->Fp;   /* Frame pointer */
146 }
147
148
149 /***********************************************************************
150  *           save_fpu
151  *
152  * Set the FPU context from a sigcontext.
153  */
154 static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
155 {
156     FIXME("not implemented\n");
157 }
158
159
160 /***********************************************************************
161  *           restore_fpu
162  *
163  * Restore the FPU context to a sigcontext.
164  */
165 static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext )
166 {
167     FIXME("not implemented\n");
168 }
169
170
171 /***********************************************************************
172  *              RtlCaptureContext (NTDLL.@)
173  */
174 /* FIXME: Use the Stack instead of the actual register values */
175 __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
176                     ".arm\n\t"
177                     "stmfd SP!, {r1}\n\t"
178                     "mov r1, #0x40\n\t"     /* CONTEXT_ARM */
179                     "add r1, r1, #0x3\n\t"  /* CONTEXT_FULL */
180                     "str r1, [r0]\n\t"      /* context->ContextFlags */
181                     "ldmfd SP!, {r1}\n\t"
182                     "str r0, [r0, #0x4]\n\t"   /* context->R0 */
183                     "str r1, [r0, #0x8]\n\t"   /* context->R1 */
184                     "str r2, [r0, #0xc]\n\t"   /* context->R2 */
185                     "str r3, [r0, #0x10]\n\t"  /* context->R3 */
186                     "str r4, [r0, #0x14]\n\t"  /* context->R4 */
187                     "str r5, [r0, #0x18]\n\t"  /* context->R5 */
188                     "str r6, [r0, #0x1c]\n\t"  /* context->R6 */
189                     "str r7, [r0, #0x20]\n\t"  /* context->R7 */
190                     "str r8, [r0, #0x24]\n\t"  /* context->R8 */
191                     "str r9, [r0, #0x28]\n\t"  /* context->R9 */
192                     "str r10, [r0, #0x2c]\n\t" /* context->R10 */
193                     "str r11, [r0, #0x30]\n\t" /* context->Fp */
194                     "str IP, [r0, #0x34]\n\t"  /* context->Ip */
195                     "str SP, [r0, #0x38]\n\t"  /* context->Sp */
196                     "str LR, [r0, #0x3c]\n\t"  /* context->Lr */
197                     "str LR, [r0, #0x40]\n\t"  /* context->Pc */
198                     "mrs r1, CPSR\n\t"
199                     "str r1, [r0, #0x44]\n\t"  /* context->Cpsr */
200                     "mov PC, LR\n"
201                     )
202
203
204 /***********************************************************************
205  *           set_cpu_context
206  *
207  * Set the new CPU context.
208  */
209 void set_cpu_context( const CONTEXT *context )
210 {
211     FIXME("not implemented\n");
212     return;
213 }
214
215
216 /***********************************************************************
217  *           copy_context
218  *
219  * Copy a register context according to the flags.
220  */
221 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
222 {
223     flags &= ~CONTEXT_ARM;  /* get rid of CPU id */
224     if (flags & CONTEXT_CONTROL)
225     {
226         to->Sp      = from->Sp;
227         to->Lr      = from->Lr;
228         to->Pc      = from->Pc;
229         to->Cpsr    = from->Cpsr;
230     }
231     if (flags & CONTEXT_INTEGER)
232     {
233         to->R0  = from->R0;
234         to->R1  = from->R1;
235         to->R2  = from->R2;
236         to->R3  = from->R3;
237         to->R4  = from->R4;
238         to->R5  = from->R5;
239         to->R6  = from->R6;
240         to->R7  = from->R7;
241         to->R8  = from->R8;
242         to->R9  = from->R9;
243         to->R10 = from->R10;
244         to->Ip  = from->Ip;
245         to->Fp  = from->Fp;
246     }
247 }
248
249
250 /***********************************************************************
251  *           context_to_server
252  *
253  * Convert a register context to the server format.
254  */
255 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
256 {
257     DWORD flags = from->ContextFlags & ~CONTEXT_ARM;  /* get rid of CPU id */
258
259     memset( to, 0, sizeof(*to) );
260     to->cpu = CPU_ARM;
261
262     if (flags & CONTEXT_CONTROL)
263     {
264         to->flags |= SERVER_CTX_CONTROL;
265         to->ctl.arm_regs.sp   = from->Sp;
266         to->ctl.arm_regs.lr   = from->Lr;
267         to->ctl.arm_regs.pc   = from->Pc;
268         to->ctl.arm_regs.cpsr = from->Cpsr;
269     }
270     if (flags & CONTEXT_INTEGER)
271     {
272         to->flags |= SERVER_CTX_INTEGER;
273         to->integer.arm_regs.r[0]  = from->R0;
274         to->integer.arm_regs.r[1]  = from->R1;
275         to->integer.arm_regs.r[2]  = from->R2;
276         to->integer.arm_regs.r[3]  = from->R3;
277         to->integer.arm_regs.r[4]  = from->R4;
278         to->integer.arm_regs.r[5]  = from->R5;
279         to->integer.arm_regs.r[6]  = from->R6;
280         to->integer.arm_regs.r[7]  = from->R7;
281         to->integer.arm_regs.r[8]  = from->R8;
282         to->integer.arm_regs.r[9]  = from->R9;
283         to->integer.arm_regs.r[10] = from->R10;
284         to->integer.arm_regs.r[11] = from->Fp;
285         to->integer.arm_regs.r[12] = from->Ip;
286     }
287     return STATUS_SUCCESS;
288 }
289
290
291 /***********************************************************************
292  *           context_from_server
293  *
294  * Convert a register context from the server format.
295  */
296 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
297 {
298     if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
299
300     to->ContextFlags = CONTEXT_ARM;
301     if (from->flags & SERVER_CTX_CONTROL)
302     {
303         to->ContextFlags |= CONTEXT_CONTROL;
304         to->Sp   = from->ctl.arm_regs.sp;
305         to->Lr   = from->ctl.arm_regs.lr;
306         to->Pc   = from->ctl.arm_regs.pc;
307         to->Cpsr = from->ctl.arm_regs.cpsr;
308     }
309     if (from->flags & SERVER_CTX_INTEGER)
310     {
311         to->ContextFlags |= CONTEXT_INTEGER;
312         to->R0  = from->integer.arm_regs.r[0];
313         to->R1  = from->integer.arm_regs.r[1];
314         to->R2  = from->integer.arm_regs.r[2];
315         to->R3  = from->integer.arm_regs.r[3];
316         to->R4  = from->integer.arm_regs.r[4];
317         to->R5  = from->integer.arm_regs.r[5];
318         to->R6  = from->integer.arm_regs.r[6];
319         to->R7  = from->integer.arm_regs.r[7];
320         to->R8  = from->integer.arm_regs.r[8];
321         to->R9  = from->integer.arm_regs.r[9];
322         to->R10 = from->integer.arm_regs.r[10];
323         to->Fp  = from->integer.arm_regs.r[11];
324         to->Ip  = from->integer.arm_regs.r[12];
325      }
326     return STATUS_SUCCESS;
327 }
328
329
330 /**********************************************************************
331  *           call_stack_handlers
332  *
333  * Call the stack handlers chain.
334  */
335 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
336 {
337     EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
338     DWORD res;
339
340     frame = NtCurrentTeb()->Tib.ExceptionList;
341     nested_frame = NULL;
342     while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
343     {
344         /* Check frame address */
345         if (!is_valid_frame( frame ))
346         {
347             rec->ExceptionFlags |= EH_STACK_INVALID;
348             break;
349         }
350
351         /* Call handler */
352         TRACE( "calling handler at %p code=%x flags=%x\n",
353                frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
354         res = frame->Handler( rec, frame, context, &dispatch );
355         TRACE( "handler at %p returned %x\n", frame->Handler, res );
356
357         if (frame == nested_frame)
358         {
359             /* no longer nested */
360             nested_frame = NULL;
361             rec->ExceptionFlags &= ~EH_NESTED_CALL;
362         }
363
364         switch(res)
365         {
366         case ExceptionContinueExecution:
367             if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
368             return STATUS_NONCONTINUABLE_EXCEPTION;
369         case ExceptionContinueSearch:
370             break;
371         case ExceptionNestedException:
372             if (nested_frame < dispatch) nested_frame = dispatch;
373             rec->ExceptionFlags |= EH_NESTED_CALL;
374             break;
375         default:
376             return STATUS_INVALID_DISPOSITION;
377         }
378         frame = frame->Prev;
379     }
380     return STATUS_UNHANDLED_EXCEPTION;
381 }
382
383
384 /*******************************************************************
385  *              raise_exception
386  *
387  * Implementation of NtRaiseException.
388  */
389 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
390 {
391     NTSTATUS status;
392
393     if (first_chance)
394     {
395         DWORD c;
396
397         for (c = 0; c < rec->NumberParameters; c++)
398             TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
399         if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
400         {
401             if (rec->ExceptionInformation[1] >> 16)
402                 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
403                          rec->ExceptionAddress,
404                          (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
405             else
406                 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
407                          rec->ExceptionAddress,
408                          (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
409         }
410         else
411         {
412             TRACE(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x r0:%04x r1:%04x r2:%04x r3:%04x\n",
413                   context->Pc, context->Sp, context->Lr, context->Cpsr,
414                   context->R0, context->R1, context->R2, context->R3);
415             TRACE(" r4:%04x r5:%04x  r6:%04x  r7:%04x r8:%04x r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
416                   context->R4, context->R5, context->R6, context->R7, context->R8,
417                   context->R9, context->R10, context->Fp, context->Ip );
418         }
419
420         status = send_debug_event( rec, TRUE, context );
421         if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
422             return STATUS_SUCCESS;
423
424         if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
425             return STATUS_SUCCESS;
426
427         if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
428             return status;
429     }
430
431     /* last chance exception */
432
433     status = send_debug_event( rec, FALSE, context );
434     if (status != DBG_CONTINUE)
435     {
436         if (rec->ExceptionFlags & EH_STACK_INVALID)
437             ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
438         else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
439             ERR("Process attempted to continue execution after noncontinuable exception.\n");
440         else
441             ERR("Unhandled exception code %x flags %x addr %p\n",
442                 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
443         NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
444     }
445     return STATUS_SUCCESS;
446 }
447
448
449 /**********************************************************************
450  *              segv_handler
451  *
452  * Handler for SIGSEGV and related errors.
453  */
454 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
455 {
456     EXCEPTION_RECORD rec;
457     CONTEXT context;
458     NTSTATUS status;
459
460     rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
461
462     /* we want the page-fault case to be fast */
463     if ( info->si_code == SEGV_ACCERR )
464         if (!(rec.ExceptionCode = virtual_handle_fault( info->si_addr, 0 ))) return;
465
466     save_context( &context, ucontext );
467     rec.ExceptionRecord  = NULL;
468     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
469     rec.ExceptionAddress = (LPVOID)context.Pc;
470     rec.NumberParameters = 2;
471     rec.ExceptionInformation[0] = 0;  /* FIXME: read/write access ? */
472     rec.ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
473
474     status = raise_exception( &rec, &context, TRUE );
475     if (status) raise_status( status, &rec );
476     restore_context( &context, ucontext );
477 }
478
479 /**********************************************************************
480  *              trap_handler
481  *
482  * Handler for SIGTRAP.
483  */
484 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
485 {
486     EXCEPTION_RECORD rec;
487     CONTEXT context;
488     NTSTATUS status;
489
490     switch ( info->si_code )
491     {
492     case TRAP_TRACE:
493         rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
494         break;
495     case TRAP_BRKPT:
496     default:
497         rec.ExceptionCode = EXCEPTION_BREAKPOINT;
498         break;
499     }
500
501     save_context( &context, ucontext );
502     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
503     rec.ExceptionRecord  = NULL;
504     rec.ExceptionAddress = (LPVOID)context.Pc;
505     rec.NumberParameters = 0;
506     status = raise_exception( &rec, &context, TRUE );
507     if (status) raise_status( status, &rec );
508     restore_context( &context, ucontext );
509 }
510
511 /**********************************************************************
512  *              fpe_handler
513  *
514  * Handler for SIGFPE.
515  */
516 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
517 {
518     EXCEPTION_RECORD rec;
519     CONTEXT context;
520     NTSTATUS status;
521
522     save_fpu( &context, sigcontext );
523     save_context( &context, sigcontext );
524
525     switch (siginfo->si_code & 0xffff )
526     {
527 #ifdef FPE_FLTSUB
528     case FPE_FLTSUB:
529         rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
530         break;
531 #endif
532 #ifdef FPE_INTDIV
533     case FPE_INTDIV:
534         rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
535         break;
536 #endif
537 #ifdef FPE_INTOVF
538     case FPE_INTOVF:
539         rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
540         break;
541 #endif
542 #ifdef FPE_FLTDIV
543     case FPE_FLTDIV:
544         rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
545         break;
546 #endif
547 #ifdef FPE_FLTOVF
548     case FPE_FLTOVF:
549         rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
550         break;
551 #endif
552 #ifdef FPE_FLTUND
553     case FPE_FLTUND:
554         rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
555         break;
556 #endif
557 #ifdef FPE_FLTRES
558     case FPE_FLTRES:
559         rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
560         break;
561 #endif
562 #ifdef FPE_FLTINV
563     case FPE_FLTINV:
564 #endif
565     default:
566         rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
567         break;
568     }
569     rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
570     rec.ExceptionRecord  = NULL;
571     rec.ExceptionAddress = (LPVOID)context.Pc;
572     rec.NumberParameters = 0;
573     status = raise_exception( &rec, &context, TRUE );
574     if (status) raise_status( status, &rec );
575
576     restore_context( &context, sigcontext );
577     restore_fpu( &context, sigcontext );
578 }
579
580 /**********************************************************************
581  *              int_handler
582  *
583  * Handler for SIGINT.
584  */
585 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
586 {
587     if (!dispatch_signal(SIGINT))
588     {
589         EXCEPTION_RECORD rec;
590         CONTEXT context;
591         NTSTATUS status;
592
593         save_context( &context, sigcontext );
594         rec.ExceptionCode    = CONTROL_C_EXIT;
595         rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
596         rec.ExceptionRecord  = NULL;
597         rec.ExceptionAddress = (LPVOID)context.Pc;
598         rec.NumberParameters = 0;
599         status = raise_exception( &rec, &context, TRUE );
600         if (status) raise_status( status, &rec );
601         restore_context( &context, sigcontext );
602     }
603 }
604
605
606 /**********************************************************************
607  *              abrt_handler
608  *
609  * Handler for SIGABRT.
610  */
611 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
612 {
613     EXCEPTION_RECORD rec;
614     CONTEXT context;
615     NTSTATUS status;
616
617     save_context( &context, sigcontext );
618     rec.ExceptionCode    = EXCEPTION_WINE_ASSERTION;
619     rec.ExceptionFlags   = EH_NONCONTINUABLE;
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 );
626 }
627
628
629 /**********************************************************************
630  *              quit_handler
631  *
632  * Handler for SIGQUIT.
633  */
634 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
635 {
636     abort_thread(0);
637 }
638
639
640 /**********************************************************************
641  *              usr1_handler
642  *
643  * Handler for SIGUSR1, used to signal a thread that it got suspended.
644  */
645 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
646 {
647     CONTEXT context;
648
649     save_context( &context, sigcontext );
650     wait_suspend( &context );
651     restore_context( &context, sigcontext );
652 }
653
654
655 /***********************************************************************
656  *           __wine_set_signal_handler   (NTDLL.@)
657  */
658 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
659 {
660     if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
661     if (handlers[sig] != NULL) return -2;
662     handlers[sig] = wsh;
663     return 0;
664 }
665
666
667 /**********************************************************************
668  *             signal_alloc_thread
669  */
670 NTSTATUS signal_alloc_thread( TEB **teb )
671 {
672     static size_t sigstack_zero_bits;
673     SIZE_T size;
674     NTSTATUS status;
675
676     if (!sigstack_zero_bits)
677     {
678         size_t min_size = getpagesize();  /* this is just for the TEB, we don't use a signal stack yet */
679         /* find the first power of two not smaller than min_size */
680         while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
681         assert( sizeof(TEB) <= min_size );
682     }
683
684     size = 1 << sigstack_zero_bits;
685     *teb = NULL;
686     if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
687                                             &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
688     {
689         (*teb)->Tib.Self = &(*teb)->Tib;
690         (*teb)->Tib.ExceptionList = (void *)~0UL;
691     }
692     return status;
693 }
694
695
696 /**********************************************************************
697  *             signal_free_thread
698  */
699 void signal_free_thread( TEB *teb )
700 {
701     SIZE_T size;
702
703     if (teb->DeallocationStack)
704     {
705         size = 0;
706         NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
707     }
708     size = 0;
709     NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
710 }
711
712
713 /**********************************************************************
714  *              signal_init_thread
715  */
716 void signal_init_thread( TEB *teb )
717 {
718     static int init_done;
719
720     if (!init_done)
721     {
722         pthread_key_create( &teb_key, NULL );
723         init_done = 1;
724     }
725     pthread_setspecific( teb_key, teb );
726 }
727
728
729 /**********************************************************************
730  *              signal_init_process
731  */
732 void signal_init_process(void)
733 {
734     struct sigaction sig_act;
735
736     sig_act.sa_mask = server_block_set;
737     sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
738
739     sig_act.sa_sigaction = int_handler;
740     if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
741     sig_act.sa_sigaction = fpe_handler;
742     if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
743     sig_act.sa_sigaction = abrt_handler;
744     if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
745     sig_act.sa_sigaction = quit_handler;
746     if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
747     sig_act.sa_sigaction = usr1_handler;
748     if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
749
750     sig_act.sa_sigaction = segv_handler;
751     if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
752     if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
753 #ifdef SIGBUS
754     if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
755 #endif
756
757 #ifdef SIGTRAP
758     sig_act.sa_sigaction = trap_handler;
759     if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
760 #endif
761     return;
762
763  error:
764     perror("sigaction");
765     exit(1);
766 }
767
768
769 /**********************************************************************
770  *              __wine_enter_vm86   (NTDLL.@)
771  */
772 void __wine_enter_vm86( CONTEXT *context )
773 {
774     MESSAGE("vm86 mode not supported on this platform\n");
775 }
776
777 /***********************************************************************
778  *            RtlUnwind  (NTDLL.@)
779  */
780 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
781 {
782     FIXME( "Not implemented on ARM\n" );
783 }
784
785 /*******************************************************************
786  *              NtRaiseException (NTDLL.@)
787  */
788 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
789 {
790     NTSTATUS status = raise_exception( rec, context, first_chance );
791     if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
792     return status;
793 }
794
795 /***********************************************************************
796  *              RtlRaiseException (NTDLL.@)
797  */
798 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
799 {
800     CONTEXT context;
801     NTSTATUS status;
802
803     RtlCaptureContext( &context );
804     rec->ExceptionAddress = (LPVOID)context.Pc;
805     status = raise_exception( rec, &context, TRUE );
806     if (status) raise_status( status, rec );
807 }
808
809 /*************************************************************************
810  *             RtlCaptureStackBackTrace (NTDLL.@)
811  */
812 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
813 {
814     FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
815     return 0;
816 }
817
818 /***********************************************************************
819  *           call_thread_entry_point
820  */
821 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
822 {
823     __TRY
824     {
825         exit_thread( entry( arg ));
826     }
827     __EXCEPT(unhandled_exception_filter)
828     {
829         NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
830     }
831     __ENDTRY
832     abort();  /* should not be reached */
833 }
834
835 /***********************************************************************
836  *           RtlExitUserThread  (NTDLL.@)
837  */
838 void WINAPI RtlExitUserThread( ULONG status )
839 {
840     exit_thread( status );
841 }
842
843 /***********************************************************************
844  *           abort_thread
845  */
846 void abort_thread( int status )
847 {
848     terminate_thread( status );
849 }
850
851 /**********************************************************************
852  *              DbgBreakPoint   (NTDLL.@)
853  */
854 void WINAPI DbgBreakPoint(void)
855 {
856      kill(getpid(), SIGTRAP);
857 }
858
859 /**********************************************************************
860  *              DbgUserBreakPoint   (NTDLL.@)
861  */
862 void WINAPI DbgUserBreakPoint(void)
863 {
864      kill(getpid(), SIGTRAP);
865 }
866
867 /**********************************************************************
868  *           NtCurrentTeb   (NTDLL.@)
869  */
870 TEB * WINAPI NtCurrentTeb(void)
871 {
872     return pthread_getspecific( teb_key );
873 }
874
875 #endif  /* __arm__ */