/* Special hack to workaround the fact that the * when the SEH handler is called the stack is * to small to recover. * * Stack walking part of this method is from mono_handle_exception * * The idea is simple; * - walk the stack to free some space (64k) * - set esp to new stack location * - call mono_arch_handle_exception with stack overflow exception * - set esp to SEH handlers stack * - done */ static void win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) { SYSTEM_INFO si; DWORD page_size; MonoDomain *domain = mono_domain_get (); MonoJitInfo rji; MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); MonoLMF *lmf = jit_tls->lmf; MonoContext initial_ctx; MonoContext ctx; guint32 free_stack = 0; StackFrameInfo frame; /* convert sigcontext to MonoContext (due to reuse of stack walking helpers */ mono_arch_sigctx_to_monoctx (sctx, &ctx); /* get our os page size */ GetSystemInfo(&si); page_size = si.dwPageSize; /* Let's walk the stack to recover * the needed stack space (if possible) */ memset (&rji, 0, sizeof (rji)); initial_ctx = ctx; free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx)); /* try to free 64kb from our stack */ do { MonoContext new_ctx; mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, &lmf, NULL, &frame); if (!frame.ji) { g_warning ("Exception inside function without unwind info"); g_assert_not_reached (); } if (frame.ji != (gpointer)-1) { free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx)); } /* todo: we should call abort if ji is -1 */ ctx = new_ctx; } while (free_stack < 64 * 1024 && frame.ji != (gpointer) -1); /* convert into sigcontext to be used in mono_arch_handle_exception */ mono_arch_monoctx_to_sigctx (&ctx, sctx); /* todo: install new stack-guard page */ /* use the new stack and call mono_arch_handle_exception () */ restore_stack (sctx); }
static void mono_native_state_add_ctx (MonoStateWriter *writer, MonoContext *ctx) { // Context mono_state_writer_indent (writer); mono_state_writer_object_key (writer, "ctx"); mono_state_writer_printf(writer, "{\n"); writer->indent++; assert_has_space (writer); mono_state_writer_indent (writer); mono_state_writer_object_key (writer, "IP"); mono_state_writer_printf(writer, "\"%p\",\n", (gpointer) MONO_CONTEXT_GET_IP (ctx)); assert_has_space (writer); mono_state_writer_indent (writer); mono_state_writer_object_key (writer, "SP"); mono_state_writer_printf(writer, "\"%p\",\n", (gpointer) MONO_CONTEXT_GET_SP (ctx)); assert_has_space (writer); mono_state_writer_indent (writer); mono_state_writer_object_key (writer, "BP"); mono_state_writer_printf(writer, "\"%p\"\n", (gpointer) MONO_CONTEXT_GET_BP (ctx)); writer->indent--; mono_state_writer_indent (writer); mono_state_writer_printf(writer, "}"); }
static int call_filter (MonoContext *ctx, gpointer ip) { int (*filter) (MonoContext *, gpointer); gpointer fp = MONO_CONTEXT_GET_BP (ctx); filter = get_real_call_filter (); return filter (fp, ip); }
/* mono_arch_find_jit_info: * * This function is used to gather information from @ctx. It return the * MonoJitInfo of the corresponding function, unwinds one stack frame and * stores the resulting context into @new_ctx. It also stores a string * describing the stack location into @trace (if not NULL), and modifies * the @lmf if necessary. @native_offset return the IP offset from the * start of the function or -1 if that info is not available. */ gboolean mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, mgreg_t **save_locations, StackFrameInfo *frame) { gpointer *window; memset (frame, 0, sizeof (StackFrameInfo)); frame->ji = ji; frame->managed = FALSE; *new_ctx = *ctx; if (ji != NULL) { frame->type = FRAME_TYPE_MANAGED; if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) { /* remove any unused lmf */ *lmf = (*lmf)->previous_lmf; } /* Restore ip and sp from the saved register window */ window = MONO_SPARC_WINDOW_ADDR (ctx->sp); new_ctx->ip = window [sparc_i7 - 16]; new_ctx->sp = (gpointer*)(window [sparc_i6 - 16]); new_ctx->fp = (gpointer*)(MONO_SPARC_WINDOW_ADDR (new_ctx->sp) [sparc_i6 - 16]); return TRUE; } else { if (!(*lmf)) return FALSE; if (!(*lmf)->method) return FALSE; ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->ip, NULL); if (!ji) return FALSE; frame->ji = ji; frame->type = FRAME_TYPE_MANAGED_TO_NATIVE; new_ctx->ip = (*lmf)->ip; new_ctx->sp = (*lmf)->sp; new_ctx->fp = (*lmf)->ebp; *lmf = (*lmf)->previous_lmf; return TRUE; } }
/* * mono_arch_find_jit_info: * * See exceptions-amd64.c for docs. */ gboolean mono_arch_find_jit_info (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); memset (frame, 0, sizeof (StackFrameInfo)); frame->ji = ji; *new_ctx = *ctx; if (ji != NULL) { gssize regs [MONO_MAX_IREGS + 1]; guint8 *cfa; guint32 unwind_info_len; guint8 *unwind_info; frame->type = FRAME_TYPE_MANAGED; if (ji->from_aot) unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len); else unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len); regs [X86_EAX] = new_ctx->eax; regs [X86_EBX] = new_ctx->ebx; regs [X86_ECX] = new_ctx->ecx; regs [X86_EDX] = new_ctx->edx; regs [X86_ESP] = new_ctx->esp; regs [X86_EBP] = new_ctx->ebp; regs [X86_ESI] = new_ctx->esi; regs [X86_EDI] = new_ctx->edi; regs [X86_NREG] = new_ctx->eip; mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, (guint8*)ji->code_start + ji->code_size, ip, regs, MONO_MAX_IREGS + 1, save_locations, MONO_MAX_IREGS, &cfa); new_ctx->eax = regs [X86_EAX]; new_ctx->ebx = regs [X86_EBX]; new_ctx->ecx = regs [X86_ECX]; new_ctx->edx = regs [X86_EDX]; new_ctx->esp = regs [X86_ESP]; new_ctx->ebp = regs [X86_EBP]; new_ctx->esi = regs [X86_ESI]; new_ctx->edi = regs [X86_EDI]; new_ctx->eip = regs [X86_NREG]; /* The CFA becomes the new SP value */ new_ctx->esp = (gssize)cfa; /* Adjust IP */ new_ctx->eip --; if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) { /* remove any unused lmf */ *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3); } /* Pop arguments off the stack */ /* * FIXME: LLVM doesn't push these, we can't use ji->from_llvm as it describes * the callee. */ #ifndef ENABLE_LLVM if (ji->has_arch_eh_info) new_ctx->esp += mono_jit_info_get_arch_eh_info (ji)->stack_size; #endif return TRUE; } else if (*lmf) { if (((guint64)(*lmf)->previous_lmf) & 2) { /* * This LMF entry is created by the soft debug code to mark transitions to * managed code done during invokes. */ MonoLMFExt *ext = (MonoLMFExt*)(*lmf); g_assert (ext->debugger_invoke); memcpy (new_ctx, &ext->ctx, sizeof (MonoContext)); *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3); frame->type = FRAME_TYPE_DEBUGGER_INVOKE; return TRUE; } if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) { } else { if (!((guint32)((*lmf)->previous_lmf) & 1)) /* Top LMF entry */ return FALSE; g_assert_not_reached (); /* Trampoline lmf frame */ frame->method = (*lmf)->method; } new_ctx->esi = (*lmf)->esi; new_ctx->edi = (*lmf)->edi; new_ctx->ebx = (*lmf)->ebx; new_ctx->ebp = (*lmf)->ebp; new_ctx->eip = (*lmf)->eip; /* Adjust IP */ new_ctx->eip --; frame->ji = ji; frame->type = FRAME_TYPE_MANAGED_TO_NATIVE; /* Check if we are in a trampoline LMF frame */ if ((guint32)((*lmf)->previous_lmf) & 1) { /* lmf->esp is set by the trampoline code */ new_ctx->esp = (*lmf)->esp; /* Pop arguments off the stack */ /* FIXME: Handle the delegate case too ((*lmf)->method == NULL) */ /* FIXME: Handle the IMT/vtable case too */ #if 0 #ifndef ENABLE_LLVM if ((*lmf)->method) { MonoMethod *method = (*lmf)->method; MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (method)->param_count + 1); guint32 stack_to_pop = mono_arch_get_argument_info (NULL, mono_method_signature (method), mono_method_signature (method)->param_count, arg_info); new_ctx->esp += stack_to_pop; } #endif #endif } else /* the lmf is always stored on the stack, so the following * expression points to a stack location which can be used as ESP */ new_ctx->esp = (unsigned long)&((*lmf)->eip); *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3); return TRUE; } return FALSE; }
static void SIG_HANDLER_SIGNATURE (sigprof_signal_handler) { int call_chain_depth = mono_profiler_stat_get_call_chain_depth (); MonoProfilerCallChainStrategy call_chain_strategy = mono_profiler_stat_get_call_chain_strategy (); GET_CONTEXT; if (call_chain_depth == 0) { mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx); } else { MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); int current_frame_index = 1; MonoContext mono_context; guchar *ips [call_chain_depth + 1]; mono_arch_sigctx_to_monoctx (ctx, &mono_context); ips [0] = MONO_CONTEXT_GET_IP (&mono_context); if (jit_tls != NULL) { if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_NATIVE) { #if FULL_STAT_PROFILER_BACKTRACE guchar *current_frame; guchar *stack_bottom; guchar *stack_top; stack_bottom = jit_tls->end_of_stack; stack_top = MONO_CONTEXT_GET_SP (&mono_context); current_frame = MONO_CONTEXT_GET_BP (&mono_context); while ((current_frame_index <= call_chain_depth) && (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) && ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) { ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame); current_frame_index ++; stack_top = current_frame; current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame); } #else call_chain_strategy = MONO_PROFILER_CALL_CHAIN_GLIBC; #endif } if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_GLIBC) { #if GLIBC_PROFILER_BACKTRACE current_frame_index = backtrace ((void**) & ips [1], call_chain_depth); #else call_chain_strategy = MONO_PROFILER_CALL_CHAIN_MANAGED; #endif } if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_MANAGED) { MonoDomain *domain = mono_domain_get (); if (domain != NULL) { MonoLMF *lmf = NULL; MonoJitInfo *ji; MonoJitInfo res; MonoContext new_mono_context; int native_offset; ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context, &new_mono_context, NULL, &lmf, &native_offset, NULL); while ((ji != NULL) && (current_frame_index <= call_chain_depth)) { ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context); current_frame_index ++; mono_context = new_mono_context; ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context, &new_mono_context, NULL, &lmf, &native_offset, NULL); } } } } mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx); } mono_chain_signal (SIG_HANDLER_PARAMS); }
/* mono_arch_find_jit_info: * * This function is used to gather information from @ctx. It returns the * MonoJitInfo of the corresponding function, unwinds one stack frame and * stores the resulting context into @new_ctx. It also stores a string * describing the stack location into @trace (if not NULL), and modifies * the @lmf if necessary. @native_offset return the IP offset from the * start of the function or -1 if that info is not available. */ MonoJitInfo * mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed) { MonoJitInfo *ji; gpointer ip = MONO_CONTEXT_GET_IP (ctx); gpointer fp = MONO_CONTEXT_GET_BP (ctx); guint32 sp; /* Avoid costly table lookup during stack overflow */ if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size))) ji = prev_ji; else ji = mini_jit_info_table_find (domain, ip, NULL); if (managed) *managed = FALSE; memcpy (new_ctx, ctx, sizeof (MonoContext)); if (ji != NULL) { int i; gint32 address; int offset = 0; if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) { /* remove any unused lmf */ *lmf = (*lmf)->previous_lmf; } address = (char *)ip - (char *)ji->code_start; if (managed) if (!ji->method->wrapper_type) *managed = TRUE; /* My stack frame */ fp = MONO_CONTEXT_GET_BP (ctx); /* Compute the previous stack frame */ sp = (guint32)(fp) - (short)(*(guint32 *)(ji->code_start)); /* Sanity check the frame */ if (!sp || (sp == 0xffffffff) || (sp & 0x07) || (sp < 64*1024)) { #ifdef DEBUG_EXCEPTIONS g_print ("mono_arch_find_jit_info: bad stack sp=%p\n", (void *) sp); #endif return (gpointer)-1; } if (ji->method->save_lmf && 0) { /* only enable this when prologue stops emitting * normal save of s-regs when save_lmf is true. * Will have to sync with prologue code at that point. */ memcpy (&new_ctx->sc_fpregs, (char*)sp - sizeof (float) * MONO_SAVED_FREGS, sizeof (float) * MONO_SAVED_FREGS); memcpy (&new_ctx->sc_regs, (char*)sp - sizeof (float) * MONO_SAVED_FREGS - sizeof (gulong) * MONO_SAVED_GREGS, sizeof (gulong) * MONO_SAVED_GREGS); } else if (ji->used_regs) { guint32 *insn; guint32 mask = ji->used_regs; /* these all happen before adjustment of fp */ /* Look for sw ??, ????(sp) */ insn = ((guint32 *)ji->code_start) + 1; while (!*insn || ((*insn & 0xffe00000) == 0xafa00000) || ((*insn & 0xffe00000) == 0xffa00000)) { int reg = (*insn >> 16) & 0x1f; guint32 addr = (((guint32)fp) + (short)(*insn & 0x0000ffff)); mask &= ~(1 << reg); if ((*insn & 0xffe00000) == 0xafa00000) new_ctx->sc_regs [reg] = *(guint32 *)addr; else new_ctx->sc_regs [reg] = *(guint64 *)addr; insn++; } MONO_CONTEXT_SET_SP (new_ctx, sp); MONO_CONTEXT_SET_BP (new_ctx, sp); /* assert that we found all registers we were supposed to */ g_assert (!mask); }
/* mono_arch_find_jit_info: * * This function is used to gather information from @ctx. It return the * MonoJitInfo of the corresponding function, unwinds one stack frame and * stores the resulting context into @new_ctx. It also stores a string * describing the stack location into @trace (if not NULL), and modifies * the @lmf if necessary. @native_offset return the IP offset from the * start of the function or -1 if that info is not available. */ MonoJitInfo * mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed) { MonoJitInfo *ji; gpointer ip = MONO_CONTEXT_GET_IP (ctx); gpointer *window; /* Avoid costly table lookup during stack overflow */ if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size))) ji = prev_ji; else ji = mini_jit_info_table_find (domain, ip, NULL); if (managed) *managed = FALSE; if (ji != NULL) { *new_ctx = *ctx; if (managed) if (!ji->method->wrapper_type) *managed = TRUE; if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) { /* remove any unused lmf */ *lmf = (*lmf)->previous_lmf; } /* Restore ip and sp from the saved register window */ window = MONO_SPARC_WINDOW_ADDR (ctx->sp); new_ctx->ip = window [sparc_i7 - 16]; new_ctx->sp = (gpointer*)(window [sparc_i6 - 16]); new_ctx->fp = (gpointer*)(MONO_SPARC_WINDOW_ADDR (new_ctx->sp) [sparc_i6 - 16]); return ji; } else { if (!(*lmf)) return NULL; *new_ctx = *ctx; if (!(*lmf)->method) return (gpointer)-1; if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->ip, NULL))) { } else { memset (res, 0, MONO_SIZEOF_JIT_INFO); res->method = (*lmf)->method; } new_ctx->ip = (*lmf)->ip; new_ctx->sp = (*lmf)->sp; new_ctx->fp = (*lmf)->ebp; *lmf = (*lmf)->previous_lmf; return ji ? ji : res; } }