X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fexceptions-arm.c;h=95a83109f1343ccd0ffff915e428b969c69c794f;hb=53f83c9f56f372f4e801227fc5d60f0f4b8d1c8b;hp=25593b6bedd8fb0486cab101f41b65e048cf3e1b;hpb=81b4a277b2b752b8b76c2613b83b07d6da13a0a2;p=mono.git diff --git a/mono/mini/exceptions-arm.c b/mono/mini/exceptions-arm.c index 25593b6bedd..95a83109f13 100644 --- a/mono/mini/exceptions-arm.c +++ b/mono/mini/exceptions-arm.c @@ -12,7 +12,16 @@ #include #include #include + +#ifndef MONO_CROSS_COMPILE +#ifdef HAVE_ASM_SIGCONTEXT_H +#include +#endif /* def HAVE_ASM_SIGCONTEXT_H */ +#endif + +#ifdef HAVE_UCONTEXT_H #include +#endif /* def HAVE_UCONTEXT_H */ #include #include @@ -24,79 +33,7 @@ #include "mini.h" #include "mini-arm.h" - -/* - -struct sigcontext { - unsigned long trap_no; - unsigned long error_code; - unsigned long oldmask; - unsigned long arm_r0; - unsigned long arm_r1; - unsigned long arm_r2; - unsigned long arm_r3; - unsigned long arm_r4; - unsigned long arm_r5; - unsigned long arm_r6; - unsigned long arm_r7; - unsigned long arm_r8; - unsigned long arm_r9; - unsigned long arm_r10; - unsigned long arm_fp; - unsigned long arm_ip; - unsigned long arm_sp; - unsigned long arm_lr; - unsigned long arm_pc; - unsigned long arm_cpsr; - unsigned long fault_address; -}; - -gregs below is this struct -struct user_regs { - unsigned long int uregs[18]; -}; - -the companion user_fpregs has just 8 double registers -(it's valid for FPA mode, will need changes for VFP) - -typedef struct { - gregset_t gregs; - fpregset_t fpregs; -} mcontext_t; - -typedef struct ucontext { - unsigned long int uc_flags; - struct ucontext *uc_link; - __sigset_t uc_sigmask; - stack_t uc_stack; - mcontext_t uc_mcontext; - long int uc_filler[5]; -} ucontext_t; - -*/ - -/* - * So, it turns out that the ucontext struct defined by libc is incorrect. - * We define our own version here and use it instead. - */ - -#if __APPLE__ -#define my_ucontext ucontext_t -#else -typedef struct my_ucontext { - unsigned long uc_flags; - struct my_ucontext *uc_link; - struct { - void *p; - int flags; - size_t size; - } sstack_data; - struct sigcontext sig_ctx; - /* some 2.6.x kernel has fp data here after a few other fields - * we don't use them for now... - */ -} my_ucontext; -#endif +#include "mono/utils/mono-sigcontext.h" /* * arch_get_restore_context: @@ -105,13 +42,13 @@ typedef struct my_ucontext { * The first argument in r0 is the pointer to the context. */ gpointer -mono_arch_get_restore_context_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot) +mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) { guint8 *code; guint8 *start; int ctx_reg; - - *ji = NULL; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; start = code = mono_global_codeman_reserve (128); @@ -122,15 +59,9 @@ mono_arch_get_restore_context_full (guint32 *code_size, MonoJumpInfo **ji, gbool ctx_reg = ARMREG_R0; - /* move eip to PC */ - ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, eip)); - ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_PC * 4)); - /* move sp to SP */ - ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, esp)); - ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_SP * 4)); - /* move ebp to FP */ - ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, ebp)); - ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 4)); + /* move pc to PC */ + ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, pc)); + ARM_STR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_PC * sizeof (mgreg_t))); /* restore everything */ ARM_ADD_REG_IMM8 (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET(MonoContext, regs)); @@ -143,7 +74,8 @@ mono_arch_get_restore_context_full (guint32 *code_size, MonoJumpInfo **ji, gbool mono_arch_flush_icache (start, code - start); - *code_size = code - start; + if (info) + *info = mono_tramp_info_create (g_strdup_printf ("restore_context"), start, code - start, ji, unwind_ops); return start; } @@ -156,13 +88,13 @@ mono_arch_get_restore_context_full (guint32 *code_size, MonoJumpInfo **ji, gbool * @exc object in this case). */ gpointer -mono_arch_get_call_filter_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot) +mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) { guint8 *code; guint8* start; int ctx_reg; - - *ji = NULL; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */ start = code = mono_global_codeman_reserve (320); @@ -173,8 +105,8 @@ mono_arch_get_call_filter_full (guint32 *code_size, MonoJumpInfo **ji, gboolean /* restore all the regs from ctx (in r0), but not sp, the stack pointer */ ctx_reg = ARMREG_R0; - ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, eip)); - ARM_ADD_REG_IMM8 (code, ARMREG_LR, ctx_reg, G_STRUCT_OFFSET(MonoContext, regs) + (4 * 4)); + ARM_LDR_IMM (code, ARMREG_IP, ctx_reg, G_STRUCT_OFFSET (MonoContext, pc)); + ARM_ADD_REG_IMM8 (code, ARMREG_LR, ctx_reg, G_STRUCT_OFFSET(MonoContext, regs) + (MONO_ARM_FIRST_SAVED_REG * sizeof (mgreg_t))); ARM_LDM (code, ARMREG_LR, MONO_ARM_REGSAVE_MASK); /* call handler at eip (r1) and set the first arg with the exception (r2) */ ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_R2); @@ -188,30 +120,31 @@ mono_arch_get_call_filter_full (guint32 *code_size, MonoJumpInfo **ji, gboolean mono_arch_flush_icache (start, code - start); - *code_size = code - start; + if (info) + *info = mono_tramp_info_create (g_strdup_printf ("call_filter"), start, code - start, ji, unwind_ops); return start; } void -mono_arm_throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs) +mono_arm_throw_exception (MonoObject *exc, mgreg_t pc, mgreg_t sp, mgreg_t *int_regs, gdouble *fp_regs) { static void (*restore_context) (MonoContext *); MonoContext ctx; - gboolean rethrow = eip & 1; + gboolean rethrow = pc & 1; if (!restore_context) restore_context = mono_get_restore_context (); - eip &= ~1; /* clear the optional rethrow bit */ + pc &= ~1; /* clear the optional rethrow bit */ /* adjust eip so that it point into the call instruction */ - eip -= 4; + pc -= 4; /*printf ("stack in throw: %p\n", esp);*/ MONO_CONTEXT_SET_BP (&ctx, int_regs [ARMREG_FP - 4]); - MONO_CONTEXT_SET_SP (&ctx, esp); - MONO_CONTEXT_SET_IP (&ctx, eip); - memcpy (((guint8*)&ctx.regs) + (4 * 4), int_regs, sizeof (gulong) * 8); + MONO_CONTEXT_SET_SP (&ctx, sp); + MONO_CONTEXT_SET_IP (&ctx, pc); + memcpy (((guint8*)&ctx.regs) + (ARMREG_R4 * sizeof (mgreg_t)), int_regs, 8 * sizeof (mgreg_t)); /* memcpy (&ctx.fregs, fp_regs, sizeof (double) * MONO_SAVED_FREGS); */ if (mono_object_isinst (exc, mono_defaults.exception_class)) { @@ -219,19 +152,39 @@ mono_arm_throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, if (!rethrow) mono_ex->stack_trace = NULL; } - mono_handle_exception (&ctx, exc, (gpointer)(eip + 4), FALSE); + mono_handle_exception (&ctx, exc); restore_context (&ctx); g_assert_not_reached (); } void -mono_arm_throw_exception_by_token (guint32 type_token, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs) +mono_arm_throw_exception_by_token (guint32 type_token, mgreg_t pc, mgreg_t sp, mgreg_t *int_regs, gdouble *fp_regs) +{ + /* Clear thumb bit */ + pc &= ~1; + + mono_arm_throw_exception ((MonoObject*)mono_exception_from_token (mono_defaults.corlib, type_token), pc, sp, int_regs, fp_regs); +} + +void +mono_arm_resume_unwind (guint32 dummy1, mgreg_t pc, mgreg_t sp, mgreg_t *int_regs, gdouble *fp_regs) { - mono_arm_throw_exception ((MonoObject*)mono_exception_from_token (mono_defaults.corlib, type_token), eip, esp, int_regs, fp_regs); + MonoContext ctx; + + pc &= ~1; /* clear the optional rethrow bit */ + /* adjust eip so that it point into the call instruction */ + pc -= 4; + + MONO_CONTEXT_SET_BP (&ctx, int_regs [ARMREG_FP - 4]); + MONO_CONTEXT_SET_SP (&ctx, sp); + MONO_CONTEXT_SET_IP (&ctx, pc); + memcpy (((guint8*)&ctx.regs) + (ARMREG_R4 * sizeof (mgreg_t)), int_regs, 8 * sizeof (mgreg_t)); + + mono_resume_unwind (&ctx); } /** - * arch_get_throw_exception_generic: + * get_throw_trampoline: * * Returns a function pointer which can be used to raise * exceptions. The returned function has the following @@ -240,25 +193,33 @@ mono_arm_throw_exception_by_token (guint32 type_token, unsigned long eip, unsign * */ static gpointer -mono_arch_get_throw_exception_generic (int size, int by_token, gboolean rethrow, guint32 *code_size, MonoJumpInfo **ji, gboolean aot) +get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm, gboolean resume_unwind, const char *tramp_name, MonoTrampInfo **info, gboolean aot) { guint8 *start; guint8 *code; - - *ji = NULL; + MonoJumpInfo *ji = NULL; + GSList *unwind_ops = NULL; code = start = mono_global_codeman_reserve (size); + mono_add_unwind_op_def_cfa (unwind_ops, code, start, ARMREG_SP, 0); + /* save all the regs on the stack */ ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP); ARM_PUSH (code, MONO_ARM_REGSAVE_MASK); + mono_add_unwind_op_def_cfa (unwind_ops, code, start, ARMREG_SP, MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t)); + mono_add_unwind_op_offset (unwind_ops, code, start, ARMREG_LR, - sizeof (mgreg_t)); + /* call throw_exception (exc, ip, sp, int_regs, fp_regs) */ /* caller sp */ - ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, 10 * 4); /* 10 saved regs */ + ARM_ADD_REG_IMM8 (code, ARMREG_R2, ARMREG_SP, MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t)); /* exc is already in place in r0 */ - if (by_token) { + if (corlib) { /* The caller ip is already in R1 */ + if (llvm) + /* Negate the ip adjustment done in mono_arm_throw_exception */ + ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4); } else { ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR); /* caller ip */ } @@ -271,14 +232,23 @@ mono_arch_get_throw_exception_generic (int size, int by_token, gboolean rethrow, ARM_ORR_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, rethrow); if (aot) { - *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, by_token ? "mono_arm_throw_exception_by_token" : "mono_arm_throw_exception"); + const char *icall_name; + + if (resume_unwind) + icall_name = "mono_arm_resume_unwind"; + else if (corlib) + icall_name = "mono_arm_throw_exception_by_token"; + else + icall_name = "mono_arm_throw_exception"; + + ji = mono_patch_info_list_prepend (ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name); ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0); ARM_B (code, 0); *(gpointer*)(gpointer)code = NULL; code += 4; ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_PC, ARMREG_IP); } else { - code = mono_arm_emit_load_imm (code, ARMREG_IP, GPOINTER_TO_UINT (by_token ? (gpointer)mono_arm_throw_exception_by_token : (gpointer)mono_arm_throw_exception)); + 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))); } ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC); ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP); @@ -287,25 +257,12 @@ mono_arch_get_throw_exception_generic (int size, int by_token, gboolean rethrow, g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); - *code_size = code - start; + if (info) + *info = mono_tramp_info_create (g_strdup_printf (tramp_name), start, code - start, ji, unwind_ops); return start; } -/** - * mono_arch_get_rethrow_exception: - * - * Returns a function pointer which can be used to rethrow - * exceptions. The returned function has the following - * signature: void (*func) (MonoException *exc); - * - */ -gpointer -mono_arch_get_rethrow_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot) -{ - return mono_arch_get_throw_exception_generic (132, FALSE, TRUE, code_size, ji, aot); -} - /** * arch_get_throw_exception: * @@ -319,27 +276,23 @@ mono_arch_get_rethrow_exception_full (guint32 *code_size, MonoJumpInfo **ji, gbo * */ gpointer -mono_arch_get_throw_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot) +mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot) { - return mono_arch_get_throw_exception_generic (132, FALSE, FALSE, code_size, ji, aot); + return get_throw_trampoline (132, FALSE, FALSE, FALSE, FALSE, "throw_exception", info, aot); } -gpointer -mono_arch_get_throw_exception_by_name_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot) -{ - guint8* start; - guint8 *code; - - *ji = NULL; - - start = code = mono_global_codeman_reserve (64); - - /* Not used on ARM */ - ARM_DBRK (code); - - *code_size = code - start; - - return start; +/** + * mono_arch_get_rethrow_exception: + * + * Returns a function pointer which can be used to rethrow + * exceptions. The returned function has the following + * signature: void (*func) (MonoException *exc); + * + */ +gpointer +mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot) +{ + return get_throw_trampoline (132, FALSE, TRUE, FALSE, FALSE, "rethrow_exception", info, aot); } /** @@ -354,27 +307,72 @@ mono_arch_get_throw_exception_by_name_full (guint32 *code_size, MonoJumpInfo **j * On ARM, the ip is passed instead of an offset. */ gpointer -mono_arch_get_throw_corlib_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot) +mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { - return mono_arch_get_throw_exception_generic (168, TRUE, FALSE, code_size, ji, aot); + return get_throw_trampoline (168, TRUE, FALSE, FALSE, FALSE, "throw_corlib_exception", info, aot); } +GSList* +mono_arm_get_exception_trampolines (gboolean aot) +{ + MonoTrampInfo *info; + GSList *tramps = NULL; + + /* LLVM uses the normal trampolines, but with a different name */ + get_throw_trampoline (168, TRUE, FALSE, FALSE, FALSE, "llvm_throw_corlib_exception_trampoline", &info, aot); + tramps = g_slist_prepend (tramps, info); + + get_throw_trampoline (168, TRUE, FALSE, TRUE, FALSE, "llvm_throw_corlib_exception_abs_trampoline", &info, aot); + tramps = g_slist_prepend (tramps, info); + + get_throw_trampoline (168, FALSE, FALSE, FALSE, TRUE, "llvm_resume_unwind_trampoline", &info, aot); + tramps = g_slist_prepend (tramps, info); + + return tramps; +} + +void +mono_arch_exceptions_init (void) +{ + guint8 *tramp; + GSList *tramps, *l; + + if (mono_aot_only) { + tramp = mono_aot_get_trampoline ("llvm_throw_corlib_exception_trampoline"); + mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_trampoline", NULL, TRUE); + tramp = mono_aot_get_trampoline ("llvm_throw_corlib_exception_abs_trampoline"); + mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_abs_trampoline", NULL, TRUE); + tramp = mono_aot_get_trampoline ("llvm_resume_unwind_trampoline"); + mono_register_jit_icall (tramp, "llvm_resume_unwind_trampoline", NULL, TRUE); + } else { + tramps = mono_arm_get_exception_trampolines (FALSE); + for (l = tramps; l; l = l->next) { + MonoTrampInfo *info = l->data; + + mono_register_jit_icall (info->code, g_strdup (info->name), NULL, TRUE); + mono_save_trampoline_xdebug_info (info); + mono_tramp_info_free (info); + } + g_slist_free (tramps); + } +} + /* - * mono_arch_find_jit_info_ext: + * mono_arch_find_jit_info: * * See exceptions-amd64.c for docs; */ gboolean -mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, +mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *ctx, - MonoContext *new_ctx, MonoLMF **lmf, + MonoContext *new_ctx, MonoLMF **lmf, + mgreg_t **save_locations, StackFrameInfo *frame) { gpointer ip = MONO_CONTEXT_GET_IP (ctx); memset (frame, 0, sizeof (StackFrameInfo)); frame->ji = ji; - frame->managed = FALSE; *new_ctx = *ctx; @@ -387,9 +385,6 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, frame->type = FRAME_TYPE_MANAGED; - if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) - frame->managed = TRUE; - if (ji->from_aot) unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len); else @@ -397,25 +392,27 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, for (i = 0; i < 16; ++i) regs [i] = new_ctx->regs [i]; - regs [ARMREG_SP] = new_ctx->esp; mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, (guint8*)ji->code_start + ji->code_size, - ip, regs, MONO_MAX_IREGS, &cfa); + ip, regs, MONO_MAX_IREGS, + save_locations, MONO_MAX_IREGS, &cfa); for (i = 0; i < 16; ++i) new_ctx->regs [i] = regs [i]; - new_ctx->eip = regs [ARMREG_LR]; - new_ctx->esp = (gsize)cfa; - new_ctx->ebp = new_ctx->esp; + new_ctx->pc = regs [ARMREG_LR]; + new_ctx->regs [ARMREG_SP] = (gsize)cfa; - if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) { + if (*lmf && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->sp)) { /* remove any unused lmf */ *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3); } + /* Clear thumb bit */ + new_ctx->pc &= ~1; + /* we substract 1, so that the IP points into the call instruction */ - new_ctx->eip--; + new_ctx->pc--; return TRUE; } else if (*lmf) { @@ -440,7 +437,7 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, frame->type = FRAME_TYPE_MANAGED_TO_NATIVE; - if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) { + if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->ip, NULL))) { frame->ji = ji; } else { if (!(*lmf)->method) @@ -448,13 +445,24 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, frame->method = (*lmf)->method; } - memcpy (&new_ctx->regs [0], &(*lmf)->iregs [0], sizeof (gulong) * 13); - /* SP is skipped */ - new_ctx->regs [ARMREG_LR] = (*lmf)->iregs [ARMREG_LR - 1]; - /* This is the sp for the current frame */ - new_ctx->esp = (*lmf)->iregs [ARMREG_FP]; - new_ctx->eip = (*lmf)->iregs [13]; - new_ctx->ebp = new_ctx->esp; + /* + * The LMF is saved at the start of the method using: + * ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP) + * ARM_PUSH (code, 0x5ff0); + * So it stores the register state as it existed at the caller. We need to + * produce the register state which existed at the time of the call which + * transitioned to native call, so we save the sp/fp/ip in the LMF. + */ + memcpy (&new_ctx->regs [0], &(*lmf)->iregs [0], sizeof (mgreg_t) * 13); + new_ctx->pc = (*lmf)->ip; + new_ctx->regs [ARMREG_SP] = (*lmf)->sp; + new_ctx->regs [ARMREG_FP] = (*lmf)->fp; + + /* Clear thumb bit */ + new_ctx->pc &= ~1; + + /* we substract 1, so that the IP points into the call instruction */ + new_ctx->pc--; *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3); @@ -467,66 +475,143 @@ mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, void mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx) { -#if BROKEN_LINUX - g_assert_not_reached (); -#else - my_ucontext *my_uc = sigctx; - - mctx->eip = UCONTEXT_REG_PC (my_uc); - mctx->esp = UCONTEXT_REG_SP (my_uc); - memcpy (&mctx->regs, &UCONTEXT_REG_R0 (my_uc), sizeof (gulong) * 16); -#endif - mctx->ebp = mctx->regs [ARMREG_FP]; + mono_sigctx_to_monoctx (sigctx, mctx); } void mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *ctx) { -#if BROKEN_LINUX - g_assert_not_reached (); -#else - my_ucontext *my_uc = ctx; + mono_monoctx_to_sigctx (mctx, ctx); +} + +/* + * handle_exception: + * + * Called by resuming from a signal handler. + */ +static void +handle_signal_exception (gpointer obj) +{ + MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); + MonoContext ctx; + static void (*restore_context) (MonoContext *); + + if (!restore_context) + restore_context = mono_get_restore_context (); + + memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext)); + + mono_handle_exception (&ctx, obj); + + restore_context (&ctx); +} - UCONTEXT_REG_PC (my_uc) = mctx->eip; - UCONTEXT_REG_SP (my_uc) = mctx->ebp; - /* The upper registers are not guaranteed to be valid */ - memcpy (&UCONTEXT_REG_R0 (my_uc), &mctx->regs, sizeof (gulong) * 12); +/* + * This works around a gcc 4.5 bug: + * https://bugs.launchpad.net/ubuntu/+source/gcc-4.5/+bug/721531 + */ +#if defined(__GNUC__) +__attribute__((noinline)) #endif +static gpointer +get_handle_signal_exception_addr (void) +{ + return handle_signal_exception; } /* * This is the function called from the signal handler */ gboolean -mono_arch_handle_exception (void *ctx, gpointer obj, gboolean test_only) +mono_arch_handle_exception (void *ctx, gpointer obj) { +#if defined(MONO_CROSS_COMPILE) + g_assert_not_reached (); +#elif defined(MONO_ARCH_USE_SIGACTION) + arm_ucontext *sigctx = ctx; + /* + * Handling the exception in the signal handler is problematic, since the original + * signal is disabled, and we could run arbitrary code though the debugger. So + * resume into the normal stack and do most work there if possible. + */ + MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); + guint64 sp = UCONTEXT_REG_SP (sigctx); + + /* Pass the ctx parameter in TLS */ + mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx); + /* The others in registers */ + UCONTEXT_REG_R0 (sigctx) = (gsize)obj; + + /* Allocate a stack frame */ + sp -= 16; + UCONTEXT_REG_SP (sigctx) = sp; + + UCONTEXT_REG_PC (sigctx) = (gsize)get_handle_signal_exception_addr (); +#ifdef UCONTEXT_REG_CPSR + if ((gsize)UCONTEXT_REG_PC (sigctx) & 1) + /* Transition to thumb */ + UCONTEXT_REG_CPSR (sigctx) |= (1 << 5); + else + /* Transition to ARM */ + UCONTEXT_REG_CPSR (sigctx) &= ~(1 << 5); +#endif + + return TRUE; +#else MonoContext mctx; gboolean result; mono_arch_sigctx_to_monoctx (ctx, &mctx); - result = mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only); + result = mono_handle_exception (&mctx, obj); /* restore the context so that returning from the signal handler will invoke * the catch clause */ mono_arch_monoctx_to_sigctx (&mctx, ctx); return result; +#endif } gpointer mono_arch_ip_from_context (void *sigctx) { -#if BROKEN_LINUX +#ifdef MONO_CROSS_COMPILE g_assert_not_reached (); #else - my_ucontext *my_uc = sigctx; + arm_ucontext *my_uc = sigctx; return (void*) UCONTEXT_REG_PC (my_uc); #endif } -gboolean -mono_arch_has_unwind_info (gconstpointer addr) +void +mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data) { - return FALSE; + mgreg_t sp = (mgreg_t)MONO_CONTEXT_GET_SP (ctx); + + // FIXME: + g_assert (!user_data); + + /* Allocate a stack frame */ + sp -= 16; + MONO_CONTEXT_SET_SP (ctx, sp); + MONO_CONTEXT_SET_IP (ctx, async_cb); + + // FIXME: thumb/arm } +/* + * mono_arch_setup_resume_sighandler_ctx: + * + * Setup CTX so execution continues at FUNC. + */ +void +mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func) +{ + MONO_CONTEXT_SET_IP (ctx,func); + if ((mgreg_t)MONO_CONTEXT_GET_IP (ctx) & 1) + /* Transition to thumb */ + ctx->cpsr |= (1 << 5); + else + /* Transition to ARM */ + ctx->cpsr &= ~(1 << 5); +}