dpnet/tests: Add a trailing '\n' to some ok() calls.
[wine.git] / dlls / ntdll / signal_arm.c
blobe3ae7bd55da22fc3183c4e40fd0a0bbe162f6657
1 /*
2 * ARM signal handling routines
4 * Copyright 2002 Marcus Meissner, SuSE Linux AG
5 * Copyright 2010, 2011 André Hentschel
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #ifdef __arm__
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <signal.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
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 FAULT_sig(context) REG_sig(fault_address, context)
100 # define TRAP_sig(context) REG_sig(trap_no, context)
102 #endif /* linux */
104 enum arm_trap_code
106 TRAP_ARM_UNKNOWN = -1, /* Unknown fault (TRAP_sig not defined) */
107 TRAP_ARM_PRIVINFLT = 6, /* Invalid opcode exception */
108 TRAP_ARM_PAGEFLT = 14, /* Page fault */
109 TRAP_ARM_ALIGNFLT = 17, /* Alignment check exception */
112 typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
113 typedef int (*wine_signal_handler)(unsigned int sig);
115 static wine_signal_handler handlers[256];
118 struct UNWIND_INFO
120 WORD function_length;
121 WORD unknown1 : 7;
122 WORD count : 5;
123 WORD unknown2 : 4;
126 /***********************************************************************
127 * dispatch_signal
129 static inline int dispatch_signal(unsigned int sig)
131 if (handlers[sig] == NULL) return 0;
132 return handlers[sig](sig);
135 /*******************************************************************
136 * is_valid_frame
138 static inline BOOL is_valid_frame( void *frame )
140 if ((ULONG_PTR)frame & 3) return FALSE;
141 return (frame >= NtCurrentTeb()->Tib.StackLimit &&
142 (void **)frame < (void **)NtCurrentTeb()->Tib.StackBase - 1);
145 /***********************************************************************
146 * save_context
148 * Set the register values from a sigcontext.
150 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
152 #define C(x) context->R##x = REGn_sig(x,sigcontext)
153 /* Save normal registers */
154 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
155 #undef C
157 context->ContextFlags = CONTEXT_FULL;
158 context->Sp = SP_sig(sigcontext); /* Stack pointer */
159 context->Lr = LR_sig(sigcontext); /* Link register */
160 context->Pc = PC_sig(sigcontext); /* Program Counter */
161 context->Cpsr = CPSR_sig(sigcontext); /* Current State Register */
162 context->Ip = IP_sig(sigcontext); /* Intra-Procedure-call scratch register */
163 context->Fp = FP_sig(sigcontext); /* Frame pointer */
167 /***********************************************************************
168 * restore_context
170 * Build a sigcontext from the register values.
172 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
174 #define C(x) REGn_sig(x,sigcontext) = context->R##x
175 /* Restore normal registers */
176 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
177 #undef C
179 SP_sig(sigcontext) = context->Sp; /* Stack pointer */
180 LR_sig(sigcontext) = context->Lr ; /* Link register */
181 PC_sig(sigcontext) = context->Pc; /* Program Counter */
182 CPSR_sig(sigcontext) = context->Cpsr; /* Current State Register */
183 IP_sig(sigcontext) = context->Ip; /* Intra-Procedure-call scratch register */
184 FP_sig(sigcontext) = context->Fp; /* Frame pointer */
188 /***********************************************************************
189 * save_fpu
191 * Set the FPU context from a sigcontext.
193 static inline void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
195 FIXME("not implemented\n");
199 /***********************************************************************
200 * restore_fpu
202 * Restore the FPU context to a sigcontext.
204 static inline void restore_fpu( CONTEXT *context, const ucontext_t *sigcontext )
206 FIXME("not implemented\n");
210 /***********************************************************************
211 * RtlCaptureContext (NTDLL.@)
213 /* FIXME: Use the Stack instead of the actual register values */
214 __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
215 ".arm\n\t"
216 "stmfd SP!, {r1}\n\t"
217 "mov r1, #0x40\n\t" /* CONTEXT_ARM */
218 "add r1, r1, #0x3\n\t" /* CONTEXT_FULL */
219 "str r1, [r0]\n\t" /* context->ContextFlags */
220 "ldmfd SP!, {r1}\n\t"
221 "str r0, [r0, #0x4]\n\t" /* context->R0 */
222 "str r1, [r0, #0x8]\n\t" /* context->R1 */
223 "str r2, [r0, #0xc]\n\t" /* context->R2 */
224 "str r3, [r0, #0x10]\n\t" /* context->R3 */
225 "str r4, [r0, #0x14]\n\t" /* context->R4 */
226 "str r5, [r0, #0x18]\n\t" /* context->R5 */
227 "str r6, [r0, #0x1c]\n\t" /* context->R6 */
228 "str r7, [r0, #0x20]\n\t" /* context->R7 */
229 "str r8, [r0, #0x24]\n\t" /* context->R8 */
230 "str r9, [r0, #0x28]\n\t" /* context->R9 */
231 "str r10, [r0, #0x2c]\n\t" /* context->R10 */
232 "str r11, [r0, #0x30]\n\t" /* context->Fp */
233 "str IP, [r0, #0x34]\n\t" /* context->Ip */
234 "str SP, [r0, #0x38]\n\t" /* context->Sp */
235 "str LR, [r0, #0x3c]\n\t" /* context->Lr */
236 "str PC, [r0, #0x40]\n\t" /* context->Pc */
237 "mrs r1, CPSR\n\t"
238 "str r1, [r0, #0x44]\n\t" /* context->Cpsr */
239 "mov PC, LR\n"
243 /***********************************************************************
244 * set_cpu_context
246 * Set the new CPU context.
248 /* FIXME: What about the CPSR? */
249 __ASM_GLOBAL_FUNC( set_cpu_context,
250 "mov IP, r0\n\t"
251 "ldr r0, [IP, #0x4]\n\t" /* context->R0 */
252 "ldr r1, [IP, #0x8]\n\t" /* context->R1 */
253 "ldr r2, [IP, #0xc]\n\t" /* context->R2 */
254 "ldr r3, [IP, #0x10]\n\t" /* context->R3 */
255 "ldr r4, [IP, #0x14]\n\t" /* context->R4 */
256 "ldr r5, [IP, #0x18]\n\t" /* context->R5 */
257 "ldr r6, [IP, #0x1c]\n\t" /* context->R6 */
258 "ldr r7, [IP, #0x20]\n\t" /* context->R7 */
259 "ldr r8, [IP, #0x24]\n\t" /* context->R8 */
260 "ldr r9, [IP, #0x28]\n\t" /* context->R9 */
261 "ldr r10, [IP, #0x2c]\n\t" /* context->R10 */
262 "ldr r11, [IP, #0x30]\n\t" /* context->Fp */
263 "ldr SP, [IP, #0x38]\n\t" /* context->Sp */
264 "ldr LR, [IP, #0x3c]\n\t" /* context->Lr */
265 "ldr PC, [IP, #0x40]\n\t" /* context->Pc */
269 /***********************************************************************
270 * copy_context
272 * Copy a register context according to the flags.
274 void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
276 flags &= ~CONTEXT_ARM; /* get rid of CPU id */
277 if (flags & CONTEXT_CONTROL)
279 to->Sp = from->Sp;
280 to->Lr = from->Lr;
281 to->Pc = from->Pc;
282 to->Cpsr = from->Cpsr;
284 if (flags & CONTEXT_INTEGER)
286 to->R0 = from->R0;
287 to->R1 = from->R1;
288 to->R2 = from->R2;
289 to->R3 = from->R3;
290 to->R4 = from->R4;
291 to->R5 = from->R5;
292 to->R6 = from->R6;
293 to->R7 = from->R7;
294 to->R8 = from->R8;
295 to->R9 = from->R9;
296 to->R10 = from->R10;
297 to->Ip = from->Ip;
298 to->Fp = from->Fp;
303 /***********************************************************************
304 * context_to_server
306 * Convert a register context to the server format.
308 NTSTATUS context_to_server( context_t *to, const CONTEXT *from )
310 DWORD flags = from->ContextFlags & ~CONTEXT_ARM; /* get rid of CPU id */
312 memset( to, 0, sizeof(*to) );
313 to->cpu = CPU_ARM;
315 if (flags & CONTEXT_CONTROL)
317 to->flags |= SERVER_CTX_CONTROL;
318 to->ctl.arm_regs.sp = from->Sp;
319 to->ctl.arm_regs.lr = from->Lr;
320 to->ctl.arm_regs.pc = from->Pc;
321 to->ctl.arm_regs.cpsr = from->Cpsr;
323 if (flags & CONTEXT_INTEGER)
325 to->flags |= SERVER_CTX_INTEGER;
326 to->integer.arm_regs.r[0] = from->R0;
327 to->integer.arm_regs.r[1] = from->R1;
328 to->integer.arm_regs.r[2] = from->R2;
329 to->integer.arm_regs.r[3] = from->R3;
330 to->integer.arm_regs.r[4] = from->R4;
331 to->integer.arm_regs.r[5] = from->R5;
332 to->integer.arm_regs.r[6] = from->R6;
333 to->integer.arm_regs.r[7] = from->R7;
334 to->integer.arm_regs.r[8] = from->R8;
335 to->integer.arm_regs.r[9] = from->R9;
336 to->integer.arm_regs.r[10] = from->R10;
337 to->integer.arm_regs.r[11] = from->Fp;
338 to->integer.arm_regs.r[12] = from->Ip;
340 return STATUS_SUCCESS;
344 /***********************************************************************
345 * context_from_server
347 * Convert a register context from the server format.
349 NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
351 if (from->cpu != CPU_ARM) return STATUS_INVALID_PARAMETER;
353 to->ContextFlags = CONTEXT_ARM;
354 if (from->flags & SERVER_CTX_CONTROL)
356 to->ContextFlags |= CONTEXT_CONTROL;
357 to->Sp = from->ctl.arm_regs.sp;
358 to->Lr = from->ctl.arm_regs.lr;
359 to->Pc = from->ctl.arm_regs.pc;
360 to->Cpsr = from->ctl.arm_regs.cpsr;
362 if (from->flags & SERVER_CTX_INTEGER)
364 to->ContextFlags |= CONTEXT_INTEGER;
365 to->R0 = from->integer.arm_regs.r[0];
366 to->R1 = from->integer.arm_regs.r[1];
367 to->R2 = from->integer.arm_regs.r[2];
368 to->R3 = from->integer.arm_regs.r[3];
369 to->R4 = from->integer.arm_regs.r[4];
370 to->R5 = from->integer.arm_regs.r[5];
371 to->R6 = from->integer.arm_regs.r[6];
372 to->R7 = from->integer.arm_regs.r[7];
373 to->R8 = from->integer.arm_regs.r[8];
374 to->R9 = from->integer.arm_regs.r[9];
375 to->R10 = from->integer.arm_regs.r[10];
376 to->Fp = from->integer.arm_regs.r[11];
377 to->Ip = from->integer.arm_regs.r[12];
379 return STATUS_SUCCESS;
382 extern void raise_func_trampoline_thumb( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
383 __ASM_GLOBAL_FUNC( raise_func_trampoline_thumb,
384 ".thumb\n\t"
385 "blx r2\n\t"
386 "bkpt")
388 extern void raise_func_trampoline_arm( EXCEPTION_RECORD *rec, CONTEXT *context, raise_func func );
389 __ASM_GLOBAL_FUNC( raise_func_trampoline_arm,
390 ".arm\n\t"
391 "blx r2\n\t"
392 "bkpt")
394 /***********************************************************************
395 * setup_exception_record
397 * Setup the exception record and context on the thread stack.
399 static EXCEPTION_RECORD *setup_exception( ucontext_t *sigcontext, raise_func func )
401 struct stack_layout
403 CONTEXT context;
404 EXCEPTION_RECORD rec;
405 } *stack;
406 DWORD exception_code = 0;
408 stack = (struct stack_layout *)(SP_sig(sigcontext) & ~3);
409 stack--; /* push the stack_layout structure */
411 stack->rec.ExceptionRecord = NULL;
412 stack->rec.ExceptionCode = exception_code;
413 stack->rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
414 stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
415 stack->rec.NumberParameters = 0;
417 save_context( &stack->context, sigcontext );
419 /* now modify the sigcontext to return to the raise function */
420 SP_sig(sigcontext) = (DWORD)stack;
421 if (CPSR_sig(sigcontext) & 0x20)
422 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_thumb;
423 else
424 PC_sig(sigcontext) = (DWORD)raise_func_trampoline_arm;
425 REGn_sig(0, sigcontext) = (DWORD)&stack->rec; /* first arg for raise_func */
426 REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for raise_func */
427 REGn_sig(2, sigcontext) = (DWORD)func; /* the raise_func as third arg for the trampoline */
430 return &stack->rec;
433 /**********************************************************************
434 * raise_segv_exception
436 static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
438 NTSTATUS status;
440 switch(rec->ExceptionCode)
442 case EXCEPTION_ACCESS_VIOLATION:
443 if (rec->NumberParameters == 2)
445 if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
446 rec->ExceptionInformation[0] )))
447 goto done;
449 break;
451 status = NtRaiseException( rec, context, TRUE );
452 if (status) raise_status( status, rec );
453 done:
454 set_cpu_context( context );
457 /**********************************************************************
458 * call_stack_handlers
460 * Call the stack handlers chain.
462 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
464 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch, *nested_frame;
465 DWORD res;
467 frame = NtCurrentTeb()->Tib.ExceptionList;
468 nested_frame = NULL;
469 while (frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL)
471 /* Check frame address */
472 if (!is_valid_frame( frame ))
474 rec->ExceptionFlags |= EH_STACK_INVALID;
475 break;
478 /* Call handler */
479 TRACE( "calling handler at %p code=%x flags=%x\n",
480 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
481 res = frame->Handler( rec, frame, context, &dispatch );
482 TRACE( "handler at %p returned %x\n", frame->Handler, res );
484 if (frame == nested_frame)
486 /* no longer nested */
487 nested_frame = NULL;
488 rec->ExceptionFlags &= ~EH_NESTED_CALL;
491 switch(res)
493 case ExceptionContinueExecution:
494 if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return STATUS_SUCCESS;
495 return STATUS_NONCONTINUABLE_EXCEPTION;
496 case ExceptionContinueSearch:
497 break;
498 case ExceptionNestedException:
499 if (nested_frame < dispatch) nested_frame = dispatch;
500 rec->ExceptionFlags |= EH_NESTED_CALL;
501 break;
502 default:
503 return STATUS_INVALID_DISPOSITION;
505 frame = frame->Prev;
507 return STATUS_UNHANDLED_EXCEPTION;
511 /*******************************************************************
512 * raise_exception
514 * Implementation of NtRaiseException.
516 static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
518 NTSTATUS status;
520 if (first_chance)
522 DWORD c;
524 TRACE( "code=%x flags=%x addr=%p pc=%08x tid=%04x\n",
525 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
526 context->Pc, GetCurrentThreadId() );
527 for (c = 0; c < rec->NumberParameters; c++)
528 TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
529 if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
531 if (rec->ExceptionInformation[1] >> 16)
532 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
533 rec->ExceptionAddress,
534 (char*)rec->ExceptionInformation[0], (char*)rec->ExceptionInformation[1] );
535 else
536 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
537 rec->ExceptionAddress,
538 (char*)rec->ExceptionInformation[0], rec->ExceptionInformation[1] );
540 else
542 TRACE( " r0=%08x r1=%08x r2=%08x r3=%08x r4=%08x r5=%08x\n",
543 context->R0, context->R1, context->R2, context->R3, context->R4, context->R5 );
544 TRACE( " r6=%08x r7=%08x r8=%08x r9=%08x r10=%08x fp=%08x\n",
545 context->R6, context->R7, context->R8, context->R9, context->R10, context->Fp );
546 TRACE( " ip=%08x sp=%08x lr=%08x pc=%08x cpsr=%08x\n",
547 context->Ip, context->Sp, context->Lr, context->Pc, context->Cpsr );
550 status = send_debug_event( rec, TRUE, context );
551 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
552 return STATUS_SUCCESS;
554 if (call_vectored_handlers( rec, context ) == EXCEPTION_CONTINUE_EXECUTION)
555 return STATUS_SUCCESS;
557 if ((status = call_stack_handlers( rec, context )) != STATUS_UNHANDLED_EXCEPTION)
558 return status;
561 /* last chance exception */
563 status = send_debug_event( rec, FALSE, context );
564 if (status != DBG_CONTINUE)
566 if (rec->ExceptionFlags & EH_STACK_INVALID)
567 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
568 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
569 ERR("Process attempted to continue execution after noncontinuable exception.\n");
570 else
571 ERR("Unhandled exception code %x flags %x addr %p\n",
572 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
573 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
575 return STATUS_SUCCESS;
579 /**********************************************************************
580 * segv_handler
582 * Handler for SIGSEGV and related errors.
584 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
586 EXCEPTION_RECORD *rec;
587 ucontext_t *context = ucontext;
589 /* check for page fault inside the thread stack */
590 if (TRAP_sig(context) == TRAP_ARM_PAGEFLT &&
591 (char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
592 (char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
593 virtual_handle_stack_fault( info->si_addr ))
595 /* check if this was the last guard page */
596 if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
598 rec = setup_exception( context, raise_segv_exception );
599 rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
601 return;
604 rec = setup_exception( context, raise_segv_exception );
605 if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
607 switch(TRAP_sig(context))
609 case TRAP_ARM_PRIVINFLT: /* Invalid opcode exception */
610 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
611 break;
612 case TRAP_ARM_PAGEFLT: /* Page fault */
613 rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
614 rec->NumberParameters = 2;
615 rec->ExceptionInformation[0] = (ERROR_sig(context) & 0x800) != 0;
616 rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
617 break;
618 case TRAP_ARM_ALIGNFLT: /* Alignment check exception */
619 rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
620 break;
621 default:
622 ERR("Got unexpected trap %ld\n", TRAP_sig(context));
623 rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
624 break;
628 /**********************************************************************
629 * trap_handler
631 * Handler for SIGTRAP.
633 static void trap_handler( int signal, siginfo_t *info, void *ucontext )
635 EXCEPTION_RECORD rec;
636 CONTEXT context;
637 NTSTATUS status;
639 switch ( info->si_code )
641 case TRAP_TRACE:
642 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
643 break;
644 case TRAP_BRKPT:
645 default:
646 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
647 break;
650 save_context( &context, ucontext );
651 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
652 rec.ExceptionRecord = NULL;
653 rec.ExceptionAddress = (LPVOID)context.Pc;
654 rec.NumberParameters = 0;
655 status = raise_exception( &rec, &context, TRUE );
656 if (status) raise_status( status, &rec );
657 restore_context( &context, ucontext );
660 /**********************************************************************
661 * fpe_handler
663 * Handler for SIGFPE.
665 static void fpe_handler( int signal, siginfo_t *siginfo, void *sigcontext )
667 EXCEPTION_RECORD rec;
668 CONTEXT context;
669 NTSTATUS status;
671 save_fpu( &context, sigcontext );
672 save_context( &context, sigcontext );
674 switch (siginfo->si_code & 0xffff )
676 #ifdef FPE_FLTSUB
677 case FPE_FLTSUB:
678 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
679 break;
680 #endif
681 #ifdef FPE_INTDIV
682 case FPE_INTDIV:
683 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
684 break;
685 #endif
686 #ifdef FPE_INTOVF
687 case FPE_INTOVF:
688 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
689 break;
690 #endif
691 #ifdef FPE_FLTDIV
692 case FPE_FLTDIV:
693 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
694 break;
695 #endif
696 #ifdef FPE_FLTOVF
697 case FPE_FLTOVF:
698 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
699 break;
700 #endif
701 #ifdef FPE_FLTUND
702 case FPE_FLTUND:
703 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
704 break;
705 #endif
706 #ifdef FPE_FLTRES
707 case FPE_FLTRES:
708 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
709 break;
710 #endif
711 #ifdef FPE_FLTINV
712 case FPE_FLTINV:
713 #endif
714 default:
715 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
716 break;
718 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
719 rec.ExceptionRecord = NULL;
720 rec.ExceptionAddress = (LPVOID)context.Pc;
721 rec.NumberParameters = 0;
722 status = raise_exception( &rec, &context, TRUE );
723 if (status) raise_status( status, &rec );
725 restore_context( &context, sigcontext );
726 restore_fpu( &context, sigcontext );
729 /**********************************************************************
730 * int_handler
732 * Handler for SIGINT.
734 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
736 if (!dispatch_signal(SIGINT))
738 EXCEPTION_RECORD rec;
739 CONTEXT context;
740 NTSTATUS status;
742 save_context( &context, sigcontext );
743 rec.ExceptionCode = CONTROL_C_EXIT;
744 rec.ExceptionFlags = EXCEPTION_CONTINUABLE;
745 rec.ExceptionRecord = NULL;
746 rec.ExceptionAddress = (LPVOID)context.Pc;
747 rec.NumberParameters = 0;
748 status = raise_exception( &rec, &context, TRUE );
749 if (status) raise_status( status, &rec );
750 restore_context( &context, sigcontext );
755 /**********************************************************************
756 * abrt_handler
758 * Handler for SIGABRT.
760 static void abrt_handler( int signal, siginfo_t *siginfo, void *sigcontext )
762 EXCEPTION_RECORD rec;
763 CONTEXT context;
764 NTSTATUS status;
766 save_context( &context, sigcontext );
767 rec.ExceptionCode = EXCEPTION_WINE_ASSERTION;
768 rec.ExceptionFlags = EH_NONCONTINUABLE;
769 rec.ExceptionRecord = NULL;
770 rec.ExceptionAddress = (LPVOID)context.Pc;
771 rec.NumberParameters = 0;
772 status = raise_exception( &rec, &context, TRUE );
773 if (status) raise_status( status, &rec );
774 restore_context( &context, sigcontext );
778 /**********************************************************************
779 * quit_handler
781 * Handler for SIGQUIT.
783 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
785 abort_thread(0);
789 /**********************************************************************
790 * usr1_handler
792 * Handler for SIGUSR1, used to signal a thread that it got suspended.
794 static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
796 CONTEXT context;
798 save_context( &context, sigcontext );
799 wait_suspend( &context );
800 restore_context( &context, sigcontext );
804 /***********************************************************************
805 * __wine_set_signal_handler (NTDLL.@)
807 int CDECL __wine_set_signal_handler(unsigned int sig, wine_signal_handler wsh)
809 if (sig > sizeof(handlers) / sizeof(handlers[0])) return -1;
810 if (handlers[sig] != NULL) return -2;
811 handlers[sig] = wsh;
812 return 0;
816 /**********************************************************************
817 * signal_alloc_thread
819 NTSTATUS signal_alloc_thread( TEB **teb )
821 static size_t sigstack_zero_bits;
822 SIZE_T size;
823 NTSTATUS status;
825 if (!sigstack_zero_bits)
827 size_t min_size = page_size;
828 /* find the first power of two not smaller than min_size */
829 while ((1u << sigstack_zero_bits) < min_size) sigstack_zero_bits++;
830 assert( sizeof(TEB) <= min_size );
833 size = 1 << sigstack_zero_bits;
834 *teb = NULL;
835 if (!(status = NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb, sigstack_zero_bits,
836 &size, MEM_COMMIT | MEM_TOP_DOWN, PAGE_READWRITE )))
838 (*teb)->Tib.Self = &(*teb)->Tib;
839 (*teb)->Tib.ExceptionList = (void *)~0UL;
841 return status;
845 /**********************************************************************
846 * signal_free_thread
848 void signal_free_thread( TEB *teb )
850 SIZE_T size;
852 if (teb->DeallocationStack)
854 size = 0;
855 NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
857 size = 0;
858 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb, &size, MEM_RELEASE );
861 /**********************************************************************
862 * set_tpidrurw
864 * Win32/ARM applications expect the TEB pointer to be in the TPIDRURW register.
866 #ifdef __ARM_ARCH_7A__
867 extern void set_tpidrurw( TEB *teb );
868 __ASM_GLOBAL_FUNC( set_tpidrurw,
869 "mcr p15, 0, r0, c13, c0, 2\n\t" /* TEB -> TPIDRURW */
870 "blx lr" )
871 #else
872 void set_tpidrurw( TEB *teb )
875 #endif
877 /**********************************************************************
878 * signal_init_thread
880 void signal_init_thread( TEB *teb )
882 static BOOL init_done;
884 if (!init_done)
886 pthread_key_create( &teb_key, NULL );
887 init_done = TRUE;
889 set_tpidrurw( teb );
890 pthread_setspecific( teb_key, teb );
894 /**********************************************************************
895 * signal_init_process
897 void signal_init_process(void)
899 struct sigaction sig_act;
901 sig_act.sa_mask = server_block_set;
902 sig_act.sa_flags = SA_RESTART | SA_SIGINFO;
904 sig_act.sa_sigaction = int_handler;
905 if (sigaction( SIGINT, &sig_act, NULL ) == -1) goto error;
906 sig_act.sa_sigaction = fpe_handler;
907 if (sigaction( SIGFPE, &sig_act, NULL ) == -1) goto error;
908 sig_act.sa_sigaction = abrt_handler;
909 if (sigaction( SIGABRT, &sig_act, NULL ) == -1) goto error;
910 sig_act.sa_sigaction = quit_handler;
911 if (sigaction( SIGQUIT, &sig_act, NULL ) == -1) goto error;
912 sig_act.sa_sigaction = usr1_handler;
913 if (sigaction( SIGUSR1, &sig_act, NULL ) == -1) goto error;
915 sig_act.sa_sigaction = segv_handler;
916 if (sigaction( SIGSEGV, &sig_act, NULL ) == -1) goto error;
917 if (sigaction( SIGILL, &sig_act, NULL ) == -1) goto error;
918 #ifdef SIGBUS
919 if (sigaction( SIGBUS, &sig_act, NULL ) == -1) goto error;
920 #endif
922 #ifdef SIGTRAP
923 sig_act.sa_sigaction = trap_handler;
924 if (sigaction( SIGTRAP, &sig_act, NULL ) == -1) goto error;
925 #endif
926 return;
928 error:
929 perror("sigaction");
930 exit(1);
934 /**********************************************************************
935 * __wine_enter_vm86 (NTDLL.@)
937 void __wine_enter_vm86( CONTEXT *context )
939 MESSAGE("vm86 mode not supported on this platform\n");
943 /**********************************************************************
944 * RtlAddFunctionTable (NTDLL.@)
946 BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD addr )
948 FIXME( "%p %u %x: stub\n", table, count, addr );
949 return TRUE;
953 /**********************************************************************
954 * RtlDeleteFunctionTable (NTDLL.@)
956 BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
958 FIXME( "%p: stub\n", table );
959 return TRUE;
962 /**********************************************************************
963 * find_function_info
965 static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, HMODULE module,
966 RUNTIME_FUNCTION *func, ULONG size )
968 int min = 0;
969 int max = size/sizeof(*func) - 1;
971 while (min <= max)
973 int pos = (min + max) / 2;
974 DWORD begin = (func[pos].BeginAddress & ~1), end;
975 if (func[pos].u.s.Flag)
976 end = begin + func[pos].u.s.FunctionLength * 2;
977 else
979 struct UNWIND_INFO *info;
980 info = (struct UNWIND_INFO *)((char *)module + func[pos].u.UnwindData);
981 end = begin + info->function_length * 2;
984 if ((char *)pc < (char *)module + begin) max = pos - 1;
985 else if ((char *)pc >= (char *)module + end) min = pos + 1;
986 else return func + pos;
988 return NULL;
991 /**********************************************************************
992 * RtlLookupFunctionEntry (NTDLL.@)
994 PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, DWORD *base,
995 UNWIND_HISTORY_TABLE *table )
997 LDR_MODULE *module;
998 RUNTIME_FUNCTION *func;
999 ULONG size;
1001 /* FIXME: should use the history table to make things faster */
1003 if (LdrFindEntryForAddress( (void *)pc, &module ))
1005 WARN( "module not found for %lx\n", pc );
1006 return NULL;
1008 if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
1009 IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
1011 WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
1012 return NULL;
1014 func = find_function_info( pc, module->BaseAddress, func, size );
1015 if (func) *base = (DWORD)module->BaseAddress;
1016 return func;
1019 /***********************************************************************
1020 * RtlUnwind (NTDLL.@)
1022 void WINAPI RtlUnwind( void *endframe, void *target_ip, EXCEPTION_RECORD *rec, void *retval )
1024 CONTEXT context;
1025 EXCEPTION_RECORD record;
1026 EXCEPTION_REGISTRATION_RECORD *frame, *dispatch;
1027 DWORD res;
1029 RtlCaptureContext( &context );
1030 context.R0 = (DWORD)retval;
1032 /* build an exception record, if we do not have one */
1033 if (!rec)
1035 record.ExceptionCode = STATUS_UNWIND;
1036 record.ExceptionFlags = 0;
1037 record.ExceptionRecord = NULL;
1038 record.ExceptionAddress = (void *)context.Pc;
1039 record.NumberParameters = 0;
1040 rec = &record;
1043 rec->ExceptionFlags |= EH_UNWINDING | (endframe ? 0 : EH_EXIT_UNWIND);
1045 TRACE( "code=%x flags=%x\n", rec->ExceptionCode, rec->ExceptionFlags );
1047 /* get chain of exception frames */
1048 frame = NtCurrentTeb()->Tib.ExceptionList;
1049 while ((frame != (EXCEPTION_REGISTRATION_RECORD*)~0UL) && (frame != endframe))
1051 /* Check frame address */
1052 if (endframe && ((void*)frame > endframe))
1053 raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
1055 if (!is_valid_frame( frame )) raise_status( STATUS_BAD_STACK, rec );
1057 /* Call handler */
1058 TRACE( "calling handler at %p code=%x flags=%x\n",
1059 frame->Handler, rec->ExceptionCode, rec->ExceptionFlags );
1060 res = frame->Handler(rec, frame, &context, &dispatch);
1061 TRACE( "handler at %p returned %x\n", frame->Handler, res );
1063 switch(res)
1065 case ExceptionContinueSearch:
1066 break;
1067 case ExceptionCollidedUnwind:
1068 frame = dispatch;
1069 break;
1070 default:
1071 raise_status( STATUS_INVALID_DISPOSITION, rec );
1072 break;
1074 frame = __wine_pop_frame( frame );
1078 /*******************************************************************
1079 * NtRaiseException (NTDLL.@)
1081 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1083 NTSTATUS status = raise_exception( rec, context, first_chance );
1084 if (status == STATUS_SUCCESS) NtSetContextThread( GetCurrentThread(), context );
1085 return status;
1088 /***********************************************************************
1089 * RtlRaiseException (NTDLL.@)
1091 void WINAPI RtlRaiseException( EXCEPTION_RECORD *rec )
1093 CONTEXT context;
1094 NTSTATUS status;
1096 RtlCaptureContext( &context );
1097 rec->ExceptionAddress = (LPVOID)context.Pc;
1098 status = raise_exception( rec, &context, TRUE );
1099 if (status) raise_status( status, rec );
1102 /*************************************************************************
1103 * RtlCaptureStackBackTrace (NTDLL.@)
1105 USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
1107 FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
1108 return 0;
1111 /***********************************************************************
1112 * call_thread_entry_point
1114 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry, void *arg )
1116 __TRY
1118 exit_thread( entry( arg ));
1120 __EXCEPT(unhandled_exception_filter)
1122 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
1124 __ENDTRY
1125 abort(); /* should not be reached */
1128 /***********************************************************************
1129 * RtlExitUserThread (NTDLL.@)
1131 void WINAPI RtlExitUserThread( ULONG status )
1133 exit_thread( status );
1136 /***********************************************************************
1137 * abort_thread
1139 void abort_thread( int status )
1141 terminate_thread( status );
1144 /**********************************************************************
1145 * DbgBreakPoint (NTDLL.@)
1147 void WINAPI DbgBreakPoint(void)
1149 kill(getpid(), SIGTRAP);
1152 /**********************************************************************
1153 * DbgUserBreakPoint (NTDLL.@)
1155 void WINAPI DbgUserBreakPoint(void)
1157 kill(getpid(), SIGTRAP);
1160 /**********************************************************************
1161 * NtCurrentTeb (NTDLL.@)
1163 TEB * WINAPI NtCurrentTeb(void)
1165 return pthread_getspecific( teb_key );
1168 #endif /* __arm__ */