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
36 #include <sys/types.h>
38 #ifdef HAVE_SYS_PARAM_H
39 # include <sys/param.h>
44 # ifdef HAVE_SYS_SYSCALL_H
45 # include <sys/syscall.h>
48 #ifdef HAVE_SYS_SIGNAL_H
49 # include <sys/signal.h>
51 #ifdef HAVE_SYS_UCONTEXT_H
52 # include <sys/ucontext.h>
55 # define UNW_LOCAL_ONLY
56 # include <libunwind.h>
63 #define WIN32_NO_STATUS
68 #include "unix_private.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
74 /***********************************************************************
75 * signal context platform-specific definitions
79 #if defined(__ANDROID__) && !defined(HAVE_SYS_UCONTEXT_H)
80 typedef struct ucontext
82 unsigned long uc_flags
;
83 struct ucontext
*uc_link
;
85 struct sigcontext uc_mcontext
;
87 unsigned long uc_regspace
[128] __attribute__((__aligned__(8)));
91 /* All Registers access - only for local access */
92 # define REG_sig(reg_name, context) ((context)->uc_mcontext.reg_name)
93 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.arm_r##reg_num)
95 /* Special Registers access */
96 # define SP_sig(context) REG_sig(arm_sp, context) /* Stack pointer */
97 # define LR_sig(context) REG_sig(arm_lr, context) /* Link register */
98 # define PC_sig(context) REG_sig(arm_pc, context) /* Program counter */
99 # define CPSR_sig(context) REG_sig(arm_cpsr, context) /* Current State Register */
100 # define IP_sig(context) REG_sig(arm_ip, context) /* Intra-Procedure-call scratch register */
101 # define FP_sig(context) REG_sig(arm_fp, context) /* Frame pointer */
104 # define ERROR_sig(context) REG_sig(error_code, context)
105 # define TRAP_sig(context) REG_sig(trap_no, context)
115 struct extended_ctx ctx
;
116 unsigned long long fpregs
[32];
120 static void *get_extended_sigcontext( const ucontext_t
*sigcontext
, unsigned int magic
)
122 struct extended_ctx
*ctx
= (struct extended_ctx
*)sigcontext
->uc_regspace
;
123 while ((char *)ctx
< (char *)(sigcontext
+ 1) && ctx
->magic
&& ctx
->size
)
125 if (ctx
->magic
== magic
) return ctx
;
126 ctx
= (struct extended_ctx
*)((char *)ctx
+ ctx
->size
);
131 static void save_fpu( CONTEXT
*context
, const ucontext_t
*sigcontext
)
133 struct vfp_sigframe
*frame
= get_extended_sigcontext( sigcontext
, 0x56465001 );
136 memcpy( context
->D
, frame
->fpregs
, sizeof(context
->D
) );
137 context
->Fpscr
= frame
->fpscr
;
140 static void restore_fpu( const CONTEXT
*context
, ucontext_t
*sigcontext
)
142 struct vfp_sigframe
*frame
= get_extended_sigcontext( sigcontext
, 0x56465001 );
145 memcpy( frame
->fpregs
, context
->D
, sizeof(context
->D
) );
146 frame
->fpscr
= context
->Fpscr
;
149 #elif defined(__FreeBSD__)
151 /* All Registers access - only for local access */
152 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.__gregs[reg_num])
154 /* Special Registers access */
155 # define SP_sig(context) REGn_sig(_REG_SP, context) /* Stack pointer */
156 # define LR_sig(context) REGn_sig(_REG_LR, context) /* Link register */
157 # define PC_sig(context) REGn_sig(_REG_PC, context) /* Program counter */
158 # define CPSR_sig(context) REGn_sig(_REG_CPSR, context) /* Current State Register */
159 # define IP_sig(context) REGn_sig(_REG_R12, context) /* Intra-Procedure-call scratch register */
160 # define FP_sig(context) REGn_sig(_REG_FP, context) /* Frame pointer */
162 static void save_fpu( CONTEXT
*context
, const ucontext_t
*sigcontext
) { }
163 static void restore_fpu( const CONTEXT
*context
, ucontext_t
*sigcontext
) { }
169 TRAP_ARM_UNKNOWN
= -1, /* Unknown fault (TRAP_sig not defined) */
170 TRAP_ARM_PRIVINFLT
= 6, /* Invalid opcode exception */
171 TRAP_ARM_PAGEFLT
= 14, /* Page fault */
172 TRAP_ARM_ALIGNFLT
= 17, /* Alignment check exception */
194 UINT restore_flags
; /* 044 */
195 UINT fpscr
; /* 048 */
196 struct syscall_frame
*prev_frame
; /* 04c */
197 SYSTEM_SERVICE_TABLE
*syscall_table
; /* 050 */
198 UINT align
[3]; /* 054 */
199 ULONGLONG d
[32]; /* 060 */
202 C_ASSERT( sizeof( struct syscall_frame
) == 0x160);
204 struct arm_thread_data
206 void *exit_frame
; /* 1d4 exit frame pointer */
207 struct syscall_frame
*syscall_frame
; /* 1d8 frame pointer on syscall entry */
210 C_ASSERT( sizeof(struct arm_thread_data
) <= sizeof(((struct ntdll_thread_data
*)0)->cpu_data
) );
211 C_ASSERT( offsetof( TEB
, GdiTebBatch
) + offsetof( struct arm_thread_data
, exit_frame
) == 0x1d4 );
212 C_ASSERT( offsetof( TEB
, GdiTebBatch
) + offsetof( struct arm_thread_data
, syscall_frame
) == 0x1d8 );
214 static inline struct arm_thread_data
*arm_thread_data(void)
216 return (struct arm_thread_data
*)ntdll_get_thread_data()->cpu_data
;
219 static BOOL
is_inside_syscall( ucontext_t
*sigcontext
)
221 return ((char *)SP_sig(sigcontext
) >= (char *)ntdll_get_thread_data()->kernel_stack
&&
222 (char *)SP_sig(sigcontext
) <= (char *)arm_thread_data()->syscall_frame
);
225 extern void raise_func_trampoline( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, void *dispatcher
);
233 static uint32_t prel31_to_abs(const uint32_t *ptr
)
235 uint32_t prel31
= *ptr
;
236 uint32_t rel
= prel31
| ((prel31
<< 1) & 0x80000000);
237 return (uintptr_t)ptr
+ rel
;
240 static uint8_t get_byte(const uint32_t *ptr
, int offset
, int bytes
)
242 int word
= offset
>> 2;
243 int byte
= offset
& 0x3;
245 return 0xb0; /* finish opcode */
246 return (ptr
[word
] >> (24 - 8*byte
)) & 0xff;
249 static uint32_t get_uleb128(const uint32_t *ptr
, int *offset
, int bytes
)
255 uint8_t byte
= get_byte(ptr
, (*offset
)++, bytes
);
256 val
|= (byte
& 0x7f) << shift
;
257 if ((byte
& 0x80) == 0)
264 static void pop_regs(CONTEXT
*context
, uint32_t regs
)
268 for (i
= 0; i
< 16; i
++)
270 if (regs
& (1U << i
))
272 DWORD val
= *(DWORD
*)context
->Sp
;
274 (&context
->R0
)[i
] = val
;
280 if (regs
& (1 << 13))
281 context
->Sp
= new_sp
;
284 static void pop_vfp(CONTEXT
*context
, int first
, int last
)
287 for (i
= first
; i
<= last
; i
++)
289 context
->D
[i
] = *(ULONGLONG
*)context
->Sp
;
294 static uint32_t regmask(int first_bit
, int n_bits
)
296 return ((1U << (n_bits
+ 1)) - 1) << first_bit
;
299 /***********************************************************************
300 * ehabi_virtual_unwind
302 static NTSTATUS
ehabi_virtual_unwind( UINT ip
, DWORD
*frame
, CONTEXT
*context
,
303 const struct exidx_entry
*entry
,
304 PEXCEPTION_ROUTINE
*handler
, void **handler_data
)
307 const void *lsda
= NULL
;
308 int compact_inline
= 0;
315 UINT func_begin
= prel31_to_abs(&entry
->addr
);
317 *frame
= context
->Sp
;
319 TRACE( "ip %#x function %#x\n", ip
, func_begin
);
321 if (entry
->data
== 1)
323 ERR("EXIDX_CANTUNWIND\n");
324 return STATUS_UNSUCCESSFUL
;
326 else if (entry
->data
& 0x80000000)
328 if ((entry
->data
& 0x7f000000) != 0)
330 ERR("compact inline EXIDX must have personality 0\n");
331 return STATUS_UNSUCCESSFUL
;
338 ptr
= (uint32_t *)prel31_to_abs(&entry
->data
);
341 if ((*ptr
& 0x80000000) == 0)
344 void *personality_func
= (void *)prel31_to_abs(ptr
);
345 int words
= (ptr
[1] >> 24) & 0xff;
346 lsda
= ptr
+ 1 + words
+ 1;
348 ERR("generic EHABI unwinding not supported\n");
349 (void)personality_func
;
350 return STATUS_UNSUCCESSFUL
;
355 personality
= (*ptr
>> 24) & 0x0f;
365 extra_words
= (*ptr
>> 16) & 0xff;
366 lsda
= ptr
+ extra_words
+ 1;
370 extra_words
= (*ptr
>> 16) & 0xff;
371 lsda
= ptr
+ extra_words
+ 1;
375 ERR("unsupported compact EXIDX personality %d\n", personality
);
376 return STATUS_UNSUCCESSFUL
;
379 /* Not inspecting the descriptors */
382 bytes
= 4 + 4*extra_words
;
383 while (offset
< bytes
&& !finish
)
385 uint8_t byte
= get_byte(ptr
, offset
++, bytes
);
386 if ((byte
& 0xc0) == 0x00)
389 context
->Sp
+= (byte
& 0x3f) * 4 + 4;
391 else if ((byte
& 0xc0) == 0x40)
394 context
->Sp
-= (byte
& 0x3f) * 4 + 4;
396 else if ((byte
& 0xf0) == 0x80)
398 /* Pop {r4-r15} based on register mask */
399 int regs
= ((byte
& 0x0f) << 8) | get_byte(ptr
, offset
++, bytes
);
402 ERR("refuse to unwind\n");
403 return STATUS_UNSUCCESSFUL
;
406 pop_regs(context
, regs
);
407 if (regs
& (1 << 15))
410 else if ((byte
& 0xf0) == 0x90)
412 /* Restore Sp from other register */
413 int reg
= byte
& 0x0f;
414 if (reg
== 13 || reg
== 15)
416 ERR("reserved opcode\n");
417 return STATUS_UNSUCCESSFUL
;
419 context
->Sp
= (&context
->R0
)[reg
];
421 else if ((byte
& 0xf0) == 0xa0)
423 /* Pop r4-r(4+n) (+lr) */
425 int regs
= regmask(4, n
);
428 pop_regs(context
, regs
);
430 else if (byte
== 0xb0)
434 else if (byte
== 0xb1)
436 /* Pop {r0-r3} based on register mask */
437 int regs
= get_byte(ptr
, offset
++, bytes
);
438 if (regs
== 0 || (regs
& 0xf0) != 0)
440 ERR("spare opcode\n");
441 return STATUS_UNSUCCESSFUL
;
443 pop_regs(context
, regs
);
445 else if (byte
== 0xb2)
447 /* Increment Sp by a larger amount */
448 int imm
= get_uleb128(ptr
, &offset
, bytes
);
449 context
->Sp
+= 0x204 + imm
* 4;
451 else if (byte
== 0xb3)
453 /* Pop VFP registers as if saved by FSTMFDX; this opcode
455 ERR("FSTMFDX unsupported\n");
456 return STATUS_UNSUCCESSFUL
;
458 else if ((byte
& 0xfc) == 0xb4)
460 ERR("spare opcode\n");
461 return STATUS_UNSUCCESSFUL
;
463 else if ((byte
& 0xf8) == 0xb8)
465 /* Pop VFP registers as if saved by FSTMFDX; this opcode
467 ERR("FSTMFDX unsupported\n");
468 return STATUS_UNSUCCESSFUL
;
470 else if ((byte
& 0xf8) == 0xc0)
472 ERR("spare opcode / iWMMX\n");
473 return STATUS_UNSUCCESSFUL
;
475 else if ((byte
& 0xfe) == 0xc8)
477 /* Pop VFP registers d(16+ssss)-d(16+ssss+cccc), or
478 * d(0+ssss)-d(0+ssss+cccc) as if saved by VPUSH */
480 if ((byte
& 0x01) == 0)
484 byte
= get_byte(ptr
, offset
++, bytes
);
485 first
+= (byte
& 0xf0) >> 4;
486 last
= first
+ (byte
& 0x0f);
489 ERR("reserved opcode\n");
490 return STATUS_UNSUCCESSFUL
;
492 pop_vfp(context
, first
, last
);
494 else if ((byte
& 0xf8) == 0xc8)
496 ERR("spare opcode\n");
497 return STATUS_UNSUCCESSFUL
;
499 else if ((byte
& 0xf8) == 0xd0)
501 /* Pop VFP registers d8-d(8+n) as if saved by VPUSH */
503 pop_vfp(context
, 8, 8 + n
);
507 ERR("spare opcode\n");
508 return STATUS_UNSUCCESSFUL
;
513 ERR("truncated opcodes\n");
514 return STATUS_UNSUCCESSFUL
;
517 *handler
= NULL
; /* personality */
518 *handler_data
= NULL
; /* lsda */
520 context
->ContextFlags
|= CONTEXT_UNWOUND_TO_CALL
;
522 context
->Pc
= context
->Lr
;
524 /* There's no need to check for raise_func_trampoline and manually restore
525 * Lr separately from Pc like with libunwind; the EHABI unwind info
526 * describes how both of them are restored separately, and as long as
527 * the unwind info restored Pc, it doesn't have to be set from Lr. */
529 TRACE( "next function pc=%08lx\n", context
->Pc
);
530 TRACE(" r0=%08lx r1=%08lx r2=%08lx r3=%08lx\n",
531 context
->R0
, context
->R1
, context
->R2
, context
->R3
);
532 TRACE(" r4=%08lx r5=%08lx r6=%08lx r7=%08lx\n",
533 context
->R4
, context
->R5
, context
->R6
, context
->R7
);
534 TRACE(" r8=%08lx r9=%08lx r10=%08lx r11=%08lx\n",
535 context
->R8
, context
->R9
, context
->R10
, context
->R11
);
536 TRACE(" r12=%08lx sp=%08lx lr=%08lx pc=%08lx\n",
537 context
->R12
, context
->Sp
, context
->Lr
, context
->Pc
);
539 return STATUS_SUCCESS
;
547 struct exidx_entry
*entry
;
550 static int contains_addr(struct dl_phdr_info
*info
, const ElfW(Phdr
) *phdr
, struct iterate_data
*data
)
552 if (phdr
->p_type
!= PT_LOAD
)
554 return data
->ip
>= info
->dlpi_addr
+ phdr
->p_vaddr
&& data
->ip
< info
->dlpi_addr
+ phdr
->p_vaddr
+ phdr
->p_memsz
;
557 static int check_exidx(struct dl_phdr_info
*info
, size_t info_size
, void *arg
)
559 struct iterate_data
*data
= arg
;
562 const ElfW(Phdr
) *exidx
= NULL
;
563 struct exidx_entry
*begin
, *end
;
565 if (info
->dlpi_phnum
== 0 || data
->ip
< info
->dlpi_addr
|| data
->failed
)
569 for (i
= 0; i
< info
->dlpi_phnum
; i
++)
571 const ElfW(Phdr
) *phdr
= &info
->dlpi_phdr
[i
];
572 if (contains_addr(info
, phdr
, data
))
574 if (phdr
->p_type
== PT_ARM_EXIDX
)
578 if (!found_addr
|| !exidx
)
582 TRACE("found matching address in %s, but no EXIDX\n", info
->dlpi_name
);
588 begin
= (struct exidx_entry
*)(info
->dlpi_addr
+ exidx
->p_vaddr
);
589 end
= (struct exidx_entry
*)(info
->dlpi_addr
+ exidx
->p_vaddr
+ exidx
->p_memsz
);
590 if (data
->ip
< prel31_to_abs(&begin
->addr
))
592 TRACE("%lx before EXIDX start at %x\n", data
->ip
, prel31_to_abs(&begin
->addr
));
597 while (begin
+ 1 < end
)
599 struct exidx_entry
*mid
= begin
+ (end
- begin
)/2;
600 uint32_t abs_addr
= prel31_to_abs(&mid
->addr
);
601 if (abs_addr
> data
->ip
)
605 else if (abs_addr
< data
->ip
)
617 TRACE("found %lx in %s, base %x, entry %p with addr %x (rel %x) data %x\n",
618 data
->ip
, info
->dlpi_name
, info
->dlpi_addr
, begin
,
619 prel31_to_abs(&begin
->addr
),
620 prel31_to_abs(&begin
->addr
) - info
->dlpi_addr
, begin
->data
);
624 static const struct exidx_entry
*find_exidx_entry( void *ip
)
626 struct iterate_data data
= {};
628 data
.ip
= (ULONG_PTR
)ip
;
631 dl_iterate_phdr(check_exidx
, &data
);
637 #ifdef HAVE_LIBUNWIND
638 static NTSTATUS
libunwind_virtual_unwind( DWORD ip
, DWORD
*frame
, CONTEXT
*context
,
639 PEXCEPTION_ROUTINE
*handler
, void **handler_data
)
641 unw_context_t unw_context
;
643 unw_proc_info_t info
;
646 for (i
= 0; i
<= 12; i
++)
647 unw_context
.regs
[i
] = (&context
->R0
)[i
];
648 unw_context
.regs
[13] = context
->Sp
;
649 unw_context
.regs
[14] = context
->Lr
;
650 unw_context
.regs
[15] = context
->Pc
;
651 rc
= unw_init_local( &cursor
, &unw_context
);
653 if (rc
!= UNW_ESUCCESS
)
655 WARN( "setup failed: %d\n", rc
);
656 return STATUS_INVALID_DISPOSITION
;
658 rc
= unw_get_proc_info( &cursor
, &info
);
659 if (UNW_ENOINFO
< 0) rc
= -rc
; /* LLVM libunwind has negative error codes */
660 if (rc
!= UNW_ESUCCESS
&& rc
!= -UNW_ENOINFO
)
662 WARN( "failed to get info: %d\n", rc
);
663 return STATUS_INVALID_DISPOSITION
;
665 if (rc
== -UNW_ENOINFO
|| ip
< info
.start_ip
|| ip
> info
.end_ip
)
667 NTSTATUS status
= context
->Pc
!= context
->Lr
?
668 STATUS_SUCCESS
: STATUS_INVALID_DISPOSITION
;
669 TRACE( "no info found for %x ip %x-%x, %s\n",
670 ip
, info
.start_ip
, info
.end_ip
, status
== STATUS_SUCCESS
?
671 "assuming leaf function" : "error, stuck" );
673 *frame
= context
->Sp
;
674 context
->Pc
= context
->Lr
;
675 context
->ContextFlags
|= CONTEXT_UNWOUND_TO_CALL
;
679 TRACE( "ip %#x function %#lx-%#lx personality %#lx lsda %#lx fde %#lx\n",
680 ip
, (unsigned long)info
.start_ip
, (unsigned long)info
.end_ip
, (unsigned long)info
.handler
,
681 (unsigned long)info
.lsda
, (unsigned long)info
.unwind_info
);
683 rc
= unw_step( &cursor
);
686 WARN( "failed to unwind: %d %d\n", rc
, UNW_ENOINFO
);
687 return STATUS_INVALID_DISPOSITION
;
690 *handler
= (void *)info
.handler
;
691 *handler_data
= (void *)info
.lsda
;
692 *frame
= context
->Sp
;
694 for (i
= 0; i
<= 12; i
++)
695 unw_get_reg( &cursor
, UNW_ARM_R0
+ i
, (unw_word_t
*)&(&context
->R0
)[i
] );
696 unw_get_reg( &cursor
, UNW_ARM_R13
, (unw_word_t
*)&context
->Sp
);
697 unw_get_reg( &cursor
, UNW_ARM_R14
, (unw_word_t
*)&context
->Lr
);
698 unw_get_reg( &cursor
, UNW_REG_IP
, (unw_word_t
*)&context
->Pc
);
699 context
->ContextFlags
|= CONTEXT_UNWOUND_TO_CALL
;
701 if ((info
.start_ip
& ~(unw_word_t
)1) ==
702 ((unw_word_t
)raise_func_trampoline
& ~(unw_word_t
)1)) {
703 /* raise_func_trampoline stores the original Lr at the bottom of the
704 * stack. The unwinder normally can't restore both Pc and Lr to
705 * individual values, thus do that manually here.
706 * (The function we unwind to might be a leaf function that hasn't
707 * backed up its own original Lr value on the stack.) */
708 const DWORD
*orig_lr
= (const DWORD
*) *frame
;
709 context
->Lr
= *orig_lr
;
712 TRACE( "next function pc=%08lx%s\n", context
->Pc
, rc
? "" : " (last frame)" );
713 TRACE(" r0=%08lx r1=%08lx r2=%08lx r3=%08lx\n",
714 context
->R0
, context
->R1
, context
->R2
, context
->R3
);
715 TRACE(" r4=%08lx r5=%08lx r6=%08lx r7=%08lx\n",
716 context
->R4
, context
->R5
, context
->R6
, context
->R7
);
717 TRACE(" r8=%08lx r9=%08lx r10=%08lx r11=%08lx\n",
718 context
->R8
, context
->R9
, context
->R10
, context
->R11
);
719 TRACE(" r12=%08lx sp=%08lx lr=%08lx pc=%08lx\n",
720 context
->R12
, context
->Sp
, context
->Lr
, context
->Pc
);
721 return STATUS_SUCCESS
;
725 /***********************************************************************
728 NTSTATUS
unwind_builtin_dll( void *args
)
730 struct unwind_builtin_dll_params
*params
= args
;
731 DISPATCHER_CONTEXT
*dispatch
= params
->dispatch
;
732 CONTEXT
*context
= params
->context
;
733 DWORD ip
= context
->Pc
- (dispatch
->ControlPcIsUnwound
? 2 : 0);
735 const struct exidx_entry
*entry
= find_exidx_entry( (void *)ip
);
738 return ehabi_virtual_unwind( ip
, &dispatch
->EstablisherFrame
, context
, entry
,
739 &dispatch
->LanguageHandler
, &dispatch
->HandlerData
);
741 #ifdef HAVE_LIBUNWIND
742 return libunwind_virtual_unwind( ip
, &dispatch
->EstablisherFrame
, context
,
743 &dispatch
->LanguageHandler
, &dispatch
->HandlerData
);
745 ERR("libunwind not available, unable to unwind\n");
746 return STATUS_INVALID_DISPOSITION
;
751 /***********************************************************************
754 * Get the trap code for a signal.
756 static inline enum arm_trap_code
get_trap_code( int signal
, const ucontext_t
*sigcontext
)
759 enum arm_trap_code trap
= TRAP_sig(sigcontext
);
767 return TRAP_ARM_PRIVINFLT
;
769 return TRAP_ARM_PAGEFLT
;
771 return TRAP_ARM_ALIGNFLT
;
773 return TRAP_ARM_UNKNOWN
;
778 /***********************************************************************
781 * Get the error code for a signal.
783 static inline WORD
get_error_code( const ucontext_t
*sigcontext
)
786 return ERROR_sig(sigcontext
);
793 /***********************************************************************
796 * Get the immediate operand if the PC is at a UDF instruction.
798 static inline int get_udf_immediate( const ucontext_t
*sigcontext
)
800 if (CPSR_sig(sigcontext
) & 0x20)
802 WORD thumb_insn
= *(WORD
*)PC_sig(sigcontext
);
803 if ((thumb_insn
>> 8) == 0xde) return thumb_insn
& 0xff;
804 if ((thumb_insn
& 0xfff0) == 0xf7f0) /* udf.w */
806 WORD ext
= *(WORD
*)(PC_sig(sigcontext
) + 2);
807 if ((ext
& 0xf000) == 0xa000) return ((thumb_insn
& 0xf) << 12) | (ext
& 0x0fff);
812 DWORD arm_insn
= *(DWORD
*)PC_sig(sigcontext
);
813 if ((arm_insn
& 0xfff000f0) == 0xe7f000f0)
815 return ((arm_insn
>> 4) & 0xfff0) | (arm_insn
& 0xf);
822 /***********************************************************************
825 * Set the register values from a sigcontext.
827 static void save_context( CONTEXT
*context
, const ucontext_t
*sigcontext
)
829 #define C(x) context->R##x = REGn_sig(x,sigcontext)
830 /* Save normal registers */
831 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
834 context
->ContextFlags
= CONTEXT_FULL
;
835 context
->Sp
= SP_sig(sigcontext
); /* Stack pointer */
836 context
->Lr
= LR_sig(sigcontext
); /* Link register */
837 context
->Pc
= PC_sig(sigcontext
); /* Program Counter */
838 context
->Cpsr
= CPSR_sig(sigcontext
); /* Current State Register */
839 context
->R11
= FP_sig(sigcontext
); /* Frame pointer */
840 context
->R12
= IP_sig(sigcontext
); /* Intra-Procedure-call scratch register */
841 if (CPSR_sig(sigcontext
) & 0x20) context
->Pc
|= 1; /* Thumb mode */
842 save_fpu( context
, sigcontext
);
846 /***********************************************************************
849 * Build a sigcontext from the register values.
851 static void restore_context( const CONTEXT
*context
, ucontext_t
*sigcontext
)
853 #define C(x) REGn_sig(x,sigcontext) = context->R##x
854 /* Restore normal registers */
855 C(0); C(1); C(2); C(3); C(4); C(5); C(6); C(7); C(8); C(9); C(10);
858 SP_sig(sigcontext
) = context
->Sp
; /* Stack pointer */
859 LR_sig(sigcontext
) = context
->Lr
; /* Link register */
860 PC_sig(sigcontext
) = context
->Pc
; /* Program Counter */
861 CPSR_sig(sigcontext
) = context
->Cpsr
; /* Current State Register */
862 FP_sig(sigcontext
) = context
->R11
; /* Frame pointer */
863 IP_sig(sigcontext
) = context
->R12
; /* Intra-Procedure-call scratch register */
864 if (PC_sig(sigcontext
) & 1) CPSR_sig(sigcontext
) |= 0x20;
865 else CPSR_sig(sigcontext
) &= ~0x20;
866 restore_fpu( context
, sigcontext
);
870 /***********************************************************************
871 * signal_set_full_context
873 NTSTATUS
signal_set_full_context( CONTEXT
*context
)
875 NTSTATUS status
= NtSetContextThread( GetCurrentThread(), context
);
877 if (!status
&& (context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
878 arm_thread_data()->syscall_frame
->restore_flags
|= CONTEXT_INTEGER
;
883 /***********************************************************************
886 void *get_native_context( CONTEXT
*context
)
892 /***********************************************************************
895 void *get_wow_context( CONTEXT
*context
)
901 /***********************************************************************
902 * NtSetContextThread (NTDLL.@)
903 * ZwSetContextThread (NTDLL.@)
905 NTSTATUS WINAPI
NtSetContextThread( HANDLE handle
, const CONTEXT
*context
)
908 struct syscall_frame
*frame
= arm_thread_data()->syscall_frame
;
909 DWORD flags
= context
->ContextFlags
& ~CONTEXT_ARM
;
910 BOOL self
= (handle
== GetCurrentThread());
914 ret
= set_thread_context( handle
, context
, &self
, IMAGE_FILE_MACHINE_ARMNT
);
915 if (ret
|| !self
) return ret
;
917 if (flags
& CONTEXT_INTEGER
)
919 frame
->r0
= context
->R0
;
920 frame
->r1
= context
->R1
;
921 frame
->r2
= context
->R2
;
922 frame
->r3
= context
->R3
;
923 frame
->r4
= context
->R4
;
924 frame
->r5
= context
->R5
;
925 frame
->r6
= context
->R6
;
926 frame
->r7
= context
->R7
;
927 frame
->r8
= context
->R8
;
928 frame
->r9
= context
->R9
;
929 frame
->r10
= context
->R10
;
930 frame
->r11
= context
->R11
;
931 frame
->r12
= context
->R12
;
933 if (flags
& CONTEXT_CONTROL
)
935 frame
->sp
= context
->Sp
;
936 frame
->lr
= context
->Lr
;
937 frame
->pc
= context
->Pc
& ~1;
938 frame
->cpsr
= context
->Cpsr
;
939 if (context
->Cpsr
& 0x20) frame
->pc
|= 1; /* thumb */
941 if (flags
& CONTEXT_FLOATING_POINT
)
943 frame
->fpscr
= context
->Fpscr
;
944 memcpy( frame
->d
, context
->D
, sizeof(context
->D
) );
946 frame
->restore_flags
|= flags
& ~CONTEXT_INTEGER
;
947 return STATUS_SUCCESS
;
951 /***********************************************************************
952 * NtGetContextThread (NTDLL.@)
953 * ZwGetContextThread (NTDLL.@)
955 NTSTATUS WINAPI
NtGetContextThread( HANDLE handle
, CONTEXT
*context
)
957 struct syscall_frame
*frame
= arm_thread_data()->syscall_frame
;
958 DWORD needed_flags
= context
->ContextFlags
& ~CONTEXT_ARM
;
959 BOOL self
= (handle
== GetCurrentThread());
963 NTSTATUS ret
= get_thread_context( handle
, &context
, &self
, IMAGE_FILE_MACHINE_ARMNT
);
964 if (ret
|| !self
) return ret
;
967 if (needed_flags
& CONTEXT_INTEGER
)
969 context
->R0
= frame
->r0
;
970 context
->R1
= frame
->r1
;
971 context
->R2
= frame
->r2
;
972 context
->R3
= frame
->r3
;
973 context
->R4
= frame
->r4
;
974 context
->R5
= frame
->r5
;
975 context
->R6
= frame
->r6
;
976 context
->R7
= frame
->r7
;
977 context
->R8
= frame
->r8
;
978 context
->R9
= frame
->r9
;
979 context
->R10
= frame
->r10
;
980 context
->R11
= frame
->r11
;
981 context
->R12
= frame
->r12
;
982 context
->ContextFlags
|= CONTEXT_INTEGER
;
984 if (needed_flags
& CONTEXT_CONTROL
)
986 context
->Sp
= frame
->sp
;
987 context
->Lr
= frame
->lr
;
988 context
->Pc
= frame
->pc
;
989 context
->Cpsr
= frame
->cpsr
;
990 context
->ContextFlags
|= CONTEXT_CONTROL
;
992 if (needed_flags
& CONTEXT_FLOATING_POINT
)
994 context
->Fpscr
= frame
->fpscr
;
995 memcpy( context
->D
, frame
->d
, sizeof(frame
->d
) );
996 context
->ContextFlags
|= CONTEXT_FLOATING_POINT
;
998 return STATUS_SUCCESS
;
1002 /***********************************************************************
1003 * set_thread_wow64_context
1005 NTSTATUS
set_thread_wow64_context( HANDLE handle
, const void *ctx
, ULONG size
)
1007 return STATUS_INVALID_INFO_CLASS
;
1011 /***********************************************************************
1012 * get_thread_wow64_context
1014 NTSTATUS
get_thread_wow64_context( HANDLE handle
, void *ctx
, ULONG size
)
1016 return STATUS_INVALID_INFO_CLASS
;
1020 __ASM_GLOBAL_FUNC( raise_func_trampoline
,
1021 "push {r12,lr}\n\t" /* (Padding +) Pc in the original frame */
1022 "ldr r3, [r1, #0x38]\n\t" /* context->Sp */
1023 "push {r3}\n\t" /* Original Sp */
1024 __ASM_CFI(".cfi_escape 0x0f,0x03,0x7D,0x04,0x06\n\t") /* CFA, DW_OP_breg13 + 0x04, DW_OP_deref */
1025 __ASM_CFI(".cfi_escape 0x10,0x0e,0x02,0x7D,0x0c\n\t") /* LR, DW_OP_breg13 + 0x0c */
1026 __ASM_EHABI(".save {sp}\n\t")
1027 __ASM_EHABI(".pad #-12\n\t")
1028 __ASM_EHABI(".save {pc}\n\t")
1029 __ASM_EHABI(".pad #8\n\t")
1030 __ASM_EHABI(".save {lr}\n\t")
1031 /* We can't express restoring both Pc and Lr with CFI
1032 * directives, but we manually load Lr from the stack
1033 * in unwind_builtin_dll above. */
1034 "ldr r3, [r1, #0x3c]\n\t" /* context->Lr */
1035 "push {r3}\n\t" /* Original Lr */
1039 /***********************************************************************
1042 * Modify the signal context to call the exception raise function.
1044 static void setup_exception( ucontext_t
*sigcontext
, EXCEPTION_RECORD
*rec
)
1049 EXCEPTION_RECORD rec
;
1052 void *stack_ptr
= (void *)(SP_sig(sigcontext
) & ~3);
1056 rec
->ExceptionAddress
= (void *)PC_sig(sigcontext
);
1057 save_context( &context
, sigcontext
);
1059 status
= send_debug_event( rec
, &context
, TRUE
);
1060 if (status
== DBG_CONTINUE
|| status
== DBG_EXCEPTION_HANDLED
)
1062 restore_context( &context
, sigcontext
);
1066 stack
= virtual_setup_exception( stack_ptr
, sizeof(*stack
), rec
);
1068 stack
->context
= context
;
1070 /* now modify the sigcontext to return to the raise function */
1071 SP_sig(sigcontext
) = (DWORD
)stack
;
1072 LR_sig(sigcontext
) = context
.Pc
;
1073 PC_sig(sigcontext
) = (DWORD
)raise_func_trampoline
;
1074 if (PC_sig(sigcontext
) & 1) CPSR_sig(sigcontext
) |= 0x20;
1075 else CPSR_sig(sigcontext
) &= ~0x20;
1076 REGn_sig(0, sigcontext
) = (DWORD
)&stack
->rec
; /* first arg for KiUserExceptionDispatcher */
1077 REGn_sig(1, sigcontext
) = (DWORD
)&stack
->context
; /* second arg for KiUserExceptionDispatcher */
1078 REGn_sig(2, sigcontext
) = (DWORD
)pKiUserExceptionDispatcher
;
1082 /***********************************************************************
1083 * call_user_apc_dispatcher
1085 NTSTATUS
call_user_apc_dispatcher( CONTEXT
*context
, ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG_PTR arg3
,
1086 PNTAPCFUNC func
, NTSTATUS status
)
1088 struct syscall_frame
*frame
= arm_thread_data()->syscall_frame
;
1089 ULONG sp
= context
? context
->Sp
: frame
->sp
;
1090 struct apc_stack_layout
1098 stack
= (struct apc_stack_layout
*)sp
- 1;
1101 memmove( &stack
->context
, context
, sizeof(stack
->context
) );
1102 NtSetContextThread( GetCurrentThread(), &stack
->context
);
1106 stack
->context
.ContextFlags
= CONTEXT_FULL
;
1107 NtGetContextThread( GetCurrentThread(), &stack
->context
);
1108 stack
->context
.R0
= status
;
1110 frame
->sp
= (DWORD
)stack
;
1111 frame
->pc
= (DWORD
)pKiUserApcDispatcher
;
1112 frame
->r0
= (DWORD
)&stack
->context
;
1117 frame
->restore_flags
|= CONTEXT_CONTROL
| CONTEXT_INTEGER
;
1122 /***********************************************************************
1123 * call_raise_user_exception_dispatcher
1125 void call_raise_user_exception_dispatcher(void)
1127 arm_thread_data()->syscall_frame
->pc
= (DWORD
)pKiRaiseUserExceptionDispatcher
;
1131 /***********************************************************************
1132 * call_user_exception_dispatcher
1134 NTSTATUS
call_user_exception_dispatcher( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
1136 struct syscall_frame
*frame
= arm_thread_data()->syscall_frame
;
1137 DWORD lr
= frame
->lr
;
1138 DWORD sp
= frame
->sp
;
1139 NTSTATUS status
= NtSetContextThread( GetCurrentThread(), context
);
1141 if (status
) return status
;
1142 frame
->r0
= (DWORD
)rec
;
1143 frame
->r1
= (DWORD
)context
;
1144 frame
->pc
= (DWORD
)pKiUserExceptionDispatcher
;
1147 frame
->restore_flags
|= CONTEXT_INTEGER
| CONTEXT_CONTROL
;
1152 /***********************************************************************
1153 * call_user_mode_callback
1155 extern NTSTATUS CDECL
call_user_mode_callback( void *func
, void *stack
, void **ret_ptr
,
1156 ULONG
*ret_len
, TEB
*teb
) DECLSPEC_HIDDEN
;
1157 __ASM_GLOBAL_FUNC( call_user_mode_callback
,
1158 "push {r2-r12,lr}\n\t"
1159 "ldr r4, [sp, #0x30]\n\t" /* teb */
1160 "ldr r5, [r4]\n\t" /* teb->Tib.ExceptionList */
1161 "str r5, [sp, #0x28]\n\t"
1163 "sub sp, sp, #0x90\n\t"
1165 "vmrs r6, fpscr\n\t"
1166 "vstm r5, {d8-d15}\n\t"
1167 "str r6, [r5, #0x80]\n\t"
1169 "sub sp, sp, #0x160\n\t" /* sizeof(struct syscall_frame) + registers */
1170 "ldr r5, [r4, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
1171 "str r5, [sp, #0x4c]\n\t" /* frame->prev_frame */
1172 "str sp, [r4, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
1173 "ldr r6, [r5, #0x50]\n\t" /* prev_frame->syscall_table */
1174 "str r6, [sp, #0x50]\n\t" /* frame->syscall_table */
1181 /***********************************************************************
1182 * user_mode_callback_return
1184 extern void CDECL DECLSPEC_NORETURN
user_mode_callback_return( void *ret_ptr
, ULONG ret_len
,
1185 NTSTATUS status
, TEB
*teb
) DECLSPEC_HIDDEN
;
1186 __ASM_GLOBAL_FUNC( user_mode_callback_return
,
1187 "ldr r4, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
1188 "ldr r5, [r4, #0x4c]\n\t" /* frame->prev_frame */
1189 "str r5, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
1190 "add r5, r4, #0x160\n\t"
1192 "vldm r5, {d8-d15}\n\t"
1193 "ldr r6, [r5, #0x80]\n\t"
1194 "vmsr fpscr, r6\n\t"
1195 "add r5, r5, #0x90\n\t"
1198 "ldr r5, [sp, #0x28]\n\t"
1199 "str r5, [r3]\n\t" /* teb->Tib.ExceptionList */
1200 "pop {r5, r6}\n\t" /* ret_ptr, ret_len */
1201 "str r0, [r5]\n\t" /* ret_ptr */
1202 "str r1, [r6]\n\t" /* ret_len */
1203 "mov r0, r2\n\t" /* status */
1207 /***********************************************************************
1208 * KeUserModeCallback
1210 NTSTATUS WINAPI
KeUserModeCallback( ULONG id
, const void *args
, ULONG len
, void **ret_ptr
, ULONG
*ret_len
)
1212 struct syscall_frame
*frame
= arm_thread_data()->syscall_frame
;
1213 void *args_data
= (void *)((frame
->sp
- len
) & ~15);
1214 ULONG_PTR
*stack
= args_data
;
1216 /* if we have no syscall frame, call the callback directly */
1217 if ((char *)&frame
< (char *)ntdll_get_thread_data()->kernel_stack
||
1218 (char *)&frame
> (char *)arm_thread_data()->syscall_frame
)
1220 NTSTATUS (WINAPI
*func
)(const void *, ULONG
) = ((void **)NtCurrentTeb()->Peb
->KernelCallbackTable
)[id
];
1221 return func( args
, len
);
1224 if ((char *)ntdll_get_thread_data()->kernel_stack
+ min_kernel_stack
> (char *)&frame
)
1225 return STATUS_STACK_OVERFLOW
;
1227 memcpy( args_data
, args
, len
);
1230 *(--stack
) = (ULONG_PTR
)args_data
;
1233 return call_user_mode_callback( pKiUserCallbackDispatcher
, stack
, ret_ptr
, ret_len
, NtCurrentTeb() );
1237 /***********************************************************************
1238 * NtCallbackReturn (NTDLL.@)
1240 NTSTATUS WINAPI
NtCallbackReturn( void *ret_ptr
, ULONG ret_len
, NTSTATUS status
)
1242 if (!arm_thread_data()->syscall_frame
->prev_frame
) return STATUS_NO_CALLBACK_ACTIVE
;
1243 user_mode_callback_return( ret_ptr
, ret_len
, status
, NtCurrentTeb() );
1247 /***********************************************************************
1248 * handle_syscall_fault
1250 * Handle a page fault happening during a system call.
1252 static BOOL
handle_syscall_fault( ucontext_t
*context
, EXCEPTION_RECORD
*rec
)
1254 struct syscall_frame
*frame
= arm_thread_data()->syscall_frame
;
1257 if (!is_inside_syscall( context
) && !ntdll_get_thread_data()->jmp_buf) return FALSE
;
1259 TRACE( "code=%lx flags=%lx addr=%p pc=%08lx\n",
1260 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
, (DWORD
)PC_sig(context
) );
1261 for (i
= 0; i
< rec
->NumberParameters
; i
++)
1262 TRACE( " info[%d]=%08lx\n", i
, rec
->ExceptionInformation
[i
] );
1264 TRACE( " r0=%08lx r1=%08lx r2=%08lx r3=%08lx r4=%08lx r5=%08lx\n",
1265 (DWORD
)REGn_sig(0, context
), (DWORD
)REGn_sig(1, context
), (DWORD
)REGn_sig(2, context
),
1266 (DWORD
)REGn_sig(3, context
), (DWORD
)REGn_sig(4, context
), (DWORD
)REGn_sig(5, context
) );
1267 TRACE( " r6=%08lx r7=%08lx r8=%08lx r9=%08lx r10=%08lx r11=%08lx\n",
1268 (DWORD
)REGn_sig(6, context
), (DWORD
)REGn_sig(7, context
), (DWORD
)REGn_sig(8, context
),
1269 (DWORD
)REGn_sig(9, context
), (DWORD
)REGn_sig(10, context
), (DWORD
)FP_sig(context
) );
1270 TRACE( " r12=%08lx sp=%08lx lr=%08lx pc=%08lx cpsr=%08lx\n",
1271 (DWORD
)IP_sig(context
), (DWORD
)SP_sig(context
), (DWORD
)LR_sig(context
),
1272 (DWORD
)PC_sig(context
), (DWORD
)CPSR_sig(context
) );
1274 if (ntdll_get_thread_data()->jmp_buf)
1276 TRACE( "returning to handler\n" );
1277 REGn_sig(0, context
) = (DWORD
)ntdll_get_thread_data()->jmp_buf;
1278 REGn_sig(1, context
) = 1;
1279 PC_sig(context
) = (DWORD
)__wine_longjmp
;
1280 ntdll_get_thread_data()->jmp_buf = NULL
;
1284 TRACE( "returning to user mode ip=%08x ret=%08lx\n", frame
->pc
, rec
->ExceptionCode
);
1285 REGn_sig(0, context
) = (DWORD
)frame
;
1286 REGn_sig(1, context
) = rec
->ExceptionCode
;
1287 PC_sig(context
) = (DWORD
)__wine_syscall_dispatcher_return
;
1293 /**********************************************************************
1296 * Handler for SIGSEGV and related errors.
1298 static void segv_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1300 EXCEPTION_RECORD rec
= { 0 };
1301 ucontext_t
*context
= sigcontext
;
1303 switch (get_trap_code(signal
, context
))
1305 case TRAP_ARM_PRIVINFLT
: /* Invalid opcode exception */
1306 switch (get_udf_immediate( context
))
1308 case 0xfb: /* __fastfail */
1311 save_context( &ctx
, sigcontext
);
1312 rec
.ExceptionCode
= STATUS_STACK_BUFFER_OVERRUN
;
1313 rec
.ExceptionAddress
= (void *)ctx
.Pc
;
1314 rec
.ExceptionFlags
= EH_NONCONTINUABLE
;
1315 rec
.NumberParameters
= 1;
1316 rec
.ExceptionInformation
[0] = ctx
.R0
;
1317 NtRaiseException( &rec
, &ctx
, FALSE
);
1320 case 0xfe: /* breakpoint */
1321 rec
.ExceptionCode
= EXCEPTION_BREAKPOINT
;
1322 rec
.NumberParameters
= 1;
1325 rec
.ExceptionCode
= EXCEPTION_ILLEGAL_INSTRUCTION
;
1329 case TRAP_ARM_PAGEFLT
: /* Page fault */
1330 rec
.NumberParameters
= 2;
1331 rec
.ExceptionInformation
[0] = (get_error_code(context
) & 0x800) != 0;
1332 rec
.ExceptionInformation
[1] = (ULONG_PTR
)siginfo
->si_addr
;
1333 rec
.ExceptionCode
= virtual_handle_fault( siginfo
->si_addr
, rec
.ExceptionInformation
[0],
1334 (void *)SP_sig(context
) );
1335 if (!rec
.ExceptionCode
) return;
1337 case TRAP_ARM_ALIGNFLT
: /* Alignment check exception */
1338 rec
.ExceptionCode
= EXCEPTION_DATATYPE_MISALIGNMENT
;
1340 case TRAP_ARM_UNKNOWN
: /* Unknown fault code */
1341 rec
.ExceptionCode
= EXCEPTION_ACCESS_VIOLATION
;
1342 rec
.NumberParameters
= 2;
1343 rec
.ExceptionInformation
[0] = 0;
1344 rec
.ExceptionInformation
[1] = 0xffffffff;
1347 ERR("Got unexpected trap %d\n", get_trap_code(signal
, context
));
1348 rec
.ExceptionCode
= EXCEPTION_ILLEGAL_INSTRUCTION
;
1351 if (handle_syscall_fault( context
, &rec
)) return;
1352 setup_exception( context
, &rec
);
1356 /**********************************************************************
1359 * Handler for SIGTRAP.
1361 static void trap_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1363 EXCEPTION_RECORD rec
= { 0 };
1365 switch (siginfo
->si_code
)
1368 rec
.ExceptionCode
= EXCEPTION_SINGLE_STEP
;
1372 rec
.ExceptionCode
= EXCEPTION_BREAKPOINT
;
1373 rec
.NumberParameters
= 1;
1376 setup_exception( sigcontext
, &rec
);
1380 /**********************************************************************
1383 * Handler for SIGFPE.
1385 static void fpe_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1387 EXCEPTION_RECORD rec
= { 0 };
1389 switch (siginfo
->si_code
& 0xffff )
1393 rec
.ExceptionCode
= EXCEPTION_ARRAY_BOUNDS_EXCEEDED
;
1398 rec
.ExceptionCode
= EXCEPTION_INT_DIVIDE_BY_ZERO
;
1403 rec
.ExceptionCode
= EXCEPTION_INT_OVERFLOW
;
1408 rec
.ExceptionCode
= EXCEPTION_FLT_DIVIDE_BY_ZERO
;
1413 rec
.ExceptionCode
= EXCEPTION_FLT_OVERFLOW
;
1418 rec
.ExceptionCode
= EXCEPTION_FLT_UNDERFLOW
;
1423 rec
.ExceptionCode
= EXCEPTION_FLT_INEXACT_RESULT
;
1430 rec
.ExceptionCode
= EXCEPTION_FLT_INVALID_OPERATION
;
1433 setup_exception( sigcontext
, &rec
);
1437 /**********************************************************************
1440 * Handler for SIGINT.
1442 static void int_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1446 if (!p__wine_ctrl_routine
) return;
1447 if (!NtCreateThreadEx( &handle
, THREAD_ALL_ACCESS
, NULL
, NtCurrentProcess(),
1448 p__wine_ctrl_routine
, 0 /* CTRL_C_EVENT */, 0, 0, 0, 0, NULL
))
1453 /**********************************************************************
1456 * Handler for SIGABRT.
1458 static void abrt_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1460 EXCEPTION_RECORD rec
= { EXCEPTION_WINE_ASSERTION
, EH_NONCONTINUABLE
};
1462 setup_exception( sigcontext
, &rec
);
1466 /**********************************************************************
1469 * Handler for SIGQUIT.
1471 static void quit_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1477 /**********************************************************************
1480 * Handler for SIGUSR1, used to signal a thread that it got suspended.
1482 static void usr1_handler( int signal
, siginfo_t
*siginfo
, void *sigcontext
)
1486 if (is_inside_syscall( sigcontext
))
1488 context
.ContextFlags
= CONTEXT_FULL
;
1489 NtGetContextThread( GetCurrentThread(), &context
);
1490 wait_suspend( &context
);
1491 NtSetContextThread( GetCurrentThread(), &context
);
1495 save_context( &context
, sigcontext
);
1496 wait_suspend( &context
);
1497 restore_context( &context
, sigcontext
);
1502 /**********************************************************************
1503 * get_thread_ldt_entry
1505 NTSTATUS
get_thread_ldt_entry( HANDLE handle
, void *data
, ULONG len
, ULONG
*ret_len
)
1507 return STATUS_NOT_IMPLEMENTED
;
1511 /******************************************************************************
1512 * NtSetLdtEntries (NTDLL.@)
1513 * ZwSetLdtEntries (NTDLL.@)
1515 NTSTATUS WINAPI
NtSetLdtEntries( ULONG sel1
, LDT_ENTRY entry1
, ULONG sel2
, LDT_ENTRY entry2
)
1517 return STATUS_NOT_IMPLEMENTED
;
1521 /**********************************************************************
1522 * signal_init_threading
1524 void signal_init_threading(void)
1529 /**********************************************************************
1530 * signal_alloc_thread
1532 NTSTATUS
signal_alloc_thread( TEB
*teb
)
1534 teb
->WOW32Reserved
= __wine_syscall_dispatcher
;
1535 return STATUS_SUCCESS
;
1539 /**********************************************************************
1540 * signal_free_thread
1542 void signal_free_thread( TEB
*teb
)
1547 /**********************************************************************
1548 * signal_init_process
1550 void signal_init_process(void)
1552 struct sigaction sig_act
;
1553 void *kernel_stack
= (char *)ntdll_get_thread_data()->kernel_stack
+ kernel_stack_size
;
1555 arm_thread_data()->syscall_frame
= (struct syscall_frame
*)kernel_stack
- 1;
1557 sig_act
.sa_mask
= server_block_set
;
1558 sig_act
.sa_flags
= SA_RESTART
| SA_SIGINFO
| SA_ONSTACK
;
1560 sig_act
.sa_sigaction
= int_handler
;
1561 if (sigaction( SIGINT
, &sig_act
, NULL
) == -1) goto error
;
1562 sig_act
.sa_sigaction
= fpe_handler
;
1563 if (sigaction( SIGFPE
, &sig_act
, NULL
) == -1) goto error
;
1564 sig_act
.sa_sigaction
= abrt_handler
;
1565 if (sigaction( SIGABRT
, &sig_act
, NULL
) == -1) goto error
;
1566 sig_act
.sa_sigaction
= quit_handler
;
1567 if (sigaction( SIGQUIT
, &sig_act
, NULL
) == -1) goto error
;
1568 sig_act
.sa_sigaction
= usr1_handler
;
1569 if (sigaction( SIGUSR1
, &sig_act
, NULL
) == -1) goto error
;
1570 sig_act
.sa_sigaction
= trap_handler
;
1571 if (sigaction( SIGTRAP
, &sig_act
, NULL
) == -1) goto error
;
1572 sig_act
.sa_sigaction
= segv_handler
;
1573 if (sigaction( SIGSEGV
, &sig_act
, NULL
) == -1) goto error
;
1574 if (sigaction( SIGILL
, &sig_act
, NULL
) == -1) goto error
;
1575 if (sigaction( SIGBUS
, &sig_act
, NULL
) == -1) goto error
;
1579 perror("sigaction");
1584 /***********************************************************************
1587 void DECLSPEC_HIDDEN
call_init_thunk( LPTHREAD_START_ROUTINE entry
, void *arg
, BOOL suspend
, TEB
*teb
)
1589 struct arm_thread_data
*thread_data
= (struct arm_thread_data
*)&teb
->GdiTebBatch
;
1590 struct syscall_frame
*frame
= thread_data
->syscall_frame
;
1591 CONTEXT
*ctx
, context
= { CONTEXT_ALL
};
1593 __asm__
__volatile__( "mcr p15, 0, %0, c13, c0, 2" : : "r" (teb
) );
1595 context
.R0
= (DWORD
)entry
;
1596 context
.R1
= (DWORD
)arg
;
1597 context
.Sp
= (DWORD
)teb
->Tib
.StackBase
;
1598 context
.Pc
= (DWORD
)pRtlUserThreadStart
;
1599 if (context
.Pc
& 1) context
.Cpsr
|= 0x20; /* thumb mode */
1600 if ((ctx
= get_cpu_area( IMAGE_FILE_MACHINE_ARMNT
))) *ctx
= context
;
1602 if (suspend
) wait_suspend( &context
);
1604 ctx
= (CONTEXT
*)((ULONG_PTR
)context
.Sp
& ~15) - 1;
1606 ctx
->ContextFlags
= CONTEXT_FULL
;
1607 memset( frame
, 0, sizeof(*frame
) );
1608 NtSetContextThread( GetCurrentThread(), ctx
);
1610 frame
->sp
= (DWORD
)ctx
;
1611 frame
->pc
= (DWORD
)pLdrInitializeThunk
;
1612 frame
->r0
= (DWORD
)ctx
;
1613 frame
->prev_frame
= NULL
;
1614 frame
->restore_flags
|= CONTEXT_INTEGER
;
1615 frame
->syscall_table
= KeServiceDescriptorTable
;
1617 pthread_sigmask( SIG_UNBLOCK
, &server_block_set
, NULL
);
1618 __wine_syscall_dispatcher_return( frame
, 0 );
1622 /***********************************************************************
1623 * signal_start_thread
1625 __ASM_GLOBAL_FUNC( signal_start_thread
,
1626 __ASM_EHABI(".cantunwind\n\t")
1627 "push {r4-r12,lr}\n\t"
1628 /* store exit frame */
1629 "str sp, [r3, #0x1d4]\n\t" /* arm_thread_data()->exit_frame */
1630 /* set syscall frame */
1631 "ldr r6, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
1633 "sub r6, sp, #0x160\n\t" /* sizeof(struct syscall_frame) */
1634 "str r6, [r3, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
1635 "1:\tmov sp, r6\n\t"
1636 "bl " __ASM_NAME("call_init_thunk") )
1639 /***********************************************************************
1640 * signal_exit_thread
1642 __ASM_GLOBAL_FUNC( signal_exit_thread
,
1643 __ASM_EHABI(".cantunwind\n\t")
1644 "ldr r3, [r2, #0x1d4]\n\t" /* arm_thread_data()->exit_frame */
1646 "str ip, [r2, #0x1d4]\n\t"
1653 /***********************************************************************
1654 * __wine_syscall_dispatcher
1656 __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher
,
1657 __ASM_EHABI(".cantunwind\n\t")
1658 "mrc p15, 0, r1, c13, c0, 2\n\t" /* NtCurrentTeb() */
1659 "ldr r1, [r1, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
1660 "add r0, r1, #0x10\n\t"
1661 "stm r0, {r4-r12,lr}\n\t"
1662 "add r2, sp, #0x10\n\t"
1663 "str r2, [r1, #0x38]\n\t"
1664 "str r3, [r1, #0x3c]\n\t"
1666 "bfi r0, lr, #5, #1\n\t" /* set thumb bit */
1667 "str r0, [r1, #0x40]\n\t"
1669 "str r0, [r1, #0x44]\n\t" /* frame->restore_flags */
1671 "vmrs r0, fpscr\n\t"
1672 "str r0, [r1, #0x48]\n\t"
1673 "add r0, r1, #0x60\n\t"
1674 "vstm r0, {d0-d15}\n\t"
1679 "ldr r5, [r1, #0x50]\n\t" /* frame->syscall_table */
1680 "ubfx r4, ip, #12, #2\n\t" /* syscall table number */
1681 "bfc ip, #12, #20\n\t" /* syscall number */
1682 "add r4, r5, r4, lsl #4\n\t"
1683 "ldr r5, [r4, #8]\n\t" /* table->ServiceLimit */
1686 "ldr r5, [r4, #12]\n\t" /* table->ArgumentTable */
1687 "ldrb r5, [r5, ip]\n\t"
1691 "sub r0, sp, r5\n\t"
1694 "2:\tsubs r5, r5, #4\n\t"
1695 "ldr r0, [r6, r5]\n\t"
1696 "str r0, [sp, r5]\n\t"
1698 "pop {r0-r3}\n\t" /* first 4 args are in registers */
1699 "ldr r5, [r4]\n\t" /* table->ServiceTable */
1700 "ldr ip, [r5, ip, lsl #2]\n\t"
1702 __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") ":\n\t"
1703 "ldr ip, [r8, #0x44]\n\t" /* frame->restore_flags */
1705 "tst ip, #4\n\t" /* CONTEXT_FLOATING_POINT */
1707 "ldr r4, [r8, #0x48]\n\t"
1708 "vmsr fpscr, r4\n\t"
1709 "add r4, r8, #0x60\n\t"
1710 "vldm r4, {d0-d15}\n"
1713 "tst ip, #2\n\t" /* CONTEXT_INTEGER */
1715 "ldmne r8, {r0-r3}\n\t"
1716 "ldr lr, [r8, #0x3c]\n\t"
1717 "ldr sp, [r8, #0x38]\n\t"
1718 "add r8, r8, #0x10\n\t"
1719 "ldm r8, {r4-r12,pc}\n"
1720 "5:\tmovw r0, #0x000d\n\t" /* STATUS_INVALID_PARAMETER */
1721 "movt r0, #0xc000\n\t"
1722 "add sp, sp, #0x10\n\t"
1723 "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
1724 ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
1725 __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
1728 "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
1731 /***********************************************************************
1732 * __wine_unix_call_dispatcher
1734 __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher
,
1735 __ASM_EHABI(".cantunwind\n\t")
1736 "mrc p15, 0, r1, c13, c0, 2\n\t" /* NtCurrentTeb() */
1737 "ldr r1, [r1, #0x1d8]\n\t" /* arm_thread_data()->syscall_frame */
1738 "add ip, r1, #0x10\n\t"
1739 "stm ip, {r4-r12,lr}\n\t"
1740 "str sp, [r1, #0x38]\n\t"
1741 "str lr, [r1, #0x3c]\n\t"
1743 "bfi r4, lr, #5, #1\n\t" /* set thumb bit */
1744 "str r4, [r1, #0x40]\n\t"
1746 "str r4, [r1, #0x44]\n\t" /* frame->restore_flags */
1748 "vmrs r4, fpscr\n\t"
1749 "str r4, [r1, #0x48]\n\t"
1750 "add r4, r1, #0x60\n\t"
1751 "vstm r4, {d0-d15}\n\t"
1753 "ldr ip, [r0, r2, lsl #2]\n\t"
1755 "mov r0, r3\n\t" /* args */
1758 "ldr r1, [r8, #0x44]\n\t" /* frame->restore_flags */
1760 "ldr sp, [r8, #0x38]\n\t"
1761 "add r8, r8, #0x10\n\t"
1762 "ldm r8, {r4-r12,pc}\n\t"
1763 "1:\tb " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
1766 /***********************************************************************
1769 __ASM_GLOBAL_FUNC( __wine_setjmpex
,
1770 __ASM_EHABI(".cantunwind\n\t")
1771 "stm r0, {r1,r4-r11}\n" /* jmp_buf->Frame,R4..R11 */
1772 "str sp, [r0, #0x24]\n\t" /* jmp_buf->Sp */
1773 "str lr, [r0, #0x28]\n\t" /* jmp_buf->Pc */
1775 "vmrs r2, fpscr\n\t"
1776 "str r2, [r0, #0x2c]\n\t" /* jmp_buf->Fpscr */
1777 "add r0, r0, #0x30\n\t"
1778 "vstm r0, {d8-d15}\n\t" /* jmp_buf->D[0..7] */
1784 /***********************************************************************
1787 __ASM_GLOBAL_FUNC( __wine_longjmp
,
1788 __ASM_EHABI(".cantunwind\n\t")
1789 "ldm r0, {r3-r11}\n\t" /* jmp_buf->Frame,R4..R11 */
1790 "ldr sp, [r0, #0x24]\n\t" /* jmp_buf->Sp */
1791 "ldr r2, [r0, #0x28]\n\t" /* jmp_buf->Pc */
1793 "ldr r3, [r0, #0x2c]\n\t" /* jmp_buf->Fpscr */
1794 "vmsr fpscr, r3\n\t"
1795 "add r0, r0, #0x30\n\t"
1796 "vldm r0, {d8-d15}\n\t" /* jmp_buf->D[0..7] */
1798 "mov r0, r1\n\t" /* retval */
1801 #endif /* __arm__ */