winepulse v18: Latency and compilation improvements
[wine/multimedia.git] / dlls / ntdll / signal_arm.c
blob93a2ff5c94a333d89b4df9ebba2f8e42d148b893
1 /*
2 * ARM signal handling routines
4 * Copyright 2002 Marcus Meissner, SuSE Linux AG
5 * Copyright 2010, 2011 André Hentschel
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #ifdef __arm__
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 #ifdef HAVE_SYSCALL_H
40 # include <syscall.h>
41 #else
42 # ifdef HAVE_SYS_SYSCALL_H
43 # include <sys/syscall.h>
44 # endif
45 #endif
46 #ifdef HAVE_SYS_SIGNAL_H
47 # include <sys/signal.h>
48 #endif
50 #include "ntstatus.h"
51 #define WIN32_NO_STATUS
52 #include "windef.h"
53 #include "winternl.h"
54 #include "wine/library.h"
55 #include "wine/exception.h"
56 #include "ntdll_misc.h"
57 #include "wine/debug.h"
58 #include "winnt.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(seh);
62 static pthread_key_t teb_key;
64 /***********************************************************************
65 * signal context platform-specific definitions
67 #ifdef linux
69 typedef ucontext_t SIGCONTEXT;
71 /* All Registers access - only for local access */
72 # define REG_sig(reg_name, context) ((context)->uc_mcontext.reg_name)
73 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.arm_r##reg_num)
75 /* Special Registers access */
76 # define SP_sig(context) REG_sig(arm_sp, context) /* Stack pointer */
77 # define LR_sig(context) REG_sig(arm_lr, context) /* Link register */
78 # define PC_sig(context) REG_sig(arm_pc, context) /* Program counter */
79 # define CPSR_sig(context) REG_sig(arm_cpsr, context) /* Current State Register */
80 # define IP_sig(context) REG_sig(arm_ip, context) /* Intra-Procedure-call scratch register */
81 # define FP_sig(context) REG_sig(arm_fp, context) /* Frame pointer */
83 /* Exceptions */
84 # define ERROR_sig(context) REG_sig(error_code, context)
85 # define FAULT_sig(context) REG_sig(fault_address, context)
86 # define TRAP_sig(context) REG_sig(trap_no, context)
88 #endif /* linux */
90 enum arm_trap_code
92 TRAP_ARM_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
93 TRAP_ARM_PRIVINFLT = 6, /* Invalid opcode exception */
94 TRAP_ARM_PAGEFLT = 14, /* Page fault */
95 TRAP_ARM_ALIGNFLT = 17, /* Alignment check exception */
98 typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
99 typedef int (*wine_signal_handler)(unsigned int sig);
101 static wine_signal_handler handlers[256];
103 /***********************************************************************
104 * dispatch_signal
106 static inline int dispatch_signal(unsigned int sig)
108 if (handlers[sig] == NULL) return 0;
109 return handlers[sig](sig);
112 /*******************************************************************
113 * is_valid_frame
115 static inline BOOL is_valid_frame( void *frame )
117 if ((ULONG_PTR)frame & 3) return FALSE;
118 return (frame >= NtCurrentTeb()->Tib.StackLimit &&
119 (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1);
122 /***********************************************************************
123 * save_context
125 * Set the register values from a sigcontext.
127 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
129 #define C(x) context->R##x = REGn_sig(x,sigcontext)
130 /* Save normal registers */
131 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
132 #undef C
134 context->ContextFlags = CONTEXT_FULL;
135 context->Sp = SP_sig(sigcontext); /* Stack pointer */
136 context->Lr = LR_sig(sigcontext); /* Link register */
137 context->Pc = PC_sig(sigcontext); /* Program Counter */
138 context->Cpsr = CPSR_sig(sigcontext); /* Current State Register */
139 context->Ip = IP_sig(sigcontext); /* Intra-Procedure-call scratch register */
140 context->Fp = FP_sig(sigcontext); /* Frame pointer */
144 /***********************************************************************
145 * restore_context
147 * Build a sigcontext from the register values.
149 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
151 #define C(x) REGn_sig(x,sigcontext) = context->R##x
152 /* Restore normal registers */
153 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
154 #undef C
156 SP_sig(sigcontext) = context->Sp; /* Stack pointer */
157 LR_sig(sigcontext) = context->Lr ; /* Link register */
158 PC_sig(sigcontext) = context->Pc; /* Program Counter */
159 CPSR_sig(sigcontext) = context->Cpsr; /* Current State Register */
160 IP_sig(sigcontext) = context->Ip; /* Intra-Procedure-call scratch register */
161 FP_sig(sigcontext) = context->Fp; /* Frame pointer */
165 /***********************************************************************
166 * save_fpu
168 * Set the FPU context from a sigcontext.
170 static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
172 FIXME("not implemented\n");
176 /***********************************************************************
177 * restore_fpu
179 * Restore the FPU context to a sigcontext.
181 static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext )
183 FIXME("not implemented\n");
187 /***********************************************************************
188 * RtlCaptureContext (NTDLL.@)
190 /* FIXME: Use the Stack instead of the actual register values */
191 __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
192 ".arm\n\t"
193 "stmfd SP!, {r1}\n\t"
194 "mov r1, #0x40\n\t" /* CONTEXT_ARM */
195 "add r1, r1, #0x3\n\t" /* CONTEXT_FULL */
196 "str r1, [r0]\n\t" /* context->ContextFlags */
197 "ldmfd SP!, {r1}\n\t"
198 "str r0, [r0, #0x4]\n\t" /* context->R0 */
199 "str r1, [r0, #0x8]\n\t" /* context->R1 */
200 "str r2, [r0, #0xc]\n\t" /* context->R2 */
201 "str r3, [r0, #0x10]\n\t" /* context->R3 */
202 "str r4, [r0, #0x14]\n\t" /* context->R4 */
203 "str r5, [r0, #0x18]\n\t" /* context->R5 */
204 "str r6, [r0, #0x1c]\n\t" /* context->R6 */
205 "str r7, [r0, #0x20]\n\t" /* context->R7 */
206 "str r8, [r0, #0x24]\n\t" /* context->R8 */
207 "str r9, [r0, #0x28]\n\t" /* context->R9 */
208 "str r10, [r0, #0x2c]\n\t" /* context->R10 */
209 "str r11, [r0, #0x30]\n\t" /* context->Fp */
210 "str IP, [r0, #0x34]\n\t" /* context->Ip */
211 "str SP, [r0, #0x38]\n\t" /* context->Sp */
212 "str LR, [r0, #0x3c]\n\t" /* context->Lr */
213 "str LR, [r0, #0x40]\n\t" /* context->Pc */
214 "mrs r1, CPSR\n\t"
215 "str r1, [r0, #0x44]\n\t" /* context->Cpsr */
216 "mov PC, LR\n"
220 /***********************************************************************
221 * set_cpu_context
223 * Set the new CPU context.
225 /* FIXME: What about the CPSR? */
226 __ASM_GLOBAL_FUNC( set_cpu_context,
227 "mov IP, r0\n\t"
228 "ldr r0, [IP, #0x4]\n\t" /* context->R0 */
229 "ldr r1, [IP, #0x8]\n\t" /* context->R1 */
230 "ldr r2, [IP, #0xc]\n\t" /* context->R2 */
231 "ldr r3, [IP, #0x10]\n\t" /* context->R3 */
232 "ldr r4, [IP, #0x14]\n\t" /* context->R4 */
233 "ldr r5, [IP, #0x18]\n\t" /* context->R5 */
234 "ldr r6, [IP, #0x1c]\n\t" /* context->R6 */
235 "ldr r7, [IP, #0x20]\n\t" /* context->R7 */
236 "ldr r8, [IP, #0x24]\n\t" /* context->R8 */
237 "ldr r9, [IP, #0x28]\n\t" /* context->R9 */
238 "ldr r10, [IP, #0x2c]\n\t" /* context->R10 */
239 "ldr r11, [IP, #0x30]\n\t" /* context->Fp */
240 "ldr SP, [IP, #0x38]\n\t" /* context->Sp */
241 "ldr LR, [IP, #0x3c]\n\t" /* context->Lr */
242 "ldr PC, [IP, #0x40]\n\t" /* context->Pc */
246 /***********************************************************************
247 * copy_context
249 * Copy a register context according to the flags.
251 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
253 flags &= ~CONTEXT_ARM; /* get rid of CPU id */
254 if (flags & CONTEXT_CONTROL)
256 to->Sp = from->Sp;
257 to->Lr = from->Lr;
258 to->Pc = from->Pc;
259 to->Cpsr = from->Cpsr;
261 if (flags & CONTEXT_INTEGER)
263 to->R0 = from->R0;
264 to->R1 = from->R1;
265 to->R2 = from->R2;
266 to->R3 = from->R3;
267 to->R4 = from->R4;
268 to->R5 = from->R5;
269 to->R6 = from->R6;
270 to->R7 = from->R7;
271 to->R8 = from->R8;
272 to->R9 = from->R9;
273 to->R10 = from->R10;
274 to->Ip = from->Ip;
275 to->Fp = from->Fp;
280 /***********************************************************************
281 * context_to_server
283 * Convert a register context to the server format.
285 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
287 DWORD flags = from->ContextFlags & ~CONTEXT_ARM; /* get rid of CPU id */
289 memset( to, 0, sizeof(*to) );
290 to->cpu = CPU_ARM;
292 if (flags & CONTEXT_CONTROL)
294 to->flags |= SERVER_CTX_CONTROL;
295 to->ctl.arm_regs.sp = from->Sp;
296 to->ctl.arm_regs.lr = from->Lr;
297 to->ctl.arm_regs.pc = from->Pc;
298 to->ctl.arm_regs.cpsr = from->Cpsr;
300 if (flags & CONTEXT_INTEGER)
302 to->flags |= SERVER_CTX_INTEGER;
303 to->integer.arm_regs.r[0] = from->R0;
304 to->integer.arm_regs.r[1] = from->R1;
305 to->integer.arm_regs.r[2] = from->R2;
306 to->integer.arm_regs.r[3] = from->R3;
307 to->integer.arm_regs.r[4] = from->R4;
308 to->integer.arm_regs.r[5] = from->R5;
309 to->integer.arm_regs.r[6] = from->R6;
310 to->integer.arm_regs.r[7] = from->R7;
311 to->integer.arm_regs.r[8] = from->R8;
312 to->integer.arm_regs.r[9] = from->R9;
313 to->integer.arm_regs.r[10] = from->R10;
314 to->integer.arm_regs.r[11] = from->Fp;
315 to->integer.arm_regs.r[12] = from->Ip;
317 return STATUS_SUCCESS;
321 /***********************************************************************
322 * context_from_server
324 * Convert a register context from the server format.
326 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
328 if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
330 to->ContextFlags = CONTEXT_ARM;
331 if (from->flags & SERVER_CTX_CONTROL)
333 to->ContextFlags |= CONTEXT_CONTROL;
334 to->Sp = from->ctl.arm_regs.sp;
335 to->Lr = from->ctl.arm_regs.lr;
336 to->Pc = from->ctl.arm_regs.pc;
337 to->Cpsr = from->ctl.arm_regs.cpsr;
339 if (from->flags & SERVER_CTX_INTEGER)
341 to->ContextFlags |= CONTEXT_INTEGER;
342 to->R0 = from->integer.arm_regs.r[0];
343 to->R1 = from->integer.arm_regs.r[1];
344 to->R2 = from->integer.arm_regs.r[2];
345 to->R3 = from->integer.arm_regs.r[3];
346 to->R4 = from->integer.arm_regs.r[4];
347 to->R5 = from->integer.arm_regs.r[5];
348 to->R6 = from->integer.arm_regs.r[6];
349 to->R7 = from->integer.arm_regs.r[7];
350 to->R8 = from->integer.arm_regs.r[8];
351 to->R9 = from->integer.arm_regs.r[9];
352 to->R10 = from->integer.arm_regs.r[10];
353 to->Fp = from->integer.arm_regs.r[11];
354 to->Ip = from->integer.arm_regs.r[12];
356 return STATUS_SUCCESS;
359 extern void raise_func_trampoline_thumb( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
360 __ASM_GLOBAL_FUNC( raise_func_trampoline_thumb,
361 ".thumb\n\t"
362 "blx r2\n\t"
363 "bkpt")
365 extern void raise_func_trampoline_arm( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
366 __ASM_GLOBAL_FUNC( raise_func_trampoline_arm,
367 ".arm\n\t"
368 "blx r2\n\t"
369 "bkpt")
371 /***********************************************************************
372 * setup_exception_record
374 * Setup the exception record and context on the thread stack.
376 static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func func )
378 struct stack_layout
380 CONTEXT context;
381 EXCEPTION_RECORD rec;
382 } *stack;
383 DWORD exception_code = 0;
385 stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
386 stack--; /* push the stack_layout structure */
388 stack->rec.ExceptionRecord = NULL;
389 stack->rec.ExceptionCode = exception_code;
390 stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
391 stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
392 stack->rec.NumberParameters = 0;
394 save_context( &stack->context, sigcontext );
396 /* now modify the sigcontext to return to the raise function */
397 SP_sig(sigcontext) = (DWORD)stack;
398 if (CPSR_sig(sigcontext) & 0x20)
399 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_thumb;
400 else
401 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_arm;
402 REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for raise_func */
403 REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for raise_func */
404 REGn_sig(2, sigcontext) = (DWORD)func; /* the raise_func as third arg for the trampoline */
407 return &stack->rec;
410 /**********************************************************************
411 * raise_segv_exception
413 static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
415 NTSTATUS status;
417 switch(rec->ExceptionCode)
419 case EXCEPTION_ACCESS_VIOLATION:
420 if (rec->NumberParameters == 2)
422 if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
423 rec->ExceptionInformation[0] )))
424 goto done;
426 break;
428 status = NtRaiseException( rec, context, TRUE );
429 if (status) raise_status( status, rec );
430 done:
431 set_cpu_context( context );
434 /**********************************************************************
435 * call_stack_handlers
437 * Call the stack handlers chain.
439 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
441 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
442 DWORD res;
444 frame = NtCurrentTeb()->Tib.ExceptionList;
445 nested_frame = NULL;
446 while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
448 /* Check frame address */
449 if (!is_valid_frame( frame ))
451 rec->ExceptionFlags |= EH_STACK_INVALID;
452 break;
455 /* Call handler */
456 TRACE( "calling handler at %p code=%x flags=%x\n",
457 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
458 res = frame->Handler( rec, frame, context, &dispatch );
459 TRACE( "handler at %p returned %x\n", frame->Handler, res );
461 if (frame == nested_frame)
463 /* no longer nested */
464 nested_frame = NULL;
465 rec->ExceptionFlags &= ~EH_NESTED_CALL;
468 switch(res)
470 case ExceptionContinueExecution:
471 if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
472 return STATUS_NONCONTINUABLE_EXCEPTION;
473 case ExceptionContinueSearch:
474 break;
475 case ExceptionNestedException:
476 if (nested_frame < dispatch) nested_frame = dispatch;
477 rec->ExceptionFlags |= EH_NESTED_CALL;
478 break;
479 default:
480 return STATUS_INVALID_DISPOSITION;
482 frame = frame->Prev;
484 return STATUS_UNHANDLED_EXCEPTION;
488 /*******************************************************************
489 * raise_exception
491 * Implementation of NtRaiseException.
493 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
495 NTSTATUS status;
497 if (first_chance)
499 DWORD c;
501 for (c = 0; c < rec->NumberParameters; c++)
502 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
503 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
505 if (rec->ExceptionInformation[1] >> 16)
506 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
507 rec->ExceptionAddress,
508 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
509 else
510 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
511 rec->ExceptionAddress,
512 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
514 else
516 TRACE(" Pc:%04x Sp:%04x Lr:%04x Cpsr:%04x r0:%04x r1:%04x r2:%04x r3:%04x\n",
517 context->Pc, context->Sp, context->Lr, context->Cpsr,
518 context->R0, context->R1, context->R2, context->R3);
519 TRACE(" r4:%04x r5:%04x r6:%04x r7:%04x r8:%04x r9:%04x r10:%04x Fp:%04x Ip:%04x\n",
520 context->R4, context->R5, context->R6, context->R7, context->R8,
521 context->R9, context->R10, context->Fp, context->Ip );
524 status = send_debug_event( rec, TRUE, context );
525 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
526 return STATUS_SUCCESS;
528 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
529 return STATUS_SUCCESS;
531 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
532 return status;
535 /* last chance exception */
537 status = send_debug_event( rec, FALSE, context );
538 if (status != DBG_CONTINUE)
540 if (rec->ExceptionFlags & EH_STACK_INVALID)
541 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
542 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
543 ERR("Process attempted to continue execution after noncontinuable exception.\n");
544 else
545 ERR("Unhandled exception code %x flags %x addr %p\n",
546 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
547 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
549 return STATUS_SUCCESS;
553 /**********************************************************************
554 * segv_handler
556 * Handler for SIGSEGV and related errors.
558 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
560 EXCEPTION_RECORD *rec;
561 SIGCONTEXT *context = ucontext;
563 /* check for page fault inside the thread stack */
564 if (TRAP_sig(context) == TRAP_ARM_PAGEFLT &&
565 (char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
566 (char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
567 virtual_handle_stack_fault( info->si_addr ))
569 /* check if this was the last guard page */
570 if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
572 rec = setup_exception( context, raise_segv_exception );
573 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
575 return;
578 rec = setup_exception( context, raise_segv_exception );
579 if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
581 switch(TRAP_sig(context))
583 case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */
584 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
585 break;
586 case TRAP_ARM_PAGEFLT: /* Page fault */
587 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
588 rec->NumberParameters = 2;
589 rec->ExceptionInformation[0] = (ERROR_sig(context) & 0x800) != 0;
590 rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
591 break;
592 case TRAP_ARM_ALIGNFLT: /* Alignment check exception */
593 rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
594 break;
595 default:
596 ERR("Got unexpected trap %ld\n", TRAP_sig(context));
597 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
598 break;
602 /**********************************************************************
603 * trap_handler
605 * Handler for SIGTRAP.
607 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
609 EXCEPTION_RECORD rec;
610 CONTEXT context;
611 NTSTATUS status;
613 switch ( info->si_code )
615 case TRAP_TRACE:
616 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
617 break;
618 case TRAP_BRKPT:
619 default:
620 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
621 break;
624 save_context( &context, ucontext );
625 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
626 rec.ExceptionRecord = NULL;
627 rec.ExceptionAddress = (LPVOID)context.Pc;
628 rec.NumberParameters = 0;
629 status = raise_exception( &rec, &context, TRUE );
630 if (status) raise_status( status, &rec );
631 restore_context( &context, ucontext );
634 /**********************************************************************
635 * fpe_handler
637 * Handler for SIGFPE.
639 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
641 EXCEPTION_RECORD rec;
642 CONTEXT context;
643 NTSTATUS status;
645 save_fpu( &context, sigcontext );
646 save_context( &context, sigcontext );
648 switch (siginfo->si_code & 0xffff )
650 #ifdef FPE_FLTSUB
651 case FPE_FLTSUB:
652 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
653 break;
654 #endif
655 #ifdef FPE_INTDIV
656 case FPE_INTDIV:
657 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
658 break;
659 #endif
660 #ifdef FPE_INTOVF
661 case FPE_INTOVF:
662 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
663 break;
664 #endif
665 #ifdef FPE_FLTDIV
666 case FPE_FLTDIV:
667 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
668 break;
669 #endif
670 #ifdef FPE_FLTOVF
671 case FPE_FLTOVF:
672 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
673 break;
674 #endif
675 #ifdef FPE_FLTUND
676 case FPE_FLTUND:
677 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
678 break;
679 #endif
680 #ifdef FPE_FLTRES
681 case FPE_FLTRES:
682 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
683 break;
684 #endif
685 #ifdef FPE_FLTINV
686 case FPE_FLTINV:
687 #endif
688 default:
689 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
690 break;
692 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
693 rec.ExceptionRecord = NULL;
694 rec.ExceptionAddress = (LPVOID)context.Pc;
695 rec.NumberParameters = 0;
696 status = raise_exception( &rec, &context, TRUE );
697 if (status) raise_status( status, &rec );
699 restore_context( &context, sigcontext );
700 restore_fpu( &context, sigcontext );
703 /**********************************************************************
704 * int_handler
706 * Handler for SIGINT.
708 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
710 if (!dispatch_signal(SIGINT))
712 EXCEPTION_RECORD rec;
713 CONTEXT context;
714 NTSTATUS status;
716 save_context( &context, sigcontext );
717 rec.ExceptionCode = CONTROL_C_EXIT;
718 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
719 rec.ExceptionRecord = NULL;
720 rec.ExceptionAddress = (LPVOID)context.Pc;
721 rec.NumberParameters = 0;
722 status = raise_exception( &rec, &context, TRUE );
723 if (status) raise_status( status, &rec );
724 restore_context( &context, sigcontext );
729 /**********************************************************************
730 * abrt_handler
732 * Handler for SIGABRT.
734 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
736 EXCEPTION_RECORD rec;
737 CONTEXT context;
738 NTSTATUS status;
740 save_context( &context, sigcontext );
741 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
742 rec.ExceptionFlags = EH_NONCONTINUABLE;
743 rec.ExceptionRecord = NULL;
744 rec.ExceptionAddress = (LPVOID)context.Pc;
745 rec.NumberParameters = 0;
746 status = raise_exception( &rec, &context, TRUE );
747 if (status) raise_status( status, &rec );
748 restore_context( &context, sigcontext );
752 /**********************************************************************
753 * quit_handler
755 * Handler for SIGQUIT.
757 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
759 abort_thread(0);
763 /**********************************************************************
764 * usr1_handler
766 * Handler for SIGUSR1, used to signal a thread that it got suspended.
768 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
770 CONTEXT context;
772 save_context( &context, sigcontext );
773 wait_suspend( &context );
774 restore_context( &context, sigcontext );
778 /***********************************************************************
779 * __wine_set_signal_handler (NTDLL.@)
781 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
783 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
784 if (handlers[sig] != NULL) return -2;
785 handlers[sig] = wsh;
786 return 0;
790 /**********************************************************************
791 * signal_alloc_thread
793 NTSTATUS signal_alloc_thread( TEB **teb )
795 static size_t sigstack_zero_bits;
796 SIZE_T size;
797 NTSTATUS status;
799 if (!sigstack_zero_bits)
801 size_t min_size = getpagesize(); /* this is just for the TEB, we don't use a signal stack yet */
802 /* find the first power of two not smaller than min_size */
803 while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
804 assert( sizeof(TEB) <= min_size );
807 size = 1 << sigstack_zero_bits;
808 *teb = NULL;
809 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
810 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
812 (*teb)->Tib.Self = &(*teb)->Tib;
813 (*teb)->Tib.ExceptionList = (void *)~0UL;
815 return status;
819 /**********************************************************************
820 * signal_free_thread
822 void signal_free_thread( TEB *teb )
824 SIZE_T size;
826 if (teb->DeallocationStack)
828 size = 0;
829 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
831 size = 0;
832 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
836 /**********************************************************************
837 * signal_init_thread
839 void signal_init_thread( TEB *teb )
841 static int init_done;
843 if (!init_done)
845 pthread_key_create( &teb_key, NULL );
846 init_done = 1;
848 pthread_setspecific( teb_key, teb );
852 /**********************************************************************
853 * signal_init_process
855 void signal_init_process(void)
857 struct sigaction sig_act;
859 sig_act.sa_mask = server_block_set;
860 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
862 sig_act.sa_sigaction = int_handler;
863 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
864 sig_act.sa_sigaction = fpe_handler;
865 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
866 sig_act.sa_sigaction = abrt_handler;
867 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
868 sig_act.sa_sigaction = quit_handler;
869 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
870 sig_act.sa_sigaction = usr1_handler;
871 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
873 sig_act.sa_sigaction = segv_handler;
874 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
875 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
876 #ifdef SIGBUS
877 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
878 #endif
880 #ifdef SIGTRAP
881 sig_act.sa_sigaction = trap_handler;
882 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
883 #endif
884 return;
886 error:
887 perror("sigaction");
888 exit(1);
892 /**********************************************************************
893 * __wine_enter_vm86 (NTDLL.@)
895 void __wine_enter_vm86( CONTEXT *context )
897 MESSAGE("vm86 mode not supported on this platform\n");
900 /***********************************************************************
901 * RtlUnwind (NTDLL.@)
903 void WINAPI RtlUnwind( PVOID pEndFrame, PVOID targetIp, PEXCEPTION_RECORD pRecord, PVOID retval )
905 FIXME( "Not implemented on ARM\n" );
908 /*******************************************************************
909 * NtRaiseException (NTDLL.@)
911 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
913 NTSTATUS status = raise_exception( rec, context, first_chance );
914 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
915 return status;
918 /***********************************************************************
919 * RtlRaiseException (NTDLL.@)
921 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
923 CONTEXT context;
924 NTSTATUS status;
926 RtlCaptureContext( &context );
927 rec->ExceptionAddress = (LPVOID)context.Pc;
928 status = raise_exception( rec, &context, TRUE );
929 if (status) raise_status( status, rec );
932 /*************************************************************************
933 * RtlCaptureStackBackTrace (NTDLL.@)
935 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
937 FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
938 return 0;
941 /***********************************************************************
942 * call_thread_entry_point
944 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
946 __TRY
948 exit_thread( entry( arg ));
950 __EXCEPT(unhandled_exception_filter)
952 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
954 __ENDTRY
955 abort(); /* should not be reached */
958 /***********************************************************************
959 * RtlExitUserThread (NTDLL.@)
961 void WINAPI RtlExitUserThread( ULONG status )
963 exit_thread( status );
966 /***********************************************************************
967 * abort_thread
969 void abort_thread( int status )
971 terminate_thread( status );
974 /**********************************************************************
975 * DbgBreakPoint (NTDLL.@)
977 void WINAPI DbgBreakPoint(void)
979 kill(getpid(), SIGTRAP);
982 /**********************************************************************
983 * DbgUserBreakPoint (NTDLL.@)
985 void WINAPI DbgUserBreakPoint(void)
987 kill(getpid(), SIGTRAP);
990 /**********************************************************************
991 * NtCurrentTeb (NTDLL.@)
993 TEB * WINAPI NtCurrentTeb(void)
995 return pthread_getspecific( teb_key );
998 #endif /* __arm__ */