2 * ARM signal handling routines
4 * Copyright 2002 Marcus Meissner, SuSE Linux AG
5 * Copyright 2010 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
25 #include "wine/port.h"
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
42 # ifdef HAVE_SYS_SYSCALL_H
43 # include <sys/syscall.h>
46 #ifdef HAVE_SYS_SIGNAL_H
47 # include <sys/signal.h>
51 #define WIN32_NO_STATUS
54 #include "wine/library.h"
55 #include "wine/exception.h"
56 #include "ntdll_misc.h"
57 #include "wine/debug.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
62 static pthread_key_t teb_key
;
64 /***********************************************************************
65 * signal context platform-specific definitions
69 /* All Registers access - only for local access */
70 # define REG_sig(reg_name, context) ((context)->uc_mcontext.reg_name)
71 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.arm_r##reg_num)
73 /* Special Registers access */
74 # define SP_sig(context) REG_sig(arm_sp, context) /* Stack pointer */
75 # define LR_sig(context) REG_sig(arm_lr, context) /* Link register */
76 # define PC_sig(context) REG_sig(arm_pc, context) /* Program counter */
77 # define CPSR_sig(context) REG_sig(arm_cpsr, context) /* Current State Register */
78 # define IP_sig(context) REG_sig(arm_ip, context) /* Program counter (2?) */
79 # define FP_sig(context) REG_sig(arm_fp, context) /* Frame pointer */
83 typedef int (*wine_signal_handler
)(unsigned int sig
);
85 static wine_signal_handler handlers
[256];
87 /***********************************************************************
90 static inline int dispatch_signal(unsigned int sig
)
92 if (handlers
[sig
] == NULL
) return 0;
93 return handlers
[sig
](sig
);
96 /***********************************************************************
99 * Set the register values from a sigcontext.
101 static void save_context( CONTEXT
*context
, const ucontext_t
*sigcontext
)
103 #define C(x) context->R##x = REGn_sig(x,sigcontext)
104 /* Save normal registers */
105 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
108 context
->Sp
= SP_sig(sigcontext
); /* Stack pointer */
109 context
->Lr
= LR_sig(sigcontext
); /* Link register */
110 context
->Pc
= PC_sig(sigcontext
); /* Program Counter */
111 context
->Cpsr
= CPSR_sig(sigcontext
); /* Current State Register */
112 context
->Ip
= IP_sig(sigcontext
); /* Intra-Procedure-call scratch register */
113 context
->Fp
= FP_sig(sigcontext
); /* Frame pointer */
117 /***********************************************************************
120 * Build a sigcontext from the register values.
122 static void restore_context( const CONTEXT
*context
, ucontext_t
*sigcontext
)
124 #define C(x) REGn_sig(x,sigcontext) = context->R##x
125 /* Restore normal registers */
126 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
129 SP_sig(sigcontext
) = context
->Sp
; /* Stack pointer */
130 LR_sig(sigcontext
) = context
->Lr
; /* Link register */
131 PC_sig(sigcontext
) = context
->Pc
; /* Program Counter */
132 CPSR_sig(sigcontext
) = context
->Cpsr
; /* Current State Register */
133 IP_sig(sigcontext
) = context
->Ip
; /* Intra-Procedure-call scratch register */
134 FP_sig(sigcontext
) = context
->Fp
; /* Frame pointer */
138 /***********************************************************************
141 * Set the FPU context from a sigcontext.
143 static inline void save_fpu( CONTEXT
*context
, const ucontext_t
*sigcontext
)
145 FIXME("not implemented\n");
149 /***********************************************************************
152 * Restore the FPU context to a sigcontext.
154 static inline void restore_fpu( CONTEXT
*context
, const ucontext_t
*sigcontext
)
156 FIXME("not implemented\n");
160 /***********************************************************************
161 * RtlCaptureContext (NTDLL.@)
163 void WINAPI
RtlCaptureContext( CONTEXT
*context
)
165 FIXME("not implemented\n");
166 memset( context
, 0, sizeof(*context
) );
170 /***********************************************************************
173 * Set the new CPU context.
175 void set_cpu_context( const CONTEXT
*context
)
177 FIXME("not implemented\n");
182 /***********************************************************************
185 * Copy a register context according to the flags.
187 void copy_context( CONTEXT
*to
, const CONTEXT
*from
, DWORD flags
)
189 if (flags
& CONTEXT_CONTROL
)
194 to
->Cpsr
= from
->Cpsr
;
196 if (flags
& CONTEXT_INTEGER
)
215 /***********************************************************************
218 * Convert a register context to the server format.
220 NTSTATUS
context_to_server( context_t
*to
, const CONTEXT
*from
)
222 DWORD flags
= from
->ContextFlags
; /* no CPU id? */
224 memset( to
, 0, sizeof(*to
) );
227 if (flags
& CONTEXT_CONTROL
)
229 to
->flags
|= SERVER_CTX_CONTROL
;
230 to
->ctl
.arm_regs
.sp
= from
->Sp
;
231 to
->ctl
.arm_regs
.lr
= from
->Lr
;
232 to
->ctl
.arm_regs
.pc
= from
->Pc
;
233 to
->ctl
.arm_regs
.cpsr
= from
->Cpsr
;
235 if (flags
& CONTEXT_INTEGER
)
237 to
->flags
|= SERVER_CTX_INTEGER
;
238 to
->integer
.arm_regs
.r
[0] = from
->R0
;
239 to
->integer
.arm_regs
.r
[1] = from
->R1
;
240 to
->integer
.arm_regs
.r
[2] = from
->R2
;
241 to
->integer
.arm_regs
.r
[3] = from
->R3
;
242 to
->integer
.arm_regs
.r
[4] = from
->R4
;
243 to
->integer
.arm_regs
.r
[5] = from
->R5
;
244 to
->integer
.arm_regs
.r
[6] = from
->R6
;
245 to
->integer
.arm_regs
.r
[7] = from
->R7
;
246 to
->integer
.arm_regs
.r
[8] = from
->R8
;
247 to
->integer
.arm_regs
.r
[9] = from
->R9
;
248 to
->integer
.arm_regs
.r
[10] = from
->R10
;
249 to
->integer
.arm_regs
.r
[11] = from
->Fp
;
250 to
->integer
.arm_regs
.r
[12] = from
->Ip
;
252 return STATUS_SUCCESS
;
256 /***********************************************************************
257 * context_from_server
259 * Convert a register context from the server format.
261 NTSTATUS
context_from_server( CONTEXT
*to
, const context_t
*from
)
263 if (from
->cpu
!= CPU_ARM
) return STATUS_INVALID_PARAMETER
;
265 to
->ContextFlags
= 0; /* no CPU id? */
266 if (from
->flags
& SERVER_CTX_CONTROL
)
268 to
->ContextFlags
|= CONTEXT_CONTROL
;
269 to
->Sp
= from
->ctl
.arm_regs
.sp
;
270 to
->Lr
= from
->ctl
.arm_regs
.lr
;
271 to
->Pc
= from
->ctl
.arm_regs
.pc
;
272 to
->Cpsr
= from
->ctl
.arm_regs
.cpsr
;
274 if (from
->flags
& SERVER_CTX_INTEGER
)
276 to
->ContextFlags
|= CONTEXT_INTEGER
;
277 to
->R0
= from
->integer
.arm_regs
.r
[0];
278 to
->R1
= from
->integer
.arm_regs
.r
[1];
279 to
->R2
= from
->integer
.arm_regs
.r
[2];
280 to
->R3
= from
->integer
.arm_regs
.r
[3];
281 to
->R4
= from
->integer
.arm_regs
.r
[4];
282 to
->R5
= from
->integer
.arm_regs
.r
[5];
283 to
->R6
= from
->integer
.arm_regs
.r
[6];
284 to
->R7
= from
->integer
.arm_regs
.r
[7];
285 to
->R8
= from
->integer
.arm_regs
.r
[8];
286 to
->R9
= from
->integer
.arm_regs
.r
[9];
287 to
->R10
= from
->integer
.arm_regs
.r
[10];
288 to
->Fp
= from
->integer
.arm_regs
.r
[11];
289 to
->Ip
= from
->integer
.arm_regs
.r
[12];
291 return STATUS_SUCCESS
;
295 /**********************************************************************
296 * call_stack_handlers
298 * Call the stack handlers chain.
300 static NTSTATUS
call_stack_handlers( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
302 EXCEPTION_POINTERS ptrs
;
304 FIXME( "not implemented on ARM, exceptioncode: %x\n", rec
->ExceptionCode
);
306 /* hack: call unhandled exception filter directly */
307 ptrs
.ExceptionRecord
= rec
;
308 ptrs
.ContextRecord
= context
;
309 unhandled_exception_filter( &ptrs
);
310 return STATUS_UNHANDLED_EXCEPTION
;
314 /*******************************************************************
317 * Implementation of NtRaiseException.
319 static NTSTATUS
raise_exception( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
327 for (c
= 0; c
< rec
->NumberParameters
; c
++)
328 TRACE( " info[%d]=%08lx\n", c
, rec
->ExceptionInformation
[c
] );
329 if (rec
->ExceptionCode
== EXCEPTION_WINE_STUB
)
331 if (rec
->ExceptionInformation
[1] >> 16)
332 MESSAGE( "wine: Call from %p to unimplemented function %s.%s, aborting\n",
333 rec
->ExceptionAddress
,
334 (char*)rec
->ExceptionInformation
[0], (char*)rec
->ExceptionInformation
[1] );
336 MESSAGE( "wine: Call from %p to unimplemented function %s.%ld, aborting\n",
337 rec
->ExceptionAddress
,
338 (char*)rec
->ExceptionInformation
[0], rec
->ExceptionInformation
[1] );
342 /* FIXME: dump context */
345 status
= send_debug_event( rec
, TRUE
, context
);
346 if (status
== DBG_CONTINUE
|| status
== DBG_EXCEPTION_HANDLED
)
347 return STATUS_SUCCESS
;
349 if (call_vectored_handlers( rec
, context
) == EXCEPTION_CONTINUE_EXECUTION
)
350 return STATUS_SUCCESS
;
352 if ((status
= call_stack_handlers( rec
, context
)) != STATUS_UNHANDLED_EXCEPTION
)
356 /* last chance exception */
358 status
= send_debug_event( rec
, FALSE
, context
);
359 if (status
!= DBG_CONTINUE
)
361 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
362 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
363 else if (rec
->ExceptionCode
== STATUS_NONCONTINUABLE_EXCEPTION
)
364 ERR("Process attempted to continue execution after noncontinuable exception.\n");
366 ERR("Unhandled exception code %x flags %x addr %p\n",
367 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
);
368 NtTerminateProcess( NtCurrentProcess(), rec
->ExceptionCode
);
370 return STATUS_SUCCESS
;
374 /**********************************************************************
377 * Handler for SIGSEGV and related errors.
379 static void segv_handler( int signal
, siginfo_t
*info
, void *ucontext
)
381 EXCEPTION_RECORD rec
;
385 rec
.ExceptionCode
= EXCEPTION_ACCESS_VIOLATION
;
387 /* we want the page-fault case to be fast */
388 if ( info
->si_code
== SEGV_ACCERR
)
389 if (!(rec
.ExceptionCode
= virtual_handle_fault( info
->si_addr
, 0 ))) return;
391 save_context( &context
, ucontext
);
392 rec
.ExceptionRecord
= NULL
;
393 rec
.ExceptionFlags
= EXCEPTION_CONTINUABLE
;
394 rec
.ExceptionAddress
= (LPVOID
)context
.Pc
;
395 rec
.NumberParameters
= 2;
396 rec
.ExceptionInformation
[0] = 0; /* FIXME: read/write access ? */
397 rec
.ExceptionInformation
[1] = (ULONG_PTR
)info
->si_addr
;
399 status
= raise_exception( &rec
, &context
, TRUE
);
400 if (status
) raise_status( status
, &rec
);
401 restore_context( &context
, ucontext
);
404 /**********************************************************************
407 * Handler for SIGTRAP.
409 static void trap_handler( int signal
, siginfo_t
*info
, void *ucontext
)
411 EXCEPTION_RECORD rec
;
415 switch ( info
->si_code
)
418 rec
.ExceptionCode
= EXCEPTION_SINGLE_STEP
;
422 rec
.ExceptionCode
= EXCEPTION_BREAKPOINT
;
426 save_context( &context
, ucontext
);
427 rec
.ExceptionFlags
= EXCEPTION_CONTINUABLE
;
428 rec
.ExceptionRecord
= NULL
;
429 rec
.ExceptionAddress
= (LPVOID
)context
.Pc
;
430 rec
.NumberParameters
= 0;
431 status
= raise_exception( &rec
, &context
, TRUE
);
432 if (status
) raise_status( status
, &rec
);
433 restore_context( &context
, ucontext
);
436 /**********************************************************************
439 * Handler for SIGFPE.
441 static void fpe_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
443 EXCEPTION_RECORD rec
;
447 save_fpu( &context
, sigcontext
);
448 save_context( &context
, sigcontext
);
450 switch (siginfo
->si_code
& 0xffff )
454 rec
.ExceptionCode
= EXCEPTION_ARRAY_BOUNDS_EXCEEDED
;
459 rec
.ExceptionCode
= EXCEPTION_INT_DIVIDE_BY_ZERO
;
464 rec
.ExceptionCode
= EXCEPTION_INT_OVERFLOW
;
469 rec
.ExceptionCode
= EXCEPTION_FLT_DIVIDE_BY_ZERO
;
474 rec
.ExceptionCode
= EXCEPTION_FLT_OVERFLOW
;
479 rec
.ExceptionCode
= EXCEPTION_FLT_UNDERFLOW
;
484 rec
.ExceptionCode
= EXCEPTION_FLT_INEXACT_RESULT
;
491 rec
.ExceptionCode
= EXCEPTION_FLT_INVALID_OPERATION
;
494 rec
.ExceptionFlags
= EXCEPTION_CONTINUABLE
;
495 rec
.ExceptionRecord
= NULL
;
496 /*rec.ExceptionAddress = (LPVOID)context.Iar;*/
497 rec
.NumberParameters
= 0;
498 status
= raise_exception( &rec
, &context
, TRUE
);
499 if (status
) raise_status( status
, &rec
);
501 restore_context( &context
, sigcontext
);
502 restore_fpu( &context
, sigcontext
);
505 /**********************************************************************
508 * Handler for SIGINT.
510 static void int_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
512 if (!dispatch_signal(SIGINT
))
514 EXCEPTION_RECORD rec
;
518 save_context( &context
, sigcontext
);
519 rec
.ExceptionCode
= CONTROL_C_EXIT
;
520 rec
.ExceptionFlags
= EXCEPTION_CONTINUABLE
;
521 rec
.ExceptionRecord
= NULL
;
522 /*rec.ExceptionAddress = (LPVOID)context.Iar;*/
523 rec
.NumberParameters
= 0;
524 status
= raise_exception( &rec
, &context
, TRUE
);
525 if (status
) raise_status( status
, &rec
);
526 restore_context( &context
, sigcontext
);
531 /**********************************************************************
534 * Handler for SIGABRT.
536 static void abrt_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
538 EXCEPTION_RECORD rec
;
542 save_context( &context
, sigcontext
);
543 rec
.ExceptionCode
= EXCEPTION_WINE_ASSERTION
;
544 rec
.ExceptionFlags
= EH_NONCONTINUABLE
;
545 rec
.ExceptionRecord
= NULL
;
546 /*rec.ExceptionAddress = (LPVOID)context.Iar;*/
547 rec
.NumberParameters
= 0;
548 status
= raise_exception( &rec
, &context
, TRUE
);
549 if (status
) raise_status( status
, &rec
);
550 restore_context( &context
, sigcontext
);
554 /**********************************************************************
557 * Handler for SIGQUIT.
559 static void quit_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
565 /**********************************************************************
568 * Handler for SIGUSR1, used to signal a thread that it got suspended.
570 static void usr1_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
574 save_context( &context
, sigcontext
);
575 wait_suspend( &context
);
576 restore_context( &context
, sigcontext
);
580 /***********************************************************************
581 * __wine_set_signal_handler (NTDLL.@)
583 int CDECL
__wine_set_signal_handler(unsigned int sig
, wine_signal_handler wsh
)
585 if (sig
> sizeof(handlers
) / sizeof(handlers
[0])) return -1;
586 if (handlers
[sig
] != NULL
) return -2;
592 /**********************************************************************
593 * signal_alloc_thread
595 NTSTATUS
signal_alloc_thread( TEB
**teb
)
597 static size_t sigstack_zero_bits
;
601 if (!sigstack_zero_bits
)
603 size_t min_size
= getpagesize(); /* this is just for the TEB, we don't use a signal stack yet */
604 /* find the first power of two not smaller than min_size */
605 while ((1u << sigstack_zero_bits
) < min_size
) sigstack_zero_bits
++;
606 assert( sizeof(TEB
) <= min_size
);
609 size
= 1 << sigstack_zero_bits
;
611 if (!(status
= NtAllocateVirtualMemory( NtCurrentProcess(), (void **)teb
, sigstack_zero_bits
,
612 &size
, MEM_COMMIT
| MEM_TOP_DOWN
, PAGE_READWRITE
)))
614 (*teb
)->Tib
.Self
= &(*teb
)->Tib
;
615 (*teb
)->Tib
.ExceptionList
= (void *)~0UL;
621 /**********************************************************************
624 void signal_free_thread( TEB
*teb
)
628 if (teb
->DeallocationStack
)
631 NtFreeVirtualMemory( GetCurrentProcess(), &teb
->DeallocationStack
, &size
, MEM_RELEASE
);
634 NtFreeVirtualMemory( NtCurrentProcess(), (void **)&teb
, &size
, MEM_RELEASE
);
638 /**********************************************************************
641 void signal_init_thread( TEB
*teb
)
643 static int init_done
;
647 pthread_key_create( &teb_key
, NULL
);
650 pthread_setspecific( teb_key
, teb
);
654 /**********************************************************************
655 * signal_init_process
657 void signal_init_process(void)
659 struct sigaction sig_act
;
661 sig_act
.sa_mask
= server_block_set
;
662 sig_act
.sa_flags
= SA_RESTART
| SA_SIGINFO
;
664 sig_act
.sa_sigaction
= int_handler
;
665 if (sigaction( SIGINT
, &sig_act
, NULL
) == -1) goto error
;
666 sig_act
.sa_sigaction
= fpe_handler
;
667 if (sigaction( SIGFPE
, &sig_act
, NULL
) == -1) goto error
;
668 sig_act
.sa_sigaction
= abrt_handler
;
669 if (sigaction( SIGABRT
, &sig_act
, NULL
) == -1) goto error
;
670 sig_act
.sa_sigaction
= quit_handler
;
671 if (sigaction( SIGQUIT
, &sig_act
, NULL
) == -1) goto error
;
672 sig_act
.sa_sigaction
= usr1_handler
;
673 if (sigaction( SIGUSR1
, &sig_act
, NULL
) == -1) goto error
;
675 sig_act
.sa_sigaction
= segv_handler
;
676 if (sigaction( SIGSEGV
, &sig_act
, NULL
) == -1) goto error
;
677 if (sigaction( SIGILL
, &sig_act
, NULL
) == -1) goto error
;
679 if (sigaction( SIGBUS
, &sig_act
, NULL
) == -1) goto error
;
683 sig_act
.sa_sigaction
= trap_handler
;
684 if (sigaction( SIGTRAP
, &sig_act
, NULL
) == -1) goto error
;
694 /**********************************************************************
695 * __wine_enter_vm86 (NTDLL.@)
697 void __wine_enter_vm86( CONTEXT
*context
)
699 MESSAGE("vm86 mode not supported on this platform\n");
702 /***********************************************************************
703 * RtlUnwind (NTDLL.@)
705 void WINAPI
RtlUnwind( PVOID pEndFrame
, PVOID targetIp
, PEXCEPTION_RECORD pRecord
, PVOID retval
)
707 FIXME( "Not implemented on ARM\n" );
710 /*******************************************************************
711 * NtRaiseException (NTDLL.@)
713 NTSTATUS WINAPI
NtRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
715 NTSTATUS status
= raise_exception( rec
, context
, first_chance
);
716 if (status
== STATUS_SUCCESS
) NtSetContextThread( GetCurrentThread(), context
);
720 /***********************************************************************
721 * RtlRaiseException (NTDLL.@)
723 void WINAPI
RtlRaiseException( EXCEPTION_RECORD
*rec
)
728 RtlCaptureContext( &context
);
729 /*rec->ExceptionAddress = (void *)context.Iar;*/
730 status
= raise_exception( rec
, &context
, TRUE
);
731 if (status
) raise_status( status
, rec
);
734 /*************************************************************************
735 * RtlCaptureStackBackTrace (NTDLL.@)
737 USHORT WINAPI
RtlCaptureStackBackTrace( ULONG skip
, ULONG count
, PVOID
*buffer
, ULONG
*hash
)
739 FIXME( "(%d, %d, %p, %p) stub!\n", skip
, count
, buffer
, hash
);
743 /***********************************************************************
744 * call_thread_entry_point
746 void call_thread_entry_point( LPTHREAD_START_ROUTINE entry
, void *arg
)
750 exit_thread( entry( arg
));
752 __EXCEPT(unhandled_exception_filter
)
754 NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
757 abort(); /* should not be reached */
760 /***********************************************************************
761 * RtlExitUserThread (NTDLL.@)
763 void WINAPI
RtlExitUserThread( ULONG status
)
765 exit_thread( status
);
768 /***********************************************************************
771 void abort_thread( int status
)
773 terminate_thread( status
);
776 /**********************************************************************
777 * DbgBreakPoint (NTDLL.@)
779 void WINAPI
DbgBreakPoint(void)
781 kill(getpid(), SIGTRAP
);
784 /**********************************************************************
785 * DbgUserBreakPoint (NTDLL.@)
787 void WINAPI
DbgUserBreakPoint(void)
789 kill(getpid(), SIGTRAP
);
792 /**********************************************************************
793 * NtCurrentTeb (NTDLL.@)
795 TEB
* WINAPI
NtCurrentTeb(void)
797 return pthread_getspecific( teb_key
);