#include <sys/prctl.h>
#endif
+#ifdef HAVE_UNWIND_H
+#include <unwind.h>
+#endif
+
#include <mono/metadata/appdomain.h>
#include <mono/metadata/tabledefs.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/exception.h>
-#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/object-internals.h>
+#include <mono/metadata/gc-internals.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/profiler.h>
#include <mono/metadata/mono-endian.h>
#include <mono/metadata/environment.h>
+#include <mono/metadata/mono-mlist.h>
#include <mono/utils/mono-mmap.h>
-#include <mono/utils/mono-logger-internal.h>
+#include <mono/utils/mono-logger-internals.h>
#include "mini.h"
#include "trace.h"
#include "debugger-agent.h"
#include "seq-points.h"
+#include "llvm-runtime.h"
+#include "mini-llvm.h"
+
+#ifdef ENABLE_LLVM
+#include "mini-llvm-cpp.h"
+#endif
#ifdef ENABLE_EXTENSION_MODULE
#include "../../../mono-extensions/mono/mini/mini-exceptions.c"
MonoTrampInfo *info;
restore_context_func = mono_arch_get_restore_context (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
call_filter_func = mono_arch_get_call_filter (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
}
#ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
- try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
- restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
+ if (!mono_llvm_only) {
+ try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
+ restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
+ }
#endif
#ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
#endif
cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
- cbs.mono_raise_exception = mono_get_throw_exception ();
+
+ if (mono_llvm_only)
+ cbs.mono_raise_exception = mono_llvm_raise_exception;
+ else
+ cbs.mono_raise_exception = mono_get_throw_exception ();
cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
cbs.mono_exception_walk_trace = mono_exception_walk_trace;
cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
code = mono_aot_get_trampoline ("throw_corlib_exception");
else {
code = mono_arch_get_throw_corlib_exception (&info, FALSE);
- mono_tramp_info_register (info);
+ mono_tramp_info_register (info, NULL);
}
mono_memory_barrier ();
return TRUE;
}
+/*
+ * This function is async-safe.
+ */
static gpointer
get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
{
return len > 0;
}
-MonoString *
-ves_icall_System_Exception_get_trace (MonoException *ex)
-{
- MonoDomain *domain = mono_domain_get ();
- MonoString *res;
- MonoArray *ta = ex->trace_ips;
- int i, len;
- GString *trace_str;
-
- if (ta == NULL)
- /* Exception is not thrown yet */
- return NULL;
-
- len = mono_array_length (ta) >> 1;
- trace_str = g_string_new ("");
- for (i = 0; i < len; i++) {
- MonoJitInfo *ji;
- gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
- gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
-
- ji = mono_jit_info_table_find_internal (domain, ip, TRUE, TRUE);
- if (ji == NULL) {
- /* Unmanaged frame */
- g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
- } else if (!ji->is_trampoline) {
- gchar *location;
- gint32 address;
- MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
-
- address = (char *)ip - (char *)ji->code_start;
- location = mono_debug_print_stack_frame (
- method, address, ex->object.vtable->domain);
-
- g_string_append_printf (trace_str, "%s\n", location);
- g_free (location);
- }
- }
-
- res = mono_string_new (ex->object.vtable->domain, trace_str->str);
- g_string_free (trace_str, TRUE);
-
- return res;
-}
-
MonoArray *
ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
{
g_assert (state->valid);
+ if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
+ /* Not attached */
+ return;
+
mono_walk_stack_full (func,
&state->ctx,
state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
return TRUE;
}
-static MonoArray *
-glist_to_array (GList *list, MonoClass *eclass)
-{
- MonoDomain *domain = mono_domain_get ();
- MonoArray *res;
- int len, i;
-
- if (!list)
- return NULL;
-
- len = g_list_length (list);
- res = mono_array_new (domain, eclass, len);
-
- for (i = 0; list; list = list->next, i++)
- mono_array_set (res, gpointer, i, list->data);
-
- return res;
-}
-
static MonoClass*
get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
{
#endif
}
-#define setup_managed_stacktrace_information() do { \
- if (mono_ex && !initial_trace_ips) { \
- trace_ips = g_list_reverse (trace_ips); \
- MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class)); \
- MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace ()); \
- if (has_dynamic_methods) \
- /* These methods could go away anytime, so compute the stack trace now */ \
- MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex)); \
- } \
- g_list_free (trace_ips); \
- trace_ips = NULL; \
-} while (0)
+static void
+setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, MonoArray *initial_trace_ips, GList **trace_ips)
+{
+ if (mono_ex && !initial_trace_ips) {
+ *trace_ips = g_list_reverse (*trace_ips);
+ MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (*trace_ips, mono_defaults.int_class));
+ MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace ());
+ if (dynamic_methods) {
+ /* These methods could go away anytime, so save a reference to them in the exception object */
+ GSList *l;
+ MonoMList *list = NULL;
+
+ for (l = dynamic_methods; l; l = l->next) {
+ guint32 dis_link;
+ MonoDomain *domain = mono_domain_get ();
+
+ if (domain->method_to_dyn_method) {
+ mono_domain_lock (domain);
+ dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
+ mono_domain_unlock (domain);
+ if (dis_link) {
+ MonoObject *o = mono_gchandle_get_target (dis_link);
+ if (o) {
+ list = mono_mlist_prepend (list, o);
+ }
+ }
+ }
+ }
+
+ MONO_OBJECT_SETREF (mono_ex, dynamic_methods, list);
+ }
+ }
+ g_list_free (*trace_ips);
+ *trace_ips = NULL;
+}
+
/*
* mono_handle_exception_internal_first_pass:
*
MonoLMF *lmf = mono_get_lmf ();
MonoArray *initial_trace_ips = NULL;
GList *trace_ips = NULL;
+ GSList *dynamic_methods = NULL;
MonoException *mono_ex;
gboolean stack_overflow = FALSE;
MonoContext initial_ctx;
MonoMethod *method;
int frame_count = 0;
- gboolean has_dynamic_methods = FALSE;
gint32 filter_idx;
int i;
MonoObject *ex_obj;
}
if (!unwind_res) {
- setup_managed_stacktrace_information ();
+ setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
+ g_slist_free (dynamic_methods);
return FALSE;
}
}
if (method->dynamic)
- has_dynamic_methods = TRUE;
+ dynamic_methods = g_slist_prepend (dynamic_methods, method);
if (stack_overflow) {
if (DOES_STACK_GROWS_UP)
FIXME Not 100% sure if it's a good idea even with user clauses.
*/
if (is_user_frame)
- setup_managed_stacktrace_information ();
+ setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
#ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
if (ji->from_llvm)
if (filtered) {
if (!is_user_frame)
- setup_managed_stacktrace_information ();
+ setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
+ g_slist_free (dynamic_methods);
/* mono_debugger_agent_handle_exception () needs this */
MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
return TRUE;
}
if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (ex_obj, catch_class)) {
- setup_managed_stacktrace_information ();
+ setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
+ g_slist_free (dynamic_methods);
if (out_ji)
*out_ji = ji;
if (msg == NULL) {
msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
}
- g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
+ g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)mono_native_thread_id_get (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
g_free (msg);
if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
mono_print_thread_dump_from_ctx (ctx);
gboolean
mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
{
+ if (mono_llvm_only)
+ return FALSE;
+
/* we got a stack overflow in the soft-guard pages
* There are two cases:
* 1) managed code caused the overflow: we unprotect the soft-guard page
return FALSE;
}
- if (sigctx)
+ if (sigctx) {
mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
- else
-#if defined(MONO_CROSS_COMPILE)
- ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
-#elif MONO_ARCH_HAS_MONO_CONTEXT
- MONO_CONTEXT_GET_CURRENT (ctx->ctx);
-#else
- g_error ("Use a null sigctx requires a working mono-context");
-#endif
- ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
- ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
- ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
+ ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
+ ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
+ ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
+ }
+ else {
+ mono_thread_state_init (ctx);
+ }
if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
return FALSE;
#endif
}
+void
+mono_thread_state_init (MonoThreadUnwindState *ctx)
+{
+ MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
+
+#if defined(MONO_CROSS_COMPILE)
+ ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
+#elif MONO_ARCH_HAS_MONO_CONTEXT
+ MONO_CONTEXT_GET_CURRENT (ctx->ctx);
+#else
+ g_error ("Use a null sigctx requires a working mono-context");
+#endif
+
+ ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
+ ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
+ ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
+ ctx->valid = TRUE;
+}
+
+
gboolean
mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
{
return info->epilog_size;
}
+
+/*
+ * LLVM/Bitcode exception handling.
+ */
+
+#ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
+
+#if 0
+static gboolean show_native_addresses = TRUE;
+#else
+static gboolean show_native_addresses = FALSE;
+#endif
+
+static _Unwind_Reason_Code
+build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
+{
+ MonoDomain *domain = mono_domain_get ();
+ uintptr_t ip = _Unwind_GetIP (frame_ctx);
+
+ if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
+ GList **trace_ips = (GList **)state;
+ *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
+ }
+
+ return _URC_NO_REASON;
+}
+
+#endif
+
+static void
+throw_exception (MonoObject *ex, gboolean rethrow)
+{
+ MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+ MonoException *mono_ex;
+
+ if (!mono_object_isinst (ex, mono_defaults.exception_class))
+ mono_ex = mono_get_exception_runtime_wrapped (ex);
+ else
+ mono_ex = (MonoException*)ex;
+
+ // Note: Not pinned
+ jit_tls->thrown_exc = mono_gchandle_new ((MonoObject*)mono_ex, FALSE);
+
+ if (!rethrow) {
+#ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
+ GList *l, *ips = NULL;
+ GList *trace;
+
+ _Unwind_Backtrace (build_stack_trace, &ips);
+ /* The list contains gshared info-ip pairs */
+ trace = NULL;
+ ips = g_list_reverse (ips);
+ for (l = ips; l; l = l->next) {
+ // FIXME:
+ trace = g_list_append (trace, l->data);
+ trace = g_list_append (trace, NULL);
+ }
+ MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (trace, mono_defaults.int_class));
+ g_list_free (l);
+ g_list_free (trace);
+#endif
+ }
+
+ mono_llvm_cpp_throw_exception ();
+}
+
+void
+mono_llvm_throw_exception (MonoObject *ex)
+{
+ throw_exception (ex, FALSE);
+}
+
+void
+mono_llvm_rethrow_exception (MonoObject *ex)
+{
+ throw_exception (ex, TRUE);
+}
+
+void
+mono_llvm_raise_exception (MonoException *e)
+{
+ mono_llvm_throw_exception ((MonoObject*)e);
+}
+
+void
+mono_llvm_throw_corlib_exception (guint32 ex_token_index)
+{
+ guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
+ MonoException *ex;
+
+ ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token);
+
+ mono_llvm_throw_exception ((MonoObject*)ex);
+}
+
+/*
+ * mono_llvm_resume_exception:
+ *
+ * Resume exception propagation.
+ */
+void
+mono_llvm_resume_exception (void)
+{
+ mono_llvm_cpp_throw_exception ();
+}
+
+/*
+ * mono_llvm_load_exception:
+ *
+ * Return the currently thrown exception.
+ */
+MonoObject *
+mono_llvm_load_exception (void)
+{
+ MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+
+ MonoException *mono_ex = (MonoException*)mono_gchandle_get_target (jit_tls->thrown_exc);
+ g_assert (mono_ex->trace_ips);
+
+ GList *trace_ips = NULL;
+ gpointer ip = __builtin_return_address (0);
+
+ size_t upper = mono_array_length (mono_ex->trace_ips);
+
+ for (int i = 0; i < upper; i++) {
+ gpointer curr_ip = mono_array_get (mono_ex->trace_ips, gpointer, i);
+ trace_ips = g_list_prepend (trace_ips, curr_ip);
+
+ if (ip == curr_ip)
+ break;
+ }
+
+ // FIXME: Does this work correctly for rethrows?
+ // We may be discarding useful information
+ // when this gets GC'ed
+ MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (trace_ips, mono_defaults.int_class));
+ g_list_free (trace_ips);
+
+ // FIXME:
+ //MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
+
+ return &mono_ex->object;
+}
+
+/*
+ * mono_llvm_clear_exception:
+ *
+ * Mark the currently thrown exception as handled.
+ */
+void
+mono_llvm_clear_exception (void)
+{
+ MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+ mono_gchandle_free (jit_tls->thrown_exc);
+ jit_tls->thrown_exc = 0;
+
+ mono_memory_barrier ();
+}
+
+/*
+ * mono_llvm_match_exception:
+ *
+ * Return the innermost clause containing REGION_START-REGION_END which can handle
+ * the current exception.
+ */
+gint32
+mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end)
+{
+ MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+ MonoObject *exc;
+ gint32 index = -1;
+
+ g_assert (jit_tls->thrown_exc);
+ exc = mono_gchandle_get_target (jit_tls->thrown_exc);
+ for (int i = 0; i < jinfo->num_clauses; i++) {
+ MonoJitExceptionInfo *ei = &jinfo->clauses [i];
+
+ if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
+ continue;
+
+ // FIXME: Handle edge cases handled in get_exception_catch_class
+ if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (exc, ei->data.catch_class)) {
+ index = ei->clause_index;
+ break;
+ } else if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+ g_assert_not_reached ();
+ }
+ }
+
+ return index;
+}
+
+#ifdef ENABLE_LLVM
+_Unwind_Reason_Code
+mono_debug_personality (int a, _Unwind_Action b,
+uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
+{
+ g_assert_not_reached ();
+}
+#else
+void
+mono_debug_personality (void);
+
+void
+mono_debug_personality (void)
+{
+ g_assert_not_reached ();
+}
+#endif