ntdll: Set the initial process context on ARM.
[wine.git] / dlls / ntdll / signal_arm.c
blobbbd6c59bb8e0105c694e5a1022a8594adb5cc23f
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 * Incoming r4 contains words to allocate, converting to bytes then return
255 __ASM_GLOBAL_FUNC( __chkstk, "lsl r4, r4, #2\n\t"
256 "bx lr" )
258 /***********************************************************************
259 * RtlCaptureContext (NTDLL.@)
261 /* FIXME: Use the Stack instead of the actual register values */
262 __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
263 ".arm\n\t"
264 "stmfd SP!, {r1}\n\t"
265 "mov r1, #0x0200000\n\t"/* CONTEXT_ARM */
266 "add r1, r1, #0x3\n\t" /* CONTEXT_FULL */
267 "str r1, [r0]\n\t" /* context->ContextFlags */
268 "ldmfd SP!, {r1}\n\t"
269 "str r0, [r0, #0x4]\n\t" /* context->R0 */
270 "str r1, [r0, #0x8]\n\t" /* context->R1 */
271 "str r2, [r0, #0xc]\n\t" /* context->R2 */
272 "str r3, [r0, #0x10]\n\t" /* context->R3 */
273 "str r4, [r0, #0x14]\n\t" /* context->R4 */
274 "str r5, [r0, #0x18]\n\t" /* context->R5 */
275 "str r6, [r0, #0x1c]\n\t" /* context->R6 */
276 "str r7, [r0, #0x20]\n\t" /* context->R7 */
277 "str r8, [r0, #0x24]\n\t" /* context->R8 */
278 "str r9, [r0, #0x28]\n\t" /* context->R9 */
279 "str r10, [r0, #0x2c]\n\t" /* context->R10 */
280 "str r11, [r0, #0x30]\n\t" /* context->Fp */
281 "str IP, [r0, #0x34]\n\t" /* context->Ip */
282 "str SP, [r0, #0x38]\n\t" /* context->Sp */
283 "str LR, [r0, #0x3c]\n\t" /* context->Lr */
284 "str PC, [r0, #0x40]\n\t" /* context->Pc */
285 "mrs r1, CPSR\n\t"
286 "str r1, [r0, #0x44]\n\t" /* context->Cpsr */
287 "bx lr"
291 /***********************************************************************
292 * set_cpu_context
294 * Set the new CPU context.
296 /* FIXME: What about the CPSR? */
297 void set_cpu_context( const CONTEXT *context );
298 __ASM_GLOBAL_FUNC( set_cpu_context,
299 "mov IP, r0\n\t"
300 "ldr r0, [IP, #0x4]\n\t" /* context->R0 */
301 "ldr r1, [IP, #0x8]\n\t" /* context->R1 */
302 "ldr r2, [IP, #0xc]\n\t" /* context->R2 */
303 "ldr r3, [IP, #0x10]\n\t" /* context->R3 */
304 "ldr r4, [IP, #0x14]\n\t" /* context->R4 */
305 "ldr r5, [IP, #0x18]\n\t" /* context->R5 */
306 "ldr r6, [IP, #0x1c]\n\t" /* context->R6 */
307 "ldr r7, [IP, #0x20]\n\t" /* context->R7 */
308 "ldr r8, [IP, #0x24]\n\t" /* context->R8 */
309 "ldr r9, [IP, #0x28]\n\t" /* context->R9 */
310 "ldr r10, [IP, #0x2c]\n\t" /* context->R10 */
311 "ldr r11, [IP, #0x30]\n\t" /* context->Fp */
312 "ldr SP, [IP, #0x38]\n\t" /* context->Sp */
313 "ldr LR, [IP, #0x3c]\n\t" /* context->Lr */
314 "ldr PC, [IP, #0x40]\n\t" /* context->Pc */
318 /***********************************************************************
319 * copy_context
321 * Copy a register context according to the flags.
323 static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
325 flags &= ~CONTEXT_ARM; /* get rid of CPU id */
326 if (flags & CONTEXT_CONTROL)
328 to->Sp = from->Sp;
329 to->Lr = from->Lr;
330 to->Pc = from->Pc;
331 to->Cpsr = from->Cpsr;
333 if (flags & CONTEXT_INTEGER)
335 to->R0 = from->R0;
336 to->R1 = from->R1;
337 to->R2 = from->R2;
338 to->R3 = from->R3;
339 to->R4 = from->R4;
340 to->R5 = from->R5;
341 to->R6 = from->R6;
342 to->R7 = from->R7;
343 to->R8 = from->R8;
344 to->R9 = from->R9;
345 to->R10 = from->R10;
346 to->Ip = from->Ip;
347 to->Fp = from->Fp;
352 /***********************************************************************
353 * context_to_server
355 * Convert a register context to the server format.
357 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
359 DWORD flags = from->ContextFlags & ~CONTEXT_ARM; /* get rid of CPU id */
361 memset( to, 0, sizeof(*to) );
362 to->cpu = CPU_ARM;
364 if (flags & CONTEXT_CONTROL)
366 to->flags |= SERVER_CTX_CONTROL;
367 to->ctl.arm_regs.sp = from->Sp;
368 to->ctl.arm_regs.lr = from->Lr;
369 to->ctl.arm_regs.pc = from->Pc;
370 to->ctl.arm_regs.cpsr = from->Cpsr;
372 if (flags & CONTEXT_INTEGER)
374 to->flags |= SERVER_CTX_INTEGER;
375 to->integer.arm_regs.r[0] = from->R0;
376 to->integer.arm_regs.r[1] = from->R1;
377 to->integer.arm_regs.r[2] = from->R2;
378 to->integer.arm_regs.r[3] = from->R3;
379 to->integer.arm_regs.r[4] = from->R4;
380 to->integer.arm_regs.r[5] = from->R5;
381 to->integer.arm_regs.r[6] = from->R6;
382 to->integer.arm_regs.r[7] = from->R7;
383 to->integer.arm_regs.r[8] = from->R8;
384 to->integer.arm_regs.r[9] = from->R9;
385 to->integer.arm_regs.r[10] = from->R10;
386 to->integer.arm_regs.r[11] = from->Fp;
387 to->integer.arm_regs.r[12] = from->Ip;
389 return STATUS_SUCCESS;
393 /***********************************************************************
394 * context_from_server
396 * Convert a register context from the server format.
398 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
400 if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
402 to->ContextFlags = CONTEXT_ARM;
403 if (from->flags & SERVER_CTX_CONTROL)
405 to->ContextFlags |= CONTEXT_CONTROL;
406 to->Sp = from->ctl.arm_regs.sp;
407 to->Lr = from->ctl.arm_regs.lr;
408 to->Pc = from->ctl.arm_regs.pc;
409 to->Cpsr = from->ctl.arm_regs.cpsr;
411 if (from->flags & SERVER_CTX_INTEGER)
413 to->ContextFlags |= CONTEXT_INTEGER;
414 to->R0 = from->integer.arm_regs.r[0];
415 to->R1 = from->integer.arm_regs.r[1];
416 to->R2 = from->integer.arm_regs.r[2];
417 to->R3 = from->integer.arm_regs.r[3];
418 to->R4 = from->integer.arm_regs.r[4];
419 to->R5 = from->integer.arm_regs.r[5];
420 to->R6 = from->integer.arm_regs.r[6];
421 to->R7 = from->integer.arm_regs.r[7];
422 to->R8 = from->integer.arm_regs.r[8];
423 to->R9 = from->integer.arm_regs.r[9];
424 to->R10 = from->integer.arm_regs.r[10];
425 to->Fp = from->integer.arm_regs.r[11];
426 to->Ip = from->integer.arm_regs.r[12];
428 return STATUS_SUCCESS;
431 /***********************************************************************
432 * NtSetContextThread (NTDLL.@)
433 * ZwSetContextThread (NTDLL.@)
435 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
437 NTSTATUS ret;
438 BOOL self;
440 ret = set_thread_context( handle, context, &self );
441 if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
442 return ret;
446 /***********************************************************************
447 * NtGetContextThread (NTDLL.@)
448 * ZwGetContextThread (NTDLL.@)
450 NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
452 NTSTATUS ret;
453 DWORD needed_flags = context->ContextFlags;
454 BOOL self = (handle == GetCurrentThread());
456 if (!self)
458 if ((ret = get_thread_context( handle, context, &self ))) return ret;
459 needed_flags &= ~context->ContextFlags;
462 if (self && needed_flags)
464 CONTEXT ctx;
465 RtlCaptureContext( &ctx );
466 copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
467 context->ContextFlags |= ctx.ContextFlags & needed_flags;
469 return STATUS_SUCCESS;
473 extern void raise_func_trampoline_thumb( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
474 __ASM_GLOBAL_FUNC( raise_func_trampoline_thumb,
475 ".thumb\n\t"
476 "blx r2\n\t"
477 "bkpt")
479 extern void raise_func_trampoline_arm( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
480 __ASM_GLOBAL_FUNC( raise_func_trampoline_arm,
481 ".arm\n\t"
482 "blx r2\n\t"
483 "bkpt")
485 /***********************************************************************
486 * setup_exception_record
488 * Setup the exception record and context on the thread stack.
490 static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func func )
492 struct stack_layout
494 CONTEXT context;
495 EXCEPTION_RECORD rec;
496 } *stack;
497 DWORD exception_code = 0;
499 stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
500 stack--; /* push the stack_layout structure */
502 stack->rec.ExceptionRecord = NULL;
503 stack->rec.ExceptionCode = exception_code;
504 stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
505 stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
506 stack->rec.NumberParameters = 0;
508 save_context( &stack->context, sigcontext );
510 /* now modify the sigcontext to return to the raise function */
511 SP_sig(sigcontext) = (DWORD)stack;
512 if (CPSR_sig(sigcontext) & 0x20)
513 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_thumb;
514 else
515 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_arm;
516 REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for raise_func */
517 REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for raise_func */
518 REGn_sig(2, sigcontext) = (DWORD)func; /* the raise_func as third arg for the trampoline */
521 return &stack->rec;
524 /**********************************************************************
525 * raise_segv_exception
527 static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
529 NTSTATUS status;
531 switch(rec->ExceptionCode)
533 case EXCEPTION_ACCESS_VIOLATION:
534 if (rec->NumberParameters == 2)
536 if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
537 rec->ExceptionInformation[0], FALSE )))
538 goto done;
540 break;
542 status = NtRaiseException( rec, context, TRUE );
543 if (status) raise_status( status, rec );
544 done:
545 set_cpu_context( context );
548 /**********************************************************************
549 * call_stack_handlers
551 * Call the stack handlers chain.
553 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
555 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
556 DWORD res;
558 frame = NtCurrentTeb()->Tib.ExceptionList;
559 nested_frame = NULL;
560 while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
562 /* Check frame address */
563 if (!is_valid_frame( frame ))
565 rec->ExceptionFlags |= EH_STACK_INVALID;
566 break;
569 /* Call handler */
570 TRACE( "calling handler at %p code=%x flags=%x\n",
571 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
572 res = frame->Handler( rec, frame, context, &dispatch );
573 TRACE( "handler at %p returned %x\n", frame->Handler, res );
575 if (frame == nested_frame)
577 /* no longer nested */
578 nested_frame = NULL;
579 rec->ExceptionFlags &= ~EH_NESTED_CALL;
582 switch(res)
584 case ExceptionContinueExecution:
585 if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
586 return STATUS_NONCONTINUABLE_EXCEPTION;
587 case ExceptionContinueSearch:
588 break;
589 case ExceptionNestedException:
590 if (nested_frame < dispatch) nested_frame = dispatch;
591 rec->ExceptionFlags |= EH_NESTED_CALL;
592 break;
593 default:
594 return STATUS_INVALID_DISPOSITION;
596 frame = frame->Prev;
598 return STATUS_UNHANDLED_EXCEPTION;
602 /*******************************************************************
603 * raise_exception
605 * Implementation of NtRaiseException.
607 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
609 NTSTATUS status;
611 if (first_chance)
613 DWORD c;
615 TRACE( "code=%x flags=%x addr=%p pc=%08x tid=%04x\n",
616 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
617 context->Pc, GetCurrentThreadId() );
618 for (c = 0; c < rec->NumberParameters; c++)
619 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
620 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
622 if (rec->ExceptionInformation[1] >> 16)
623 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
624 rec->ExceptionAddress,
625 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
626 else
627 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
628 rec->ExceptionAddress,
629 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
631 else
633 TRACE( " r0=%08x r1=%08x r2=%08x r3=%08x r4=%08x r5=%08x\n",
634 context->R0, context->R1, context->R2, context->R3, context->R4, context->R5 );
635 TRACE( " r6=%08x r7=%08x r8=%08x r9=%08x r10=%08x fp=%08x\n",
636 context->R6, context->R7, context->R8, context->R9, context->R10, context->Fp );
637 TRACE( " ip=%08x sp=%08x lr=%08x pc=%08x cpsr=%08x\n",
638 context->Ip, context->Sp, context->Lr, context->Pc, context->Cpsr );
641 status = send_debug_event( rec, TRUE, context );
642 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
643 return STATUS_SUCCESS;
645 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
646 return STATUS_SUCCESS;
648 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
649 return status;
652 /* last chance exception */
654 status = send_debug_event( rec, FALSE, context );
655 if (status != DBG_CONTINUE)
657 if (rec->ExceptionFlags & EH_STACK_INVALID)
658 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
659 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
660 ERR("Process attempted to continue execution after noncontinuable exception.\n");
661 else
662 ERR("Unhandled exception code %x flags %x addr %p\n",
663 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
664 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
666 return STATUS_SUCCESS;
670 /**********************************************************************
671 * segv_handler
673 * Handler for SIGSEGV and related errors.
675 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
677 EXCEPTION_RECORD *rec;
678 ucontext_t *context = ucontext;
680 /* check for page fault inside the thread stack */
681 if (get_trap_code(context) == TRAP_ARM_PAGEFLT &&
682 (char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
683 (char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
684 virtual_handle_stack_fault( info->si_addr ))
686 /* check if this was the last guard page */
687 if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
689 rec = setup_exception( context, raise_segv_exception );
690 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
692 return;
695 rec = setup_exception( context, raise_segv_exception );
696 if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
698 switch(get_trap_code(context))
700 case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */
701 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
702 break;
703 case TRAP_ARM_PAGEFLT: /* Page fault */
704 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
705 rec->NumberParameters = 2;
706 rec->ExceptionInformation[0] = (get_error_code(context) & 0x800) != 0;
707 rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
708 break;
709 case TRAP_ARM_ALIGNFLT: /* Alignment check exception */
710 rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
711 break;
712 case TRAP_ARM_UNKNOWN: /* Unknown fault code */
713 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
714 rec->NumberParameters = 2;
715 rec->ExceptionInformation[0] = 0;
716 rec->ExceptionInformation[1] = 0xffffffff;
717 break;
718 default:
719 ERR("Got unexpected trap %d\n", get_trap_code(context));
720 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
721 break;
725 /**********************************************************************
726 * trap_handler
728 * Handler for SIGTRAP.
730 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
732 EXCEPTION_RECORD rec;
733 CONTEXT context;
734 NTSTATUS status;
736 switch ( info->si_code )
738 case TRAP_TRACE:
739 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
740 break;
741 case TRAP_BRKPT:
742 default:
743 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
744 break;
747 save_context( &context, ucontext );
748 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
749 rec.ExceptionRecord = NULL;
750 rec.ExceptionAddress = (LPVOID)context.Pc;
751 rec.NumberParameters = 0;
752 status = raise_exception( &rec, &context, TRUE );
753 if (status) raise_status( status, &rec );
754 restore_context( &context, ucontext );
757 /**********************************************************************
758 * fpe_handler
760 * Handler for SIGFPE.
762 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
764 EXCEPTION_RECORD rec;
765 CONTEXT context;
766 NTSTATUS status;
768 save_fpu( &context, sigcontext );
769 save_context( &context, sigcontext );
771 switch (siginfo->si_code & 0xffff )
773 #ifdef FPE_FLTSUB
774 case FPE_FLTSUB:
775 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
776 break;
777 #endif
778 #ifdef FPE_INTDIV
779 case FPE_INTDIV:
780 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
781 break;
782 #endif
783 #ifdef FPE_INTOVF
784 case FPE_INTOVF:
785 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
786 break;
787 #endif
788 #ifdef FPE_FLTDIV
789 case FPE_FLTDIV:
790 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
791 break;
792 #endif
793 #ifdef FPE_FLTOVF
794 case FPE_FLTOVF:
795 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
796 break;
797 #endif
798 #ifdef FPE_FLTUND
799 case FPE_FLTUND:
800 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
801 break;
802 #endif
803 #ifdef FPE_FLTRES
804 case FPE_FLTRES:
805 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
806 break;
807 #endif
808 #ifdef FPE_FLTINV
809 case FPE_FLTINV:
810 #endif
811 default:
812 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
813 break;
815 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
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 );
822 restore_context( &context, sigcontext );
823 restore_fpu( &context, sigcontext );
826 /**********************************************************************
827 * int_handler
829 * Handler for SIGINT.
831 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
833 if (!dispatch_signal(SIGINT))
835 EXCEPTION_RECORD rec;
836 CONTEXT context;
837 NTSTATUS status;
839 save_context( &context, sigcontext );
840 rec.ExceptionCode = CONTROL_C_EXIT;
841 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
842 rec.ExceptionRecord = NULL;
843 rec.ExceptionAddress = (LPVOID)context.Pc;
844 rec.NumberParameters = 0;
845 status = raise_exception( &rec, &context, TRUE );
846 if (status) raise_status( status, &rec );
847 restore_context( &context, sigcontext );
852 /**********************************************************************
853 * abrt_handler
855 * Handler for SIGABRT.
857 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
859 EXCEPTION_RECORD rec;
860 CONTEXT context;
861 NTSTATUS status;
863 save_context( &context, sigcontext );
864 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
865 rec.ExceptionFlags = EH_NONCONTINUABLE;
866 rec.ExceptionRecord = NULL;
867 rec.ExceptionAddress = (LPVOID)context.Pc;
868 rec.NumberParameters = 0;
869 status = raise_exception( &rec, &context, TRUE );
870 if (status) raise_status( status, &rec );
871 restore_context( &context, sigcontext );
875 /**********************************************************************
876 * quit_handler
878 * Handler for SIGQUIT.
880 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
882 abort_thread(0);
886 /**********************************************************************
887 * usr1_handler
889 * Handler for SIGUSR1, used to signal a thread that it got suspended.
891 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
893 CONTEXT context;
895 save_context( &context, sigcontext );
896 wait_suspend( &context );
897 restore_context( &context, sigcontext );
901 /***********************************************************************
902 * __wine_set_signal_handler (NTDLL.@)
904 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
906 if (sig >= sizeof(handlers) / sizeof(handlers[0])) return -1;
907 if (handlers[sig] != NULL) return -2;
908 handlers[sig] = wsh;
909 return 0;
913 /**********************************************************************
914 * signal_alloc_thread
916 NTSTATUS signal_alloc_thread( TEB **teb )
918 static size_t sigstack_zero_bits;
919 SIZE_T size;
920 NTSTATUS status;
922 if (!sigstack_zero_bits)
924 size_t min_size = page_size;
925 /* find the first power of two not smaller than min_size */
926 while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
927 assert( sizeof(TEB) <= min_size );
930 size = 1 << sigstack_zero_bits;
931 *teb = NULL;
932 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
933 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
935 (*teb)->Tib.Self = &(*teb)->Tib;
936 (*teb)->Tib.ExceptionList = (void *)~0UL;
938 return status;
942 /**********************************************************************
943 * signal_free_thread
945 void signal_free_thread( TEB *teb )
947 SIZE_T size;
949 if (teb->DeallocationStack)
951 size = 0;
952 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
954 size = 0;
955 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
959 /**********************************************************************
960 * signal_init_thread
962 void signal_init_thread( TEB *teb )
964 static BOOL init_done;
966 if (!init_done)
968 pthread_key_create( &teb_key, NULL );
969 init_done = TRUE;
972 #if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__)
973 /* Win32/ARM applications expect the TEB pointer to be in the TPIDRURW register. */
974 __asm__ __volatile__( "mcr p15, 0, %0, c13, c0, 2" : : "r" (teb) );
975 #endif
977 pthread_setspecific( teb_key, teb );
981 /**********************************************************************
982 * signal_init_process
984 void signal_init_process( CONTEXT *context, LPTHREAD_START_ROUTINE entry )
986 struct sigaction sig_act;
988 sig_act.sa_mask = server_block_set;
989 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
991 sig_act.sa_sigaction = int_handler;
992 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
993 sig_act.sa_sigaction = fpe_handler;
994 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
995 sig_act.sa_sigaction = abrt_handler;
996 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
997 sig_act.sa_sigaction = quit_handler;
998 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
999 sig_act.sa_sigaction = usr1_handler;
1000 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
1002 sig_act.sa_sigaction = segv_handler;
1003 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
1004 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
1005 #ifdef SIGBUS
1006 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
1007 #endif
1009 #ifdef SIGTRAP
1010 sig_act.sa_sigaction = trap_handler;
1011 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
1012 #endif
1014 /* set the initial context */
1015 context->ContextFlags = CONTEXT_FULL;
1016 context->R0 = (DWORD)kernel32_start_process;
1017 context->R1 = (DWORD)entry;
1018 context->Sp = (DWORD)NtCurrentTeb()->Tib.StackBase;
1019 context->Pc = (DWORD)call_thread_entry_point;
1020 return;
1022 error:
1023 perror("sigaction");
1024 exit(1);
1028 /**********************************************************************
1029 * __wine_enter_vm86 (NTDLL.@)
1031 void __wine_enter_vm86( CONTEXT *context )
1033 MESSAGE("vm86 mode not supported on this platform\n");
1037 /**********************************************************************
1038 * RtlAddFunctionTable (NTDLL.@)
1040 BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD addr )
1042 FIXME( "%p %u %x: stub\n", table, count, addr );
1043 return TRUE;
1047 /**********************************************************************
1048 * RtlDeleteFunctionTable (NTDLL.@)
1050 BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
1052 FIXME( "%p: stub\n", table );
1053 return TRUE;
1056 /**********************************************************************
1057 * find_function_info
1059 static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, HMODULE module,
1060 RUNTIME_FUNCTION *func, ULONG size )
1062 int min = 0;
1063 int max = size/sizeof(*func) - 1;
1065 while (min <= max)
1067 int pos = (min + max) / 2;
1068 DWORD begin = (func[pos].BeginAddress & ~1), end;
1069 if (func[pos].u.s.Flag)
1070 end = begin + func[pos].u.s.FunctionLength * 2;
1071 else
1073 struct UNWIND_INFO *info;
1074 info = (struct UNWIND_INFO *)((char *)module + func[pos].u.UnwindData);
1075 end = begin + info->function_length * 2;
1078 if ((char *)pc < (char *)module + begin) max = pos - 1;
1079 else if ((char *)pc >= (char *)module + end) min = pos + 1;
1080 else return func + pos;
1082 return NULL;
1085 /**********************************************************************
1086 * RtlLookupFunctionEntry (NTDLL.@)
1088 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, DWORD *base,
1089 UNWIND_HISTORY_TABLE *table )
1091 LDR_MODULE *module;
1092 RUNTIME_FUNCTION *func;
1093 ULONG size;
1095 /* FIXME: should use the history table to make things faster */
1097 if (LdrFindEntryForAddress( (void *)pc, &module ))
1099 WARN( "module not found for %lx\n", pc );
1100 return NULL;
1102 if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1103 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1105 WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
1106 return NULL;
1108 func = find_function_info( pc, module->BaseAddress, func, size );
1109 if (func) *base = (DWORD)module->BaseAddress;
1110 return func;
1113 /***********************************************************************
1114 * RtlUnwind (NTDLL.@)
1116 void WINAPI RtlUnwind( void *endframe, void *target_ip, EXCEPTION_RECORD *rec, void *retval )
1118 CONTEXT context;
1119 EXCEPTION_RECORD record;
1120 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch;
1121 DWORD res;
1123 RtlCaptureContext( &context );
1124 context.R0 = (DWORD)retval;
1126 /* build an exception record, if we do not have one */
1127 if (!rec)
1129 record.ExceptionCode = STATUS_UNWIND;
1130 record.ExceptionFlags = 0;
1131 record.ExceptionRecord = NULL;
1132 record.ExceptionAddress = (void *)context.Pc;
1133 record.NumberParameters = 0;
1134 rec = &record;
1137 rec->ExceptionFlags |= EH_UNWINDING | (endframe ? 0 : EH_EXIT_UNWIND);
1139 TRACE( "code=%x flags=%x\n", rec->ExceptionCode, rec->ExceptionFlags );
1141 /* get chain of exception frames */
1142 frame = NtCurrentTeb()->Tib.ExceptionList;
1143 while ((frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL) && (frame != endframe))
1145 /* Check frame address */
1146 if (endframe && ((void*)frame > endframe))
1147 raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
1149 if (!is_valid_frame( frame )) raise_status( STATUS_BAD_STACK, rec );
1151 /* Call handler */
1152 TRACE( "calling handler at %p code=%x flags=%x\n",
1153 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
1154 res = frame->Handler(rec, frame, &context, &dispatch);
1155 TRACE( "handler at %p returned %x\n", frame->Handler, res );
1157 switch(res)
1159 case ExceptionContinueSearch:
1160 break;
1161 case ExceptionCollidedUnwind:
1162 frame = dispatch;
1163 break;
1164 default:
1165 raise_status( STATUS_INVALID_DISPOSITION, rec );
1166 break;
1168 frame = __wine_pop_frame( frame );
1172 /*******************************************************************
1173 * NtRaiseException (NTDLL.@)
1175 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1177 NTSTATUS status = raise_exception( rec, context, first_chance );
1178 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
1179 return status;
1182 /***********************************************************************
1183 * RtlRaiseException (NTDLL.@)
1185 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
1187 CONTEXT context;
1188 NTSTATUS status;
1190 RtlCaptureContext( &context );
1191 rec->ExceptionAddress = (LPVOID)context.Pc;
1192 status = raise_exception( rec, &context, TRUE );
1193 if (status) raise_status( status, rec );
1196 /*************************************************************************
1197 * RtlCaptureStackBackTrace (NTDLL.@)
1199 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
1201 FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
1202 return 0;
1205 /***********************************************************************
1206 * call_thread_entry_point
1208 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
1210 __TRY
1212 exit_thread( entry( arg ));
1214 __EXCEPT(unhandled_exception_filter)
1216 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
1218 __ENDTRY
1219 abort(); /* should not be reached */
1222 /***********************************************************************
1223 * RtlExitUserThread (NTDLL.@)
1225 void WINAPI RtlExitUserThread( ULONG status )
1227 exit_thread( status );
1230 /***********************************************************************
1231 * abort_thread
1233 void abort_thread( int status )
1235 terminate_thread( status );
1238 /**********************************************************************
1239 * DbgBreakPoint (NTDLL.@)
1241 void WINAPI DbgBreakPoint(void)
1243 kill(getpid(), SIGTRAP);
1246 /**********************************************************************
1247 * DbgUserBreakPoint (NTDLL.@)
1249 void WINAPI DbgUserBreakPoint(void)
1251 kill(getpid(), SIGTRAP);
1254 /**********************************************************************
1255 * NtCurrentTeb (NTDLL.@)
1257 TEB * WINAPI NtCurrentTeb(void)
1259 return pthread_getspecific( teb_key );
1262 #endif /* __arm__ */