ntdll: Improve stub for FileFsAttributeInformation in NtQueryVolumeInformationFile.
[wine] / dlls / ntdll / signal_arm64.c
1 /*
2  * ARM64 signal handling routines
3  *
4  * Copyright 2010-2013 AndrĂ© Hentschel
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #ifdef __aarch64__
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <signal.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34
35 #ifdef HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #endif
38 #ifdef HAVE_SYSCALL_H
39 # include <syscall.h>
40 #else
41 # ifdef HAVE_SYS_SYSCALL_H
42 #  include <sys/syscall.h>
43 # endif
44 #endif
45 #ifdef HAVE_SYS_SIGNAL_H
46 # include <sys/signal.h>
47 #endif
48
49 #include "ntstatus.h"
50 #define WIN32_NO_STATUS
51 #include "windef.h"
52 #include "winternl.h"
53 #include "wine/library.h"
54 #include "wine/exception.h"
55 #include "ntdll_misc.h"
56 #include "wine/debug.h"
57 #include "winnt.h"
58
59 WINE_DEFAULT_DEBUG_CHANNEL(seh);
60
61 static pthread_key_t teb_key;
62
63 /***********************************************************************
64  * signal context platform-specific definitions
65  */
66 #ifdef linux
67
68 typedef ucontext_t SIGCONTEXT;
69
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])
73
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 */
80
81 /* Exceptions */
82 # define FAULT_sig(context)         REG_sig(fault_address, context)
83
84 #endif /* linux */
85
86 static const size_t teb_size = 0x2000;  /* we reserve two pages for the TEB */
87 static size_t signal_stack_size;
88
89 typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
90 typedef int (*wine_signal_handler)(unsigned int sig);
91
92 static wine_signal_handler handlers[256];
93
94 /***********************************************************************
95  *           dispatch_signal
96  */
97 static inline int dispatch_signal(unsigned int sig)
98 {
99     if (handlers[sig] == NULL) return 0;
100     return handlers[sig](sig);
101 }
102
103 /*******************************************************************
104  *         is_valid_frame
105  */
106 static inline BOOL is_valid_frame( void *frame )
107 {
108     if ((ULONG_PTR)frame & 3) return FALSE;
109     return (frame >= NtCurrentTeb()->Tib.StackLimit &&
110             (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1);
111 }
112
113 /***********************************************************************
114  *           save_context
115  *
116  * Set the register values from a sigcontext.
117  */
118 static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext )
119 {
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);
125 #undef C
126
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 */
131 }
132
133
134 /***********************************************************************
135  *           restore_context
136  *
137  * Build a sigcontext from the register values.
138  */
139 static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
140 {
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);
146 #undef C
147
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 */
151 }
152
153
154 /***********************************************************************
155  *           save_fpu
156  *
157  * Set the FPU context from a sigcontext.
158  */
159 static inline void save_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
160 {
161     FIXME( "Not implemented on ARM64\n" );
162 }
163
164
165 /***********************************************************************
166  *           restore_fpu
167  *
168  * Restore the FPU context to a sigcontext.
169  */
170 static inline void restore_fpu( CONTEXT *context, const SIGCONTEXT *sigcontext )
171 {
172     FIXME( "Not implemented on ARM64\n" );
173 }
174
175 /***********************************************************************
176  *              RtlCaptureContext (NTDLL.@)
177  */
178 void WINAPI RtlCaptureContext( CONTEXT *context )
179 {
180     FIXME( "Not implemented on ARM64\n" );
181     memset( context, 0, sizeof(*context) );
182 }
183
184 /***********************************************************************
185  *           set_cpu_context
186  *
187  * Set the new CPU context.
188  */
189 void set_cpu_context( const CONTEXT *context )
190 {
191     FIXME( "Not implemented on ARM64\n" );
192 }
193
194 /***********************************************************************
195  *           copy_context
196  *
197  * Copy a register context according to the flags.
198  */
199 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
200 {
201     flags &= ~CONTEXT_ARM64;  /* get rid of CPU id */
202     if (flags & CONTEXT_CONTROL)
203     {
204         to->Sp      = from->Sp;
205         to->Pc      = from->Pc;
206         to->PState  = from->PState;
207     }
208     if (flags & CONTEXT_INTEGER)
209     {
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);
215 #undef C
216     }
217 }
218
219 /***********************************************************************
220  *           context_to_server
221  *
222  * Convert a register context to the server format.
223  */
224 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
225 {
226     DWORD flags = from->ContextFlags & ~CONTEXT_ARM64;  /* get rid of CPU id */
227
228     memset( to, 0, sizeof(*to) );
229     to->cpu = CPU_ARM64;
230
231     if (flags & CONTEXT_CONTROL)
232     {
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;
237     }
238     if (flags & CONTEXT_INTEGER)
239     {
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);
246 #undef C
247     }
248     return STATUS_SUCCESS;
249 }
250
251
252 /***********************************************************************
253  *           context_from_server
254  *
255  * Convert a register context from the server format.
256  */
257 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
258 {
259     if (from->cpu != CPU_ARM64) return STATUS_INVALID_PARAMETER;
260
261     to->ContextFlags = CONTEXT_ARM64;
262     if (from->flags & SERVER_CTX_CONTROL)
263     {
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;
268     }
269     if (from->flags & SERVER_CTX_INTEGER)
270     {
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);
277 #undef C
278      }
279     return STATUS_SUCCESS;
280 }
281
282 /***********************************************************************
283  *           setup_exception_record
284  *
285  * Setup the exception record and context on the thread stack.
286  */
287 static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func )
288 {
289     struct stack_layout
290     {
291         CONTEXT           context;
292         EXCEPTION_RECORD  rec;
293     } *stack;
294     DWORD exception_code = 0;
295
296     stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
297     stack--;  /* push the stack_layout structure */
298
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;
304
305     save_context( &stack->context, sigcontext );
306
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 */
312
313     return &stack->rec;
314 }
315
316 /**********************************************************************
317  *              raise_segv_exception
318  */
319 static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
320 {
321     NTSTATUS status;
322
323     switch(rec->ExceptionCode)
324     {
325     case EXCEPTION_ACCESS_VIOLATION:
326         if (rec->NumberParameters == 2)
327         {
328             if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
329                                                              rec->ExceptionInformation[0] )))
330                 goto done;
331         }
332         break;
333     }
334     status = NtRaiseException( rec, context, TRUE );
335     if (status) raise_status( status, rec );
336 done:
337     set_cpu_context( context );
338 }
339
340 /**********************************************************************
341  *           call_stack_handlers
342  *
343  * Call the stack handlers chain.
344  */
345 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
346 {
347     EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
348     DWORD res;
349
350     frame = NtCurrentTeb()->Tib.ExceptionList;
351     nested_frame = NULL;
352     while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
353     {
354         /* Check frame address */
355         if (!is_valid_frame( frame ))
356         {
357             rec->ExceptionFlags |= EH_STACK_INVALID;
358             break;
359         }
360
361         /* Call handler */
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 );
366
367         if (frame == nested_frame)
368         {
369             /* no longer nested */
370             nested_frame = NULL;
371             rec->ExceptionFlags &= ~EH_NESTED_CALL;
372         }
373
374         switch(res)
375         {
376         case ExceptionContinueExecution:
377             if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
378             return STATUS_NONCONTINUABLE_EXCEPTION;
379         case ExceptionContinueSearch:
380             break;
381         case ExceptionNestedException:
382             if (nested_frame < dispatch) nested_frame = dispatch;
383             rec->ExceptionFlags |= EH_NESTED_CALL;
384             break;
385         default:
386             return STATUS_INVALID_DISPOSITION;
387         }
388         frame = frame->Prev;
389     }
390     return STATUS_UNHANDLED_EXCEPTION;
391 }
392
393
394 /*******************************************************************
395  *              raise_exception
396  *
397  * Implementation of NtRaiseException.
398  */
399 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
400 {
401     NTSTATUS status;
402
403     if (first_chance)
404     {
405         DWORD c;
406
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)
410         {
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] );
415             else
416                 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
417                          rec->ExceptionAddress,
418                          (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
419         }
420         else
421         {
422             /* FIXME: dump context */
423         }
424
425         status = send_debug_event( rec, TRUE, context );
426         if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
427             return STATUS_SUCCESS;
428
429         if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
430             return STATUS_SUCCESS;
431
432         if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
433             return status;
434     }
435
436     /* last chance exception */
437
438     status = send_debug_event( rec, FALSE, context );
439     if (status != DBG_CONTINUE)
440     {
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");
445         else
446             ERR("Unhandled exception code %x flags %x addr %p\n",
447                 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
448         NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
449     }
450     return STATUS_SUCCESS;
451 }
452
453 /**********************************************************************
454  *              segv_handler
455  *
456  * Handler for SIGSEGV and related errors.
457  */
458 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
459 {
460     EXCEPTION_RECORD *rec;
461     SIGCONTEXT *context = ucontext;
462
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 ))
468     {
469         /* check if this was the last guard page */
470         if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
471         {
472             rec = setup_exception( context, raise_segv_exception );
473             rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
474         }
475         return;
476     }
477
478     rec = setup_exception( context, raise_segv_exception );
479     if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
480
481     switch(signal)
482     {
483     case SIGILL:   /* Invalid opcode exception */
484         rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
485         break;
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;
492         break;
493     case SIGBUS:  /* Alignment check exception */
494         rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
495         break;
496     default:
497         ERR("Got unexpected signal %i\n", signal);
498         rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
499         break;
500     }
501 }
502
503 /**********************************************************************
504  *              trap_handler
505  *
506  * Handler for SIGTRAP.
507  */
508 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
509 {
510     EXCEPTION_RECORD rec;
511     CONTEXT context;
512     NTSTATUS status;
513
514     switch ( info->si_code )
515     {
516     case TRAP_TRACE:
517         rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
518         break;
519     case TRAP_BRKPT:
520     default:
521         rec.ExceptionCode = EXCEPTION_BREAKPOINT;
522         break;
523     }
524
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 );
533 }
534
535 /**********************************************************************
536  *              fpe_handler
537  *
538  * Handler for SIGFPE.
539  */
540 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
541 {
542     EXCEPTION_RECORD rec;
543     CONTEXT context;
544     NTSTATUS status;
545
546     save_fpu( &context, sigcontext );
547     save_context( &context, sigcontext );
548
549     switch (siginfo->si_code & 0xffff )
550     {
551 #ifdef FPE_FLTSUB
552     case FPE_FLTSUB:
553         rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
554         break;
555 #endif
556 #ifdef FPE_INTDIV
557     case FPE_INTDIV:
558         rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
559         break;
560 #endif
561 #ifdef FPE_INTOVF
562     case FPE_INTOVF:
563         rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
564         break;
565 #endif
566 #ifdef FPE_FLTDIV
567     case FPE_FLTDIV:
568         rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
569         break;
570 #endif
571 #ifdef FPE_FLTOVF
572     case FPE_FLTOVF:
573         rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
574         break;
575 #endif
576 #ifdef FPE_FLTUND
577     case FPE_FLTUND:
578         rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
579         break;
580 #endif
581 #ifdef FPE_FLTRES
582     case FPE_FLTRES:
583         rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
584         break;
585 #endif
586 #ifdef FPE_FLTINV
587     case FPE_FLTINV:
588 #endif
589     default:
590         rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
591         break;
592     }
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 );
599
600     restore_context( &context, sigcontext );
601     restore_fpu( &context, sigcontext );
602 }
603
604 /**********************************************************************
605  *              int_handler
606  *
607  * Handler for SIGINT.
608  */
609 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
610 {
611     if (!dispatch_signal(SIGINT))
612     {
613         EXCEPTION_RECORD rec;
614         CONTEXT context;
615         NTSTATUS status;
616
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 );
626     }
627 }
628
629
630 /**********************************************************************
631  *              abrt_handler
632  *
633  * Handler for SIGABRT.
634  */
635 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
636 {
637     EXCEPTION_RECORD rec;
638     CONTEXT context;
639     NTSTATUS status;
640
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 );
650 }
651
652
653 /**********************************************************************
654  *              quit_handler
655  *
656  * Handler for SIGQUIT.
657  */
658 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
659 {
660     abort_thread(0);
661 }
662
663
664 /**********************************************************************
665  *              usr1_handler
666  *
667  * Handler for SIGUSR1, used to signal a thread that it got suspended.
668  */
669 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
670 {
671     CONTEXT context;
672
673     save_context( &context, sigcontext );
674     wait_suspend( &context );
675     restore_context( &context, sigcontext );
676 }
677
678
679 /***********************************************************************
680  *           __wine_set_signal_handler   (NTDLL.@)
681  */
682 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
683 {
684     if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
685     if (handlers[sig] != NULL) return -2;
686     handlers[sig] = wsh;
687     return 0;
688 }
689
690
691 /**********************************************************************
692  *             signal_alloc_thread
693  */
694 NTSTATUS signal_alloc_thread( TEB **teb )
695 {
696     static size_t sigstack_zero_bits;
697     SIZE_T size;
698     NTSTATUS status;
699
700     if (!sigstack_zero_bits)
701     {
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 );
708     }
709
710     size = 1 << sigstack_zero_bits;
711     *teb = NULL;
712     if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
713                                             &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
714     {
715         (*teb)->Tib.Self = &(*teb)->Tib;
716         (*teb)->Tib.ExceptionList = (void *)~0UL;
717     }
718     return status;
719 }
720
721
722 /**********************************************************************
723  *             signal_free_thread
724  */
725 void signal_free_thread( TEB *teb )
726 {
727     SIZE_T size;
728
729     if (teb->DeallocationStack)
730     {
731         size = 0;
732         NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
733     }
734     size = 0;
735     NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
736 }
737
738
739 /**********************************************************************
740  *              signal_init_thread
741  */
742 void signal_init_thread( TEB *teb )
743 {
744     static int init_done;
745
746     if (!init_done)
747     {
748         pthread_key_create( &teb_key, NULL );
749         init_done = 1;
750     }
751     pthread_setspecific( teb_key, teb );
752 }
753
754
755 /**********************************************************************
756  *              signal_init_process
757  */
758 void signal_init_process(void)
759 {
760     struct sigaction sig_act;
761
762     sig_act.sa_mask = server_block_set;
763     sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
764
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;
775
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;
779 #ifdef SIGBUS
780     if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
781 #endif
782
783 #ifdef SIGTRAP
784     sig_act.sa_sigaction = trap_handler;
785     if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
786 #endif
787     return;
788
789  error:
790     perror("sigaction");
791     exit(1);
792 }
793
794
795 /**********************************************************************
796  *              __wine_enter_vm86   (NTDLL.@)
797  */
798 void __wine_enter_vm86( CONTEXT *context )
799 {
800     MESSAGE("vm86 mode not supported on this platform\n");
801 }
802
803 /***********************************************************************
804  *            RtlUnwind  (NTDLL.@)
805  */
806 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
807 {
808     FIXME( "Not implemented on ARM64\n" );
809 }
810
811 /*******************************************************************
812  *              NtRaiseException (NTDLL.@)
813  */
814 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
815 {
816     NTSTATUS status = raise_exception( rec, context, first_chance );
817     if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
818     return status;
819 }
820
821 /***********************************************************************
822  *              RtlRaiseException (NTDLL.@)
823  */
824 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
825 {
826     CONTEXT context;
827     NTSTATUS status;
828
829     RtlCaptureContext( &context );
830     rec->ExceptionAddress = (LPVOID)context.Pc;
831     status = raise_exception( rec, &context, TRUE );
832     if (status) raise_status( status, rec );
833 }
834
835 /*************************************************************************
836  *             RtlCaptureStackBackTrace (NTDLL.@)
837  */
838 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
839 {
840     FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
841     return 0;
842 }
843
844 /***********************************************************************
845  *           call_thread_entry_point
846  */
847 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
848 {
849     __TRY
850     {
851         exit_thread( entry( arg ));
852     }
853     __EXCEPT(unhandled_exception_filter)
854     {
855         NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
856     }
857     __ENDTRY
858     abort();  /* should not be reached */
859 }
860
861 /***********************************************************************
862  *           RtlExitUserThread  (NTDLL.@)
863  */
864 void WINAPI RtlExitUserThread( ULONG status )
865 {
866     exit_thread( status );
867 }
868
869 /***********************************************************************
870  *           abort_thread
871  */
872 void abort_thread( int status )
873 {
874     terminate_thread( status );
875 }
876
877 /**********************************************************************
878  *              DbgBreakPoint   (NTDLL.@)
879  */
880 void WINAPI DbgBreakPoint(void)
881 {
882      kill(getpid(), SIGTRAP);
883 }
884
885 /**********************************************************************
886  *              DbgUserBreakPoint   (NTDLL.@)
887  */
888 void WINAPI DbgUserBreakPoint(void)
889 {
890      kill(getpid(), SIGTRAP);
891 }
892
893 /**********************************************************************
894  *           NtCurrentTeb   (NTDLL.@)
895  */
896 TEB * WINAPI NtCurrentTeb(void)
897 {
898     return pthread_getspecific( teb_key );
899 }
900
901 #endif  /* __aarch64__ */