/* * mono_save_xdebug_info: * * Emit debugging info for METHOD into an assembly file which can be assembled * and loaded into gdb to provide debugging info for JITted code. * LOCKING: Acquires the loader lock. */ void mono_save_xdebug_info (MonoCompile *cfg) { MonoDebugMethodJitInfo *dmji; if (use_gdb_interface) { mono_loader_lock (); if (!xdebug_syms) xdebug_syms = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); /* * gdb is not designed to handle 1000s of symbol files (one per method). So we * group them into groups of 100. */ if ((xdebug_method_count % 100) == 0) mono_xdebug_flush (); xdebug_method_count ++; dmji = mono_debug_find_method (jinfo_get_method (cfg->jit_info), mono_domain_get ());; mono_dwarf_writer_emit_method (xdebug_writer, cfg, jinfo_get_method (cfg->jit_info), NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, dmji); mono_debug_free_method_jit_info (dmji); #if 0 /* * Emit a symbol for the code by emitting it at the beginning of the text * segment, and setting the text segment to have an absolute address. * This symbol can be used to set breakpoints in gdb. * FIXME: This doesn't work when multiple methods are emitted into the same file. */ sym = get_debug_sym (cfg->jit_info->method, "", xdebug_syms); img_writer_emit_section_change (w, ".text", 0); if (!xdebug_text_addr) { xdebug_text_addr = cfg->jit_info->code_start; img_writer_set_section_addr (w, (gssize)xdebug_text_addr); } img_writer_emit_global_with_size (w, sym, cfg->jit_info->code_size, TRUE); img_writer_emit_label (w, sym); img_writer_emit_bytes (w, cfg->jit_info->code_start, cfg->jit_info->code_size); g_free (sym); #endif mono_loader_unlock (); } else { if (!xdebug_writer) return; mono_loader_lock (); dmji = mono_debug_find_method (jinfo_get_method (cfg->jit_info), mono_domain_get ()); mono_dwarf_writer_emit_method (xdebug_writer, cfg, jinfo_get_method (cfg->jit_info), NULL, NULL, cfg->jit_info->code_start, cfg->jit_info->code_size, cfg->args, cfg->locals, cfg->unwind_ops, dmji); mono_debug_free_method_jit_info (dmji); fflush (xdebug_fp); mono_loader_unlock (); } }
MonoSecurityFrame* mono_declsec_create_frame (MonoDomain *domain, MonoJitInfo *jinfo) { MonoSecurityFrame *frame = (MonoSecurityFrame*) mono_object_new (domain, mono_defaults.runtimesecurityframe_class); MonoMethodCasInfo *info; MonoMethod *method; method = jinfo_get_method (jinfo); info = mono_jit_info_get_cas_info (jinfo); if (info && !info->cas_inited) { if (mono_method_has_declsec (method)) { /* Cache the stack modifiers into the MonoJitInfo structure to speed up future stack walks */ mono_declsec_cache_stack_modifiers (jinfo); } info->cas_inited = TRUE; } MONO_OBJECT_SETREF (frame, method, mono_method_get_object (domain, method, NULL)); MONO_OBJECT_SETREF (frame, domain, domain->domain); /* stack modifiers on methods have priority on (i.e. replaces) modifiers on class */ if (info && info->cas_method_assert) { mono_declsec_get_method_action (method, SECURITY_ACTION_ASSERT, &frame->assert); } else if (info && info->cas_class_assert) { mono_declsec_get_class_action (method->klass, SECURITY_ACTION_ASSERT, &frame->assert); } if (info && info->cas_method_deny) { mono_declsec_get_method_action (method, SECURITY_ACTION_DENY, &frame->deny); } else if (info && info->cas_class_deny) { mono_declsec_get_class_action (method->klass, SECURITY_ACTION_DENY, &frame->deny); } if (info && info->cas_method_permitonly) { mono_declsec_get_method_action (method, SECURITY_ACTION_PERMITONLY, &frame->permitonly); } else if (info && info->cas_class_permitonly) { mono_declsec_get_class_action (method->klass, SECURITY_ACTION_PERMITONLY, &frame->permitonly); } /* g_warning ("FRAME %s A(%p,%d) D(%p,%d) PO(%p,%d)", method->name, frame->assert.blob, frame->assert.size, frame->deny.blob, frame->deny.size, frame->permitonly.blob,frame->permitonly.size); */ return frame; }
/* * Fill actions for the specific index (which may either be an encoded class token or * an encoded method token) from the metadata image. * Returns TRUE if some actions requiring code generation are present, FALSE otherwise. */ void mono_declsec_cache_stack_modifiers (MonoJitInfo *jinfo) { MonoMethodCasInfo *info = mono_jit_info_get_cas_info (jinfo); MonoMethod *method; guint32 flags; if (!info) return; method = jinfo_get_method (jinfo); /* first find the stack modifiers applied to the method */ flags = mono_declsec_flags_from_method (method); info->cas_method_assert = (flags & MONO_DECLSEC_FLAG_ASSERT) != 0; info->cas_method_deny = (flags & MONO_DECLSEC_FLAG_DENY) != 0; info->cas_method_permitonly = (flags & MONO_DECLSEC_FLAG_PERMITONLY) != 0; /* then find the stack modifiers applied to the class */ flags = mono_declsec_flags_from_class (method->klass); info->cas_class_assert = (flags & MONO_DECLSEC_FLAG_ASSERT) != 0; info->cas_class_deny = (flags & MONO_DECLSEC_FLAG_DENY) != 0; info->cas_class_permitonly = (flags & MONO_DECLSEC_FLAG_PERMITONLY) != 0; }
static MonoException* continuation_mark_frame (MonoContinuation *cont) { MonoJitTlsData *jit_tls; MonoLMF *lmf; MonoContext ctx, new_ctx; MonoJitInfo *ji, rji; int endloop = FALSE; if (cont->domain) return mono_get_exception_argument ("cont", "Already marked"); jit_tls = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id); lmf = mono_get_lmf(); cont->domain = mono_domain_get (); cont->thread_id = mono_native_thread_id_get (); /* get to the frame that called Mark () */ memset (&rji, 0, sizeof (rji)); memset (&ctx, 0, sizeof (ctx)); do { ji = mono_find_jit_info (cont->domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, NULL); if (!ji || ji == (gpointer)-1) { return mono_get_exception_not_supported ("Invalid stack frame"); } ctx = new_ctx; if (endloop) break; if (!ji->is_trampoline && strcmp (jinfo_get_method (ji)->name, "Mark") == 0) endloop = TRUE; } while (1); cont->top_sp = MONO_CONTEXT_GET_SP (&ctx); /*g_print ("method: %s, sp: %p\n", jinfo_get_method (ji)->name, cont->top_sp);*/ return NULL; }
void mono_arch_handle_altstack_exception (void *sigctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, gpointer fault_addr, gboolean stack_ovf) { #ifdef MONO_CROSS_COMPILE g_assert_not_reached (); #else #ifdef MONO_ARCH_USE_SIGACTION os_ucontext *uc = (ucontext_t*)sigctx; os_ucontext *uc_copy; MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (sigctx), NULL); gpointer *sp; int frame_size; if (stack_ovf) { const char *method; /* we don't do much now, but we can warn the user with a useful message */ fprintf (stderr, "Stack overflow: IP: %p, SP: %p\n", mono_arch_ip_from_context (sigctx), (gpointer)UCONTEXT_REG_Rn(uc, 1)); if (ji && !ji->is_trampoline && jinfo_get_method (ji)) method = mono_method_full_name (jinfo_get_method (ji), TRUE); else method = "Unmanaged"; fprintf (stderr, "At %s\n", method); abort (); } if (!ji) mono_handle_native_crash ("SIGSEGV", sigctx, siginfo); /* setup a call frame on the real stack so that control is returned there * and exception handling can continue. * The frame looks like: * ucontext struct * ... * 224 is the size of the red zone */ frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 16 + 224; frame_size += 15; frame_size &= ~15; sp = (gpointer)(UCONTEXT_REG_Rn(uc, 1) & ~15); sp = (gpointer)((char*)sp - frame_size); /* may need to adjust pointers in the new struct copy, depending on the OS */ uc_copy = (ucontext_t*)(sp + 16); memcpy (uc_copy, uc, sizeof (os_ucontext)); #if defined(__linux__) && !defined(__mono_ppc64__) uc_copy->uc_mcontext.uc_regs = (gpointer)((char*)uc_copy + ((char*)uc->uc_mcontext.uc_regs - (char*)uc)); #endif g_assert (mono_arch_ip_from_context (uc) == mono_arch_ip_from_context (uc_copy)); /* at the return form the signal handler execution starts in altstack_handle_and_restore() */ UCONTEXT_REG_LNK(uc) = UCONTEXT_REG_NIP(uc); #ifdef PPC_USES_FUNCTION_DESCRIPTOR { MonoPPCFunctionDescriptor *handler_ftnptr = (MonoPPCFunctionDescriptor*)altstack_handle_and_restore; UCONTEXT_REG_NIP(uc) = (gulong)handler_ftnptr->code; UCONTEXT_REG_Rn(uc, 2) = (gulong)handler_ftnptr->toc; } #else UCONTEXT_REG_NIP(uc) = (unsigned long)altstack_handle_and_restore; #if _CALL_ELF == 2 /* ELF v2 ABI calling convention requires to put the target address into * r12 if we use the global entry point of a function. */ UCONTEXT_REG_Rn(uc, 12) = (unsigned long) altstack_handle_and_restore; #endif #endif UCONTEXT_REG_Rn(uc, 1) = (unsigned long)sp; UCONTEXT_REG_Rn(uc, PPC_FIRST_ARG_REG) = (unsigned long)(sp + 16); UCONTEXT_REG_Rn(uc, PPC_FIRST_ARG_REG + 1) = 0; UCONTEXT_REG_Rn(uc, PPC_FIRST_ARG_REG + 2) = 0; #endif #endif /* !MONO_CROSS_COMPILE */ }
/* * mono_arch_unwind_frame: * * See exceptions-amd64.c for docs. */ gboolean mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, mgreg_t **save_locations, StackFrameInfo *frame) { gpointer ip = MONO_CONTEXT_GET_IP (ctx); MonoPPCStackFrame *sframe; memset (frame, 0, sizeof (StackFrameInfo)); frame->ji = ji; *new_ctx = *ctx; setup_context (new_ctx); if (ji != NULL) { int i; mgreg_t regs [ppc_lr + 1]; guint8 *cfa; guint32 unwind_info_len; guint8 *unwind_info; if (ji->is_trampoline) frame->type = FRAME_TYPE_TRAMPOLINE; else frame->type = FRAME_TYPE_MANAGED; unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len); sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx); MONO_CONTEXT_SET_BP (new_ctx, sframe->sp); if (!ji->is_trampoline && jinfo_get_method (ji)->save_lmf) { /* sframe->sp points just past the end of the LMF */ guint8 *lmf_addr = (guint8*)sframe->sp - sizeof (MonoLMF); memcpy (&new_ctx->fregs [MONO_PPC_FIRST_SAVED_FREG], lmf_addr + G_STRUCT_OFFSET (MonoLMF, fregs), sizeof (double) * MONO_SAVED_FREGS); memcpy (&new_ctx->regs [MONO_PPC_FIRST_SAVED_GREG], lmf_addr + G_STRUCT_OFFSET (MonoLMF, iregs), sizeof (mgreg_t) * MONO_SAVED_GREGS); /* the calling IP is in the parent frame */ sframe = (MonoPPCStackFrame*)sframe->sp; /* we substract 4, so that the IP points into the call instruction */ MONO_CONTEXT_SET_IP (new_ctx, sframe->lr - 4); } else { regs [ppc_lr] = ctx->sc_ir; regs [ppc_sp] = ctx->sc_sp; for (i = MONO_PPC_FIRST_SAVED_GREG; i < MONO_MAX_IREGS; ++i) regs [i] = ctx->regs [i]; mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, (guint8*)ji->code_start + ji->code_size, ip, NULL, regs, ppc_lr + 1, save_locations, MONO_MAX_IREGS, &cfa); /* we substract 4, so that the IP points into the call instruction */ MONO_CONTEXT_SET_IP (new_ctx, regs [ppc_lr] - 4); MONO_CONTEXT_SET_BP (new_ctx, cfa); for (i = MONO_PPC_FIRST_SAVED_GREG; i < MONO_MAX_IREGS; ++i) new_ctx->regs [i] = regs [i]; } return TRUE; } else if (*lmf) { if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) { } else { if (!(*lmf)->method) return FALSE; /* Trampoline lmf frame */ frame->method = (*lmf)->method; } /*sframe = (MonoPPCStackFrame*)MONO_CONTEXT_GET_SP (ctx); MONO_CONTEXT_SET_BP (new_ctx, sframe->sp); MONO_CONTEXT_SET_IP (new_ctx, sframe->lr);*/ MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp); MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip); memcpy (&new_ctx->regs [MONO_PPC_FIRST_SAVED_GREG], (*lmf)->iregs, sizeof (mgreg_t) * MONO_SAVED_GREGS); memcpy (&new_ctx->fregs [MONO_PPC_FIRST_SAVED_FREG], (*lmf)->fregs, sizeof (double) * MONO_SAVED_FREGS); frame->ji = ji; frame->type = FRAME_TYPE_MANAGED_TO_NATIVE; /* FIXME: what about trampoline LMF frames? see exceptions-x86.c */ *lmf = (*lmf)->previous_lmf; return TRUE; } return FALSE; }
/* * mini_add_method_trampoline: * * Add static rgctx/gsharedvt_in/unbox trampolines to M/COMPILED_METHOD if needed. Return the trampoline address, or * COMPILED_METHOD if no trampoline is needed. * ORIG_METHOD is the method the caller originally called i.e. an iface method, or NULL. */ gpointer mini_add_method_trampoline (MonoMethod *orig_method, MonoMethod *m, gpointer compiled_method, gboolean add_static_rgctx_tramp, gboolean add_unbox_tramp) { gpointer addr = compiled_method; gboolean callee_gsharedvt, callee_array_helper; MonoMethod *jmethod = NULL; MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), mono_get_addr_from_ftnptr (compiled_method), NULL); // FIXME: This loads information from AOT callee_gsharedvt = mini_jit_info_is_gsharedvt (ji); callee_array_helper = FALSE; if (m->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) { WrapperInfo *info = mono_marshal_get_wrapper_info (m); /* * generic array helpers. * Have to replace the wrappers with the original generic instances. */ if (info && info->subtype == WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER) { callee_array_helper = TRUE; m = info->d.generic_array_helper.method; } } else if (m->wrapper_type == MONO_WRAPPER_UNKNOWN) { WrapperInfo *info = mono_marshal_get_wrapper_info (m); /* Same for synchronized inner wrappers */ if (info && info->subtype == WRAPPER_SUBTYPE_SYNCHRONIZED_INNER) { m = info->d.synchronized_inner.method; } } if (!orig_method) orig_method = m; if (callee_gsharedvt) g_assert (m->is_inflated); addr = compiled_method; if (add_unbox_tramp) { /* * The unbox trampolines call the method directly, so need to add * an rgctx tramp before them. */ if (mono_aot_only) { addr = mono_aot_get_unbox_trampoline (m); } else { unbox_trampolines ++; addr = mono_arch_get_unbox_trampoline (m, addr); } } if (ji) jmethod = jinfo_get_method (ji); if (callee_gsharedvt && mini_is_gsharedvt_variable_signature (mono_method_signature (jmethod))) { MonoGenericSharingContext *gsctx; MonoMethodSignature *sig, *gsig; /* Here m is a generic instance, while ji->method is the gsharedvt method implementing it */ /* Call from normal/gshared code to gsharedvt code with variable signature */ gsctx = mono_jit_info_get_generic_sharing_context (ji); sig = mono_method_signature (m); gsig = mono_method_signature (jmethod); addr = mini_get_gsharedvt_wrapper (TRUE, addr, sig, gsig, gsctx, -1, FALSE); //printf ("IN: %s\n", mono_method_full_name (m, TRUE)); } if (add_static_rgctx_tramp && !callee_array_helper) addr = mono_create_static_rgctx_trampoline (m, addr); return addr; }