X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-exceptions.c;h=707951af02e15c807e7eccced069307a22af527b;hb=919a03d17d36604f05e1d99c3f9f26a1509e9655;hp=68427314ac5e3fef0b4526e3ae0f117652d5202d;hpb=3ab1a56f73cac926676e24b58d07bf0c4e75d3eb;p=mono.git diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 68427314ac5..707951af02e 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -1,5 +1,6 @@ -/* - * mini-exceptions.c: generic exception support +/** + * \file + * generic exception support * * Authors: * Dietmar Maurer (dietmar@ximian.com) @@ -57,8 +58,9 @@ #include #include #include +#include #include -#include +#include #include #include #include @@ -73,18 +75,33 @@ #include "seq-points.h" #include "llvm-runtime.h" #include "mini-llvm.h" +#include "interp/interp.h" #ifdef ENABLE_LLVM #include "mini-llvm-cpp.h" #endif +#ifdef TARGET_ARM +#include "mini-arm.h" +#endif + #ifndef MONO_ARCH_CONTEXT_DEF #define MONO_ARCH_CONTEXT_DEF #endif -#ifndef MONO_ARCH_STACK_GROWS_UP -#define MONO_ARCH_STACK_GROWS_UP 0 -#endif +/* + * Raw frame information is stored in MonoException.trace_ips as an IntPtr[]. + * This structure represents one entry. + * This should consists of pointers only. + */ +typedef struct +{ + gpointer ip; + gpointer generic_info; +} ExceptionTraceIp; + +/* Number of words in trace_ips belonging to one entry */ +#define TRACE_IP_ENTRY_SIZE (sizeof (ExceptionTraceIp) / sizeof (gpointer)) static gpointer restore_context_func, call_filter_func; static gpointer throw_exception_func, rethrow_exception_func; @@ -99,6 +116,7 @@ static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx); static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data); static gboolean mono_current_thread_has_handle_block_guard (void); +static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx); static gboolean first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr) @@ -127,18 +145,6 @@ mono_thread_get_managed_sp (void) return addr; } -static inline int -mini_abort_threshold_offset (gpointer threshold, gpointer sp) -{ - intptr_t stack_threshold = (intptr_t) threshold; - intptr_t stack_pointer = (intptr_t) sp; - - const int direction = MONO_ARCH_STACK_GROWS_UP ? -1 : 1; - intptr_t magnitude = stack_pointer - stack_threshold; - - return direction * magnitude; -} - static inline void mini_clear_abort_threshold (void) { @@ -154,7 +160,7 @@ mini_set_abort_threshold (MonoContext *ctx) // Only move it up, to avoid thrown/caught // exceptions lower in the stack from triggering // a rethrow - gboolean above_threshold = mini_abort_threshold_offset (jit_tls->abort_exc_stack_threshold, sp) >= 0; + gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold; if (!jit_tls->abort_exc_stack_threshold || above_threshold) { jit_tls->abort_exc_stack_threshold = sp; } @@ -172,7 +178,7 @@ mini_above_abort_threshold (void) if (!sp) return TRUE; - gboolean above_threshold = mini_abort_threshold_offset (jit_tls->abort_exc_stack_threshold, sp) >= 0; + gboolean above_threshold = (gsize) sp >= (gsize) jit_tls->abort_exc_stack_threshold; if (above_threshold) jit_tls->abort_exc_stack_threshold = sp; @@ -220,13 +226,22 @@ mono_exceptions_init (void) #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT mono_arch_exceptions_init (); #endif - cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx; +#ifdef ENABLE_INTERPRETER + if (mono_use_interpreter) + cbs.mono_walk_stack_with_ctx = interp_walk_stack_with_ctx; + else +#endif + cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx; + cbs.mono_walk_stack_with_state = mono_walk_stack_with_state; - if (mono_llvm_only) + if (mono_llvm_only) { cbs.mono_raise_exception = mono_llvm_raise_exception; - else + cbs.mono_reraise_exception = mono_llvm_reraise_exception; + } else { cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception (); + cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_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; @@ -322,7 +337,7 @@ is_address_protected (MonoJitInfo *ji, MonoJitExceptionInfo *ei, gpointer ip) for (i = 0; i < table->num_holes; ++i) { MonoTryBlockHoleJitInfo *hole = &table->holes [i]; - if (hole->clause == clause && hole->offset <= offset && hole->offset + hole->length > offset) + if (ji->clauses [hole->clause].try_offset == ji->clauses [clause].try_offset && hole->offset <= offset && hole->offset + hole->length > offset) return FALSE; } return TRUE; @@ -559,7 +574,7 @@ mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, if (!err) return FALSE; - if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) { + if (frame->type != FRAME_TYPE_INTERP_TO_MANAGED && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) { /* * Remove any unused lmf. * Mask out the lower bits which might be used to hold additional information. @@ -622,6 +637,49 @@ mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, return TRUE; } +typedef struct { + gboolean in_interp; + MonoInterpStackIter interp_iter; +} Unwinder; + +static void +unwinder_init (Unwinder *unwinder) +{ + memset (unwinder, 0, sizeof (Unwinder)); +} + +#if defined(__GNUC__) && defined(TARGET_ARM64) +/* gcc 4.9.2 seems to miscompile this on arm64 */ +static __attribute__((optimize("O0"))) gboolean +#else +static gboolean +#endif +unwinder_unwind_frame (Unwinder *unwinder, + MonoDomain *domain, MonoJitTlsData *jit_tls, + MonoJitInfo *prev_ji, MonoContext *ctx, + MonoContext *new_ctx, char **trace, MonoLMF **lmf, + mgreg_t **save_locations, + StackFrameInfo *frame) +{ + if (unwinder->in_interp) { + unwinder->in_interp = mono_interp_frame_iter_next (&unwinder->interp_iter, frame); + if (!unwinder->in_interp) { + return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame); + } + return TRUE; + } else { + gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, + save_locations, frame); + if (!res) + return FALSE; + if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) { + unwinder->in_interp = TRUE; + mono_interp_frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data); + } + return TRUE; + } +} + /* * This function is async-safe. */ @@ -753,10 +811,9 @@ get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) /** * mono_exception_walk_native_trace: - * @ex: The exception object whose frames should be walked - * @func: callback to call for each stack frame - * @user_data: data passed to the callback - * + * \param ex The exception object whose frames should be walked + * \param func callback to call for each stack frame + * \param user_data data passed to the callback * This function walks the stacktrace of an exception. For * each frame the callback function is called with the relevant info. * The walk ends when no more stack frames are found or when the callback @@ -775,10 +832,13 @@ mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpoin if (ta == NULL) return FALSE; - len = mono_array_length (ta) >> 1; + len = mono_array_length (ta) / TRACE_IP_ENTRY_SIZE; for (i = 0; i < len; i++) { - gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0); - gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1); + ExceptionTraceIp trace_ip; + + memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp)); + gpointer ip = trace_ip.ip; + gpointer generic_info = trace_ip.generic_info; MonoJitInfo *ji = mono_jit_info_table_find (domain, (char *)ip); if (ji == NULL) { @@ -811,7 +871,7 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info return res; } - len = mono_array_length (ta) >> 1; + len = mono_array_length (ta) / TRACE_IP_ENTRY_SIZE; res = mono_array_new_checked (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0, &error); if (mono_error_set_pending_exception (&error)) @@ -824,8 +884,10 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info mono_error_set_pending_exception (&error); return NULL; } - gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0); - gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1); + ExceptionTraceIp trace_ip; + memcpy (&trace_ip, mono_array_addr_fast (ta, ExceptionTraceIp, i), sizeof (ExceptionTraceIp)); + gpointer ip = trace_ip.ip; + gpointer generic_info = trace_ip.generic_info; MonoMethod *method; ji = mono_jit_info_table_find (domain, (char *)ip); @@ -847,8 +909,13 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info sf->method = NULL; s = mono_method_get_name_full (method, TRUE, FALSE, MONO_TYPE_NAME_FORMAT_REFLECTION); - MONO_OBJECT_SETREF (sf, internal_method_name, mono_string_new (domain, s)); + MonoString *name = mono_string_new_checked (domain, s, &error); g_free (s); + if (!is_ok (&error)) { + mono_error_set_pending_exception (&error); + return NULL; + } + MONO_OBJECT_SETREF (sf, internal_method_name, name); } else { MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, &error); @@ -881,7 +948,12 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info if (need_file_info) { if (location && location->source_file) { - MONO_OBJECT_SETREF (sf, filename, mono_string_new (domain, location->source_file)); + MonoString *filename = mono_string_new_checked (domain, location->source_file, &error); + if (!is_ok (&error)) { + mono_error_set_pending_exception (&error); + return NULL; + } + MONO_OBJECT_SETREF (sf, filename, filename); sf->line = location->row; sf->column = location->column; } else { @@ -909,10 +981,8 @@ mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, } /** * mono_walk_stack_with_ctx: - * - * Unwind the current thread starting at @start_ctx. - * - * If @start_ctx is null, we capture the current context. + * Unwind the current thread starting at \p start_ctx. + * If \p start_ctx is null, we capture the current context. */ void mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data) @@ -940,14 +1010,13 @@ mono_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnw /** * mono_walk_stack_with_state: - * - * Unwind a thread described by @state. + * Unwind a thread described by \p state. * * State must be valid (state->valid == TRUE). * * If you are using this function to unwind another thread, make sure it is suspended. * - * If @state is null, we capture the current context. + * If \p state is null, we capture the current context. */ void mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state, MonoUnwindOptions unwind_options, void *user_data) @@ -985,16 +1054,15 @@ mono_walk_stack (MonoJitStackWalk func, MonoUnwindOptions options, void *user_da /** * mono_walk_stack_full: - * @func: callback to call for each stack frame - * @domain: starting appdomain, can be NULL to use the current domain - * @unwind_options: what extra information the unwinder should gather - * @start_ctx: starting state of the stack walk, can be NULL. - * @thread: the thread whose stack to walk, can be NULL to use the current thread - * @lmf: the LMF of @thread, can be NULL to use the LMF of the current thread - * @user_data: data passed to the callback - * + * \param func callback to call for each stack frame + * \param domain starting appdomain, can be NULL to use the current domain + * \param unwind_options what extra information the unwinder should gather + * \param start_ctx starting state of the stack walk, can be NULL. + * \param thread the thread whose stack to walk, can be NULL to use the current thread + * \param lmf the LMF of \p thread, can be NULL to use the LMF of the current thread + * \param user_data data passed to the callback * This function walks the stack of a thread, starting from the state - * represented by start_ctx. For each frame the callback + * represented by \p start_ctx. For each frame the callback * function is called with the relevant info. The walk ends when no more * managed stack frames are found or when the callback returns a TRUE value. */ @@ -1009,6 +1077,7 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain mgreg_t *new_reg_locations [MONO_MAX_IREGS]; gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS; gboolean async = mono_thread_info_is_async_context (); + Unwinder unwinder; if (mono_llvm_only) { GSList *l, *ips; @@ -1053,9 +1122,11 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain memcpy (&ctx, start_ctx, sizeof (MonoContext)); memset (reg_locations, 0, sizeof (reg_locations)); + unwinder_init (&unwinder); + while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) { frame.lmf = lmf; - res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame); + res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame); if (!res) return; @@ -1116,6 +1187,8 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, MonoMethod *jmethod = NULL, *actual_method; StackFrameInfo frame; gboolean res; + Unwinder unwinder; + int il_offset = -1; MONO_ARCH_CONTEXT_DEF; @@ -1157,29 +1230,43 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info); #endif + unwinder_init (&unwinder); + new_ctx = ctx; do { ctx = new_ctx; - res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame); + res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame); if (!res) return FALSE; - - if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || - frame.type == FRAME_TYPE_DEBUGGER_INVOKE || - frame.type == FRAME_TYPE_TRAMPOLINE) + switch (frame.type) { + case FRAME_TYPE_MANAGED_TO_NATIVE: + case FRAME_TYPE_DEBUGGER_INVOKE: + case FRAME_TYPE_TRAMPOLINE: + case FRAME_TYPE_INTERP_TO_MANAGED: continue; + case FRAME_TYPE_INTERP: + skip--; + break; + default: + ji = frame.ji; + *native_offset = frame.native_offset; - ji = frame.ji; - *native_offset = frame.native_offset; - - /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */ - jmethod = jinfo_get_method (ji); - if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE) - continue; - skip--; + /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */ + jmethod = jinfo_get_method (ji); + if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE) + continue; + skip--; + break; + } } while (skip >= 0); - actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx)); + if (frame.type == FRAME_TYPE_INTERP) { + jmethod = frame.method; + actual_method = frame.actual_method; + *native_offset = frame.native_offset; + } else { + actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx)); + } } MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, &error); @@ -1189,7 +1276,11 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, } mono_gc_wbarrier_generic_store (method, (MonoObject*) rm); - location = mono_debug_lookup_source_location (jmethod, *native_offset, domain); + if (il_offset != -1) { + location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain); + } else { + location = mono_debug_lookup_source_location (jmethod, *native_offset, domain); + } if (location) *iloffset = location->il_offset; else @@ -1197,7 +1288,12 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, if (need_file_info) { if (location) { - mono_gc_wbarrier_generic_store (file, (MonoObject*) mono_string_new (domain, location->source_file)); + MonoString *filename = mono_string_new_checked (domain, location->source_file, &error); + if (!is_ok (&error)) { + mono_error_set_pending_exception (&error); + return FALSE; + } + mono_gc_wbarrier_generic_store (file, (MonoObject*)filename); *line = location->row; *column = location->column; } else { @@ -1319,6 +1415,11 @@ wrap_non_exception_throws (MonoMethod *m) int i; gboolean val = FALSE; + if (m->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) { + MonoDynamicMethod *dm = (MonoDynamicMethod *)m; + if (dm->assembly) + ass = dm->assembly; + } g_assert (ass); if (ass->wrap_non_exception_throws_inited) return ass->wrap_non_exception_throws; @@ -1375,7 +1476,7 @@ wrap_non_exception_throws (MonoMethod *m) static MonoArray* build_native_trace (MonoError *error) { - mono_error_init (error); + error_init (error); /* This puppy only makes sense on mobile, IOW, ARM. */ #if defined (HAVE_BACKTRACE_SYMBOLS) && defined (TARGET_ARM) MonoArray *res; @@ -1466,6 +1567,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi gint32 filter_idx; int i; MonoObject *ex_obj; + Unwinder unwinder; + gboolean in_interp; g_assert (ctx != NULL); @@ -1475,13 +1578,13 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi mono_ex = (MonoException*)obj; MonoArray *initial_trace_ips = mono_ex->trace_ips; if (initial_trace_ips) { - int len = mono_array_length (initial_trace_ips) >> 1; + int len = mono_array_length (initial_trace_ips) / TRACE_IP_ENTRY_SIZE; for (i = 0; i < (len - 1); i++) { - gpointer ip = mono_array_get (initial_trace_ips, gpointer, i * 2 + 0); - gpointer generic_info = mono_array_get (initial_trace_ips, gpointer, i * 2 + 1); - trace_ips = g_list_prepend (trace_ips, ip); - trace_ips = g_list_prepend (trace_ips, generic_info); + for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) { + gpointer p = mono_array_get (initial_trace_ips, gpointer, (i * TRACE_IP_ENTRY_SIZE) + j); + trace_ips = g_list_prepend (trace_ips, p); + } } } @@ -1505,6 +1608,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi filter_idx = 0; initial_ctx = *ctx; + unwinder_init (&unwinder); + while (1) { MonoContext new_ctx; guint32 free_stack; @@ -1516,24 +1621,37 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi if (out_prev_ji) *out_prev_ji = ji; - unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); - if (unwind_res) { - if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || - frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || - frame.type == FRAME_TYPE_TRAMPOLINE) { - *ctx = new_ctx; - continue; - } - g_assert (frame.type == FRAME_TYPE_MANAGED); - ji = frame.ji; - } - + unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); if (!unwind_res) { setup_stack_trace (mono_ex, dynamic_methods, &trace_ips); g_slist_free (dynamic_methods); return FALSE; } + switch (frame.type) { + case FRAME_TYPE_DEBUGGER_INVOKE: + case FRAME_TYPE_MANAGED_TO_NATIVE: + case FRAME_TYPE_TRAMPOLINE: + case FRAME_TYPE_INTERP_TO_MANAGED: + *ctx = new_ctx; + continue; + case FRAME_TYPE_INTERP: + case FRAME_TYPE_MANAGED: + break; + default: + g_assert_not_reached (); + break; + } + + in_interp = frame.type == FRAME_TYPE_INTERP; + ji = frame.ji; + + gpointer ip; + if (in_interp) + ip = (guint8*)ji->code_start + frame.native_offset; + else + ip = MONO_CONTEXT_GET_IP (ctx); + frame_count ++; method = jinfo_get_method (ji); //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count); @@ -1556,10 +1674,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi dynamic_methods = g_slist_prepend (dynamic_methods, method); if (stack_overflow) { - if (MONO_ARCH_STACK_GROWS_UP) - free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx)); - else - free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)); + free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)); } else { free_stack = 0xffffff; } @@ -1575,7 +1690,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi if (free_stack <= (64 * 1024)) continue; - if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) { + if (is_address_protected (ji, ei, ip)) { /* catch block */ MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx); @@ -1590,7 +1705,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) { #ifndef DISABLE_PERFCOUNTERS - mono_perfcounters->exceptions_filters++; + InterlockedIncrement (&mono_perfcounters->exceptions_filters); #endif #ifndef MONO_CROSS_COMPILE @@ -1638,7 +1753,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi } MonoError isinst_error; - mono_error_init (&isinst_error); + error_init (&isinst_error); if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, &error)) { setup_stack_trace (mono_ex, dynamic_methods, &trace_ips); g_slist_free (dynamic_methods); @@ -1647,7 +1762,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi *out_ji = ji; /* mono_debugger_agent_handle_exception () needs this */ - MONO_CONTEXT_SET_IP (ctx, ei->handler_start); + if (!in_interp) + MONO_CONTEXT_SET_IP (ctx, ei->handler_start); return TRUE; } mono_error_cleanup (&isinst_error); @@ -1662,9 +1778,9 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi /** * mono_handle_exception_internal: - * @ctx: saved processor state - * @obj: the exception object - * @resume: whenever to resume unwinding based on the state in MonoJitTlsData. + * \param ctx saved processor state + * \param obj the exception object + * \param resume whenever to resume unwinding based on the state in \c MonoJitTlsData. */ static gboolean mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resume, MonoJitInfo **out_ji) @@ -1684,11 +1800,15 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu int i; MonoObject *ex_obj; MonoObject *non_exception = NULL; + Unwinder unwinder; + gboolean in_interp; g_assert (ctx != NULL); if (!obj) { MonoException *ex = mono_get_exception_null_reference (); - MONO_OBJECT_SETREF (ex, message, mono_string_new (domain, "Object reference not set to an instance of an object")); + MonoString *msg = mono_string_new_checked (domain, "Object reference not set to an instance of an object", &error); + mono_error_assert_ok (&error); + MONO_OBJECT_SETREF (ex, message, msg); obj = (MonoObject *)ex; } @@ -1733,18 +1853,26 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu char *from_name = mono_type_get_full_name (jit_tls->class_cast_from); char *to_name = mono_type_get_full_name (jit_tls->class_cast_to); char *msg = g_strdup_printf ("Unable to cast object of type '%s' to type '%s'.", from_name, to_name); - mono_ex->message = mono_string_new (domain, msg); + mono_ex->message = mono_string_new_checked (domain, msg, &error); g_free (from_name); g_free (to_name); + if (!is_ok (&error)) { + mono_runtime_printf_err ("Error creating class cast exception message '%s'\n", msg); + mono_error_assert_ok (&error); + } g_free (msg); } if (!strcmp (mono_ex->object.vtable->klass->name, "ArrayTypeMismatchException")) { char *from_name = mono_type_get_full_name (jit_tls->class_cast_from); char *to_name = mono_type_get_full_name (jit_tls->class_cast_to); char *msg = g_strdup_printf ("Source array of type '%s' cannot be cast to destination array type '%s'.", from_name, to_name); - mono_ex->message = mono_string_new (domain, msg); + mono_ex->message = mono_string_new_checked (domain, msg, &error); g_free (from_name); g_free (to_name); + if (!is_ok (&error)) { + mono_runtime_printf_err ("Error creating array type mismatch exception message '%s'\n", msg); + mono_error_assert_ok (&error); + } g_free (msg); } } @@ -1799,7 +1927,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu mono_print_thread_dump_from_ctx (ctx); } jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_thrown (obj); + MONO_PROFILER_RAISE (exception_throw, (obj)); jit_tls->orig_ex_ctx_set = FALSE; res = mono_handle_exception_internal_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception); @@ -1846,11 +1974,15 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu filter_idx = 0; initial_ctx = *ctx; + unwinder_init (&unwinder); + while (1) { MonoContext new_ctx; guint32 free_stack; int clause_index_start = 0; gboolean unwind_res = TRUE; + StackFrameInfo frame; + gpointer ip; if (resume) { resume = FALSE; @@ -1860,38 +1992,45 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu lmf = jit_tls->resume_state.lmf; first_filter_idx = jit_tls->resume_state.first_filter_idx; filter_idx = jit_tls->resume_state.filter_idx; + in_interp = FALSE; } else { - StackFrameInfo frame; - - unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); - if (unwind_res) { - if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || - frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || - frame.type == FRAME_TYPE_TRAMPOLINE) { - *ctx = new_ctx; - continue; - } - g_assert (frame.type == FRAME_TYPE_MANAGED); - ji = frame.ji; + unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); + if (!unwind_res) { + *(mono_get_lmf_addr ()) = lmf; + + jit_tls->abort_func (obj); + g_assert_not_reached (); + } + switch (frame.type) { + case FRAME_TYPE_DEBUGGER_INVOKE: + case FRAME_TYPE_MANAGED_TO_NATIVE: + case FRAME_TYPE_TRAMPOLINE: + *ctx = new_ctx; + continue; + case FRAME_TYPE_INTERP_TO_MANAGED: + continue; + case FRAME_TYPE_INTERP: + case FRAME_TYPE_MANAGED: + break; + default: + g_assert_not_reached (); + break; } + in_interp = frame.type == FRAME_TYPE_INTERP; + ji = frame.ji; } - if (!unwind_res) { - *(mono_get_lmf_addr ()) = lmf; - - jit_tls->abort_func (obj); - g_assert_not_reached (); - } + if (in_interp) + ip = (guint8*)ji->code_start + frame.native_offset; + else + ip = MONO_CONTEXT_GET_IP (ctx); method = jinfo_get_method (ji); frame_count ++; //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count); if (stack_overflow) { - if (MONO_ARCH_STACK_GROWS_UP) - free_stack = (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (ctx)); - else - free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)); + free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx)); } else { free_stack = 0xffffff; } @@ -1907,7 +2046,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu if (free_stack <= (64 * 1024)) continue; - if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) { + if (is_address_protected (ji, ei, ip)) { /* catch block */ MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx); @@ -1946,7 +2085,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu filter_idx ++; } - mono_error_init (&error); + error_init (&error); if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst_checked (ex_obj, catch_class, &error)) || filtered) { /* @@ -1954,11 +2093,12 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu * that was called by the EH machinery. It won't have a guard trampoline installed, so we must * check for this situation here and resume interruption if we are below the guarded block. */ - if (G_UNLIKELY (jit_tls->handler_block_return_address)) { + if (G_UNLIKELY (jit_tls->handler_block)) { gboolean is_outside = FALSE; gpointer prot_bp = MONO_CONTEXT_GET_BP (&jit_tls->handler_block_context); gpointer catch_bp = MONO_CONTEXT_GET_BP (ctx); //FIXME make this stack direction aware + if (catch_bp > prot_bp) { is_outside = TRUE; } else if (catch_bp == prot_bp) { @@ -1978,22 +2118,47 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu } } if (is_outside) { - jit_tls->handler_block_return_address = NULL; jit_tls->handler_block = NULL; - mono_thread_resume_interruption (); /*We ignore the exception here, it will be raised later*/ + mono_thread_resume_interruption (TRUE); /*We ignore the exception here, it will be raised later*/ } } if (mono_trace_is_enabled () && mono_trace_eval (method)) g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE)); jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_clause_handler (method, ei->flags, i); + MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj)); jit_tls->orig_ex_ctx_set = FALSE; mini_set_abort_threshold (ctx); - MONO_CONTEXT_SET_IP (ctx, ei->handler_start); + + if (in_interp) { + /* + * ctx->pc points into the interpreter, after the call which transitioned to + * JITted code. Store the unwind state into the + * interpeter state, then resume, the interpreter will unwind itself until + * it reaches the target frame and will continue execution from there. + * The resuming is kinda hackish, from the native code standpoint, it looks + * like the call which transitioned to JITted code has succeeded, but the + * return value register etc. is not set, so we have to be careful. + */ + mono_interp_set_resume_state (jit_tls, mono_ex, frame.interp_frame, ei->handler_start); + /* Undo the IP adjustment done by mono_arch_unwind_frame () */ +#if defined(TARGET_AMD64) + ctx->gregs [AMD64_RIP] ++; +#elif defined(TARGET_ARM) + ctx->pc ++; + if (mono_arm_thumb_supported ()) + ctx->pc |= 1; +#elif defined(TARGET_ARM64) + ctx->pc ++; +#else + NOT_IMPLEMENTED; +#endif + } else { + MONO_CONTEXT_SET_IP (ctx, ei->handler_start); + } mono_set_lmf (lmf); #ifndef DISABLE_PERFCOUNTERS - mono_perfcounters->exceptions_depth += frame_count; + InterlockedAdd (&mono_perfcounters->exceptions_depth, frame_count); #endif if (obj == (MonoObject *)domain->stack_overflow_ex) jit_tls->handling_stack_ovf = FALSE; @@ -2005,20 +2170,20 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu if (mono_trace_is_enabled () && mono_trace_eval (method)) g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE)); jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_clause_handler (method, ei->flags, i); + MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj)); jit_tls->orig_ex_ctx_set = FALSE; - mini_set_abort_threshold (ctx); - call_filter (ctx, ei->handler_start); } if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { if (mono_trace_is_enabled () && mono_trace_eval (method)) g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE)); jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_clause_handler (method, ei->flags, i); + MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj)); jit_tls->orig_ex_ctx_set = FALSE; #ifndef DISABLE_PERFCOUNTERS - mono_perfcounters->exceptions_finallys++; + InterlockedIncrement (&mono_perfcounters->exceptions_finallys); #endif + } + if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { mono_set_lmf (lmf); if (ji->from_llvm) { /* @@ -2042,15 +2207,21 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu return 0; } else { mini_set_abort_threshold (ctx); - call_filter (ctx, ei->handler_start); + if (in_interp) + mono_interp_run_finally (&frame, i, ei->handler_start); + else + call_filter (ctx, ei->handler_start); } } } } - jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_method_leave (method); - jit_tls->orig_ex_ctx_set = FALSE; + if (MONO_PROFILER_ENABLED (method_exception_leave) && + mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) { + jit_tls->orig_ex_ctx_set = TRUE; + MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj)); + jit_tls->orig_ex_ctx_set = FALSE; + } *ctx = new_ctx; } @@ -2060,13 +2231,11 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu /** * mono_debugger_run_finally: - * @start_ctx: saved processor state - * - * This method is called by the Mono Debugger to call all `finally' clauses of the - * current stack frame. It's used when the user issues a `return' command to make + * \param start_ctx saved processor state + * This method is called by the Mono Debugger to call all \c finally clauses of the + * current stack frame. It's used when the user issues a \c return command to make * the current stack frame return. After returning from this method, the debugger * unwinds the stack one frame and gives control back to the user. - * * NOTE: This method is only used when running inside the Mono Debugger. */ void @@ -2101,8 +2270,11 @@ mono_debugger_run_finally (MonoContext *start_ctx) /** * mono_handle_exception: - * @ctx: saved processor state - * @obj: the exception object + * \param ctx saved processor state + * \param obj the exception object + * + * Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and + * return TRUE. */ gboolean mono_handle_exception (MonoContext *ctx, MonoObject *obj) @@ -2110,7 +2282,7 @@ mono_handle_exception (MonoContext *ctx, MonoObject *obj) MONO_REQ_GC_UNSAFE_MODE; #ifndef DISABLE_PERFCOUNTERS - mono_perfcounters->exceptions_thrown++; + InterlockedIncrement (&mono_perfcounters->exceptions_thrown); #endif return mono_handle_exception_internal (ctx, obj, FALSE, NULL); @@ -2451,7 +2623,7 @@ static void print_process_map (void) #endif } -static gboolean handling_sigsegv = FALSE; +static gboolean handle_crash_loop = FALSE; /* * mono_handle_native_crash: @@ -2467,9 +2639,7 @@ mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_T #endif MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - gboolean is_sigsegv = !strcmp ("SIGSEGV", signal); - - if (handling_sigsegv && is_sigsegv) + if (handle_crash_loop) return; if (mini_get_debug_options ()->suspend_on_native_crash) { @@ -2484,9 +2654,8 @@ mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_T #endif } - /* To prevent infinite loops when the stack walk causes a crash */ - if (is_sigsegv) - handling_sigsegv = TRUE; + /* prevent infinite loops in crash handling */ + handle_crash_loop = TRUE; /* !jit_tls means the thread was not registered with the runtime */ if (jit_tls && mono_thread_internal_current ()) { @@ -2526,12 +2695,12 @@ mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_T * glibc fork acquires some locks, so if the crash happened inside malloc/free, * it will deadlock. Call the syscall directly instead. */ -#if defined(PLATFORM_ANDROID) +#if defined(HOST_ANDROID) /* SYS_fork is defined to be __NR_fork which is not defined in some ndk versions */ g_assert_not_reached (); -#elif !defined(PLATFORM_MACOSX) && defined(SYS_fork) +#elif !defined(HOST_DARWIN) && defined(SYS_fork) pid = (pid_t) syscall (SYS_fork); -#elif defined(PLATFORM_MACOSX) && HAVE_FORK +#elif defined(HOST_DARWIN) && HAVE_FORK pid = (pid_t) fork (); #else g_assert_not_reached (); @@ -2559,7 +2728,7 @@ mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_T #endif } #else -#ifdef PLATFORM_ANDROID +#ifdef HOST_ANDROID /* set DUMPABLE for this process so debuggerd can attach with ptrace(2), see: * https://android.googlesource.com/platform/bionic/+/151da681000c07da3c24cd30a3279b1ca017f452/linker/debugger.cpp#206 * this has changed on later versions of Android. Also, we don't want to @@ -2599,7 +2768,7 @@ mono_handle_native_crash (const char *signal, void *ctx, MONO_SIG_HANDLER_INFO_T if (!mono_do_crash_chaining) { /*Android abort is a fluke, it doesn't abort, it triggers another segv. */ -#if defined (PLATFORM_ANDROID) +#if defined (HOST_ANDROID) exit (-1); #else abort (); @@ -2662,7 +2831,7 @@ mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx) mono_runtime_printf ("%s", text->str); -#if PLATFORM_WIN32 && TARGET_WIN32 && _DEBUG +#if HOST_WIN32 && TARGET_WIN32 && _DEBUG OutputDebugStringA(text->str); #endif @@ -2670,11 +2839,11 @@ mono_print_thread_dump_internal (void *sigctx, MonoContext *start_ctx) mono_runtime_stdout_fflush (); } -/* +/** * mono_print_thread_dump: * - * Print information about the current thread to stdout. - * SIGCTX can be NULL, allowing this to be called from gdb. + * Print information about the current thread to stdout. + * \p sigctx can be NULL, allowing this to be called from gdb. */ void mono_print_thread_dump (void *sigctx) @@ -2711,8 +2880,6 @@ mono_resume_unwind (MonoContext *ctx) mono_restore_context (&new_ctx); } -#ifdef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD - typedef struct { MonoJitInfo *ji; MonoContext ctx; @@ -2738,7 +2905,7 @@ find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data) continue; /*If ip points to the first instruction it means the handler block didn't start so we can leave its execution to the EH machinery*/ - if (ei->handler_start < ip && ip < ei->data.handler_end) { + if (ei->handler_start <= ip && ip < ei->data.handler_end) { pdata->ji = ji; pdata->ei = ei; pdata->ctx = *ctx; @@ -2749,12 +2916,13 @@ find_last_handler_block (StackFrameInfo *frame, MonoContext *ctx, gpointer data) } -static gpointer +static void install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx) { int i; MonoJitExceptionInfo *clause = NULL; gpointer ip; + guint8 *bp; ip = MONO_CONTEXT_GET_IP (ctx); @@ -2762,40 +2930,32 @@ install_handler_block_guard (MonoJitInfo *ji, MonoContext *ctx) clause = &ji->clauses [i]; if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) continue; - if (clause->handler_start < ip && clause->data.handler_end > ip) + if (clause->handler_start <= ip && clause->data.handler_end > ip) break; } /*no matching finally */ if (i == ji->num_clauses) - return NULL; - - /*If we stopped on the instruction right before the try, we haven't actually started executing it*/ - if (ip == clause->handler_start) - return NULL; + return; - return mono_arch_install_handler_block_guard (ji, clause, ctx, mono_create_handler_block_trampoline ()); + /*Load the spvar*/ + bp = (guint8*)MONO_CONTEXT_GET_BP (ctx); + *(bp + clause->exvar_offset) = 1; } /* * Finds the bottom handler block running and install a block guard if needed. */ -gboolean +static gboolean mono_install_handler_block_guard (MonoThreadUnwindState *ctx) { FindHandlerBlockData data = { 0 }; MonoJitTlsData *jit_tls = (MonoJitTlsData *)ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS]; - gpointer resume_ip; - -#ifndef MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD_AOT - if (mono_aot_only) - return FALSE; -#endif /* Guard against a null MonoJitTlsData. This can happens if the thread receives the * interrupt signal before the JIT has time to initialize its TLS data for the given thread. */ - if (!jit_tls || jit_tls->handler_block_return_address) + if (!jit_tls || jit_tls->handler_block) return FALSE; /* Do an async safe stack walk */ @@ -2808,11 +2968,8 @@ mono_install_handler_block_guard (MonoThreadUnwindState *ctx) memcpy (&jit_tls->handler_block_context, &data.ctx, sizeof (MonoContext)); - resume_ip = install_handler_block_guard (data.ji, &data.ctx); - if (resume_ip == NULL) - return FALSE; + install_handler_block_guard (data.ji, &data.ctx); - jit_tls->handler_block_return_address = resume_ip; jit_tls->handler_block = data.ei; return TRUE; @@ -2822,24 +2979,9 @@ static gboolean mono_current_thread_has_handle_block_guard (void) { MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - return jit_tls && jit_tls->handler_block_return_address != NULL; + return jit_tls && jit_tls->handler_block != NULL; } -#else -gboolean -mono_install_handler_block_guard (MonoThreadUnwindState *ctx) -{ - return FALSE; -} - -static gboolean -mono_current_thread_has_handle_block_guard (void) -{ - return FALSE; -} - -#endif - void mono_set_cast_details (MonoClass *from, MonoClass *to) { @@ -2994,7 +3136,12 @@ mono_restore_context (MonoContext *ctx) guint8* mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len) { - if (ji->from_aot) + if (ji->has_unwind_info) { + /* The address/length in the MonoJitInfo structure itself */ + MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji); + *unwind_info_len = info->unw_info_len; + return info->unw_info; + } else if (ji->from_aot) return mono_aot_get_unwind_info (ji, unwind_info_len); else return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len); @@ -3078,6 +3225,12 @@ mono_llvm_raise_exception (MonoException *e) mono_llvm_throw_exception ((MonoObject*)e); } +void +mono_llvm_reraise_exception (MonoException *e) +{ + mono_llvm_rethrow_exception ((MonoObject*)e); +} + void mono_llvm_throw_corlib_exception (guint32 ex_token_index) { @@ -3115,16 +3268,16 @@ mono_llvm_load_exception (void) if (mono_ex->trace_ips) { GList *trace_ips = NULL; - gpointer ip = __builtin_return_address (0); + gpointer ip = MONO_RETURN_ADDRESS (); size_t upper = mono_array_length (mono_ex->trace_ips); - for (int i = 0; i < upper; i+= 2) { + for (int i = 0; i < upper; i += TRACE_IP_ENTRY_SIZE) { gpointer curr_ip = mono_array_get (mono_ex->trace_ips, gpointer, i); - gpointer curr_info = mono_array_get (mono_ex->trace_ips, gpointer, i + 1); - trace_ips = g_list_append (trace_ips, curr_ip); - trace_ips = g_list_append (trace_ips, curr_info); - + for (int j = 0; j < TRACE_IP_ENTRY_SIZE; ++j) { + gpointer p = mono_array_get (mono_ex->trace_ips, gpointer, i + j); + trace_ips = g_list_append (trace_ips, p); + } if (ip == curr_ip) break; }