3 * exception support for ARM
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * (C) 2001 Ximian, Inc.
17 #ifndef MONO_CROSS_COMPILE
19 #include <asm/sigcontext.h>
20 #endif /* def HOST_ANDROID */
23 #ifdef HAVE_UCONTEXT_H
25 #endif /* def HAVE_UCONTEXT_H */
27 #include <mono/arch/arm/arm-codegen.h>
28 #include <mono/arch/arm/arm-vfp-codegen.h>
29 #include <mono/metadata/abi-details.h>
30 #include <mono/metadata/appdomain.h>
31 #include <mono/metadata/tabledefs.h>
32 #include <mono/metadata/threads.h>
33 #include <mono/metadata/debug-helpers.h>
34 #include <mono/metadata/exception.h>
35 #include <mono/metadata/mono-debug.h>
39 #include "mini-runtime.h"
40 #include "aot-runtime.h"
41 #include "mono/utils/mono-sigcontext.h"
42 #include "mono/utils/mono-compiler.h"
43 #include "mono/utils/mono-tls-inline.h"
48 * arch_get_restore_context:
50 * Returns a pointer to a method which restores a previously saved sigcontext.
51 * The first argument in r0 is the pointer to the context.
54 mono_arch_get_restore_context (MonoTrampInfo
**info
, gboolean aot
)
59 MonoJumpInfo
*ji
= NULL
;
60 GSList
*unwind_ops
= NULL
;
62 start
= code
= mono_global_codeman_reserve (128);
65 * Move things to their proper place so we can restore all the registers with
71 if (!mono_arch_is_soft_float ()) {
72 ARM_ADD_REG_IMM8 (code
, ARMREG_IP
, ctx_reg
, MONO_STRUCT_OFFSET (MonoContext
, fregs
));
73 ARM_FLDMD (code
, ARM_VFP_D0
, 16, ARMREG_IP
);
77 ARM_LDR_IMM (code
, ARMREG_IP
, ctx_reg
, MONO_STRUCT_OFFSET (MonoContext
, pc
));
78 ARM_STR_IMM (code
, ARMREG_IP
, ctx_reg
, MONO_STRUCT_OFFSET (MonoContext
, regs
) + (ARMREG_PC
* sizeof (target_mgreg_t
)));
80 /* restore everything */
81 ARM_ADD_REG_IMM8 (code
, ARMREG_IP
, ctx_reg
, MONO_STRUCT_OFFSET(MonoContext
, regs
));
82 ARM_LDM (code
, ARMREG_IP
, 0xffff);
87 g_assert ((code
- start
) < 128);
89 mono_arch_flush_icache (start
, code
- start
);
90 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING
, NULL
));
93 *info
= mono_tramp_info_create ("restore_context", start
, code
- start
, ji
, unwind_ops
);
99 * arch_get_call_filter:
101 * Returns a pointer to a method which calls an exception filter. We
102 * also use this function to call finally handlers (we pass NULL as
103 * @exc object in this case).
106 mono_arch_get_call_filter (MonoTrampInfo
**info
, gboolean aot
)
111 MonoJumpInfo
*ji
= NULL
;
112 GSList
*unwind_ops
= NULL
;
114 /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
115 start
= code
= mono_global_codeman_reserve (320);
117 /* save all the regs on the stack */
118 ARM_MOV_REG_REG (code
, ARMREG_IP
, ARMREG_SP
);
119 ARM_PUSH (code
, MONO_ARM_REGSAVE_MASK
);
121 ARM_SUB_REG_IMM8 (code
, ARMREG_SP
, ARMREG_SP
, 8);
123 /* restore all the regs from ctx (in r0), but not sp, the stack pointer */
125 ARM_LDR_IMM (code
, ARMREG_IP
, ctx_reg
, MONO_STRUCT_OFFSET (MonoContext
, pc
));
126 ARM_ADD_REG_IMM8 (code
, ARMREG_LR
, ctx_reg
, MONO_STRUCT_OFFSET(MonoContext
, regs
) + (MONO_ARM_FIRST_SAVED_REG
* sizeof (target_mgreg_t
)));
127 ARM_LDM (code
, ARMREG_LR
, MONO_ARM_REGSAVE_MASK
);
128 /* call handler at eip (r1) and set the first arg with the exception (r2) */
129 ARM_MOV_REG_REG (code
, ARMREG_R0
, ARMREG_R2
);
130 ARM_MOV_REG_REG (code
, ARMREG_LR
, ARMREG_PC
);
131 ARM_MOV_REG_REG (code
, ARMREG_PC
, ARMREG_R1
);
133 ARM_ADD_REG_IMM8 (code
, ARMREG_SP
, ARMREG_SP
, 8);
136 ARM_POP_NWB (code
, 0xff0 | ((1 << ARMREG_SP
) | (1 << ARMREG_PC
)));
138 g_assert ((code
- start
) < 320);
140 mono_arch_flush_icache (start
, code
- start
);
141 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING
, NULL
));
144 *info
= mono_tramp_info_create ("call_filter", start
, code
- start
, ji
, unwind_ops
);
149 #endif /* DISABLE_JIT */
152 mono_arm_throw_exception (MonoObject
*exc
, host_mgreg_t pc
, host_mgreg_t sp
, host_mgreg_t
*int_regs
, gdouble
*fp_regs
, gboolean preserve_ips
)
156 gboolean rethrow
= sp
& 1;
158 sp
&= ~1; /* clear the optional rethrow bit */
159 pc
&= ~1; /* clear the thumb bit */
160 /* adjust eip so that it point into the call instruction */
163 /*printf ("stack in throw: %p\n", esp);*/
164 MONO_CONTEXT_SET_BP (&ctx
, int_regs
[ARMREG_FP
- 4]);
165 MONO_CONTEXT_SET_SP (&ctx
, sp
);
166 MONO_CONTEXT_SET_IP (&ctx
, pc
);
167 memcpy (((guint8
*)&ctx
.regs
) + (ARMREG_R4
* sizeof (host_mgreg_t
)), int_regs
, 8 * sizeof (host_mgreg_t
));
168 memcpy (&ctx
.fregs
, fp_regs
, sizeof (double) * 16);
170 if (mono_object_isinst_checked (exc
, mono_defaults
.exception_class
, error
)) {
171 MonoException
*mono_ex
= (MonoException
*)exc
;
172 if (!rethrow
&& !mono_ex
->caught_in_unmanaged
) {
173 mono_ex
->stack_trace
= NULL
;
174 mono_ex
->trace_ips
= NULL
;
175 } else if (preserve_ips
) {
176 mono_ex
->caught_in_unmanaged
= TRUE
;
179 mono_error_assert_ok (error
);
180 mono_handle_exception (&ctx
, exc
);
181 mono_restore_context (&ctx
);
182 g_assert_not_reached ();
186 mono_arm_throw_exception_by_token (guint32 ex_token_index
, host_mgreg_t pc
, host_mgreg_t sp
, host_mgreg_t
*int_regs
, gdouble
*fp_regs
)
188 guint32 ex_token
= MONO_TOKEN_TYPE_DEF
| ex_token_index
;
189 /* Clear thumb bit */
192 mono_arm_throw_exception ((MonoObject
*)mono_exception_from_token (mono_defaults
.corlib
, ex_token
), pc
, sp
, int_regs
, fp_regs
, FALSE
);
196 mono_arm_resume_unwind (guint32 dummy1
, host_mgreg_t pc
, host_mgreg_t sp
, host_mgreg_t
*int_regs
, gdouble
*fp_regs
)
200 pc
&= ~1; /* clear the optional rethrow bit */
201 /* adjust eip so that it point into the call instruction */
204 MONO_CONTEXT_SET_BP (&ctx
, int_regs
[ARMREG_FP
- 4]);
205 MONO_CONTEXT_SET_SP (&ctx
, sp
);
206 MONO_CONTEXT_SET_IP (&ctx
, pc
);
207 memcpy (((guint8
*)&ctx
.regs
) + (ARMREG_R4
* sizeof (host_mgreg_t
)), int_regs
, 8 * sizeof (host_mgreg_t
));
209 mono_resume_unwind (&ctx
);
215 * get_throw_trampoline:
217 * Returns a function pointer which can be used to raise
218 * exceptions. The returned function has the following
219 * signature: void (*func) (MonoException *exc); or
220 * void (*func) (guint32 ex_token, guint8* ip);
224 get_throw_trampoline (int size
, gboolean corlib
, gboolean rethrow
, gboolean llvm
, gboolean resume_unwind
, const char *tramp_name
, MonoTrampInfo
**info
, gboolean aot
, gboolean preserve_ips
)
228 MonoJumpInfo
*ji
= NULL
;
229 GSList
*unwind_ops
= NULL
;
232 code
= start
= mono_global_codeman_reserve (size
);
234 mono_add_unwind_op_def_cfa (unwind_ops
, code
, start
, ARMREG_SP
, 0);
236 /* save all the regs on the stack */
237 ARM_MOV_REG_REG (code
, ARMREG_IP
, ARMREG_SP
);
238 ARM_PUSH (code
, MONO_ARM_REGSAVE_MASK
);
240 cfa_offset
= MONO_ARM_NUM_SAVED_REGS
* sizeof (target_mgreg_t
);
241 mono_add_unwind_op_def_cfa (unwind_ops
, code
, start
, ARMREG_SP
, cfa_offset
);
242 mono_add_unwind_op_offset (unwind_ops
, code
, start
, ARMREG_LR
, -(ptrdiff_t)sizeof (target_mgreg_t
));
245 if (!mono_arch_is_soft_float ()) {
246 ARM_SUB_REG_IMM8 (code
, ARMREG_SP
, ARMREG_SP
, sizeof (double) * 16);
247 cfa_offset
+= sizeof (double) * 16;
248 mono_add_unwind_op_def_cfa_offset (unwind_ops
, code
, start
, cfa_offset
);
249 ARM_FSTMD (code
, ARM_VFP_D0
, 16, ARMREG_SP
);
254 if (!resume_unwind
&& !corlib
)
255 param_size
+= 4; // Extra arg
256 /* SP isn't 16byte aligned at this point which matters for some targets */
257 param_size
= ALIGN_TO (cfa_offset
+ param_size
, MONO_ARCH_FRAME_ALIGNMENT
) - cfa_offset
;
258 ARM_SUB_REG_IMM8 (code
, ARMREG_SP
, ARMREG_SP
, param_size
);
259 cfa_offset
+= param_size
;
260 mono_add_unwind_op_def_cfa_offset (unwind_ops
, code
, start
, cfa_offset
);
262 /* call throw_exception (exc, ip, sp, int_regs, fp_regs) */
264 ARM_ADD_REG_IMM8 (code
, ARMREG_R2
, ARMREG_SP
, cfa_offset
);
265 /* we encode rethrow in sp */
267 g_assert (!resume_unwind
);
269 ARM_ORR_REG_IMM8 (code
, ARMREG_R2
, ARMREG_R2
, rethrow
);
271 /* exc is already in place in r0 */
273 /* The caller ip is already in R1 */
276 * The address passed by llvm might point to before the call,
277 * thus outside the eh range recorded by llvm. Use the return
279 * FIXME: Do this on more platforms.
281 ARM_MOV_REG_REG (code
, ARMREG_R1
, ARMREG_LR
); /* caller ip */
284 ARM_MOV_REG_REG (code
, ARMREG_R1
, ARMREG_LR
); /* caller ip */
287 ARM_ADD_REG_IMM8 (code
, ARMREG_R3
, ARMREG_SP
, (cfa_offset
- (MONO_ARM_NUM_SAVED_REGS
* sizeof (target_mgreg_t
))));
288 if (resume_unwind
|| corlib
) {
290 ARM_ADD_REG_IMM8 (code
, ARMREG_LR
, ARMREG_SP
, 8);
291 ARM_STR_IMM (code
, ARMREG_LR
, ARMREG_SP
, 0);
294 ARM_MOV_REG_IMM8 (code
, ARMREG_R5
, preserve_ips
);
295 ARM_STR_IMM (code
, ARMREG_R5
, ARMREG_SP
, 4);
298 ARM_ADD_REG_IMM8 (code
, ARMREG_LR
, ARMREG_SP
, 8);
299 ARM_STR_IMM (code
, ARMREG_LR
, ARMREG_SP
, 0);
303 MonoJitICallId icall_id
;
306 icall_id
= MONO_JIT_ICALL_mono_arm_resume_unwind
;
308 icall_id
= MONO_JIT_ICALL_mono_arm_throw_exception_by_token
;
310 icall_id
= MONO_JIT_ICALL_mono_arm_throw_exception
;
312 ji
= mono_patch_info_list_prepend (ji
, code
- start
, MONO_PATCH_INFO_JIT_ICALL_ADDR
, GUINT_TO_POINTER (icall_id
));
313 ARM_LDR_IMM (code
, ARMREG_IP
, ARMREG_PC
, 0);
315 *(gpointer
*)(gpointer
)code
= NULL
;
317 ARM_LDR_REG_REG (code
, ARMREG_IP
, ARMREG_PC
, ARMREG_IP
);
319 code
= mono_arm_emit_load_imm (code
, ARMREG_IP
, GPOINTER_TO_UINT (resume_unwind
? (gpointer
)mono_arm_resume_unwind
: (corlib
? (gpointer
)mono_arm_throw_exception_by_token
: (gpointer
)mono_arm_throw_exception
)));
321 ARM_MOV_REG_REG (code
, ARMREG_LR
, ARMREG_PC
);
322 ARM_MOV_REG_REG (code
, ARMREG_PC
, ARMREG_IP
);
323 /* we should never reach this breakpoint */
325 g_assert ((code
- start
) < size
);
326 mono_arch_flush_icache (start
, code
- start
);
327 MONO_PROFILER_RAISE (jit_code_buffer
, (start
, code
- start
, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING
, NULL
));
330 *info
= mono_tramp_info_create (tramp_name
, start
, code
- start
, ji
, unwind_ops
);
336 * arch_get_throw_exception:
338 * Returns a function pointer which can be used to raise
339 * exceptions. The returned function has the following
340 * signature: void (*func) (MonoException *exc);
341 * For example to raise an arithmetic exception you can use:
343 * x86_push_imm (code, mono_get_exception_arithmetic ());
344 * x86_call_code (code, arch_get_throw_exception ());
348 mono_arch_get_throw_exception (MonoTrampInfo
**info
, gboolean aot
)
350 return get_throw_trampoline (132, FALSE
, FALSE
, FALSE
, FALSE
, "throw_exception", info
, aot
, FALSE
);
354 * mono_arch_get_rethrow_exception:
356 * Returns a function pointer which can be used to rethrow
357 * exceptions. The returned function has the following
358 * signature: void (*func) (MonoException *exc);
362 mono_arch_get_rethrow_exception (MonoTrampInfo
**info
, gboolean aot
)
364 return get_throw_trampoline (132, FALSE
, TRUE
, FALSE
, FALSE
, "rethrow_exception", info
, aot
, FALSE
);
368 mono_arch_get_rethrow_preserve_exception (MonoTrampInfo
**info
, gboolean aot
)
370 return get_throw_trampoline (132, FALSE
, TRUE
, FALSE
, FALSE
, "rethrow_preserve_exception", info
, aot
, TRUE
);
374 * mono_arch_get_throw_corlib_exception:
375 * \returns a function pointer which can be used to raise
376 * corlib exceptions. The returned function has the following
377 * signature: void (*func) (guint32 ex_token, guint32 offset);
378 * Here, \c offset is the offset which needs to be substracted from the caller IP
379 * to get the IP of the throw. Passing the offset has the advantage that it
380 * needs no relocations in the caller.
381 * On ARM, the ip is passed instead of an offset.
384 mono_arch_get_throw_corlib_exception (MonoTrampInfo
**info
, gboolean aot
)
386 return get_throw_trampoline (168, TRUE
, FALSE
, FALSE
, FALSE
, "throw_corlib_exception", info
, aot
, FALSE
);
390 mono_arm_get_exception_trampolines (gboolean aot
)
393 GSList
*tramps
= NULL
;
395 // FIXME Macro to make one line per trampoline and less repetition of names.
397 /* LLVM uses the normal trampolines, but with a different name */
398 get_throw_trampoline (168, TRUE
, FALSE
, FALSE
, FALSE
, "llvm_throw_corlib_exception_trampoline", &info
, aot
, FALSE
);
399 info
->jit_icall_info
= &mono_get_jit_icall_info ()->mono_llvm_throw_corlib_exception_trampoline
;
400 tramps
= g_slist_prepend (tramps
, info
);
402 get_throw_trampoline (168, TRUE
, FALSE
, TRUE
, FALSE
, "llvm_throw_corlib_exception_abs_trampoline", &info
, aot
, FALSE
);
403 info
->jit_icall_info
= &mono_get_jit_icall_info ()->mono_llvm_throw_corlib_exception_abs_trampoline
;
404 tramps
= g_slist_prepend (tramps
, info
);
406 get_throw_trampoline (168, FALSE
, FALSE
, FALSE
, TRUE
, "llvm_resume_unwind_trampoline", &info
, aot
, FALSE
);
407 info
->jit_icall_info
= &mono_get_jit_icall_info ()->mono_llvm_resume_unwind_trampoline
;
408 tramps
= g_slist_prepend (tramps
, info
);
416 mono_arm_get_exception_trampolines (gboolean aot
)
418 g_assert_not_reached ();
425 mono_arch_exceptions_init (void)
434 tramp
= mono_aot_get_trampoline ("llvm_throw_corlib_exception_trampoline");
435 mono_register_jit_icall_info (&mono_get_jit_icall_info ()->mono_llvm_throw_corlib_exception_trampoline
, tramp
, "llvm_throw_corlib_exception_trampoline", NULL
, TRUE
, NULL
);
437 tramp
= mono_aot_get_trampoline ("llvm_throw_corlib_exception_abs_trampoline");
438 mono_register_jit_icall_info (&mono_get_jit_icall_info ()->mono_llvm_throw_corlib_exception_abs_trampoline
, tramp
, "llvm_throw_corlib_exception_abs_trampoline", NULL
, TRUE
, NULL
);
440 tramp
= mono_aot_get_trampoline ("llvm_resume_unwind_trampoline");
441 mono_register_jit_icall_info (&mono_get_jit_icall_info ()->mono_llvm_resume_unwind_trampoline
, tramp
, "llvm_resume_unwind_trampoline", NULL
, TRUE
, NULL
);
444 tramps
= mono_arm_get_exception_trampolines (FALSE
);
445 for (l
= tramps
; l
; l
= l
->next
) {
446 MonoTrampInfo
*info
= (MonoTrampInfo
*)l
->data
;
447 mono_register_jit_icall_info (info
->jit_icall_info
, info
->code
, g_strdup (info
->name
), NULL
, TRUE
, NULL
);
448 mono_tramp_info_register (info
, NULL
);
450 g_slist_free (tramps
);
455 * mono_arch_unwind_frame:
457 * See exceptions-amd64.c for docs;
460 mono_arch_unwind_frame (MonoDomain
*domain
, MonoJitTlsData
*jit_tls
,
461 MonoJitInfo
*ji
, MonoContext
*ctx
,
462 MonoContext
*new_ctx
, MonoLMF
**lmf
,
463 host_mgreg_t
**save_locations
,
464 StackFrameInfo
*frame
)
466 gpointer ip
= MONO_CONTEXT_GET_IP (ctx
);
468 memset (frame
, 0, sizeof (StackFrameInfo
));
475 mono_unwind_reg_t regs
[MONO_MAX_IREGS
+ 1 + 8];
477 guint32 unwind_info_len
;
480 if (ji
->is_trampoline
)
481 frame
->type
= FRAME_TYPE_TRAMPOLINE
;
483 frame
->type
= FRAME_TYPE_MANAGED
;
485 unwind_info
= mono_jinfo_get_unwind_info (ji
, &unwind_info_len
);
488 printf ("%s %p %p\n", ji->d.method->name, ji->code_start, ip);
489 mono_print_unwind_info (unwind_info, unwind_info_len);
492 for (i
= 0; i
< 16; ++i
)
493 regs
[i
] = new_ctx
->regs
[i
];
495 /* On IOS, d8..d15 are callee saved. They are mapped to 8..15 in unwind.c */
496 for (i
= 0; i
< 8; ++i
)
497 regs
[MONO_MAX_IREGS
+ i
] = *(guint64
*)&(new_ctx
->fregs
[8 + i
]);
500 gboolean success
= mono_unwind_frame (unwind_info
, unwind_info_len
, (guint8
*)ji
->code_start
,
501 (guint8
*)ji
->code_start
+ ji
->code_size
,
502 (guint8
*)ip
, NULL
, regs
, MONO_MAX_IREGS
+ 8,
503 save_locations
, MONO_MAX_IREGS
, &cfa
);
508 for (i
= 0; i
< 16; ++i
)
509 new_ctx
->regs
[i
] = regs
[i
];
510 new_ctx
->pc
= regs
[ARMREG_LR
];
511 new_ctx
->regs
[ARMREG_SP
] = (gsize
)cfa
;
513 for (i
= 0; i
< 8; ++i
)
514 new_ctx
->fregs
[8 + i
] = *(double*)&(regs
[MONO_MAX_IREGS
+ i
]);
517 /* Clear thumb bit */
520 /* we substract 1, so that the IP points into the call instruction */
525 g_assert ((((guint64
)(*lmf
)->previous_lmf
) & 2) == 0);
527 frame
->type
= FRAME_TYPE_MANAGED_TO_NATIVE
;
529 if ((ji
= mini_jit_info_table_find (domain
, (gpointer
)(gsize
)(*lmf
)->ip
, NULL
))) {
534 frame
->method
= (*lmf
)->method
;
538 * The LMF is saved at the start of the method using:
539 * ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP)
540 * ARM_PUSH (code, 0x5ff0);
541 * So it stores the register state as it existed at the caller. We need to
542 * produce the register state which existed at the time of the call which
543 * transitioned to native call, so we save the sp/fp/ip in the LMF.
545 memcpy (&new_ctx
->regs
[0], &(*lmf
)->iregs
[0], sizeof (host_mgreg_t
) * 13);
546 new_ctx
->pc
= (*lmf
)->ip
;
547 new_ctx
->regs
[ARMREG_SP
] = (*lmf
)->sp
;
548 new_ctx
->regs
[ARMREG_FP
] = (*lmf
)->fp
;
550 /* Clear thumb bit */
553 /* we substract 1, so that the IP points into the call instruction */
556 *lmf
= (MonoLMF
*)(((gsize
)(*lmf
)->previous_lmf
) & ~3);
567 * Called by resuming from a signal handler.
570 handle_signal_exception (gpointer obj
)
572 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
575 memcpy (&ctx
, &jit_tls
->ex_ctx
, sizeof (MonoContext
));
577 mono_handle_exception (&ctx
, (MonoObject
*)obj
);
579 mono_restore_context (&ctx
);
583 * This works around a gcc 4.5 bug:
584 * https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/721531
586 static MONO_NEVER_INLINE gpointer
587 get_handle_signal_exception_addr (void)
589 return (gpointer
)handle_signal_exception
;
593 * This is the function called from the signal handler
596 mono_arch_handle_exception (void *ctx
, gpointer obj
)
598 #if defined(MONO_CROSS_COMPILE)
599 g_assert_not_reached ();
600 #elif defined(MONO_ARCH_USE_SIGACTION)
601 arm_ucontext
*sigctx
= (arm_ucontext
*)ctx
;
603 * Handling the exception in the signal handler is problematic, since the original
604 * signal is disabled, and we could run arbitrary code though the debugger. So
605 * resume into the normal stack and do most work there if possible.
607 MonoJitTlsData
*jit_tls
= mono_tls_get_jit_tls ();
608 guint64 sp
= UCONTEXT_REG_SP (sigctx
);
610 /* Pass the ctx parameter in TLS */
611 mono_sigctx_to_monoctx (sigctx
, &jit_tls
->ex_ctx
);
612 /* The others in registers */
613 UCONTEXT_REG_R0 (sigctx
) = (gsize
)obj
;
615 /* Allocate a stack frame */
617 UCONTEXT_REG_SP (sigctx
) = sp
;
619 UCONTEXT_REG_PC (sigctx
) = (gsize
)get_handle_signal_exception_addr ();
620 #ifdef UCONTEXT_REG_CPSR
621 if ((gsize
)UCONTEXT_REG_PC (sigctx
) & 1)
622 /* Transition to thumb */
623 UCONTEXT_REG_CPSR (sigctx
) |= (1 << 5);
625 /* Transition to ARM */
626 UCONTEXT_REG_CPSR (sigctx
) &= ~(1 << 5);
634 mono_sigctx_to_monoctx (ctx
, &mctx
);
636 result
= mono_handle_exception (&mctx
, obj
);
637 /* restore the context so that returning from the signal handler will invoke
640 mono_monoctx_to_sigctx (&mctx
, ctx
);
646 mono_arch_ip_from_context (void *sigctx
)
648 #ifdef MONO_CROSS_COMPILE
649 g_assert_not_reached ();
651 arm_ucontext
*my_uc
= (arm_ucontext
*)sigctx
;
652 return (void*) UCONTEXT_REG_PC (my_uc
);
657 mono_arch_setup_async_callback (MonoContext
*ctx
, void (*async_cb
)(void *fun
), gpointer user_data
)
659 host_mgreg_t sp
= (host_mgreg_t
)MONO_CONTEXT_GET_SP (ctx
);
662 g_assert (!user_data
);
664 /* Allocate a stack frame */
666 MONO_CONTEXT_SET_SP (ctx
, sp
);
668 mono_arch_setup_resume_sighandler_ctx (ctx
, (gpointer
)async_cb
);
672 * mono_arch_setup_resume_sighandler_ctx:
674 * Setup CTX so execution continues at FUNC.
677 mono_arch_setup_resume_sighandler_ctx (MonoContext
*ctx
, gpointer func
)
679 MONO_CONTEXT_SET_IP (ctx
,func
);
680 if ((host_mgreg_t
)MONO_CONTEXT_GET_IP (ctx
) & 1)
681 /* Transition to thumb */
682 ctx
->cpsr
|= (1 << 5);
684 /* Transition to ARM */
685 ctx
->cpsr
&= ~(1 << 5);
689 mono_arch_undo_ip_adjustment (MonoContext
*ctx
)
693 if (mono_arm_thumb_supported ())
698 mono_arch_do_ip_adjustment (MonoContext
*ctx
)
700 /* Clear thumb bit */