comctl32: Fix a typo in comment.
[wine.git] / dlls / ntdll / signal_arm.c
blob272fc7b3fd8b1616c321da7a7321b4bce26ec68a
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);
65 WINE_DECLARE_DEBUG_CHANNEL(relay);
67 static pthread_key_t teb_key;
69 /***********************************************************************
70 * signal context platform-specific definitions
72 #ifdef linux
74 #if defined(__ANDROID__) && !defined(HAVE_SYS_UCONTEXT_H)
75 typedef struct ucontext
77 unsigned long uc_flags;
78 struct ucontext *uc_link;
79 stack_t uc_stack;
80 struct sigcontext uc_mcontext;
81 sigset_t uc_sigmask;
82 unsigned long uc_regspace[128] __attribute__((__aligned__(8)));
83 } ucontext_t;
84 #endif
86 /* All Registers access - only for local access */
87 # define REG_sig(reg_name, context) ((context)->uc_mcontext.reg_name)
88 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.arm_r##reg_num)
90 /* Special Registers access */
91 # define SP_sig(context) REG_sig(arm_sp, context) /* Stack pointer */
92 # define LR_sig(context) REG_sig(arm_lr, context) /* Link register */
93 # define PC_sig(context) REG_sig(arm_pc, context) /* Program counter */
94 # define CPSR_sig(context) REG_sig(arm_cpsr, context) /* Current State Register */
95 # define IP_sig(context) REG_sig(arm_ip, context) /* Intra-Procedure-call scratch register */
96 # define FP_sig(context) REG_sig(arm_fp, context) /* Frame pointer */
98 /* Exceptions */
99 # define ERROR_sig(context) REG_sig(error_code, context)
100 # define TRAP_sig(context) REG_sig(trap_no, context)
102 #elif defined(__FreeBSD__)
104 /* All Registers access - only for local access */
105 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.__gregs[reg_num])
107 /* Special Registers access */
108 # define SP_sig(context) REGn_sig(_REG_SP, context) /* Stack pointer */
109 # define LR_sig(context) REGn_sig(_REG_LR, context) /* Link register */
110 # define PC_sig(context) REGn_sig(_REG_PC, context) /* Program counter */
111 # define CPSR_sig(context) REGn_sig(_REG_CPSR, context) /* Current State Register */
112 # define IP_sig(context) REGn_sig(_REG_R12, context) /* Intra-Procedure-call scratch register */
113 # define FP_sig(context) REGn_sig(_REG_FP, context) /* Frame pointer */
115 #endif /* linux */
117 enum arm_trap_code
119 TRAP_ARM_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
120 TRAP_ARM_PRIVINFLT = 6, /* Invalid opcode exception */
121 TRAP_ARM_PAGEFLT = 14, /* Page fault */
122 TRAP_ARM_ALIGNFLT = 17, /* Alignment check exception */
125 typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
126 typedef int (*wine_signal_handler)(unsigned int sig);
128 static wine_signal_handler handlers[256];
131 struct UNWIND_INFO
133 WORD function_length;
134 WORD unknown1 : 7;
135 WORD count : 5;
136 WORD unknown2 : 4;
140 /***********************************************************************
141 * get_trap_code
143 * Get the trap code for a signal.
145 static inline enum arm_trap_code get_trap_code( const ucontext_t *sigcontext )
147 #ifdef TRAP_sig
148 return TRAP_sig(sigcontext);
149 #else
150 return TRAP_ARM_UNKNOWN; /* unknown trap code */
151 #endif
154 /***********************************************************************
155 * get_error_code
157 * Get the error code for a signal.
159 static inline WORD get_error_code( const ucontext_t *sigcontext )
161 #ifdef ERROR_sig
162 return ERROR_sig(sigcontext);
163 #else
164 return 0;
165 #endif
168 /***********************************************************************
169 * dispatch_signal
171 static inline int dispatch_signal(unsigned int sig)
173 if (handlers[sig] == NULL) return 0;
174 return handlers[sig](sig);
177 /*******************************************************************
178 * is_valid_frame
180 static inline BOOL is_valid_frame( void *frame )
182 if ((ULONG_PTR)frame & 3) return FALSE;
183 return (frame >= NtCurrentTeb()->Tib.StackLimit &&
184 (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1);
187 /***********************************************************************
188 * save_context
190 * Set the register values from a sigcontext.
192 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
194 #define C(x) context->R##x = REGn_sig(x,sigcontext)
195 /* Save normal registers */
196 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
197 #undef C
199 context->ContextFlags = CONTEXT_FULL;
200 context->Sp = SP_sig(sigcontext); /* Stack pointer */
201 context->Lr = LR_sig(sigcontext); /* Link register */
202 context->Pc = PC_sig(sigcontext); /* Program Counter */
203 context->Cpsr = CPSR_sig(sigcontext); /* Current State Register */
204 context->R11 = FP_sig(sigcontext); /* Frame pointer */
205 context->R12 = IP_sig(sigcontext); /* Intra-Procedure-call scratch register */
209 /***********************************************************************
210 * restore_context
212 * Build a sigcontext from the register values.
214 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
216 #define C(x) REGn_sig(x,sigcontext) = context->R##x
217 /* Restore normal registers */
218 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
219 #undef C
221 SP_sig(sigcontext) = context->Sp; /* Stack pointer */
222 LR_sig(sigcontext) = context->Lr ; /* Link register */
223 PC_sig(sigcontext) = context->Pc; /* Program Counter */
224 CPSR_sig(sigcontext) = context->Cpsr; /* Current State Register */
225 FP_sig(sigcontext) = context->R11; /* Frame pointer */
226 IP_sig(sigcontext) = context->R12; /* Intra-Procedure-call scratch register */
230 /***********************************************************************
231 * save_fpu
233 * Set the FPU context from a sigcontext.
235 static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
237 FIXME("not implemented\n");
241 /***********************************************************************
242 * restore_fpu
244 * Restore the FPU context to a sigcontext.
246 static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext )
248 FIXME("not implemented\n");
251 /**************************************************************************
252 * __chkstk (NTDLL.@)
254 * Incoming r4 contains words to allocate, converting to bytes then return
256 __ASM_GLOBAL_FUNC( __chkstk, "lsl r4, r4, #2\n\t"
257 "bx lr" )
259 /***********************************************************************
260 * RtlCaptureContext (NTDLL.@)
262 /* FIXME: Use the Stack instead of the actual register values */
263 __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
264 ".arm\n\t"
265 "stmib r0, {r0-r12}\n\t" /* context->R0..R12 */
266 "mov r1, #0x0200000\n\t" /* CONTEXT_ARM */
267 "add r1, r1, #0x3\n\t" /* CONTEXT_FULL */
268 "str r1, [r0]\n\t" /* context->ContextFlags */
269 "str SP, [r0, #0x38]\n\t" /* context->Sp */
270 "str LR, [r0, #0x3c]\n\t" /* context->Lr */
271 "str PC, [r0, #0x40]\n\t" /* context->Pc */
272 "mrs r1, CPSR\n\t"
273 "str r1, [r0, #0x44]\n\t" /* context->Cpsr */
274 "bx lr"
278 /***********************************************************************
279 * set_cpu_context
281 * Set the new CPU context.
283 void DECLSPEC_HIDDEN set_cpu_context( const CONTEXT *context );
284 __ASM_GLOBAL_FUNC( set_cpu_context,
285 ".arm\n\t"
286 "ldr r1, [r0, #0x44]\n\t" /* context->Cpsr */
287 "msr CPSR_f, r1\n\t"
288 "ldr r1, [r0, #0x40]\n\t" /* context->Pc */
289 "ldr lr, [r0, #0x3c]\n\t" /* context->Lr */
290 "ldr sp, [r0, #0x38]\n\t" /* context->Sp */
291 "push {r1}\n\t"
292 "ldmib r0, {r0-r12}\n\t" /* context->R0..R12 */
293 "pop {pc}" )
296 /***********************************************************************
297 * copy_context
299 * Copy a register context according to the flags.
301 static void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
303 flags &= ~CONTEXT_ARM; /* get rid of CPU id */
304 if (flags & CONTEXT_CONTROL)
306 to->Sp = from->Sp;
307 to->Lr = from->Lr;
308 to->Pc = from->Pc;
309 to->Cpsr = from->Cpsr;
311 if (flags & CONTEXT_INTEGER)
313 to->R0 = from->R0;
314 to->R1 = from->R1;
315 to->R2 = from->R2;
316 to->R3 = from->R3;
317 to->R4 = from->R4;
318 to->R5 = from->R5;
319 to->R6 = from->R6;
320 to->R7 = from->R7;
321 to->R8 = from->R8;
322 to->R9 = from->R9;
323 to->R10 = from->R10;
324 to->R11 = from->R11;
325 to->R12 = from->R12;
327 if (flags & CONTEXT_FLOATING_POINT)
329 to->Fpscr = from->Fpscr;
330 memcpy( to->u.D, from->u.D, sizeof(to->u.D) );
335 /***********************************************************************
336 * context_to_server
338 * Convert a register context to the server format.
340 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
342 DWORD i, flags = from->ContextFlags & ~CONTEXT_ARM; /* get rid of CPU id */
344 memset( to, 0, sizeof(*to) );
345 to->cpu = CPU_ARM;
347 if (flags & CONTEXT_CONTROL)
349 to->flags |= SERVER_CTX_CONTROL;
350 to->ctl.arm_regs.sp = from->Sp;
351 to->ctl.arm_regs.lr = from->Lr;
352 to->ctl.arm_regs.pc = from->Pc;
353 to->ctl.arm_regs.cpsr = from->Cpsr;
355 if (flags & CONTEXT_INTEGER)
357 to->flags |= SERVER_CTX_INTEGER;
358 to->integer.arm_regs.r[0] = from->R0;
359 to->integer.arm_regs.r[1] = from->R1;
360 to->integer.arm_regs.r[2] = from->R2;
361 to->integer.arm_regs.r[3] = from->R3;
362 to->integer.arm_regs.r[4] = from->R4;
363 to->integer.arm_regs.r[5] = from->R5;
364 to->integer.arm_regs.r[6] = from->R6;
365 to->integer.arm_regs.r[7] = from->R7;
366 to->integer.arm_regs.r[8] = from->R8;
367 to->integer.arm_regs.r[9] = from->R9;
368 to->integer.arm_regs.r[10] = from->R10;
369 to->integer.arm_regs.r[11] = from->R11;
370 to->integer.arm_regs.r[12] = from->R12;
372 if (flags & CONTEXT_FLOATING_POINT)
374 to->flags |= SERVER_CTX_FLOATING_POINT;
375 for (i = 0; i < 32; i++) to->fp.arm_regs.d[i] = from->u.D[i];
376 to->fp.arm_regs.fpscr = from->Fpscr;
378 if (flags & CONTEXT_DEBUG_REGISTERS)
380 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
381 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bvr[i] = from->Bvr[i];
382 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bcr[i] = from->Bcr[i];
383 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wvr[i] = from->Wvr[i];
384 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wcr[i] = from->Wcr[i];
386 return STATUS_SUCCESS;
390 /***********************************************************************
391 * context_from_server
393 * Convert a register context from the server format.
395 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
397 DWORD i;
399 if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
401 to->ContextFlags = CONTEXT_ARM;
402 if (from->flags & SERVER_CTX_CONTROL)
404 to->ContextFlags |= CONTEXT_CONTROL;
405 to->Sp = from->ctl.arm_regs.sp;
406 to->Lr = from->ctl.arm_regs.lr;
407 to->Pc = from->ctl.arm_regs.pc;
408 to->Cpsr = from->ctl.arm_regs.cpsr;
410 if (from->flags & SERVER_CTX_INTEGER)
412 to->ContextFlags |= CONTEXT_INTEGER;
413 to->R0 = from->integer.arm_regs.r[0];
414 to->R1 = from->integer.arm_regs.r[1];
415 to->R2 = from->integer.arm_regs.r[2];
416 to->R3 = from->integer.arm_regs.r[3];
417 to->R4 = from->integer.arm_regs.r[4];
418 to->R5 = from->integer.arm_regs.r[5];
419 to->R6 = from->integer.arm_regs.r[6];
420 to->R7 = from->integer.arm_regs.r[7];
421 to->R8 = from->integer.arm_regs.r[8];
422 to->R9 = from->integer.arm_regs.r[9];
423 to->R10 = from->integer.arm_regs.r[10];
424 to->R11 = from->integer.arm_regs.r[11];
425 to->R12 = from->integer.arm_regs.r[12];
427 if (from->flags & SERVER_CTX_FLOATING_POINT)
429 to->ContextFlags |= CONTEXT_FLOATING_POINT;
430 for (i = 0; i < 32; i++) to->u.D[i] = from->fp.arm_regs.d[i];
431 to->Fpscr = from->fp.arm_regs.fpscr;
433 if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
435 to->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
436 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm_regs.bvr[i];
437 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm_regs.bcr[i];
438 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm_regs.wvr[i];
439 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm_regs.wcr[i];
441 return STATUS_SUCCESS;
444 /***********************************************************************
445 * NtSetContextThread (NTDLL.@)
446 * ZwSetContextThread (NTDLL.@)
448 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
450 NTSTATUS ret;
451 BOOL self;
453 ret = set_thread_context( handle, context, &self );
454 if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
455 return ret;
459 /***********************************************************************
460 * NtGetContextThread (NTDLL.@)
461 * ZwGetContextThread (NTDLL.@)
463 NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
465 NTSTATUS ret;
466 DWORD needed_flags = context->ContextFlags;
467 BOOL self = (handle == GetCurrentThread());
469 if (!self)
471 if ((ret = get_thread_context( handle, context, &self ))) return ret;
472 needed_flags &= ~context->ContextFlags;
475 if (self && needed_flags)
477 CONTEXT ctx;
478 RtlCaptureContext( &ctx );
479 copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
480 context->ContextFlags |= ctx.ContextFlags & needed_flags;
482 return STATUS_SUCCESS;
486 extern void raise_func_trampoline_thumb( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
487 __ASM_GLOBAL_FUNC( raise_func_trampoline_thumb,
488 ".thumb\n\t"
489 "blx r2\n\t"
490 "bkpt")
492 extern void raise_func_trampoline_arm( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
493 __ASM_GLOBAL_FUNC( raise_func_trampoline_arm,
494 ".arm\n\t"
495 "blx r2\n\t"
496 "bkpt")
498 /***********************************************************************
499 * setup_exception_record
501 * Setup the exception record and context on the thread stack.
503 static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func func )
505 struct stack_layout
507 CONTEXT context;
508 EXCEPTION_RECORD rec;
509 } *stack;
510 DWORD exception_code = 0;
512 stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
513 stack--; /* push the stack_layout structure */
515 stack->rec.ExceptionRecord = NULL;
516 stack->rec.ExceptionCode = exception_code;
517 stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
518 stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
519 stack->rec.NumberParameters = 0;
521 save_context( &stack->context, sigcontext );
523 /* now modify the sigcontext to return to the raise function */
524 SP_sig(sigcontext) = (DWORD)stack;
525 if (CPSR_sig(sigcontext) & 0x20)
526 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_thumb;
527 else
528 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_arm;
529 REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for raise_func */
530 REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for raise_func */
531 REGn_sig(2, sigcontext) = (DWORD)func; /* the raise_func as third arg for the trampoline */
534 return &stack->rec;
537 /**********************************************************************
538 * raise_segv_exception
540 static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
542 NTSTATUS status;
544 switch(rec->ExceptionCode)
546 case EXCEPTION_ACCESS_VIOLATION:
547 if (rec->NumberParameters == 2)
549 if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
550 rec->ExceptionInformation[0], FALSE )))
551 goto done;
553 break;
555 status = NtRaiseException( rec, context, TRUE );
556 if (status) raise_status( status, rec );
557 done:
558 set_cpu_context( context );
561 /**********************************************************************
562 * call_stack_handlers
564 * Call the stack handlers chain.
566 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
568 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
569 DWORD res;
571 frame = NtCurrentTeb()->Tib.ExceptionList;
572 nested_frame = NULL;
573 while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
575 /* Check frame address */
576 if (!is_valid_frame( frame ))
578 rec->ExceptionFlags |= EH_STACK_INVALID;
579 break;
582 /* Call handler */
583 TRACE( "calling handler at %p code=%x flags=%x\n",
584 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
585 res = frame->Handler( rec, frame, context, &dispatch );
586 TRACE( "handler at %p returned %x\n", frame->Handler, res );
588 if (frame == nested_frame)
590 /* no longer nested */
591 nested_frame = NULL;
592 rec->ExceptionFlags &= ~EH_NESTED_CALL;
595 switch(res)
597 case ExceptionContinueExecution:
598 if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
599 return STATUS_NONCONTINUABLE_EXCEPTION;
600 case ExceptionContinueSearch:
601 break;
602 case ExceptionNestedException:
603 if (nested_frame < dispatch) nested_frame = dispatch;
604 rec->ExceptionFlags |= EH_NESTED_CALL;
605 break;
606 default:
607 return STATUS_INVALID_DISPOSITION;
609 frame = frame->Prev;
611 return STATUS_UNHANDLED_EXCEPTION;
615 /*******************************************************************
616 * raise_exception
618 * Implementation of NtRaiseException.
620 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
622 NTSTATUS status;
624 if (first_chance)
626 DWORD c;
628 TRACE( "code=%x flags=%x addr=%p pc=%08x tid=%04x\n",
629 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
630 context->Pc, GetCurrentThreadId() );
631 for (c = 0; c < rec->NumberParameters; c++)
632 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
633 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
635 if (rec->ExceptionInformation[1] >> 16)
636 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
637 rec->ExceptionAddress,
638 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
639 else
640 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
641 rec->ExceptionAddress,
642 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
644 else
646 TRACE( " r0=%08x r1=%08x r2=%08x r3=%08x r4=%08x r5=%08x\n",
647 context->R0, context->R1, context->R2, context->R3, context->R4, context->R5 );
648 TRACE( " r6=%08x r7=%08x r8=%08x r9=%08x r10=%08x r11=%08x\n",
649 context->R6, context->R7, context->R8, context->R9, context->R10, context->R11 );
650 TRACE( " r12=%08x sp=%08x lr=%08x pc=%08x cpsr=%08x\n",
651 context->R12, context->Sp, context->Lr, context->Pc, context->Cpsr );
654 status = send_debug_event( rec, TRUE, context );
655 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
656 return STATUS_SUCCESS;
658 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
659 return STATUS_SUCCESS;
661 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
662 return status;
665 /* last chance exception */
667 status = send_debug_event( rec, FALSE, context );
668 if (status != DBG_CONTINUE)
670 if (rec->ExceptionFlags & EH_STACK_INVALID)
671 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
672 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
673 ERR("Process attempted to continue execution after noncontinuable exception.\n");
674 else
675 ERR("Unhandled exception code %x flags %x addr %p\n",
676 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
677 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
679 return STATUS_SUCCESS;
683 /**********************************************************************
684 * segv_handler
686 * Handler for SIGSEGV and related errors.
688 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
690 EXCEPTION_RECORD *rec;
691 ucontext_t *context = ucontext;
693 /* check for page fault inside the thread stack */
694 if (get_trap_code(context) == TRAP_ARM_PAGEFLT &&
695 (char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
696 (char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
697 virtual_handle_stack_fault( info->si_addr ))
699 /* check if this was the last guard page */
700 if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
702 rec = setup_exception( context, raise_segv_exception );
703 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
705 return;
708 rec = setup_exception( context, raise_segv_exception );
709 if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
711 switch(get_trap_code(context))
713 case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */
714 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
715 break;
716 case TRAP_ARM_PAGEFLT: /* Page fault */
717 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
718 rec->NumberParameters = 2;
719 rec->ExceptionInformation[0] = (get_error_code(context) & 0x800) != 0;
720 rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
721 break;
722 case TRAP_ARM_ALIGNFLT: /* Alignment check exception */
723 rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
724 break;
725 case TRAP_ARM_UNKNOWN: /* Unknown fault code */
726 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
727 rec->NumberParameters = 2;
728 rec->ExceptionInformation[0] = 0;
729 rec->ExceptionInformation[1] = 0xffffffff;
730 break;
731 default:
732 ERR("Got unexpected trap %d\n", get_trap_code(context));
733 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
734 break;
738 /**********************************************************************
739 * trap_handler
741 * Handler for SIGTRAP.
743 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
745 EXCEPTION_RECORD rec;
746 CONTEXT context;
747 NTSTATUS status;
749 switch ( info->si_code )
751 case TRAP_TRACE:
752 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
753 break;
754 case TRAP_BRKPT:
755 default:
756 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
757 break;
760 save_context( &context, ucontext );
761 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
762 rec.ExceptionRecord = NULL;
763 rec.ExceptionAddress = (LPVOID)context.Pc;
764 rec.NumberParameters = 0;
765 status = raise_exception( &rec, &context, TRUE );
766 if (status) raise_status( status, &rec );
767 restore_context( &context, ucontext );
770 /**********************************************************************
771 * fpe_handler
773 * Handler for SIGFPE.
775 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
777 EXCEPTION_RECORD rec;
778 CONTEXT context;
779 NTSTATUS status;
781 save_fpu( &context, sigcontext );
782 save_context( &context, sigcontext );
784 switch (siginfo->si_code & 0xffff )
786 #ifdef FPE_FLTSUB
787 case FPE_FLTSUB:
788 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
789 break;
790 #endif
791 #ifdef FPE_INTDIV
792 case FPE_INTDIV:
793 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
794 break;
795 #endif
796 #ifdef FPE_INTOVF
797 case FPE_INTOVF:
798 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
799 break;
800 #endif
801 #ifdef FPE_FLTDIV
802 case FPE_FLTDIV:
803 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
804 break;
805 #endif
806 #ifdef FPE_FLTOVF
807 case FPE_FLTOVF:
808 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
809 break;
810 #endif
811 #ifdef FPE_FLTUND
812 case FPE_FLTUND:
813 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
814 break;
815 #endif
816 #ifdef FPE_FLTRES
817 case FPE_FLTRES:
818 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
819 break;
820 #endif
821 #ifdef FPE_FLTINV
822 case FPE_FLTINV:
823 #endif
824 default:
825 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
826 break;
828 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
829 rec.ExceptionRecord = NULL;
830 rec.ExceptionAddress = (LPVOID)context.Pc;
831 rec.NumberParameters = 0;
832 status = raise_exception( &rec, &context, TRUE );
833 if (status) raise_status( status, &rec );
835 restore_context( &context, sigcontext );
836 restore_fpu( &context, sigcontext );
839 /**********************************************************************
840 * int_handler
842 * Handler for SIGINT.
844 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
846 if (!dispatch_signal(SIGINT))
848 EXCEPTION_RECORD rec;
849 CONTEXT context;
850 NTSTATUS status;
852 save_context( &context, sigcontext );
853 rec.ExceptionCode = CONTROL_C_EXIT;
854 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
855 rec.ExceptionRecord = NULL;
856 rec.ExceptionAddress = (LPVOID)context.Pc;
857 rec.NumberParameters = 0;
858 status = raise_exception( &rec, &context, TRUE );
859 if (status) raise_status( status, &rec );
860 restore_context( &context, sigcontext );
865 /**********************************************************************
866 * abrt_handler
868 * Handler for SIGABRT.
870 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
872 EXCEPTION_RECORD rec;
873 CONTEXT context;
874 NTSTATUS status;
876 save_context( &context, sigcontext );
877 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
878 rec.ExceptionFlags = EH_NONCONTINUABLE;
879 rec.ExceptionRecord = NULL;
880 rec.ExceptionAddress = (LPVOID)context.Pc;
881 rec.NumberParameters = 0;
882 status = raise_exception( &rec, &context, TRUE );
883 if (status) raise_status( status, &rec );
884 restore_context( &context, sigcontext );
888 /**********************************************************************
889 * quit_handler
891 * Handler for SIGQUIT.
893 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
895 abort_thread(0);
899 /**********************************************************************
900 * usr1_handler
902 * Handler for SIGUSR1, used to signal a thread that it got suspended.
904 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
906 CONTEXT context;
908 save_context( &context, sigcontext );
909 wait_suspend( &context );
910 restore_context( &context, sigcontext );
914 /***********************************************************************
915 * __wine_set_signal_handler (NTDLL.@)
917 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
919 if (sig >= sizeof(handlers) / sizeof(handlers[0])) return -1;
920 if (handlers[sig] != NULL) return -2;
921 handlers[sig] = wsh;
922 return 0;
926 /**********************************************************************
927 * signal_alloc_thread
929 NTSTATUS signal_alloc_thread( TEB **teb )
931 static size_t sigstack_zero_bits;
932 SIZE_T size;
933 NTSTATUS status;
935 if (!sigstack_zero_bits)
937 size_t min_size = page_size;
938 /* find the first power of two not smaller than min_size */
939 while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
940 assert( sizeof(TEB) <= min_size );
943 size = 1 << sigstack_zero_bits;
944 *teb = NULL;
945 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
946 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
948 (*teb)->Tib.Self = &(*teb)->Tib;
949 (*teb)->Tib.ExceptionList = (void *)~0UL;
951 return status;
955 /**********************************************************************
956 * signal_free_thread
958 void signal_free_thread( TEB *teb )
960 SIZE_T size = 0;
962 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
966 /**********************************************************************
967 * signal_init_thread
969 void signal_init_thread( TEB *teb )
971 static BOOL init_done;
973 if (!init_done)
975 pthread_key_create( &teb_key, NULL );
976 init_done = TRUE;
979 #if defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_8A__)
980 /* Win32/ARM applications expect the TEB pointer to be in the TPIDRURW register. */
981 __asm__ __volatile__( "mcr p15, 0, %0, c13, c0, 2" : : "r" (teb) );
982 #endif
984 pthread_setspecific( teb_key, teb );
988 /**********************************************************************
989 * signal_init_process
991 void signal_init_process(void)
993 struct sigaction sig_act;
995 sig_act.sa_mask = server_block_set;
996 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
998 sig_act.sa_sigaction = int_handler;
999 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
1000 sig_act.sa_sigaction = fpe_handler;
1001 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
1002 sig_act.sa_sigaction = abrt_handler;
1003 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
1004 sig_act.sa_sigaction = quit_handler;
1005 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
1006 sig_act.sa_sigaction = usr1_handler;
1007 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
1009 sig_act.sa_sigaction = segv_handler;
1010 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
1011 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
1012 #ifdef SIGBUS
1013 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
1014 #endif
1016 #ifdef SIGTRAP
1017 sig_act.sa_sigaction = trap_handler;
1018 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
1019 #endif
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 static void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
1210 __TRY
1212 TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
1213 RtlExitUserThread( entry( arg ));
1215 __EXCEPT(unhandled_exception_filter)
1217 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
1219 __ENDTRY
1220 abort(); /* should not be reached */
1223 extern void DECLSPEC_NORETURN start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend,
1224 void *relay, TEB *teb );
1225 __ASM_GLOBAL_FUNC( start_thread,
1226 ".arm\n\t"
1227 "push {r4-r12,lr}\n\t"
1228 /* store exit frame */
1229 "ldr r4, [sp, #40]\n\t" /* teb */
1230 "str sp, [r4, #0x1d4]\n\t" /* teb->SystemReserved2 */
1231 /* build initial context on thread stack */
1232 "ldr r4, [r4, #4]\n\t" /* teb->Tib.StackBase */
1233 "sub r5, r4, #0x1a0\n\t" /* sizeof(CONTEXT) */
1234 "mov ip, #0x0200000\n\t" /* CONTEXT_ARM */
1235 "add ip, #0x3\n\t" /* CONTEXT_FULL */
1236 "str ip, [r5]\n\t" /* context->ContextFlags */
1237 "str r0, [r5, #0x4]\n\t" /* context->R0 = entry */
1238 "str r1, [r5, #0x8]\n\t" /* context->R1 = arg */
1239 "str r4, [r5, #0x38]\n\t" /* context->Sp = stack */
1240 "str r3, [r5, #0x40]\n\t" /* context->Pc = relay */
1241 /* switch to thread stack */
1242 "mov sp, r5\n\t"
1243 /* attach dlls */
1244 "mov r0, r5\n\t" /* context */
1245 "mov r1, r2\n\t" /* suspend */
1246 "bl " __ASM_NAME("attach_dlls") "\n\t"
1247 /* switch to the initial context */
1248 "mov r0, r5\n\t"
1249 "b " __ASM_NAME("set_cpu_context") )
1251 extern void DECLSPEC_NORETURN call_thread_exit_func( int status, void (*func)(int), TEB *teb );
1252 __ASM_GLOBAL_FUNC( call_thread_exit_func,
1253 ".arm\n\t"
1254 "ldr r3, [r2, #0x1d4]\n\t" /* teb->SystemReserved2 */
1255 "mov ip, #0\n\t"
1256 "str ip, [r2, #0x1d4]\n\t"
1257 "cmp r3, ip\n\t"
1258 "movne sp, r3\n\t"
1259 "blx r1" )
1261 /***********************************************************************
1262 * signal_start_thread
1264 * Thread startup sequence:
1265 * signal_start_thread()
1266 * -> thread_startup()
1267 * -> call_thread_entry_point()
1269 void signal_start_thread( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend )
1271 start_thread( entry, arg, suspend, call_thread_entry_point, NtCurrentTeb() );
1274 /**********************************************************************
1275 * signal_start_process
1277 * Process startup sequence:
1278 * signal_start_process()
1279 * -> thread_startup()
1280 * -> kernel32_start_process()
1282 void signal_start_process( LPTHREAD_START_ROUTINE entry, BOOL suspend )
1284 start_thread( entry, NtCurrentTeb()->Peb, suspend, kernel32_start_process, NtCurrentTeb() );
1287 /***********************************************************************
1288 * signal_exit_thread
1290 void signal_exit_thread( int status )
1292 call_thread_exit_func( status, exit_thread, NtCurrentTeb() );
1295 /***********************************************************************
1296 * signal_exit_process
1298 void signal_exit_process( int status )
1300 call_thread_exit_func( status, exit, NtCurrentTeb() );
1303 /**********************************************************************
1304 * DbgBreakPoint (NTDLL.@)
1306 void WINAPI DbgBreakPoint(void)
1308 kill(getpid(), SIGTRAP);
1311 /**********************************************************************
1312 * DbgUserBreakPoint (NTDLL.@)
1314 void WINAPI DbgUserBreakPoint(void)
1316 kill(getpid(), SIGTRAP);
1319 /**********************************************************************
1320 * NtCurrentTeb (NTDLL.@)
1322 TEB * WINAPI NtCurrentTeb(void)
1324 return pthread_getspecific( teb_key );
1327 #endif /* __arm__ */