Revert "[mono][debugger] First PR to implement iCorDebug on mono (#20757)"
[mono-project.git] / mono / mini / exceptions-arm.c
blob4433324103d4bfccc6ba5dbd7d07a77768e8d815
1 /**
2 * \file
3 * exception support for ARM
5 * Authors:
6 * Dietmar Maurer (dietmar@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * (C) 2001 Ximian, Inc.
12 #include <config.h>
13 #include <glib.h>
14 #include <signal.h>
15 #include <string.h>
17 #ifndef MONO_CROSS_COMPILE
18 #ifdef HOST_ANDROID
19 #include <asm/sigcontext.h>
20 #endif /* def HOST_ANDROID */
21 #endif
23 #ifdef HAVE_UCONTEXT_H
24 #include <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>
37 #include "mini.h"
38 #include "mini-arm.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"
45 #ifndef DISABLE_JIT
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.
53 gpointer
54 mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
56 guint8 *code;
57 guint8 *start;
58 int ctx_reg;
59 MonoJumpInfo *ji = NULL;
60 GSList *unwind_ops = NULL;
62 start = code = mono_global_codeman_reserve (128);
64 /*
65 * Move things to their proper place so we can restore all the registers with
66 * one instruction.
69 ctx_reg = ARMREG_R0;
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);
76 /* move pc to PC */
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);
84 /* never reached */
85 ARM_DBRK (code);
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));
92 if (info)
93 *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops);
95 return start;
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).
105 gpointer
106 mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
108 guint8 *code;
109 guint8* start;
110 int ctx_reg;
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 */
124 ctx_reg = ARMREG_R0;
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);
135 /* epilog */
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));
143 if (info)
144 *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops);
146 return start;
149 #endif /* DISABLE_JIT */
151 void
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)
154 ERROR_DECL (error);
155 MonoContext ctx;
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 */
161 pc -= 4;
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 ();
185 void
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 */
190 pc &= ~1;
192 mono_arm_throw_exception ((MonoObject*)mono_exception_from_token (mono_defaults.corlib, ex_token), pc, sp, int_regs, fp_regs, FALSE);
195 void
196 mono_arm_resume_unwind (guint32 dummy1, host_mgreg_t pc, host_mgreg_t sp, host_mgreg_t *int_regs, gdouble *fp_regs)
198 MonoContext ctx;
200 pc &= ~1; /* clear the optional rethrow bit */
201 /* adjust eip so that it point into the call instruction */
202 pc -= 4;
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);
212 #ifndef DISABLE_JIT
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);
223 static gpointer
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)
226 guint8 *start;
227 guint8 *code;
228 MonoJumpInfo *ji = NULL;
229 GSList *unwind_ops = NULL;
230 int cfa_offset;
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));
244 /* Save fp regs */
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);
252 /* Param area */
253 int param_size = 8;
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) */
263 /* caller sp */
264 ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, cfa_offset);
265 /* we encode rethrow in sp */
266 if (rethrow) {
267 g_assert (!resume_unwind);
268 g_assert (!corlib);
269 ARM_ORR_REG_IMM8 (code, ARMREG_R2, ARMREG_R2, rethrow);
271 /* exc is already in place in r0 */
272 if (corlib) {
273 /* The caller ip is already in R1 */
274 if (llvm) {
276 * The address passed by llvm might point to before the call,
277 * thus outside the eh range recorded by llvm. Use the return
278 * address instead.
279 * FIXME: Do this on more platforms.
281 ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */
283 } else {
284 ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */
286 /* int regs */
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) {
289 /* fp regs */
290 ARM_ADD_REG_IMM8 (code, ARMREG_LR, ARMREG_SP, 8);
291 ARM_STR_IMM (code, ARMREG_LR, ARMREG_SP, 0);
292 } else {
293 /* preserve_ips */
294 ARM_MOV_REG_IMM8 (code, ARMREG_R5, preserve_ips);
295 ARM_STR_IMM (code, ARMREG_R5, ARMREG_SP, 4);
297 /* fp regs */
298 ARM_ADD_REG_IMM8 (code, ARMREG_LR, ARMREG_SP, 8);
299 ARM_STR_IMM (code, ARMREG_LR, ARMREG_SP, 0);
302 if (aot) {
303 MonoJitICallId icall_id;
305 if (resume_unwind)
306 icall_id = MONO_JIT_ICALL_mono_arm_resume_unwind;
307 else if (corlib)
308 icall_id = MONO_JIT_ICALL_mono_arm_throw_exception_by_token;
309 else
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);
314 ARM_B (code, 0);
315 *(gpointer*)(gpointer)code = NULL;
316 code += 4;
317 ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP);
318 } else {
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 */
324 ARM_DBRK (code);
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));
329 if (info)
330 *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops);
332 return start;
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 ());
347 gpointer
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);
361 gpointer
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);
367 gpointer
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.
383 gpointer
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);
389 GSList*
390 mono_arm_get_exception_trampolines (gboolean aot)
392 MonoTrampInfo *info;
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);
410 return tramps;
413 #else
415 GSList*
416 mono_arm_get_exception_trampolines (gboolean aot)
418 g_assert_not_reached ();
419 return NULL;
422 #endif
424 void
425 mono_arch_exceptions_init (void)
427 gpointer tramp;
428 GSList *tramps, *l;
430 if (mono_aot_only) {
432 // FIXME Macroize.
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);
443 } else {
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;
459 gboolean
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));
469 frame->ji = ji;
471 *new_ctx = *ctx;
473 if (ji != NULL) {
474 int i;
475 mono_unwind_reg_t regs [MONO_MAX_IREGS + 1 + 8];
476 guint8 *cfa;
477 guint32 unwind_info_len;
478 guint8 *unwind_info;
480 if (ji->is_trampoline)
481 frame->type = FRAME_TYPE_TRAMPOLINE;
482 else
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];
494 #ifdef TARGET_IOS
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]);
498 #endif
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);
505 if (!success)
506 return FALSE;
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;
512 #ifdef TARGET_IOS
513 for (i = 0; i < 8; ++i)
514 new_ctx->fregs [8 + i] = *(double*)&(regs [MONO_MAX_IREGS + i]);
515 #endif
517 /* Clear thumb bit */
518 new_ctx->pc &= ~1;
520 /* we substract 1, so that the IP points into the call instruction */
521 new_ctx->pc--;
523 return TRUE;
524 } else if (*lmf) {
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))) {
530 frame->ji = ji;
531 } else {
532 if (!(*lmf)->method)
533 return FALSE;
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 */
551 new_ctx->pc &= ~1;
553 /* we substract 1, so that the IP points into the call instruction */
554 new_ctx->pc--;
556 *lmf = (MonoLMF*)(((gsize)(*lmf)->previous_lmf) & ~3);
558 return TRUE;
561 return FALSE;
565 * handle_exception:
567 * Called by resuming from a signal handler.
569 static void
570 handle_signal_exception (gpointer obj)
572 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
573 MonoContext ctx;
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
595 gboolean
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 */
616 sp -= 16;
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);
624 else
625 /* Transition to ARM */
626 UCONTEXT_REG_CPSR (sigctx) &= ~(1 << 5);
627 #endif
629 return TRUE;
630 #else
631 MonoContext mctx;
632 gboolean result;
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
638 * the catch clause
640 mono_monoctx_to_sigctx (&mctx, ctx);
641 return result;
642 #endif
645 gpointer
646 mono_arch_ip_from_context (void *sigctx)
648 #ifdef MONO_CROSS_COMPILE
649 g_assert_not_reached ();
650 #else
651 arm_ucontext *my_uc = (arm_ucontext*)sigctx;
652 return (void*) UCONTEXT_REG_PC (my_uc);
653 #endif
656 void
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);
661 // FIXME:
662 g_assert (!user_data);
664 /* Allocate a stack frame */
665 sp -= 16;
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.
676 void
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);
683 else
684 /* Transition to ARM */
685 ctx->cpsr &= ~(1 << 5);
688 void
689 mono_arch_undo_ip_adjustment (MonoContext *ctx)
691 ctx->pc++;
693 if (mono_arm_thumb_supported ())
694 ctx->pc |= 1;
697 void
698 mono_arch_do_ip_adjustment (MonoContext *ctx)
700 /* Clear thumb bit */
701 ctx->pc &= ~1;
703 ctx->pc--;