winedump: Add more image debug types.
[wine.git] / dlls / ntdll / signal_arm.c
blobbdb27afd0e6725c01ded6d8a5182e9029698036a
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");
251 /***********************************************************************
252 * RtlCaptureContext (NTDLL.@)
254 /* FIXME: Use the Stack instead of the actual register values */
255 __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
256 ".arm\n\t"
257 "stmfd SP!, {r1}\n\t"
258 "mov r1, #0x40\n\t" /* CONTEXT_ARM */
259 "add r1, r1, #0x3\n\t" /* CONTEXT_FULL */
260 "str r1, [r0]\n\t" /* context->ContextFlags */
261 "ldmfd SP!, {r1}\n\t"
262 "str r0, [r0, #0x4]\n\t" /* context->R0 */
263 "str r1, [r0, #0x8]\n\t" /* context->R1 */
264 "str r2, [r0, #0xc]\n\t" /* context->R2 */
265 "str r3, [r0, #0x10]\n\t" /* context->R3 */
266 "str r4, [r0, #0x14]\n\t" /* context->R4 */
267 "str r5, [r0, #0x18]\n\t" /* context->R5 */
268 "str r6, [r0, #0x1c]\n\t" /* context->R6 */
269 "str r7, [r0, #0x20]\n\t" /* context->R7 */
270 "str r8, [r0, #0x24]\n\t" /* context->R8 */
271 "str r9, [r0, #0x28]\n\t" /* context->R9 */
272 "str r10, [r0, #0x2c]\n\t" /* context->R10 */
273 "str r11, [r0, #0x30]\n\t" /* context->Fp */
274 "str IP, [r0, #0x34]\n\t" /* context->Ip */
275 "str SP, [r0, #0x38]\n\t" /* context->Sp */
276 "str LR, [r0, #0x3c]\n\t" /* context->Lr */
277 "str PC, [r0, #0x40]\n\t" /* context->Pc */
278 "mrs r1, CPSR\n\t"
279 "str r1, [r0, #0x44]\n\t" /* context->Cpsr */
280 "mov PC, LR\n"
284 /***********************************************************************
285 * set_cpu_context
287 * Set the new CPU context.
289 /* FIXME: What about the CPSR? */
290 __ASM_GLOBAL_FUNC( set_cpu_context,
291 "mov IP, r0\n\t"
292 "ldr r0, [IP, #0x4]\n\t" /* context->R0 */
293 "ldr r1, [IP, #0x8]\n\t" /* context->R1 */
294 "ldr r2, [IP, #0xc]\n\t" /* context->R2 */
295 "ldr r3, [IP, #0x10]\n\t" /* context->R3 */
296 "ldr r4, [IP, #0x14]\n\t" /* context->R4 */
297 "ldr r5, [IP, #0x18]\n\t" /* context->R5 */
298 "ldr r6, [IP, #0x1c]\n\t" /* context->R6 */
299 "ldr r7, [IP, #0x20]\n\t" /* context->R7 */
300 "ldr r8, [IP, #0x24]\n\t" /* context->R8 */
301 "ldr r9, [IP, #0x28]\n\t" /* context->R9 */
302 "ldr r10, [IP, #0x2c]\n\t" /* context->R10 */
303 "ldr r11, [IP, #0x30]\n\t" /* context->Fp */
304 "ldr SP, [IP, #0x38]\n\t" /* context->Sp */
305 "ldr LR, [IP, #0x3c]\n\t" /* context->Lr */
306 "ldr PC, [IP, #0x40]\n\t" /* context->Pc */
310 /***********************************************************************
311 * copy_context
313 * Copy a register context according to the flags.
315 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
317 flags &= ~CONTEXT_ARM; /* get rid of CPU id */
318 if (flags & CONTEXT_CONTROL)
320 to->Sp = from->Sp;
321 to->Lr = from->Lr;
322 to->Pc = from->Pc;
323 to->Cpsr = from->Cpsr;
325 if (flags & CONTEXT_INTEGER)
327 to->R0 = from->R0;
328 to->R1 = from->R1;
329 to->R2 = from->R2;
330 to->R3 = from->R3;
331 to->R4 = from->R4;
332 to->R5 = from->R5;
333 to->R6 = from->R6;
334 to->R7 = from->R7;
335 to->R8 = from->R8;
336 to->R9 = from->R9;
337 to->R10 = from->R10;
338 to->Ip = from->Ip;
339 to->Fp = from->Fp;
344 /***********************************************************************
345 * context_to_server
347 * Convert a register context to the server format.
349 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
351 DWORD flags = from->ContextFlags & ~CONTEXT_ARM; /* get rid of CPU id */
353 memset( to, 0, sizeof(*to) );
354 to->cpu = CPU_ARM;
356 if (flags & CONTEXT_CONTROL)
358 to->flags |= SERVER_CTX_CONTROL;
359 to->ctl.arm_regs.sp = from->Sp;
360 to->ctl.arm_regs.lr = from->Lr;
361 to->ctl.arm_regs.pc = from->Pc;
362 to->ctl.arm_regs.cpsr = from->Cpsr;
364 if (flags & CONTEXT_INTEGER)
366 to->flags |= SERVER_CTX_INTEGER;
367 to->integer.arm_regs.r[0] = from->R0;
368 to->integer.arm_regs.r[1] = from->R1;
369 to->integer.arm_regs.r[2] = from->R2;
370 to->integer.arm_regs.r[3] = from->R3;
371 to->integer.arm_regs.r[4] = from->R4;
372 to->integer.arm_regs.r[5] = from->R5;
373 to->integer.arm_regs.r[6] = from->R6;
374 to->integer.arm_regs.r[7] = from->R7;
375 to->integer.arm_regs.r[8] = from->R8;
376 to->integer.arm_regs.r[9] = from->R9;
377 to->integer.arm_regs.r[10] = from->R10;
378 to->integer.arm_regs.r[11] = from->Fp;
379 to->integer.arm_regs.r[12] = from->Ip;
381 return STATUS_SUCCESS;
385 /***********************************************************************
386 * context_from_server
388 * Convert a register context from the server format.
390 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
392 if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
394 to->ContextFlags = CONTEXT_ARM;
395 if (from->flags & SERVER_CTX_CONTROL)
397 to->ContextFlags |= CONTEXT_CONTROL;
398 to->Sp = from->ctl.arm_regs.sp;
399 to->Lr = from->ctl.arm_regs.lr;
400 to->Pc = from->ctl.arm_regs.pc;
401 to->Cpsr = from->ctl.arm_regs.cpsr;
403 if (from->flags & SERVER_CTX_INTEGER)
405 to->ContextFlags |= CONTEXT_INTEGER;
406 to->R0 = from->integer.arm_regs.r[0];
407 to->R1 = from->integer.arm_regs.r[1];
408 to->R2 = from->integer.arm_regs.r[2];
409 to->R3 = from->integer.arm_regs.r[3];
410 to->R4 = from->integer.arm_regs.r[4];
411 to->R5 = from->integer.arm_regs.r[5];
412 to->R6 = from->integer.arm_regs.r[6];
413 to->R7 = from->integer.arm_regs.r[7];
414 to->R8 = from->integer.arm_regs.r[8];
415 to->R9 = from->integer.arm_regs.r[9];
416 to->R10 = from->integer.arm_regs.r[10];
417 to->Fp = from->integer.arm_regs.r[11];
418 to->Ip = from->integer.arm_regs.r[12];
420 return STATUS_SUCCESS;
423 extern void raise_func_trampoline_thumb( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
424 __ASM_GLOBAL_FUNC( raise_func_trampoline_thumb,
425 ".thumb\n\t"
426 "blx r2\n\t"
427 "bkpt")
429 extern void raise_func_trampoline_arm( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
430 __ASM_GLOBAL_FUNC( raise_func_trampoline_arm,
431 ".arm\n\t"
432 "blx r2\n\t"
433 "bkpt")
435 /***********************************************************************
436 * setup_exception_record
438 * Setup the exception record and context on the thread stack.
440 static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func func )
442 struct stack_layout
444 CONTEXT context;
445 EXCEPTION_RECORD rec;
446 } *stack;
447 DWORD exception_code = 0;
449 stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
450 stack--; /* push the stack_layout structure */
452 stack->rec.ExceptionRecord = NULL;
453 stack->rec.ExceptionCode = exception_code;
454 stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
455 stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
456 stack->rec.NumberParameters = 0;
458 save_context( &stack->context, sigcontext );
460 /* now modify the sigcontext to return to the raise function */
461 SP_sig(sigcontext) = (DWORD)stack;
462 if (CPSR_sig(sigcontext) & 0x20)
463 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_thumb;
464 else
465 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_arm;
466 REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for raise_func */
467 REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for raise_func */
468 REGn_sig(2, sigcontext) = (DWORD)func; /* the raise_func as third arg for the trampoline */
471 return &stack->rec;
474 /**********************************************************************
475 * raise_segv_exception
477 static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
479 NTSTATUS status;
481 switch(rec->ExceptionCode)
483 case EXCEPTION_ACCESS_VIOLATION:
484 if (rec->NumberParameters == 2)
486 if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
487 rec->ExceptionInformation[0], FALSE )))
488 goto done;
490 break;
492 status = NtRaiseException( rec, context, TRUE );
493 if (status) raise_status( status, rec );
494 done:
495 set_cpu_context( context );
498 /**********************************************************************
499 * call_stack_handlers
501 * Call the stack handlers chain.
503 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
505 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
506 DWORD res;
508 frame = NtCurrentTeb()->Tib.ExceptionList;
509 nested_frame = NULL;
510 while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
512 /* Check frame address */
513 if (!is_valid_frame( frame ))
515 rec->ExceptionFlags |= EH_STACK_INVALID;
516 break;
519 /* Call handler */
520 TRACE( "calling handler at %p code=%x flags=%x\n",
521 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
522 res = frame->Handler( rec, frame, context, &dispatch );
523 TRACE( "handler at %p returned %x\n", frame->Handler, res );
525 if (frame == nested_frame)
527 /* no longer nested */
528 nested_frame = NULL;
529 rec->ExceptionFlags &= ~EH_NESTED_CALL;
532 switch(res)
534 case ExceptionContinueExecution:
535 if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
536 return STATUS_NONCONTINUABLE_EXCEPTION;
537 case ExceptionContinueSearch:
538 break;
539 case ExceptionNestedException:
540 if (nested_frame < dispatch) nested_frame = dispatch;
541 rec->ExceptionFlags |= EH_NESTED_CALL;
542 break;
543 default:
544 return STATUS_INVALID_DISPOSITION;
546 frame = frame->Prev;
548 return STATUS_UNHANDLED_EXCEPTION;
552 /*******************************************************************
553 * raise_exception
555 * Implementation of NtRaiseException.
557 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
559 NTSTATUS status;
561 if (first_chance)
563 DWORD c;
565 TRACE( "code=%x flags=%x addr=%p pc=%08x tid=%04x\n",
566 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
567 context->Pc, GetCurrentThreadId() );
568 for (c = 0; c < rec->NumberParameters; c++)
569 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
570 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
572 if (rec->ExceptionInformation[1] >> 16)
573 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
574 rec->ExceptionAddress,
575 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
576 else
577 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
578 rec->ExceptionAddress,
579 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
581 else
583 TRACE( " r0=%08x r1=%08x r2=%08x r3=%08x r4=%08x r5=%08x\n",
584 context->R0, context->R1, context->R2, context->R3, context->R4, context->R5 );
585 TRACE( " r6=%08x r7=%08x r8=%08x r9=%08x r10=%08x fp=%08x\n",
586 context->R6, context->R7, context->R8, context->R9, context->R10, context->Fp );
587 TRACE( " ip=%08x sp=%08x lr=%08x pc=%08x cpsr=%08x\n",
588 context->Ip, context->Sp, context->Lr, context->Pc, context->Cpsr );
591 status = send_debug_event( rec, TRUE, context );
592 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
593 return STATUS_SUCCESS;
595 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
596 return STATUS_SUCCESS;
598 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
599 return status;
602 /* last chance exception */
604 status = send_debug_event( rec, FALSE, context );
605 if (status != DBG_CONTINUE)
607 if (rec->ExceptionFlags & EH_STACK_INVALID)
608 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
609 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
610 ERR("Process attempted to continue execution after noncontinuable exception.\n");
611 else
612 ERR("Unhandled exception code %x flags %x addr %p\n",
613 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
614 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
616 return STATUS_SUCCESS;
620 /**********************************************************************
621 * segv_handler
623 * Handler for SIGSEGV and related errors.
625 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
627 EXCEPTION_RECORD *rec;
628 ucontext_t *context = ucontext;
630 /* check for page fault inside the thread stack */
631 if (get_trap_code(context) == TRAP_ARM_PAGEFLT &&
632 (char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
633 (char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
634 virtual_handle_stack_fault( info->si_addr ))
636 /* check if this was the last guard page */
637 if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
639 rec = setup_exception( context, raise_segv_exception );
640 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
642 return;
645 rec = setup_exception( context, raise_segv_exception );
646 if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
648 switch(get_trap_code(context))
650 case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */
651 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
652 break;
653 case TRAP_ARM_PAGEFLT: /* Page fault */
654 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
655 rec->NumberParameters = 2;
656 rec->ExceptionInformation[0] = (get_error_code(context) & 0x800) != 0;
657 rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
658 break;
659 case TRAP_ARM_ALIGNFLT: /* Alignment check exception */
660 rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
661 break;
662 case TRAP_ARM_UNKNOWN: /* Unknown fault code */
663 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
664 rec->NumberParameters = 2;
665 rec->ExceptionInformation[0] = 0;
666 rec->ExceptionInformation[1] = 0xffffffff;
667 break;
668 default:
669 ERR("Got unexpected trap %d\n", get_trap_code(context));
670 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
671 break;
675 /**********************************************************************
676 * trap_handler
678 * Handler for SIGTRAP.
680 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
682 EXCEPTION_RECORD rec;
683 CONTEXT context;
684 NTSTATUS status;
686 switch ( info->si_code )
688 case TRAP_TRACE:
689 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
690 break;
691 case TRAP_BRKPT:
692 default:
693 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
694 break;
697 save_context( &context, ucontext );
698 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
699 rec.ExceptionRecord = NULL;
700 rec.ExceptionAddress = (LPVOID)context.Pc;
701 rec.NumberParameters = 0;
702 status = raise_exception( &rec, &context, TRUE );
703 if (status) raise_status( status, &rec );
704 restore_context( &context, ucontext );
707 /**********************************************************************
708 * fpe_handler
710 * Handler for SIGFPE.
712 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
714 EXCEPTION_RECORD rec;
715 CONTEXT context;
716 NTSTATUS status;
718 save_fpu( &context, sigcontext );
719 save_context( &context, sigcontext );
721 switch (siginfo->si_code & 0xffff )
723 #ifdef FPE_FLTSUB
724 case FPE_FLTSUB:
725 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
726 break;
727 #endif
728 #ifdef FPE_INTDIV
729 case FPE_INTDIV:
730 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
731 break;
732 #endif
733 #ifdef FPE_INTOVF
734 case FPE_INTOVF:
735 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
736 break;
737 #endif
738 #ifdef FPE_FLTDIV
739 case FPE_FLTDIV:
740 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
741 break;
742 #endif
743 #ifdef FPE_FLTOVF
744 case FPE_FLTOVF:
745 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
746 break;
747 #endif
748 #ifdef FPE_FLTUND
749 case FPE_FLTUND:
750 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
751 break;
752 #endif
753 #ifdef FPE_FLTRES
754 case FPE_FLTRES:
755 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
756 break;
757 #endif
758 #ifdef FPE_FLTINV
759 case FPE_FLTINV:
760 #endif
761 default:
762 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
763 break;
765 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
766 rec.ExceptionRecord = NULL;
767 rec.ExceptionAddress = (LPVOID)context.Pc;
768 rec.NumberParameters = 0;
769 status = raise_exception( &rec, &context, TRUE );
770 if (status) raise_status( status, &rec );
772 restore_context( &context, sigcontext );
773 restore_fpu( &context, sigcontext );
776 /**********************************************************************
777 * int_handler
779 * Handler for SIGINT.
781 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
783 if (!dispatch_signal(SIGINT))
785 EXCEPTION_RECORD rec;
786 CONTEXT context;
787 NTSTATUS status;
789 save_context( &context, sigcontext );
790 rec.ExceptionCode = CONTROL_C_EXIT;
791 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
792 rec.ExceptionRecord = NULL;
793 rec.ExceptionAddress = (LPVOID)context.Pc;
794 rec.NumberParameters = 0;
795 status = raise_exception( &rec, &context, TRUE );
796 if (status) raise_status( status, &rec );
797 restore_context( &context, sigcontext );
802 /**********************************************************************
803 * abrt_handler
805 * Handler for SIGABRT.
807 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
809 EXCEPTION_RECORD rec;
810 CONTEXT context;
811 NTSTATUS status;
813 save_context( &context, sigcontext );
814 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
815 rec.ExceptionFlags = EH_NONCONTINUABLE;
816 rec.ExceptionRecord = NULL;
817 rec.ExceptionAddress = (LPVOID)context.Pc;
818 rec.NumberParameters = 0;
819 status = raise_exception( &rec, &context, TRUE );
820 if (status) raise_status( status, &rec );
821 restore_context( &context, sigcontext );
825 /**********************************************************************
826 * quit_handler
828 * Handler for SIGQUIT.
830 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
832 abort_thread(0);
836 /**********************************************************************
837 * usr1_handler
839 * Handler for SIGUSR1, used to signal a thread that it got suspended.
841 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
843 CONTEXT context;
845 save_context( &context, sigcontext );
846 wait_suspend( &context );
847 restore_context( &context, sigcontext );
851 /***********************************************************************
852 * __wine_set_signal_handler (NTDLL.@)
854 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
856 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
857 if (handlers[sig] != NULL) return -2;
858 handlers[sig] = wsh;
859 return 0;
863 /**********************************************************************
864 * signal_alloc_thread
866 NTSTATUS signal_alloc_thread( TEB **teb )
868 static size_t sigstack_zero_bits;
869 SIZE_T size;
870 NTSTATUS status;
872 if (!sigstack_zero_bits)
874 size_t min_size = page_size;
875 /* find the first power of two not smaller than min_size */
876 while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
877 assert( sizeof(TEB) <= min_size );
880 size = 1 << sigstack_zero_bits;
881 *teb = NULL;
882 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
883 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
885 (*teb)->Tib.Self = &(*teb)->Tib;
886 (*teb)->Tib.ExceptionList = (void *)~0UL;
888 return status;
892 /**********************************************************************
893 * signal_free_thread
895 void signal_free_thread( TEB *teb )
897 SIZE_T size;
899 if (teb->DeallocationStack)
901 size = 0;
902 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
904 size = 0;
905 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
908 /**********************************************************************
909 * set_tpidrurw
911 * Win32/ARM applications expect the TEB pointer to be in the TPIDRURW register.
913 #ifdef __ARM_ARCH_7A__
914 extern void set_tpidrurw( TEB *teb );
915 __ASM_GLOBAL_FUNC( set_tpidrurw,
916 "mcr p15, 0, r0, c13, c0, 2\n\t" /* TEB -> TPIDRURW */
917 "blx lr" )
918 #else
919 void set_tpidrurw( TEB *teb )
922 #endif
924 /**********************************************************************
925 * signal_init_thread
927 void signal_init_thread( TEB *teb )
929 static BOOL init_done;
931 if (!init_done)
933 pthread_key_create( &teb_key, NULL );
934 init_done = TRUE;
936 set_tpidrurw( teb );
937 pthread_setspecific( teb_key, teb );
941 /**********************************************************************
942 * signal_init_process
944 void signal_init_process(void)
946 struct sigaction sig_act;
948 sig_act.sa_mask = server_block_set;
949 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
951 sig_act.sa_sigaction = int_handler;
952 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
953 sig_act.sa_sigaction = fpe_handler;
954 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
955 sig_act.sa_sigaction = abrt_handler;
956 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
957 sig_act.sa_sigaction = quit_handler;
958 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
959 sig_act.sa_sigaction = usr1_handler;
960 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
962 sig_act.sa_sigaction = segv_handler;
963 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
964 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
965 #ifdef SIGBUS
966 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
967 #endif
969 #ifdef SIGTRAP
970 sig_act.sa_sigaction = trap_handler;
971 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
972 #endif
973 return;
975 error:
976 perror("sigaction");
977 exit(1);
981 /**********************************************************************
982 * __wine_enter_vm86 (NTDLL.@)
984 void __wine_enter_vm86( CONTEXT *context )
986 MESSAGE("vm86 mode not supported on this platform\n");
990 /**********************************************************************
991 * RtlAddFunctionTable (NTDLL.@)
993 BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD addr )
995 FIXME( "%p %u %x: stub\n", table, count, addr );
996 return TRUE;
1000 /**********************************************************************
1001 * RtlDeleteFunctionTable (NTDLL.@)
1003 BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
1005 FIXME( "%p: stub\n", table );
1006 return TRUE;
1009 /**********************************************************************
1010 * find_function_info
1012 static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, HMODULE module,
1013 RUNTIME_FUNCTION *func, ULONG size )
1015 int min = 0;
1016 int max = size/sizeof(*func) - 1;
1018 while (min <= max)
1020 int pos = (min + max) / 2;
1021 DWORD begin = (func[pos].BeginAddress & ~1), end;
1022 if (func[pos].u.s.Flag)
1023 end = begin + func[pos].u.s.FunctionLength * 2;
1024 else
1026 struct UNWIND_INFO *info;
1027 info = (struct UNWIND_INFO *)((char *)module + func[pos].u.UnwindData);
1028 end = begin + info->function_length * 2;
1031 if ((char *)pc < (char *)module + begin) max = pos - 1;
1032 else if ((char *)pc >= (char *)module + end) min = pos + 1;
1033 else return func + pos;
1035 return NULL;
1038 /**********************************************************************
1039 * RtlLookupFunctionEntry (NTDLL.@)
1041 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, DWORD *base,
1042 UNWIND_HISTORY_TABLE *table )
1044 LDR_MODULE *module;
1045 RUNTIME_FUNCTION *func;
1046 ULONG size;
1048 /* FIXME: should use the history table to make things faster */
1050 if (LdrFindEntryForAddress( (void *)pc, &module ))
1052 WARN( "module not found for %lx\n", pc );
1053 return NULL;
1055 if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1056 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1058 WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
1059 return NULL;
1061 func = find_function_info( pc, module->BaseAddress, func, size );
1062 if (func) *base = (DWORD)module->BaseAddress;
1063 return func;
1066 /***********************************************************************
1067 * RtlUnwind (NTDLL.@)
1069 void WINAPI RtlUnwind( void *endframe, void *target_ip, EXCEPTION_RECORD *rec, void *retval )
1071 CONTEXT context;
1072 EXCEPTION_RECORD record;
1073 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch;
1074 DWORD res;
1076 RtlCaptureContext( &context );
1077 context.R0 = (DWORD)retval;
1079 /* build an exception record, if we do not have one */
1080 if (!rec)
1082 record.ExceptionCode = STATUS_UNWIND;
1083 record.ExceptionFlags = 0;
1084 record.ExceptionRecord = NULL;
1085 record.ExceptionAddress = (void *)context.Pc;
1086 record.NumberParameters = 0;
1087 rec = &record;
1090 rec->ExceptionFlags |= EH_UNWINDING | (endframe ? 0 : EH_EXIT_UNWIND);
1092 TRACE( "code=%x flags=%x\n", rec->ExceptionCode, rec->ExceptionFlags );
1094 /* get chain of exception frames */
1095 frame = NtCurrentTeb()->Tib.ExceptionList;
1096 while ((frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL) && (frame != endframe))
1098 /* Check frame address */
1099 if (endframe && ((void*)frame > endframe))
1100 raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
1102 if (!is_valid_frame( frame )) raise_status( STATUS_BAD_STACK, rec );
1104 /* Call handler */
1105 TRACE( "calling handler at %p code=%x flags=%x\n",
1106 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
1107 res = frame->Handler(rec, frame, &context, &dispatch);
1108 TRACE( "handler at %p returned %x\n", frame->Handler, res );
1110 switch(res)
1112 case ExceptionContinueSearch:
1113 break;
1114 case ExceptionCollidedUnwind:
1115 frame = dispatch;
1116 break;
1117 default:
1118 raise_status( STATUS_INVALID_DISPOSITION, rec );
1119 break;
1121 frame = __wine_pop_frame( frame );
1125 /*******************************************************************
1126 * NtRaiseException (NTDLL.@)
1128 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1130 NTSTATUS status = raise_exception( rec, context, first_chance );
1131 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
1132 return status;
1135 /***********************************************************************
1136 * RtlRaiseException (NTDLL.@)
1138 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
1140 CONTEXT context;
1141 NTSTATUS status;
1143 RtlCaptureContext( &context );
1144 rec->ExceptionAddress = (LPVOID)context.Pc;
1145 status = raise_exception( rec, &context, TRUE );
1146 if (status) raise_status( status, rec );
1149 /*************************************************************************
1150 * RtlCaptureStackBackTrace (NTDLL.@)
1152 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
1154 FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
1155 return 0;
1158 /***********************************************************************
1159 * call_thread_entry_point
1161 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
1163 __TRY
1165 exit_thread( entry( arg ));
1167 __EXCEPT(unhandled_exception_filter)
1169 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
1171 __ENDTRY
1172 abort(); /* should not be reached */
1175 /***********************************************************************
1176 * RtlExitUserThread (NTDLL.@)
1178 void WINAPI RtlExitUserThread( ULONG status )
1180 exit_thread( status );
1183 /***********************************************************************
1184 * abort_thread
1186 void abort_thread( int status )
1188 terminate_thread( status );
1191 /**********************************************************************
1192 * DbgBreakPoint (NTDLL.@)
1194 void WINAPI DbgBreakPoint(void)
1196 kill(getpid(), SIGTRAP);
1199 /**********************************************************************
1200 * DbgUserBreakPoint (NTDLL.@)
1202 void WINAPI DbgUserBreakPoint(void)
1204 kill(getpid(), SIGTRAP);
1207 /**********************************************************************
1208 * NtCurrentTeb (NTDLL.@)
1210 TEB * WINAPI NtCurrentTeb(void)
1212 return pthread_getspecific( teb_key );
1215 #endif /* __arm__ */