ieframe: shellbrowser: Strip 'file://' from file URLs in BEFORENAVIGATE2 callbacks.
[wine/multimedia.git] / dlls / ntdll / signal_arm.c
blob0c51c4956211214f17264330b23c15408c52e188
1 /*
2 * ARM signal handling routines
4 * Copyright 2002 Marcus Meissner, SuSE Linux AG
5 * Copyright 2010-2013, 2015 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
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 #ifdef HAVE_SYS_UCONTEXT_H
49 # include <sys/ucontext.h>
50 #endif
52 #define NONAMELESSUNION
53 #define NONAMELESSSTRUCT
54 #include "ntstatus.h"
55 #define WIN32_NO_STATUS
56 #include "windef.h"
57 #include "winternl.h"
58 #include "wine/library.h"
59 #include "wine/exception.h"
60 #include "ntdll_misc.h"
61 #include "wine/debug.h"
62 #include "winnt.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(seh);
66 static pthread_key_t teb_key;
68 /***********************************************************************
69 * signal context platform-specific definitions
71 #ifdef linux
73 #if defined(__ANDROID__) && !defined(HAVE_SYS_UCONTEXT_H)
74 typedef struct ucontext
76 unsigned long uc_flags;
77 struct ucontext *uc_link;
78 stack_t uc_stack;
79 struct sigcontext uc_mcontext;
80 sigset_t uc_sigmask;
81 unsigned long uc_regspace[128] __attribute__((__aligned__(8)));
82 } ucontext_t;
83 #endif
85 /* All Registers access - only for local access */
86 # define REG_sig(reg_name, context) ((context)->uc_mcontext.reg_name)
87 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.arm_r##reg_num)
89 /* Special Registers access */
90 # define SP_sig(context) REG_sig(arm_sp, context) /* Stack pointer */
91 # define LR_sig(context) REG_sig(arm_lr, context) /* Link register */
92 # define PC_sig(context) REG_sig(arm_pc, context) /* Program counter */
93 # define CPSR_sig(context) REG_sig(arm_cpsr, context) /* Current State Register */
94 # define IP_sig(context) REG_sig(arm_ip, context) /* Intra-Procedure-call scratch register */
95 # define FP_sig(context) REG_sig(arm_fp, context) /* Frame pointer */
97 /* Exceptions */
98 # define ERROR_sig(context) REG_sig(error_code, context)
99 # define TRAP_sig(context) REG_sig(trap_no, context)
101 #elif defined(__FreeBSD__)
103 /* All Registers access - only for local access */
104 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.__gregs[reg_num])
106 /* Special Registers access */
107 # define SP_sig(context) REGn_sig(_REG_SP, context) /* Stack pointer */
108 # define LR_sig(context) REGn_sig(_REG_LR, context) /* Link register */
109 # define PC_sig(context) REGn_sig(_REG_PC, context) /* Program counter */
110 # define CPSR_sig(context) REGn_sig(_REG_CPSR, context) /* Current State Register */
111 # define IP_sig(context) REGn_sig(_REG_R12, context) /* Intra-Procedure-call scratch register */
112 # define FP_sig(context) REGn_sig(_REG_FP, context) /* Frame pointer */
114 #endif /* linux */
116 enum arm_trap_code
118 TRAP_ARM_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
119 TRAP_ARM_PRIVINFLT = 6, /* Invalid opcode exception */
120 TRAP_ARM_PAGEFLT = 14, /* Page fault */
121 TRAP_ARM_ALIGNFLT = 17, /* Alignment check exception */
124 typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
125 typedef int (*wine_signal_handler)(unsigned int sig);
127 static wine_signal_handler handlers[256];
130 struct UNWIND_INFO
132 WORD function_length;
133 WORD unknown1 : 7;
134 WORD count : 5;
135 WORD unknown2 : 4;
139 /***********************************************************************
140 * get_trap_code
142 * Get the trap code for a signal.
144 static inline enum arm_trap_code get_trap_code( const ucontext_t *sigcontext )
146 #ifdef TRAP_sig
147 return TRAP_sig(sigcontext);
148 #else
149 return TRAP_ARM_UNKNOWN; /* unknown trap code */
150 #endif
153 /***********************************************************************
154 * get_error_code
156 * Get the error code for a signal.
158 static inline WORD get_error_code( const ucontext_t *sigcontext )
160 #ifdef ERROR_sig
161 return ERROR_sig(sigcontext);
162 #else
163 return 0;
164 #endif
167 /***********************************************************************
168 * dispatch_signal
170 static inline int dispatch_signal(unsigned int sig)
172 if (handlers[sig] == NULL) return 0;
173 return handlers[sig](sig);
176 /*******************************************************************
177 * is_valid_frame
179 static inline BOOL is_valid_frame( void *frame )
181 if ((ULONG_PTR)frame & 3) return FALSE;
182 return (frame >= NtCurrentTeb()->Tib.StackLimit &&
183 (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1);
186 /***********************************************************************
187 * save_context
189 * Set the register values from a sigcontext.
191 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
193 #define C(x) context->R##x = REGn_sig(x,sigcontext)
194 /* Save normal registers */
195 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
196 #undef C
198 context->ContextFlags = CONTEXT_FULL;
199 context->Sp = SP_sig(sigcontext); /* Stack pointer */
200 context->Lr = LR_sig(sigcontext); /* Link register */
201 context->Pc = PC_sig(sigcontext); /* Program Counter */
202 context->Cpsr = CPSR_sig(sigcontext); /* Current State Register */
203 context->Ip = IP_sig(sigcontext); /* Intra-Procedure-call scratch register */
204 context->Fp = FP_sig(sigcontext); /* Frame pointer */
208 /***********************************************************************
209 * restore_context
211 * Build a sigcontext from the register values.
213 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
215 #define C(x) REGn_sig(x,sigcontext) = context->R##x
216 /* Restore normal registers */
217 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
218 #undef C
220 SP_sig(sigcontext) = context->Sp; /* Stack pointer */
221 LR_sig(sigcontext) = context->Lr ; /* Link register */
222 PC_sig(sigcontext) = context->Pc; /* Program Counter */
223 CPSR_sig(sigcontext) = context->Cpsr; /* Current State Register */
224 IP_sig(sigcontext) = context->Ip; /* Intra-Procedure-call scratch register */
225 FP_sig(sigcontext) = context->Fp; /* Frame pointer */
229 /***********************************************************************
230 * save_fpu
232 * Set the FPU context from a sigcontext.
234 static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
236 FIXME("not implemented\n");
240 /***********************************************************************
241 * restore_fpu
243 * Restore the FPU context to a sigcontext.
245 static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext )
247 FIXME("not implemented\n");
250 /**************************************************************************
251 * __chkstk (NTDLL.@)
253 * Should check if we can decrement SP by the value provided in r4, but we shouldn't need that.
255 __ASM_GLOBAL_FUNC( __chkstk, "bx lr" )
257 /***********************************************************************
258 * RtlCaptureContext (NTDLL.@)
260 /* FIXME: Use the Stack instead of the actual register values */
261 __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
262 ".arm\n\t"
263 "stmfd SP!, {r1}\n\t"
264 "mov r1, #0x40\n\t" /* CONTEXT_ARM */
265 "add r1, r1, #0x3\n\t" /* CONTEXT_FULL */
266 "str r1, [r0]\n\t" /* context->ContextFlags */
267 "ldmfd SP!, {r1}\n\t"
268 "str r0, [r0, #0x4]\n\t" /* context->R0 */
269 "str r1, [r0, #0x8]\n\t" /* context->R1 */
270 "str r2, [r0, #0xc]\n\t" /* context->R2 */
271 "str r3, [r0, #0x10]\n\t" /* context->R3 */
272 "str r4, [r0, #0x14]\n\t" /* context->R4 */
273 "str r5, [r0, #0x18]\n\t" /* context->R5 */
274 "str r6, [r0, #0x1c]\n\t" /* context->R6 */
275 "str r7, [r0, #0x20]\n\t" /* context->R7 */
276 "str r8, [r0, #0x24]\n\t" /* context->R8 */
277 "str r9, [r0, #0x28]\n\t" /* context->R9 */
278 "str r10, [r0, #0x2c]\n\t" /* context->R10 */
279 "str r11, [r0, #0x30]\n\t" /* context->Fp */
280 "str IP, [r0, #0x34]\n\t" /* context->Ip */
281 "str SP, [r0, #0x38]\n\t" /* context->Sp */
282 "str LR, [r0, #0x3c]\n\t" /* context->Lr */
283 "str PC, [r0, #0x40]\n\t" /* context->Pc */
284 "mrs r1, CPSR\n\t"
285 "str r1, [r0, #0x44]\n\t" /* context->Cpsr */
286 "bx lr"
290 /***********************************************************************
291 * set_cpu_context
293 * Set the new CPU context.
295 /* FIXME: What about the CPSR? */
296 __ASM_GLOBAL_FUNC( set_cpu_context,
297 "mov IP, r0\n\t"
298 "ldr r0, [IP, #0x4]\n\t" /* context->R0 */
299 "ldr r1, [IP, #0x8]\n\t" /* context->R1 */
300 "ldr r2, [IP, #0xc]\n\t" /* context->R2 */
301 "ldr r3, [IP, #0x10]\n\t" /* context->R3 */
302 "ldr r4, [IP, #0x14]\n\t" /* context->R4 */
303 "ldr r5, [IP, #0x18]\n\t" /* context->R5 */
304 "ldr r6, [IP, #0x1c]\n\t" /* context->R6 */
305 "ldr r7, [IP, #0x20]\n\t" /* context->R7 */
306 "ldr r8, [IP, #0x24]\n\t" /* context->R8 */
307 "ldr r9, [IP, #0x28]\n\t" /* context->R9 */
308 "ldr r10, [IP, #0x2c]\n\t" /* context->R10 */
309 "ldr r11, [IP, #0x30]\n\t" /* context->Fp */
310 "ldr SP, [IP, #0x38]\n\t" /* context->Sp */
311 "ldr LR, [IP, #0x3c]\n\t" /* context->Lr */
312 "ldr PC, [IP, #0x40]\n\t" /* context->Pc */
316 /***********************************************************************
317 * copy_context
319 * Copy a register context according to the flags.
321 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
323 flags &= ~CONTEXT_ARM; /* get rid of CPU id */
324 if (flags & CONTEXT_CONTROL)
326 to->Sp = from->Sp;
327 to->Lr = from->Lr;
328 to->Pc = from->Pc;
329 to->Cpsr = from->Cpsr;
331 if (flags & CONTEXT_INTEGER)
333 to->R0 = from->R0;
334 to->R1 = from->R1;
335 to->R2 = from->R2;
336 to->R3 = from->R3;
337 to->R4 = from->R4;
338 to->R5 = from->R5;
339 to->R6 = from->R6;
340 to->R7 = from->R7;
341 to->R8 = from->R8;
342 to->R9 = from->R9;
343 to->R10 = from->R10;
344 to->Ip = from->Ip;
345 to->Fp = from->Fp;
350 /***********************************************************************
351 * context_to_server
353 * Convert a register context to the server format.
355 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
357 DWORD flags = from->ContextFlags & ~CONTEXT_ARM; /* get rid of CPU id */
359 memset( to, 0, sizeof(*to) );
360 to->cpu = CPU_ARM;
362 if (flags & CONTEXT_CONTROL)
364 to->flags |= SERVER_CTX_CONTROL;
365 to->ctl.arm_regs.sp = from->Sp;
366 to->ctl.arm_regs.lr = from->Lr;
367 to->ctl.arm_regs.pc = from->Pc;
368 to->ctl.arm_regs.cpsr = from->Cpsr;
370 if (flags & CONTEXT_INTEGER)
372 to->flags |= SERVER_CTX_INTEGER;
373 to->integer.arm_regs.r[0] = from->R0;
374 to->integer.arm_regs.r[1] = from->R1;
375 to->integer.arm_regs.r[2] = from->R2;
376 to->integer.arm_regs.r[3] = from->R3;
377 to->integer.arm_regs.r[4] = from->R4;
378 to->integer.arm_regs.r[5] = from->R5;
379 to->integer.arm_regs.r[6] = from->R6;
380 to->integer.arm_regs.r[7] = from->R7;
381 to->integer.arm_regs.r[8] = from->R8;
382 to->integer.arm_regs.r[9] = from->R9;
383 to->integer.arm_regs.r[10] = from->R10;
384 to->integer.arm_regs.r[11] = from->Fp;
385 to->integer.arm_regs.r[12] = from->Ip;
387 return STATUS_SUCCESS;
391 /***********************************************************************
392 * context_from_server
394 * Convert a register context from the server format.
396 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
398 if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
400 to->ContextFlags = CONTEXT_ARM;
401 if (from->flags & SERVER_CTX_CONTROL)
403 to->ContextFlags |= CONTEXT_CONTROL;
404 to->Sp = from->ctl.arm_regs.sp;
405 to->Lr = from->ctl.arm_regs.lr;
406 to->Pc = from->ctl.arm_regs.pc;
407 to->Cpsr = from->ctl.arm_regs.cpsr;
409 if (from->flags & SERVER_CTX_INTEGER)
411 to->ContextFlags |= CONTEXT_INTEGER;
412 to->R0 = from->integer.arm_regs.r[0];
413 to->R1 = from->integer.arm_regs.r[1];
414 to->R2 = from->integer.arm_regs.r[2];
415 to->R3 = from->integer.arm_regs.r[3];
416 to->R4 = from->integer.arm_regs.r[4];
417 to->R5 = from->integer.arm_regs.r[5];
418 to->R6 = from->integer.arm_regs.r[6];
419 to->R7 = from->integer.arm_regs.r[7];
420 to->R8 = from->integer.arm_regs.r[8];
421 to->R9 = from->integer.arm_regs.r[9];
422 to->R10 = from->integer.arm_regs.r[10];
423 to->Fp = from->integer.arm_regs.r[11];
424 to->Ip = from->integer.arm_regs.r[12];
426 return STATUS_SUCCESS;
429 extern void raise_func_trampoline_thumb( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
430 __ASM_GLOBAL_FUNC( raise_func_trampoline_thumb,
431 ".thumb\n\t"
432 "blx r2\n\t"
433 "bkpt")
435 extern void raise_func_trampoline_arm( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
436 __ASM_GLOBAL_FUNC( raise_func_trampoline_arm,
437 ".arm\n\t"
438 "blx r2\n\t"
439 "bkpt")
441 /***********************************************************************
442 * setup_exception_record
444 * Setup the exception record and context on the thread stack.
446 static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func func )
448 struct stack_layout
450 CONTEXT context;
451 EXCEPTION_RECORD rec;
452 } *stack;
453 DWORD exception_code = 0;
455 stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
456 stack--; /* push the stack_layout structure */
458 stack->rec.ExceptionRecord = NULL;
459 stack->rec.ExceptionCode = exception_code;
460 stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
461 stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
462 stack->rec.NumberParameters = 0;
464 save_context( &stack->context, sigcontext );
466 /* now modify the sigcontext to return to the raise function */
467 SP_sig(sigcontext) = (DWORD)stack;
468 if (CPSR_sig(sigcontext) & 0x20)
469 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_thumb;
470 else
471 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_arm;
472 REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for raise_func */
473 REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for raise_func */
474 REGn_sig(2, sigcontext) = (DWORD)func; /* the raise_func as third arg for the trampoline */
477 return &stack->rec;
480 /**********************************************************************
481 * raise_segv_exception
483 static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
485 NTSTATUS status;
487 switch(rec->ExceptionCode)
489 case EXCEPTION_ACCESS_VIOLATION:
490 if (rec->NumberParameters == 2)
492 if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
493 rec->ExceptionInformation[0], FALSE )))
494 goto done;
496 break;
498 status = NtRaiseException( rec, context, TRUE );
499 if (status) raise_status( status, rec );
500 done:
501 set_cpu_context( context );
504 /**********************************************************************
505 * call_stack_handlers
507 * Call the stack handlers chain.
509 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
511 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
512 DWORD res;
514 frame = NtCurrentTeb()->Tib.ExceptionList;
515 nested_frame = NULL;
516 while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
518 /* Check frame address */
519 if (!is_valid_frame( frame ))
521 rec->ExceptionFlags |= EH_STACK_INVALID;
522 break;
525 /* Call handler */
526 TRACE( "calling handler at %p code=%x flags=%x\n",
527 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
528 res = frame->Handler( rec, frame, context, &dispatch );
529 TRACE( "handler at %p returned %x\n", frame->Handler, res );
531 if (frame == nested_frame)
533 /* no longer nested */
534 nested_frame = NULL;
535 rec->ExceptionFlags &= ~EH_NESTED_CALL;
538 switch(res)
540 case ExceptionContinueExecution:
541 if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
542 return STATUS_NONCONTINUABLE_EXCEPTION;
543 case ExceptionContinueSearch:
544 break;
545 case ExceptionNestedException:
546 if (nested_frame < dispatch) nested_frame = dispatch;
547 rec->ExceptionFlags |= EH_NESTED_CALL;
548 break;
549 default:
550 return STATUS_INVALID_DISPOSITION;
552 frame = frame->Prev;
554 return STATUS_UNHANDLED_EXCEPTION;
558 /*******************************************************************
559 * raise_exception
561 * Implementation of NtRaiseException.
563 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
565 NTSTATUS status;
567 if (first_chance)
569 DWORD c;
571 TRACE( "code=%x flags=%x addr=%p pc=%08x tid=%04x\n",
572 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
573 context->Pc, GetCurrentThreadId() );
574 for (c = 0; c < rec->NumberParameters; c++)
575 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
576 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
578 if (rec->ExceptionInformation[1] >> 16)
579 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
580 rec->ExceptionAddress,
581 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
582 else
583 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
584 rec->ExceptionAddress,
585 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
587 else
589 TRACE( " r0=%08x r1=%08x r2=%08x r3=%08x r4=%08x r5=%08x\n",
590 context->R0, context->R1, context->R2, context->R3, context->R4, context->R5 );
591 TRACE( " r6=%08x r7=%08x r8=%08x r9=%08x r10=%08x fp=%08x\n",
592 context->R6, context->R7, context->R8, context->R9, context->R10, context->Fp );
593 TRACE( " ip=%08x sp=%08x lr=%08x pc=%08x cpsr=%08x\n",
594 context->Ip, context->Sp, context->Lr, context->Pc, context->Cpsr );
597 status = send_debug_event( rec, TRUE, context );
598 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
599 return STATUS_SUCCESS;
601 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
602 return STATUS_SUCCESS;
604 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
605 return status;
608 /* last chance exception */
610 status = send_debug_event( rec, FALSE, context );
611 if (status != DBG_CONTINUE)
613 if (rec->ExceptionFlags & EH_STACK_INVALID)
614 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
615 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
616 ERR("Process attempted to continue execution after noncontinuable exception.\n");
617 else
618 ERR("Unhandled exception code %x flags %x addr %p\n",
619 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
620 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
622 return STATUS_SUCCESS;
626 /**********************************************************************
627 * segv_handler
629 * Handler for SIGSEGV and related errors.
631 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
633 EXCEPTION_RECORD *rec;
634 ucontext_t *context = ucontext;
636 /* check for page fault inside the thread stack */
637 if (get_trap_code(context) == TRAP_ARM_PAGEFLT &&
638 (char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
639 (char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
640 virtual_handle_stack_fault( info->si_addr ))
642 /* check if this was the last guard page */
643 if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
645 rec = setup_exception( context, raise_segv_exception );
646 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
648 return;
651 rec = setup_exception( context, raise_segv_exception );
652 if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
654 switch(get_trap_code(context))
656 case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */
657 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
658 break;
659 case TRAP_ARM_PAGEFLT: /* Page fault */
660 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
661 rec->NumberParameters = 2;
662 rec->ExceptionInformation[0] = (get_error_code(context) & 0x800) != 0;
663 rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
664 break;
665 case TRAP_ARM_ALIGNFLT: /* Alignment check exception */
666 rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
667 break;
668 case TRAP_ARM_UNKNOWN: /* Unknown fault code */
669 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
670 rec->NumberParameters = 2;
671 rec->ExceptionInformation[0] = 0;
672 rec->ExceptionInformation[1] = 0xffffffff;
673 break;
674 default:
675 ERR("Got unexpected trap %d\n", get_trap_code(context));
676 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
677 break;
681 /**********************************************************************
682 * trap_handler
684 * Handler for SIGTRAP.
686 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
688 EXCEPTION_RECORD rec;
689 CONTEXT context;
690 NTSTATUS status;
692 switch ( info->si_code )
694 case TRAP_TRACE:
695 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
696 break;
697 case TRAP_BRKPT:
698 default:
699 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
700 break;
703 save_context( &context, ucontext );
704 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
705 rec.ExceptionRecord = NULL;
706 rec.ExceptionAddress = (LPVOID)context.Pc;
707 rec.NumberParameters = 0;
708 status = raise_exception( &rec, &context, TRUE );
709 if (status) raise_status( status, &rec );
710 restore_context( &context, ucontext );
713 /**********************************************************************
714 * fpe_handler
716 * Handler for SIGFPE.
718 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
720 EXCEPTION_RECORD rec;
721 CONTEXT context;
722 NTSTATUS status;
724 save_fpu( &context, sigcontext );
725 save_context( &context, sigcontext );
727 switch (siginfo->si_code & 0xffff )
729 #ifdef FPE_FLTSUB
730 case FPE_FLTSUB:
731 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
732 break;
733 #endif
734 #ifdef FPE_INTDIV
735 case FPE_INTDIV:
736 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
737 break;
738 #endif
739 #ifdef FPE_INTOVF
740 case FPE_INTOVF:
741 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
742 break;
743 #endif
744 #ifdef FPE_FLTDIV
745 case FPE_FLTDIV:
746 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
747 break;
748 #endif
749 #ifdef FPE_FLTOVF
750 case FPE_FLTOVF:
751 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
752 break;
753 #endif
754 #ifdef FPE_FLTUND
755 case FPE_FLTUND:
756 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
757 break;
758 #endif
759 #ifdef FPE_FLTRES
760 case FPE_FLTRES:
761 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
762 break;
763 #endif
764 #ifdef FPE_FLTINV
765 case FPE_FLTINV:
766 #endif
767 default:
768 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
769 break;
771 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
772 rec.ExceptionRecord = NULL;
773 rec.ExceptionAddress = (LPVOID)context.Pc;
774 rec.NumberParameters = 0;
775 status = raise_exception( &rec, &context, TRUE );
776 if (status) raise_status( status, &rec );
778 restore_context( &context, sigcontext );
779 restore_fpu( &context, sigcontext );
782 /**********************************************************************
783 * int_handler
785 * Handler for SIGINT.
787 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
789 if (!dispatch_signal(SIGINT))
791 EXCEPTION_RECORD rec;
792 CONTEXT context;
793 NTSTATUS status;
795 save_context( &context, sigcontext );
796 rec.ExceptionCode = CONTROL_C_EXIT;
797 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
798 rec.ExceptionRecord = NULL;
799 rec.ExceptionAddress = (LPVOID)context.Pc;
800 rec.NumberParameters = 0;
801 status = raise_exception( &rec, &context, TRUE );
802 if (status) raise_status( status, &rec );
803 restore_context( &context, sigcontext );
808 /**********************************************************************
809 * abrt_handler
811 * Handler for SIGABRT.
813 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
815 EXCEPTION_RECORD rec;
816 CONTEXT context;
817 NTSTATUS status;
819 save_context( &context, sigcontext );
820 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
821 rec.ExceptionFlags = EH_NONCONTINUABLE;
822 rec.ExceptionRecord = NULL;
823 rec.ExceptionAddress = (LPVOID)context.Pc;
824 rec.NumberParameters = 0;
825 status = raise_exception( &rec, &context, TRUE );
826 if (status) raise_status( status, &rec );
827 restore_context( &context, sigcontext );
831 /**********************************************************************
832 * quit_handler
834 * Handler for SIGQUIT.
836 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
838 abort_thread(0);
842 /**********************************************************************
843 * usr1_handler
845 * Handler for SIGUSR1, used to signal a thread that it got suspended.
847 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
849 CONTEXT context;
851 save_context( &context, sigcontext );
852 wait_suspend( &context );
853 restore_context( &context, sigcontext );
857 /***********************************************************************
858 * __wine_set_signal_handler (NTDLL.@)
860 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
862 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
863 if (handlers[sig] != NULL) return -2;
864 handlers[sig] = wsh;
865 return 0;
869 /**********************************************************************
870 * signal_alloc_thread
872 NTSTATUS signal_alloc_thread( TEB **teb )
874 static size_t sigstack_zero_bits;
875 SIZE_T size;
876 NTSTATUS status;
878 if (!sigstack_zero_bits)
880 size_t min_size = page_size;
881 /* find the first power of two not smaller than min_size */
882 while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
883 assert( sizeof(TEB) <= min_size );
886 size = 1 << sigstack_zero_bits;
887 *teb = NULL;
888 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
889 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
891 (*teb)->Tib.Self = &(*teb)->Tib;
892 (*teb)->Tib.ExceptionList = (void *)~0UL;
894 return status;
898 /**********************************************************************
899 * signal_free_thread
901 void signal_free_thread( TEB *teb )
903 SIZE_T size;
905 if (teb->DeallocationStack)
907 size = 0;
908 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
910 size = 0;
911 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
914 /**********************************************************************
915 * set_tpidrurw
917 * Win32/ARM applications expect the TEB pointer to be in the TPIDRURW register.
919 #ifdef __ARM_ARCH_7A__
920 extern void set_tpidrurw( TEB *teb );
921 __ASM_GLOBAL_FUNC( set_tpidrurw,
922 "mcr p15, 0, r0, c13, c0, 2\n\t" /* TEB -> TPIDRURW */
923 "bx lr" )
924 #else
925 void set_tpidrurw( TEB *teb )
928 #endif
930 /**********************************************************************
931 * signal_init_thread
933 void signal_init_thread( TEB *teb )
935 static BOOL init_done;
937 if (!init_done)
939 pthread_key_create( &teb_key, NULL );
940 init_done = TRUE;
942 set_tpidrurw( teb );
943 pthread_setspecific( teb_key, teb );
947 /**********************************************************************
948 * signal_init_process
950 void signal_init_process(void)
952 struct sigaction sig_act;
954 sig_act.sa_mask = server_block_set;
955 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
957 sig_act.sa_sigaction = int_handler;
958 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
959 sig_act.sa_sigaction = fpe_handler;
960 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
961 sig_act.sa_sigaction = abrt_handler;
962 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
963 sig_act.sa_sigaction = quit_handler;
964 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
965 sig_act.sa_sigaction = usr1_handler;
966 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
968 sig_act.sa_sigaction = segv_handler;
969 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
970 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
971 #ifdef SIGBUS
972 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
973 #endif
975 #ifdef SIGTRAP
976 sig_act.sa_sigaction = trap_handler;
977 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
978 #endif
979 return;
981 error:
982 perror("sigaction");
983 exit(1);
987 /**********************************************************************
988 * __wine_enter_vm86 (NTDLL.@)
990 void __wine_enter_vm86( CONTEXT *context )
992 MESSAGE("vm86 mode not supported on this platform\n");
996 /**********************************************************************
997 * RtlAddFunctionTable (NTDLL.@)
999 BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD addr )
1001 FIXME( "%p %u %x: stub\n", table, count, addr );
1002 return TRUE;
1006 /**********************************************************************
1007 * RtlDeleteFunctionTable (NTDLL.@)
1009 BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
1011 FIXME( "%p: stub\n", table );
1012 return TRUE;
1015 /**********************************************************************
1016 * find_function_info
1018 static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, HMODULE module,
1019 RUNTIME_FUNCTION *func, ULONG size )
1021 int min = 0;
1022 int max = size/sizeof(*func) - 1;
1024 while (min <= max)
1026 int pos = (min + max) / 2;
1027 DWORD begin = (func[pos].BeginAddress & ~1), end;
1028 if (func[pos].u.s.Flag)
1029 end = begin + func[pos].u.s.FunctionLength * 2;
1030 else
1032 struct UNWIND_INFO *info;
1033 info = (struct UNWIND_INFO *)((char *)module + func[pos].u.UnwindData);
1034 end = begin + info->function_length * 2;
1037 if ((char *)pc < (char *)module + begin) max = pos - 1;
1038 else if ((char *)pc >= (char *)module + end) min = pos + 1;
1039 else return func + pos;
1041 return NULL;
1044 /**********************************************************************
1045 * RtlLookupFunctionEntry (NTDLL.@)
1047 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, DWORD *base,
1048 UNWIND_HISTORY_TABLE *table )
1050 LDR_MODULE *module;
1051 RUNTIME_FUNCTION *func;
1052 ULONG size;
1054 /* FIXME: should use the history table to make things faster */
1056 if (LdrFindEntryForAddress( (void *)pc, &module ))
1058 WARN( "module not found for %lx\n", pc );
1059 return NULL;
1061 if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1062 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1064 WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
1065 return NULL;
1067 func = find_function_info( pc, module->BaseAddress, func, size );
1068 if (func) *base = (DWORD)module->BaseAddress;
1069 return func;
1072 /***********************************************************************
1073 * RtlUnwind (NTDLL.@)
1075 void WINAPI RtlUnwind( void *endframe, void *target_ip, EXCEPTION_RECORD *rec, void *retval )
1077 CONTEXT context;
1078 EXCEPTION_RECORD record;
1079 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch;
1080 DWORD res;
1082 RtlCaptureContext( &context );
1083 context.R0 = (DWORD)retval;
1085 /* build an exception record, if we do not have one */
1086 if (!rec)
1088 record.ExceptionCode = STATUS_UNWIND;
1089 record.ExceptionFlags = 0;
1090 record.ExceptionRecord = NULL;
1091 record.ExceptionAddress = (void *)context.Pc;
1092 record.NumberParameters = 0;
1093 rec = &record;
1096 rec->ExceptionFlags |= EH_UNWINDING | (endframe ? 0 : EH_EXIT_UNWIND);
1098 TRACE( "code=%x flags=%x\n", rec->ExceptionCode, rec->ExceptionFlags );
1100 /* get chain of exception frames */
1101 frame = NtCurrentTeb()->Tib.ExceptionList;
1102 while ((frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL) && (frame != endframe))
1104 /* Check frame address */
1105 if (endframe && ((void*)frame > endframe))
1106 raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
1108 if (!is_valid_frame( frame )) raise_status( STATUS_BAD_STACK, rec );
1110 /* Call handler */
1111 TRACE( "calling handler at %p code=%x flags=%x\n",
1112 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
1113 res = frame->Handler(rec, frame, &context, &dispatch);
1114 TRACE( "handler at %p returned %x\n", frame->Handler, res );
1116 switch(res)
1118 case ExceptionContinueSearch:
1119 break;
1120 case ExceptionCollidedUnwind:
1121 frame = dispatch;
1122 break;
1123 default:
1124 raise_status( STATUS_INVALID_DISPOSITION, rec );
1125 break;
1127 frame = __wine_pop_frame( frame );
1131 /*******************************************************************
1132 * NtRaiseException (NTDLL.@)
1134 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1136 NTSTATUS status = raise_exception( rec, context, first_chance );
1137 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
1138 return status;
1141 /***********************************************************************
1142 * RtlRaiseException (NTDLL.@)
1144 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
1146 CONTEXT context;
1147 NTSTATUS status;
1149 RtlCaptureContext( &context );
1150 rec->ExceptionAddress = (LPVOID)context.Pc;
1151 status = raise_exception( rec, &context, TRUE );
1152 if (status) raise_status( status, rec );
1155 /*************************************************************************
1156 * RtlCaptureStackBackTrace (NTDLL.@)
1158 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
1160 FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
1161 return 0;
1164 /***********************************************************************
1165 * call_thread_entry_point
1167 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
1169 __TRY
1171 exit_thread( entry( arg ));
1173 __EXCEPT(unhandled_exception_filter)
1175 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
1177 __ENDTRY
1178 abort(); /* should not be reached */
1181 /***********************************************************************
1182 * RtlExitUserThread (NTDLL.@)
1184 void WINAPI RtlExitUserThread( ULONG status )
1186 exit_thread( status );
1189 /***********************************************************************
1190 * abort_thread
1192 void abort_thread( int status )
1194 terminate_thread( status );
1197 /**********************************************************************
1198 * DbgBreakPoint (NTDLL.@)
1200 void WINAPI DbgBreakPoint(void)
1202 kill(getpid(), SIGTRAP);
1205 /**********************************************************************
1206 * DbgUserBreakPoint (NTDLL.@)
1208 void WINAPI DbgUserBreakPoint(void)
1210 kill(getpid(), SIGTRAP);
1213 /**********************************************************************
1214 * NtCurrentTeb (NTDLL.@)
1216 TEB * WINAPI NtCurrentTeb(void)
1218 return pthread_getspecific( teb_key );
1221 #endif /* __arm__ */