static int intern_regions (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr, unw_dyn_region_info_t **regionp, void *arg) { uint32_t insn_count, op_count, i; unw_dyn_region_info_t *region; unw_word_t next_addr; int ret; *regionp = NULL; if (!*addr) return 0; /* NULL region-list */ if ((ret = fetchw (as, a, addr, &next_addr, arg)) < 0 || (ret = fetch32 (as, a, addr, (int32_t *) &insn_count, arg)) < 0 || (ret = fetch32 (as, a, addr, (int32_t *) &op_count, arg)) < 0) return ret; region = calloc (1, _U_dyn_region_info_size (op_count)); if (!region) { ret = -UNW_ENOMEM; goto out; } region->insn_count = insn_count; region->op_count = op_count; for (i = 0; i < op_count; ++i) if ((ret = intern_op (as, a, addr, region->op + i, arg)) < 0) goto out; if (next_addr) if ((ret = intern_regions (as, a, &next_addr, ®ion->next, arg)) < 0) goto out; *regionp = region; return 0; out: if (region) free_regions (region); return ret; }
/** * mono_arch_get_throw_corlib_exception: * * Returns a function pointer which can be used to raise * corlib exceptions. The returned function has the following * signature: void (*func) (guint32 ex_token_index, guint32 offset); * Here, offset is the offset which needs to be substracted from the caller IP * to get the IP of the throw. Passing the offset has the advantage that it * needs no relocations in the caller. */ gpointer mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot) { static guint8* res; static gboolean inited = FALSE; guint8 *start; gpointer ptr; int i, in0, local0, out0, nout; Ia64CodegenState code; unw_dyn_info_t *di; unw_dyn_region_info_t *r_pro; g_assert (!aot); if (info) *info = NULL; if (inited) return res; start = mono_global_codeman_reserve (1024); in0 = 32; local0 = in0 + 2; out0 = local0 + 4; nout = 3; ia64_codegen_init (code, start); ia64_alloc (code, local0 + 0, local0 - in0, out0 - local0, nout, 0); ia64_mov_from_br (code, local0 + 1, IA64_RP); r_pro = g_malloc0 (_U_dyn_region_info_size (2)); r_pro->op_count = 2; r_pro->insn_count = 6; i = 0; _U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 2, /* reg=*/ UNW_IA64_AR_PFS, /* dst=*/ UNW_IA64_GR + local0 + 0); _U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 5, /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + local0 + 1); g_assert ((unsigned) i <= r_pro->op_count); /* Call exception_from_token */ ia64_movl (code, out0 + 0, mono_defaults.exception_class->image); ia64_mov (code, out0 + 1, in0 + 0); ia64_movl (code, GP_SCRATCH_REG, MONO_TOKEN_TYPE_DEF); ia64_add (code, out0 + 1, in0 + 0, GP_SCRATCH_REG); ptr = mono_exception_from_token; ia64_movl (code, GP_SCRATCH_REG, ptr); ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8); ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2); ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG); ia64_br_call_reg (code, IA64_B0, IA64_B6); ia64_mov (code, local0 + 3, IA64_R8); /* Compute throw ip */ ia64_mov (code, local0 + 2, local0 + 1); ia64_sub (code, local0 + 2, local0 + 2, in0 + 1); /* Trick the unwind library into using throw_ip as the IP in the caller frame */ ia64_mov (code, local0 + 1, local0 + 2); /* Set args */ ia64_mov (code, out0 + 0, local0 + 3); ia64_mov (code, out0 + 1, IA64_R0); /* Call throw_exception */ ptr = throw_exception; ia64_movl (code, GP_SCRATCH_REG, ptr); ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8); ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2); ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG); ia64_br_call_reg (code, IA64_B0, IA64_B6); ia64_break_i (code, 1002); ia64_codegen_close (code); g_assert ((code.buf - start) <= 1024); di = g_malloc0 (sizeof (unw_dyn_info_t)); di->start_ip = (unw_word_t) start; di->end_ip = (unw_word_t) code.buf; di->gp = 0; di->format = UNW_INFO_FORMAT_DYNAMIC; di->u.pi.name_ptr = (unw_word_t)"throw_corlib_exception_trampoline"; di->u.pi.regions = r_pro; _U_dyn_register (di); mono_arch_flush_icache (start, code.buf - start); res = ia64_create_ftnptr (start); inited = TRUE; return res; }
static gpointer get_throw_trampoline (gboolean rethrow) { guint8* start; Ia64CodegenState code; gpointer ptr = throw_exception; int i, in0, local0, out0; unw_dyn_info_t *di; unw_dyn_region_info_t *r_pro; start = mono_global_codeman_reserve (256); in0 = 32; local0 = in0 + 1; out0 = local0 + 2; ia64_codegen_init (code, start); ia64_alloc (code, local0 + 0, local0 - in0, out0 - local0, 3, 0); ia64_mov_from_br (code, local0 + 1, IA64_B0); /* FIXME: This depends on the current instruction emitter */ r_pro = g_malloc0 (_U_dyn_region_info_size (2)); r_pro->op_count = 2; r_pro->insn_count = 6; i = 0; _U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 2, /* reg=*/ UNW_IA64_AR_PFS, /* dst=*/ UNW_IA64_GR + local0 + 0); _U_dyn_op_save_reg (&r_pro->op[i++], _U_QP_TRUE, /* when=*/ 5, /* reg=*/ UNW_IA64_RP, /* dst=*/ UNW_IA64_GR + local0 + 1); g_assert ((unsigned) i <= r_pro->op_count); /* Set args */ ia64_mov (code, out0 + 0, in0 + 0); ia64_adds_imm (code, out0 + 1, rethrow, IA64_R0); /* Call throw_exception */ ia64_movl (code, GP_SCRATCH_REG, ptr); ia64_ld8_inc_imm (code, GP_SCRATCH_REG2, GP_SCRATCH_REG, 8); ia64_mov_to_br (code, IA64_B6, GP_SCRATCH_REG2); ia64_ld8 (code, IA64_GP, GP_SCRATCH_REG); ia64_br_call_reg (code, IA64_B0, IA64_B6); /* Not reached */ ia64_break_i (code, 1000); ia64_codegen_close (code); g_assert ((code.buf - start) <= 256); mono_arch_flush_icache (start, code.buf - start); di = g_malloc0 (sizeof (unw_dyn_info_t)); di->start_ip = (unw_word_t) start; di->end_ip = (unw_word_t) code.buf; di->gp = 0; di->format = UNW_INFO_FORMAT_DYNAMIC; di->u.pi.name_ptr = (unw_word_t)"throw_trampoline"; di->u.pi.regions = r_pro; _U_dyn_register (di); return ia64_create_ftnptr (start); }