gboolean mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only) { #if defined(MONO_ARCH_USE_SIGACTION) MonoContext mctx; ucontext_t *ctx = (ucontext_t*)sigctx; /* * 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); /* Pass the ctx parameter in TLS */ mono_arch_sigctx_to_monoctx (ctx, &jit_tls->ex_ctx); g_assert (!test_only); mctx = jit_tls->ex_ctx; mono_setup_async_callback (&mctx, handle_signal_exception, obj); mono_monoctx_to_sigctx (&mctx, sigctx); return TRUE; #elif defined (TARGET_WIN32) MonoContext mctx; MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); struct sigcontext *ctx = (struct sigcontext *)sigctx; mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx); g_assert (!test_only); mctx = jit_tls->ex_ctx; mono_setup_async_callback (&mctx, handle_signal_exception, obj); mono_monoctx_to_sigctx (&mctx, sigctx); return TRUE; #else MonoContext mctx; mono_arch_sigctx_to_monoctx (sigctx, &mctx); if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) return TRUE; mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only); mono_arch_monoctx_to_sigctx (&mctx, sigctx); return TRUE; #endif }
MonoThreadInfo* mono_thread_info_attach (void *baseptr) { MonoThreadInfo *info; if (!mono_threads_inited) { #ifdef HOST_WIN32 /* This can happen from DllMain(DLL_THREAD_ATTACH) on Windows, if a * thread is created before an embedding API user initialized Mono. */ THREADS_DEBUG ("mono_thread_info_attach called before mono_threads_init\n"); return NULL; #else g_assert (mono_threads_inited); #endif } info = (MonoThreadInfo *) mono_native_tls_get_value (thread_info_key); if (!info) { info = (MonoThreadInfo *) g_malloc0 (thread_info_size); THREADS_DEBUG ("attaching %p\n", info); if (!register_thread (info, baseptr)) return NULL; } else if (threads_callbacks.thread_attach) { threads_callbacks.thread_attach (info); } return info; }
/* mono_chain_signal: * * Call the original signal handler for the signal given by the arguments, which * should be the same as for a signal handler. Returns TRUE if the original handler * was called, false otherwise. */ gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal) { MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); jit_tls->mono_win_chained_exception_needs_run = TRUE; return TRUE; }
MonoThreadInfo* mono_thread_info_current (void) { MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key); if (info) return info; info = mono_thread_info_lookup (mono_native_thread_id_get ()); /*info on HP1*/ /* We might be called during thread cleanup, but we cannot be called after cleanup as happened. The way to distinguish between before, during and after cleanup is the following: -If the TLS key is set, cleanup has not begun; -If the TLS key is clean, but the thread remains registered, cleanup is in progress; -If the thread is nowhere to be found, cleanup has finished. We cannot function after cleanup since there's no way to ensure what will happen. */ g_assert (info); /*We're looking up the current thread which will not be freed until we finish running, so no need to keep it on a HP */ mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); return info; }
/** * mono_arch_handle_exception: * * @ctx: saved processor state * @obj: the exception object */ gboolean mono_arch_handle_exception (void *sigctx, gpointer obj) { #if defined(MONO_ARCH_USE_SIGACTION) MonoContext mctx; /* * 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 = (MonoJitTlsData *)mono_native_tls_get_value (mono_jit_tls_id); /* Pass the ctx parameter in TLS */ mono_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx); mctx = jit_tls->ex_ctx; mono_arch_setup_async_callback (&mctx, handle_signal_exception, obj); mono_monoctx_to_sigctx (&mctx, sigctx); return TRUE; #else MonoContext mctx; mono_sigctx_to_monoctx (sigctx, &mctx); mono_handle_exception (&mctx, obj); mono_monoctx_to_sigctx (&mctx, sigctx); return TRUE; #endif }
/* * This is the function called from the signal handler */ gboolean mono_arch_handle_exception (void *ctx, gpointer obj) { #if defined(MONO_CROSS_COMPILE) g_assert_not_reached (); #else MonoJitTlsData *jit_tls; void *sigctx = ctx; /* * Resume into the normal stack and handle the exception there. */ jit_tls = mono_native_tls_get_value (mono_jit_tls_id); /* Pass the ctx parameter in TLS */ mono_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx); /* The others in registers */ UCONTEXT_REG_R0 (sigctx) = (gsize)obj; UCONTEXT_REG_PC (sigctx) = (gsize)handle_signal_exception; UCONTEXT_REG_SP (sigctx) = UCONTEXT_REG_SP (sigctx) - MONO_ARCH_REDZONE_SIZE; #endif return TRUE; }
static void restore_soft_guard_pages (void) { MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); if (jit_tls->stack_ovf_guard_base) mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_NONE); }
int mono_thread_info_get_small_id (void) { gpointer val = mono_native_tls_get_value (small_id_key); if (!val) return -1; return GPOINTER_TO_INT (val) - 1; }
/* * mono_thread_info_is_exiting: * * Return whenever the current thread is exiting, i.e. it is running pthread * dtors. */ gboolean mono_thread_info_is_exiting (void) { #if defined(__MACH__) if (mono_native_tls_get_value (thread_exited_key) == GUINT_TO_POINTER (1)) return TRUE; #endif return FALSE; }
void mono_thread_info_dettach (void) { MonoThreadInfo *info = mono_native_tls_get_value (thread_info_key); if (info) { THREADS_DEBUG ("detaching %p\n", info); unregister_thread (info); } }
MonoAsyncJob mono_threads_consume_async_jobs (void) { MonoThreadInfo *info = (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key); if (!info) return (MonoAsyncJob) 0; return (MonoAsyncJob) InterlockedExchange (&info->service_requests, 0); }
/* 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); }
int mono_thread_info_get_small_id (void) { #ifdef HAVE_KW_THREAD return tls_small_id; #else gpointer val = mono_native_tls_get_value (small_id_key); if (!val) return -1; return GPOINTER_TO_INT (val) - 1; #endif }
static CheckState* get_state (void) { CheckState *state = mono_native_tls_get_value (thread_status); if (!state) { state = g_new0 (CheckState, 1); state->transitions = g_ptr_array_new (); mono_native_tls_set_value (thread_status, state); } return state; }
/* * 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; memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext)); mono_handle_exception (&ctx, obj); mono_restore_context (&ctx); }
/* * Unhandled Exception Filter * Top-level per-process exception handler. */ LONG CALLBACK seh_vectored_exception_handler(EXCEPTION_POINTERS* ep) { EXCEPTION_RECORD* er; CONTEXT* ctx; LONG res; MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); /* If the thread is not managed by the runtime return early */ if (!jit_tls) return EXCEPTION_CONTINUE_SEARCH; jit_tls->mono_win_chained_exception_needs_run = FALSE; res = EXCEPTION_CONTINUE_EXECUTION; er = ep->ExceptionRecord; ctx = ep->ContextRecord; switch (er->ExceptionCode) { case EXCEPTION_STACK_OVERFLOW: win32_handle_stack_overflow (ep, ctx); break; case EXCEPTION_ACCESS_VIOLATION: W32_SEH_HANDLE_EX(segv); break; case EXCEPTION_ILLEGAL_INSTRUCTION: W32_SEH_HANDLE_EX(ill); break; case EXCEPTION_INT_DIVIDE_BY_ZERO: case EXCEPTION_INT_OVERFLOW: case EXCEPTION_FLT_DIVIDE_BY_ZERO: case EXCEPTION_FLT_OVERFLOW: case EXCEPTION_FLT_UNDERFLOW: case EXCEPTION_FLT_INEXACT_RESULT: W32_SEH_HANDLE_EX(fpe); break; default: jit_tls->mono_win_chained_exception_needs_run = TRUE; break; } if (jit_tls->mono_win_chained_exception_needs_run) { /* Don't copy context back if we chained exception * as the handler may have modfied the EXCEPTION_POINTERS * directly. We don't pass sigcontext to chained handlers. * Return continue search so the UnhandledExceptionFilter * can correctly chain the exception. */ res = EXCEPTION_CONTINUE_SEARCH; } return res; }
static void coop_tls_push (gpointer cookie) { GArray *stack; stack = mono_native_tls_get_value (coop_reset_count_stack_key); if (!stack) { stack = g_array_new (FALSE, FALSE, sizeof(gpointer)); mono_native_tls_set_value (coop_reset_count_stack_key, stack); } g_array_append_val (stack, cookie); }
/** * mono_threads_attach_tools_thread * * Attach the current thread as a tool thread. DON'T USE THIS FUNCTION WITHOUT READING ALL DISCLAIMERS. * * A tools thread is a very special kind of thread that needs access to core runtime facilities but should * not be counted as a regular thread for high order facilities such as executing managed code or accessing * the managed heap. * * This is intended only to tools such as a profiler than needs to be able to use our lock-free support when * doing things like resolving backtraces in their background processing thread. */ void mono_threads_attach_tools_thread (void) { int dummy = 0; MonoThreadInfo *info; /* Must only be called once */ g_assert (!mono_native_tls_get_value (thread_info_key)); info = mono_thread_info_attach (&dummy); g_assert (info); info->tools_thread = TRUE; }
MonoThreadInfo* mono_thread_info_attach (void *baseptr) { MonoThreadInfo *info = mono_native_tls_get_value (thread_info_key); if (!info) { info = g_malloc0 (thread_info_size); THREADS_DEBUG ("attaching %p\n", info); if (!register_thread (info, baseptr)) return NULL; } else if (threads_callbacks.thread_attach) { threads_callbacks.thread_attach (info); } return info; }
/* * This is the function called from the signal handler */ gboolean mono_arch_handle_exception (void *ctx, gpointer obj) { #if defined(MONO_CROSS_COMPILE) || !defined(MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX) 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); /* 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 }
void mono_thread_info_dettach (void) { MonoThreadInfo *info; if (!mono_threads_inited) { /* This can happen from DllMain(THREAD_DETACH) on Windows, if a thread * is created before an embedding API user initialized Mono. */ THREADS_DEBUG ("mono_thread_info_dettach called before mono_threads_init\n"); return; } info = mono_native_tls_get_value (thread_info_key); if (info) { THREADS_DEBUG ("detaching %p\n", info); unregister_thread (info); } }
gboolean mono_arch_handle_exception (void *ctx, gpointer obj) { #if defined(MONO_ARCH_USE_SIGACTION) && defined(UCONTEXT_REG_Rn) /* * 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); mgreg_t sp; void *sigctx = ctx; int frame_size; void *uc = sigctx; /* Pass the ctx parameter in TLS */ mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx); /* The others in registers */ UCONTEXT_REG_Rn (sigctx, PPC_FIRST_ARG_REG) = (gsize)obj; /* Allocate a stack frame below the red zone */ /* Similar to mono_arch_handle_altstack_exception () */ frame_size = 224; frame_size += 15; frame_size &= ~15; sp = (mgreg_t)(UCONTEXT_REG_Rn(uc, 1) & ~15); sp = (mgreg_t)(sp - frame_size); UCONTEXT_REG_Rn(uc, 1) = (mgreg_t)sp; setup_ucontext_return (uc, handle_signal_exception); return TRUE; #else MonoContext mctx; gboolean result; mono_arch_sigctx_to_monoctx (ctx, &mctx); 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 }
/* * 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)); if (mono_debugger_handle_exception (&ctx, (MonoObject *)obj)) return; mono_handle_exception (&ctx, obj); restore_context (&ctx); }
/* * This is the function called from the signal handler */ gboolean mono_arch_handle_exception (void *ctx, gpointer obj) { #if defined(MONO_CROSS_COMPILE) g_assert_not_reached (); #elif defined(MONO_ARCH_USE_SIGACTION) void *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_GREGS (sigctx) [mips_sp]; /* Pass the ctx parameter in TLS */ mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx); /* The others in registers */ UCONTEXT_GREGS (sigctx)[mips_a0] = (gsize)obj; /* Allocate a stack frame */ sp -= 256; UCONTEXT_GREGS (sigctx)[mips_sp] = sp; UCONTEXT_REG_PC (sigctx) = (gsize)handle_signal_exception; return TRUE; #else MonoContext mctx; gboolean result; mono_arch_sigctx_to_monoctx (ctx, &mctx); 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 }
static void coop_tls_pop (gpointer received_cookie) { GArray *stack; gpointer expected_cookie; stack = mono_native_tls_get_value (coop_reset_count_stack_key); if (!stack || 0 == stack->len) mono_fatal_with_history ("Received cookie %p but found no stack at all\n", received_cookie); expected_cookie = g_array_index (stack, gpointer, stack->len - 1); stack->len --; if (0 == stack->len) { g_array_free (stack,TRUE); mono_native_tls_set_value (coop_reset_count_stack_key, NULL); } if (expected_cookie != received_cookie) mono_fatal_with_history ("Received cookie %p but expected %p\n", received_cookie, expected_cookie); }
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; }
static void handler_block_trampoline_helper (gpointer *ptr) { MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); *ptr = jit_tls->handler_block_return_address; }
MonoThreadInfo* mono_thread_info_current_unchecked (void) { return (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key); }
MonoThreadInfo* mono_thread_info_current_unchecked (void) { return mono_threads_inited ? (MonoThreadInfo*)mono_native_tls_get_value (thread_info_key) : NULL; }
MonoThreadInfo* mono_thread_info_current (void) { return mono_native_tls_get_value (thread_info_key); }