ntdll: Use nameless unions/structs for register contexts.
[wine.git] / dlls / ntdll / unix / signal_arm.c
blob640ea39f5d99d353dd2d289c5b0626e6943d922e
1 /*
2 * ARM signal handling routines
4 * Copyright 2002 Marcus Meissner, SuSE Linux AG
5 * Copyright 2010-2013, 2015 André Hentschel
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #if 0
23 #pragma makedep unix
24 #endif
26 #ifdef __arm__
28 #include "config.h"
30 #include <assert.h>
31 #include <pthread.h>
32 #include <signal.h>
33 #include <stdlib.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #ifdef HAVE_SYS_PARAM_H
39 # include <sys/param.h>
40 #endif
41 #ifdef HAVE_SYSCALL_H
42 # include <syscall.h>
43 #else
44 # ifdef HAVE_SYS_SYSCALL_H
45 # include <sys/syscall.h>
46 # endif
47 #endif
48 #ifdef HAVE_SYS_SIGNAL_H
49 # include <sys/signal.h>
50 #endif
51 #ifdef HAVE_SYS_UCONTEXT_H
52 # include <sys/ucontext.h>
53 #endif
54 #ifdef HAVE_LIBUNWIND
55 # define UNW_LOCAL_ONLY
56 # include <libunwind.h>
57 #endif
58 #ifdef HAVE_LINK_H
59 # include <link.h>
60 #endif
62 #include "ntstatus.h"
63 #define WIN32_NO_STATUS
64 #include "windef.h"
65 #include "winnt.h"
66 #include "winternl.h"
67 #include "wine/asm.h"
68 #include "unix_private.h"
69 #include "wine/debug.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(seh);
74 /***********************************************************************
75 * signal context platform-specific definitions
77 #ifdef linux
79 #if defined(__ANDROID__) && !defined(HAVE_SYS_UCONTEXT_H)
80 typedef struct ucontext
82 unsigned long uc_flags;
83 struct ucontext *uc_link;
84 stack_t uc_stack;
85 struct sigcontext uc_mcontext;
86 sigset_t uc_sigmask;
87 unsigned long uc_regspace[128] __attribute__((__aligned__(8)));
88 } ucontext_t;
89 #endif
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 */
103 /* Exceptions */
104 # define ERROR_sig(context) REG_sig(error_code, context)
105 # define TRAP_sig(context) REG_sig(trap_no, context)
107 struct extended_ctx
109 unsigned long magic;
110 unsigned long size;
113 struct vfp_sigframe
115 struct extended_ctx ctx;
116 unsigned long long fpregs[32];
117 unsigned long fpscr;
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);
128 return NULL;
131 static void save_fpu( CONTEXT *context, const ucontext_t *sigcontext )
133 struct vfp_sigframe *frame = get_extended_sigcontext( sigcontext, 0x56465001 );
135 if (!frame) return;
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 );
144 if (!frame) return;
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 ) { }
165 #endif /* linux */
167 enum arm_trap_code
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 */
175 struct syscall_frame
177 UINT r0; /* 000 */
178 UINT r1; /* 004 */
179 UINT r2; /* 008 */
180 UINT r3; /* 00c */
181 UINT r4; /* 010 */
182 UINT r5; /* 014 */
183 UINT r6; /* 018 */
184 UINT r7; /* 01c */
185 UINT r8; /* 020 */
186 UINT r9; /* 024 */
187 UINT r10; /* 028 */
188 UINT r11; /* 02c */
189 UINT r12; /* 030 */
190 UINT pc; /* 034 */
191 UINT sp; /* 038 */
192 UINT lr; /* 03c */
193 UINT cpsr; /* 040 */
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 );
227 struct exidx_entry
229 uint32_t addr;
230 uint32_t data;
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;
244 if (offset >= bytes)
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)
251 int shift = 0;
252 uint32_t val = 0;
253 while (1)
255 uint8_t byte = get_byte(ptr, (*offset)++, bytes);
256 val |= (byte & 0x7f) << shift;
257 if ((byte & 0x80) == 0)
258 break;
259 shift += 7;
261 return val;
264 static void pop_regs(CONTEXT *context, uint32_t regs)
266 int i;
267 DWORD new_sp = 0;
268 for (i = 0; i < 16; i++)
270 if (regs & (1U << i))
272 DWORD val = *(DWORD *)context->Sp;
273 if (i != 13)
274 (&context->R0)[i] = val;
275 else
276 new_sp = val;
277 context->Sp += 4;
280 if (regs & (1 << 13))
281 context->Sp = new_sp;
284 static void pop_vfp(CONTEXT *context, int first, int last)
286 int i;
287 for (i = first; i <= last; i++)
289 context->D[i] = *(ULONGLONG *)context->Sp;
290 context->Sp += 8;
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 )
306 const uint32_t *ptr;
307 const void *lsda = NULL;
308 int compact_inline = 0;
309 int offset = 0;
310 int bytes = 0;
311 int personality;
312 int extra_words;
313 int finish = 0;
314 int set_pc = 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;
333 ptr = &entry->data;
334 compact_inline = 1;
336 else
338 ptr = (uint32_t *)prel31_to_abs(&entry->data);
341 if ((*ptr & 0x80000000) == 0)
343 /* Generic */
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;
353 /* Compact */
355 personality = (*ptr >> 24) & 0x0f;
356 switch (personality)
358 case 0:
359 if (!compact_inline)
360 lsda = ptr + 1;
361 extra_words = 0;
362 offset = 1;
363 break;
364 case 1:
365 extra_words = (*ptr >> 16) & 0xff;
366 lsda = ptr + extra_words + 1;
367 offset = 2;
368 break;
369 case 2:
370 extra_words = (*ptr >> 16) & 0xff;
371 lsda = ptr + extra_words + 1;
372 offset = 2;
373 break;
374 default:
375 ERR("unsupported compact EXIDX personality %d\n", personality);
376 return STATUS_UNSUCCESSFUL;
379 /* Not inspecting the descriptors */
380 (void)lsda;
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)
388 /* Increment Sp */
389 context->Sp += (byte & 0x3f) * 4 + 4;
391 else if ((byte & 0xc0) == 0x40)
393 /* Decrement Sp */
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);
400 if (!regs)
402 ERR("refuse to unwind\n");
403 return STATUS_UNSUCCESSFUL;
405 regs <<= 4;
406 pop_regs(context, regs);
407 if (regs & (1 << 15))
408 set_pc = 1;
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) */
424 int n = byte & 0x07;
425 int regs = regmask(4, n);
426 if (byte & 0x08)
427 regs |= 1 << 14;
428 pop_regs(context, regs);
430 else if (byte == 0xb0)
432 finish = 1;
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
454 * is deprecated. */
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
466 * is deprecated. */
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 */
479 int first, last;
480 if ((byte & 0x01) == 0)
481 first = 16;
482 else
483 first = 0;
484 byte = get_byte(ptr, offset++, bytes);
485 first += (byte & 0xf0) >> 4;
486 last = first + (byte & 0x0f);
487 if (last >= 32)
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 */
502 int n = byte & 0x07;
503 pop_vfp(context, 8, 8 + n);
505 else
507 ERR("spare opcode\n");
508 return STATUS_UNSUCCESSFUL;
511 if (offset > bytes)
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;
521 if (!set_pc)
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;
542 #ifdef linux
543 struct iterate_data
545 ULONG_PTR ip;
546 int failed;
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)
553 return 0;
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;
560 int i;
561 int found_addr;
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)
566 return 0;
568 found_addr = 0;
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))
573 found_addr = 1;
574 if (phdr->p_type == PT_ARM_EXIDX)
575 exidx = phdr;
578 if (!found_addr || !exidx)
580 if (found_addr)
582 TRACE("found matching address in %s, but no EXIDX\n", info->dlpi_name);
583 data->failed = 1;
585 return 0;
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));
593 data->failed = 1;
594 return 0;
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)
603 end = mid;
605 else if (abs_addr < data->ip)
607 begin = mid;
609 else
611 begin = mid;
612 end = mid + 1;
616 data->entry = begin;
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);
621 return 1;
624 static const struct exidx_entry *find_exidx_entry( void *ip )
626 struct iterate_data data = {};
628 data.ip = (ULONG_PTR)ip;
629 data.failed = 0;
630 data.entry = NULL;
631 dl_iterate_phdr(check_exidx, &data);
633 return data.entry;
635 #endif
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;
642 unw_cursor_t cursor;
643 unw_proc_info_t info;
644 int rc, i;
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" );
672 *handler = NULL;
673 *frame = context->Sp;
674 context->Pc = context->Lr;
675 context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
676 return status;
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 );
684 if (rc < 0)
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;
723 #endif
725 /***********************************************************************
726 * unwind_builtin_dll
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);
734 #ifdef linux
735 const struct exidx_entry *entry = find_exidx_entry( (void *)ip );
737 if (entry)
738 return ehabi_virtual_unwind( ip, &dispatch->EstablisherFrame, context, entry,
739 &dispatch->LanguageHandler, &dispatch->HandlerData );
740 #endif
741 #ifdef HAVE_LIBUNWIND
742 return libunwind_virtual_unwind( ip, &dispatch->EstablisherFrame, context,
743 &dispatch->LanguageHandler, &dispatch->HandlerData );
744 #else
745 ERR("libunwind not available, unable to unwind\n");
746 return STATUS_INVALID_DISPOSITION;
747 #endif
751 /***********************************************************************
752 * get_trap_code
754 * Get the trap code for a signal.
756 static inline enum arm_trap_code get_trap_code( int signal, const ucontext_t *sigcontext )
758 #ifdef TRAP_sig
759 enum arm_trap_code trap = TRAP_sig(sigcontext);
760 if (trap)
761 return trap;
762 #endif
764 switch (signal)
766 case SIGILL:
767 return TRAP_ARM_PRIVINFLT;
768 case SIGSEGV:
769 return TRAP_ARM_PAGEFLT;
770 case SIGBUS:
771 return TRAP_ARM_ALIGNFLT;
772 default:
773 return TRAP_ARM_UNKNOWN;
778 /***********************************************************************
779 * get_error_code
781 * Get the error code for a signal.
783 static inline WORD get_error_code( const ucontext_t *sigcontext )
785 #ifdef ERROR_sig
786 return ERROR_sig(sigcontext);
787 #else
788 return 0;
789 #endif
793 /***********************************************************************
794 * get_udf_immediate
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);
810 else
812 DWORD arm_insn = *(DWORD *)PC_sig(sigcontext);
813 if ((arm_insn & 0xfff000f0) == 0xe7f000f0)
815 return ((arm_insn >> 4) & 0xfff0) | (arm_insn & 0xf);
818 return -1;
822 /***********************************************************************
823 * save_context
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);
832 #undef C
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 /***********************************************************************
847 * restore_context
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);
856 #undef C
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;
879 return status;
883 /***********************************************************************
884 * get_native_context
886 void *get_native_context( CONTEXT *context )
888 return context;
892 /***********************************************************************
893 * get_wow_context
895 void *get_wow_context( CONTEXT *context )
897 return NULL;
901 /***********************************************************************
902 * NtSetContextThread (NTDLL.@)
903 * ZwSetContextThread (NTDLL.@)
905 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
907 NTSTATUS ret;
908 struct syscall_frame *frame = arm_thread_data()->syscall_frame;
909 DWORD flags = context->ContextFlags & ~CONTEXT_ARM;
910 BOOL self = (handle == GetCurrentThread());
912 if (!self)
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());
961 if (!self)
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 */
1036 "blx r2\n\t"
1037 "udf #0")
1039 /***********************************************************************
1040 * setup_exception
1042 * Modify the signal context to call the exception raise function.
1044 static void setup_exception( ucontext_t *sigcontext, EXCEPTION_RECORD *rec )
1046 struct
1048 CONTEXT context;
1049 EXCEPTION_RECORD rec;
1050 } *stack;
1052 void *stack_ptr = (void *)(SP_sig(sigcontext) & ~3);
1053 CONTEXT context;
1054 NTSTATUS status;
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 );
1063 return;
1066 stack = virtual_setup_exception( stack_ptr, sizeof(*stack), rec );
1067 stack->rec = *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
1092 void *func;
1093 void *align;
1094 CONTEXT context;
1095 } *stack;
1097 sp &= ~15;
1098 stack = (struct apc_stack_layout *)sp - 1;
1099 if (context)
1101 memmove( &stack->context, context, sizeof(stack->context) );
1102 NtSetContextThread( GetCurrentThread(), &stack->context );
1104 else
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;
1113 frame->r1 = arg1;
1114 frame->r2 = arg2;
1115 frame->r3 = arg3;
1116 stack->func = func;
1117 frame->restore_flags |= CONTEXT_CONTROL | CONTEXT_INTEGER;
1118 return status;
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;
1145 frame->lr = lr;
1146 frame->sp = sp;
1147 frame->restore_flags |= CONTEXT_INTEGER | CONTEXT_CONTROL;
1148 return status;
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"
1162 #ifndef __SOFTFP__
1163 "sub sp, sp, #0x90\n\t"
1164 "mov r5, sp\n\t"
1165 "vmrs r6, fpscr\n\t"
1166 "vstm r5, {d8-d15}\n\t"
1167 "str r6, [r5, #0x80]\n\t"
1168 #endif
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 */
1175 "mov ip, r0\n\t"
1176 "mov sp, r1\n\t"
1177 "pop {r0-r3}\n\t"
1178 "bx ip" )
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"
1191 #ifndef __SOFTFP__
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"
1196 #endif
1197 "mov sp, r5\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 */
1204 "pop {r4-r12,pc}" )
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 );
1228 *(--stack) = 0;
1229 *(--stack) = len;
1230 *(--stack) = (ULONG_PTR)args_data;
1231 *(--stack) = id;
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;
1255 UINT i;
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;
1282 else
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;
1289 return TRUE;
1293 /**********************************************************************
1294 * segv_handler
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 */
1310 CONTEXT ctx;
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 );
1318 return;
1320 case 0xfe: /* breakpoint */
1321 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1322 rec.NumberParameters = 1;
1323 break;
1324 default:
1325 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
1326 break;
1328 break;
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;
1336 break;
1337 case TRAP_ARM_ALIGNFLT: /* Alignment check exception */
1338 rec.ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
1339 break;
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;
1345 break;
1346 default:
1347 ERR("Got unexpected trap %d\n", get_trap_code(signal, context));
1348 rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
1349 break;
1351 if (handle_syscall_fault( context, &rec )) return;
1352 setup_exception( context, &rec );
1356 /**********************************************************************
1357 * trap_handler
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)
1367 case TRAP_TRACE:
1368 rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
1369 break;
1370 case TRAP_BRKPT:
1371 default:
1372 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1373 rec.NumberParameters = 1;
1374 break;
1376 setup_exception( sigcontext, &rec );
1380 /**********************************************************************
1381 * fpe_handler
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 )
1391 #ifdef FPE_FLTSUB
1392 case FPE_FLTSUB:
1393 rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
1394 break;
1395 #endif
1396 #ifdef FPE_INTDIV
1397 case FPE_INTDIV:
1398 rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
1399 break;
1400 #endif
1401 #ifdef FPE_INTOVF
1402 case FPE_INTOVF:
1403 rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
1404 break;
1405 #endif
1406 #ifdef FPE_FLTDIV
1407 case FPE_FLTDIV:
1408 rec.ExceptionCode = EXCEPTION_FLT_DIVIDE_BY_ZERO;
1409 break;
1410 #endif
1411 #ifdef FPE_FLTOVF
1412 case FPE_FLTOVF:
1413 rec.ExceptionCode = EXCEPTION_FLT_OVERFLOW;
1414 break;
1415 #endif
1416 #ifdef FPE_FLTUND
1417 case FPE_FLTUND:
1418 rec.ExceptionCode = EXCEPTION_FLT_UNDERFLOW;
1419 break;
1420 #endif
1421 #ifdef FPE_FLTRES
1422 case FPE_FLTRES:
1423 rec.ExceptionCode = EXCEPTION_FLT_INEXACT_RESULT;
1424 break;
1425 #endif
1426 #ifdef FPE_FLTINV
1427 case FPE_FLTINV:
1428 #endif
1429 default:
1430 rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
1431 break;
1433 setup_exception( sigcontext, &rec );
1437 /**********************************************************************
1438 * int_handler
1440 * Handler for SIGINT.
1442 static void int_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1444 HANDLE handle;
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 ))
1449 NtClose( handle );
1453 /**********************************************************************
1454 * abrt_handler
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 /**********************************************************************
1467 * quit_handler
1469 * Handler for SIGQUIT.
1471 static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext )
1473 abort_thread(0);
1477 /**********************************************************************
1478 * usr1_handler
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 )
1484 CONTEXT context;
1486 if (is_inside_syscall( sigcontext ))
1488 context.ContextFlags = CONTEXT_FULL;
1489 NtGetContextThread( GetCurrentThread(), &context );
1490 wait_suspend( &context );
1491 NtSetContextThread( GetCurrentThread(), &context );
1493 else
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;
1576 return;
1578 error:
1579 perror("sigaction");
1580 exit(1);
1584 /***********************************************************************
1585 * call_init_thunk
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;
1605 *ctx = context;
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 */
1632 "cbnz r6, 1f\n\t"
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 */
1645 "mov ip, #0\n\t"
1646 "str ip, [r2, #0x1d4]\n\t"
1647 "cmp r3, ip\n\t"
1648 "it ne\n\t"
1649 "movne sp, r3\n\t"
1650 "blx r1" )
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"
1665 "mrs r0, CPSR\n\t"
1666 "bfi r0, lr, #5, #1\n\t" /* set thumb bit */
1667 "str r0, [r1, #0x40]\n\t"
1668 "mov r0, #0\n\t"
1669 "str r0, [r1, #0x44]\n\t" /* frame->restore_flags */
1670 #ifndef __SOFTFP__
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"
1675 #endif
1676 "mov r6, sp\n\t"
1677 "mov sp, r1\n\t"
1678 "mov r8, r1\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 */
1684 "cmp ip, r5\n\t"
1685 "bcs 5f\n\t"
1686 "ldr r5, [r4, #12]\n\t" /* table->ArgumentTable */
1687 "ldrb r5, [r5, ip]\n\t"
1688 "cmp r5, #16\n\t"
1689 "it le\n\t"
1690 "movle r5, #16\n\t"
1691 "sub r0, sp, r5\n\t"
1692 "and r0, #~7\n\t"
1693 "mov sp, r0\n"
1694 "2:\tsubs r5, r5, #4\n\t"
1695 "ldr r0, [r6, r5]\n\t"
1696 "str r0, [sp, r5]\n\t"
1697 "bgt 2b\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"
1701 "blx ip\n"
1702 __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") ":\n\t"
1703 "ldr ip, [r8, #0x44]\n\t" /* frame->restore_flags */
1704 #ifndef __SOFTFP__
1705 "tst ip, #4\n\t" /* CONTEXT_FLOATING_POINT */
1706 "beq 3f\n\t"
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"
1711 "3:\n\t"
1712 #endif
1713 "tst ip, #2\n\t" /* CONTEXT_INTEGER */
1714 "it ne\n\t"
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"
1726 "mov r8, r0\n\t"
1727 "mov r0, r1\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"
1742 "mrs r4, CPSR\n\t"
1743 "bfi r4, lr, #5, #1\n\t" /* set thumb bit */
1744 "str r4, [r1, #0x40]\n\t"
1745 "mov r4, #0\n\t"
1746 "str r4, [r1, #0x44]\n\t" /* frame->restore_flags */
1747 #ifndef __SOFTFP__
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"
1752 #endif
1753 "ldr ip, [r0, r2, lsl #2]\n\t"
1754 "mov sp, r1\n\t"
1755 "mov r0, r3\n\t" /* args */
1756 "blx ip\n"
1757 "mov r8, sp\n\t"
1758 "ldr r1, [r8, #0x44]\n\t" /* frame->restore_flags */
1759 "cbnz r1, 1f\n\t"
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 /***********************************************************************
1767 * __wine_setjmpex
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 */
1774 #ifndef __SOFTFP__
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] */
1779 #endif
1780 "mov r0, #0\n\t"
1781 "bx lr" )
1784 /***********************************************************************
1785 * __wine_longjmp
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 */
1792 #ifndef __SOFTFP__
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] */
1797 #endif
1798 "mov r0, r1\n\t" /* retval */
1799 "bx r2" )
1801 #endif /* __arm__ */