diff options
-rw-r--r-- | mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs | 3 | ||||
-rw-r--r-- | mcs/class/Mono.Debugger.Soft/Test/dtest.cs | 4 | ||||
-rw-r--r-- | mono/mini/debugger-agent.c | 52 | ||||
-rw-r--r-- | mono/mini/debugger-agent.h | 4 | ||||
-rw-r--r-- | mono/mini/interp/interp-stubs.c | 16 | ||||
-rw-r--r-- | mono/mini/interp/interp.c | 98 | ||||
-rw-r--r-- | mono/mini/interp/interp.h | 8 | ||||
-rw-r--r-- | mono/mini/interp/transform.c | 9 | ||||
-rw-r--r-- | mono/mini/mini-exceptions.c | 107 |
9 files changed, 214 insertions, 87 deletions
diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs index d2b408a68ed..82efc79e51d 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs @@ -343,7 +343,8 @@ public class Tests : TestsBase, ITest2 gc_suspend (); set_ip (); step_filters (); - local_reflect (); + if (args.Length > 0 && args [0] == "local-reflect") + local_reflect (); if (args.Length > 0 && args [0] == "domain-test") /* This takes a lot of time, so execute it conditionally */ domains (); diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs index b9cc720155d..ccd3b6b7602 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs @@ -560,6 +560,10 @@ public class DebuggerTests [Test] public void ClassLocalReflection () { + vm.Detach (); + + Start (new string [] { "dtest-app.exe", "local-reflect" }); + MethodMirror m = entry_point.DeclaringType.Assembly.GetType ("LocalReflectClass").GetMethod ("RunMe"); Assert.IsNotNull (m); diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index 71a050b0703..eb02291e5df 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -239,11 +239,8 @@ typedef struct { */ InvokeData *invoke; - /* - * The context where single stepping should resume while the thread is suspended because - * of an EXCEPTION event. - */ - MonoThreadUnwindState catch_state; + StackFrameInfo catch_frame; + gboolean has_catch_frame; /* * The context which needs to be restored after handling a single step/breakpoint @@ -3239,8 +3236,10 @@ compute_frame_info (MonoInternalThread *thread, DebuggerTlsData *tls) * * First we add all the frames from inside the filter; 'tls->ctx' has the current context. */ - if (tls->context.valid) + if (tls->context.valid) { mono_walk_stack_with_state (process_filter_frame, &tls->context, opts, &user_data); + DEBUG_PRINTF (1, "\tFrame: <call filter>\n"); + } /* * After that, we resume unwinding from the location where the exception has been thrown. */ @@ -5843,23 +5842,14 @@ ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, StepFilte ss_req->start_sp = ss_req->last_sp = MONO_CONTEXT_GET_SP (&tls->context.ctx); - if (tls->catch_state.valid) { - gboolean res; + if (tls->has_catch_frame) { StackFrameInfo frame; - MonoContext new_ctx; - MonoLMF *lmf = NULL; /* * We are stopped at a throw site. Stepping should go to the catch site. */ - - /* Find the the jit info for the catch context */ - res = mono_find_jit_info_ext ( - (MonoDomain *)tls->catch_state.unwind_data [MONO_UNWIND_DATA_DOMAIN], - (MonoJitTlsData *)((MonoThreadInfo*)thread->thread_info)->jit_data, - NULL, &tls->catch_state.ctx, &new_ctx, NULL, &lmf, NULL, &frame); - g_assert (res); - g_assert (frame.type == FRAME_TYPE_MANAGED); + frame = tls->catch_frame; + g_assert (frame.type == FRAME_TYPE_MANAGED || frame.type == FRAME_TYPE_INTERP); /* * Find the seq point corresponding to the landing site ip, which is the first seq @@ -6028,8 +6018,8 @@ mono_debugger_agent_unhandled_exception (MonoException *exc) #endif void -mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, - MonoContext *catch_ctx) +mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, + MonoContext *catch_ctx, StackFrameInfo *catch_frame) { int i, j, suspend_policy; GSList *events; @@ -6096,8 +6086,8 @@ mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx return; ji = mini_jit_info_table_find (mono_domain_get (), (char *)MONO_CONTEXT_GET_IP (throw_ctx), NULL); - if (catch_ctx) - catch_ji = mini_jit_info_table_find (mono_domain_get (), (char *)MONO_CONTEXT_GET_IP (catch_ctx), NULL); + if (catch_frame) + catch_ji = catch_frame->ji; else catch_ji = NULL; @@ -6135,16 +6125,18 @@ mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx mono_loader_unlock (); if (tls && ei.caught && catch_ctx) { - memset (&tls->catch_state, 0, sizeof (tls->catch_state)); - tls->catch_state.ctx = *catch_ctx; - tls->catch_state.unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get (); - tls->catch_state.valid = TRUE; + if (catch_frame) { + tls->has_catch_frame = TRUE; + tls->catch_frame = *catch_frame; + } else { + memset (&tls->catch_frame, 0, sizeof (tls->catch_frame)); + } } process_event (EVENT_KIND_EXCEPTION, &ei, 0, throw_ctx, events, suspend_policy); if (tls) - tls->catch_state.valid = FALSE; + tls->has_catch_frame = FALSE; } void @@ -9566,7 +9558,7 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf) if (tls->frames [0]->ji->is_interp) { MonoJitTlsData *jit_data = ((MonoThreadInfo*)thread->thread_info)->jit_data; - mono_interp_set_resume_state (jit_data, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset); + mono_interp_set_resume_state (jit_data, NULL, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset); } else { MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset); } @@ -10586,8 +10578,8 @@ mono_debugger_agent_free_domain_info (MonoDomain *domain) } void -mono_debugger_agent_handle_exception (MonoException *ext, MonoContext *throw_ctx, - MonoContext *catch_ctx) +mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, + MonoContext *catch_ctx, StackFrameInfo *catch_frame) { } diff --git a/mono/mini/debugger-agent.h b/mono/mini/debugger-agent.h index 3267f82740e..1ff9de11db4 100644 --- a/mono/mini/debugger-agent.h +++ b/mono/mini/debugger-agent.h @@ -6,6 +6,7 @@ #define __MONO_DEBUGGER_AGENT_H__ #include "mini.h" +#include <mono/utils/mono-stack-unwinding.h> MONO_API void mono_debugger_agent_parse_options (char *options); @@ -34,7 +35,8 @@ mono_debugger_agent_unhandled_exception (MonoException *exc); #endif void -mono_debugger_agent_handle_exception (MonoException *ext, MonoContext *throw_ctx, MonoContext *catch_ctx); +mono_debugger_agent_handle_exception (MonoException *exc, MonoContext *throw_ctx, + MonoContext *catch_ctx, StackFrameInfo *catch_frame); void mono_debugger_agent_begin_exception_filter (MonoException *exc, MonoContext *ctx, MonoContext *orig_ctx); diff --git a/mono/mini/interp/interp-stubs.c b/mono/mini/interp/interp-stubs.c index 176e45b6080..294e6e55311 100644 --- a/mono/mini/interp/interp-stubs.c +++ b/mono/mini/interp/interp-stubs.c @@ -59,6 +59,13 @@ mono_interp_frame_get_this (MonoInterpFrameHandle frame) return NULL; } +MonoInterpFrameHandle +mono_interp_frame_get_parent (MonoInterpFrameHandle frame) +{ + g_assert_not_reached (); + return NULL; +} + void mono_interp_start_single_stepping (void) { @@ -70,7 +77,7 @@ mono_interp_stop_single_stepping (void) } void -mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip) +mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip) { g_assert_not_reached (); } @@ -81,6 +88,13 @@ mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handl g_assert_not_reached (); } +gboolean +mono_interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip) +{ + g_assert_not_reached (); + return FALSE; +} + void mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data) { diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index 627480c44ac..5ca1ea7f18b 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -109,7 +109,8 @@ static gboolean ss_enabled; static char* dump_frame (InterpFrame *inv); static MonoArray *get_trace_ips (MonoDomain *domain, InterpFrame *top); -static void ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally); +static void interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame); +static void interp_exec_method (InterpFrame *frame, ThreadContext *context); typedef void (*ICallMethod) (InterpFrame *frame); @@ -1252,7 +1253,7 @@ get_trace_ips (MonoDomain *domain, InterpFrame *top) if (inv->imethod != NULL) ++i; - res = mono_array_new_checked (domain, mono_defaults.int_class, 2 * i, &error); + res = mono_array_new_checked (domain, mono_defaults.int_class, 3 * i, &error); mono_error_cleanup (&error); /* FIXME: don't swallow the error */ for (i = 0, inv = top; inv; inv = inv->parent) @@ -1261,6 +1262,8 @@ get_trace_ips (MonoDomain *domain, InterpFrame *top) ++i; mono_array_set (res, gpointer, i, (gpointer)inv->ip); ++i; + mono_array_set (res, gpointer, i, NULL); + ++i; } return res; @@ -1393,7 +1396,7 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb if (exc) frame.invoke_trap = 1; - ves_exec_method_with_context (&frame, context, NULL, NULL, -1); + interp_exec_method (&frame, context); if (context == &context_struct) set_context (NULL); @@ -1537,7 +1540,7 @@ interp_entry (InterpEntryData *data) break; } - ves_exec_method_with_context (&frame, context, NULL, NULL, -1); + interp_exec_method (&frame, context); if (context == &context_struct) set_context (NULL); else @@ -2185,9 +2188,10 @@ static int opcode_counts[512]; /* * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index. + * If BASE_FRAME is not NULL, copy arguments/locals from BASE_FRAME. */ static void -ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally) +interp_exec_method_full (InterpFrame *frame, ThreadContext *context, guint16 *start_with_ip, MonoException *filter_exception, int exit_at_finally, InterpFrame *base_frame) { InterpFrame child_frame; GSList *finally_ips = NULL; @@ -2239,13 +2243,17 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign } rtm = frame->imethod; - if (!start_with_ip ) { + if (!start_with_ip) { frame->args = alloca (rtm->alloca_size); memset (frame->args, 0, rtm->alloca_size); ip = rtm->code; } else { ip = start_with_ip; + if (base_frame) { + frame->args = alloca (rtm->alloca_size); + memcpy (frame->args, base_frame->args, rtm->alloca_size); + } } sp = frame->stack = (stackval *) ((char *) frame->args + rtm->args_size); vt_sp = (unsigned char *) sp + rtm->stack_size; @@ -2444,7 +2452,7 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign } } - ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); + interp_exec_method (&child_frame, context); context->current_frame = frame; @@ -2536,7 +2544,7 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign --sp; child_frame.stack_args = sp; - ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); + interp_exec_method (&child_frame, context); context->current_frame = frame; @@ -2578,7 +2586,7 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign } child_frame.stack_args = sp; - ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); + interp_exec_method (&child_frame, context); context->current_frame = frame; @@ -2651,7 +2659,7 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign sp [0].data.p = unboxed; } - ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); + interp_exec_method (&child_frame, context); context->current_frame = frame; @@ -2705,7 +2713,7 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign sp [0].data.p = unboxed; } - ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); + interp_exec_method (&child_frame, context); context->current_frame = frame; @@ -3523,7 +3531,7 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign g_assert (csig->call_convention == MONO_CALL_DEFAULT); - ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); + interp_exec_method (&child_frame, context); context->current_frame = frame; @@ -4410,7 +4418,6 @@ array_constructed: frame->ip = ip; if (frame->ex_handler != NULL && MONO_OFFSET_IN_HANDLER(frame->ex_handler, frame->ip - rtm->code)) { - MonoException *exc = frame->ex; frame->ex_handler = NULL; frame->ex = NULL; if (frame->imethod->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) { @@ -4991,7 +4998,7 @@ array_constructed: stackval retval; memcpy (&dup_frame, inv, sizeof (InterpFrame)); dup_frame.retval = &retval; - ves_exec_method_with_context (&dup_frame, context, inv->imethod->code + clause->data.filter_offset, frame->ex, -1); + interp_exec_method_full (&dup_frame, context, inv->imethod->code + clause->data.filter_offset, frame->ex, -1, NULL); if (dup_frame.retval->data.i) { #if DEBUG_INTERP if (tracing) @@ -5159,6 +5166,9 @@ check_lmf: exit_frame: + if (base_frame) + memcpy (base_frame->args, frame->args, rtm->alloca_size); + if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) { MonoProfilerCallContext *prof_ctx = NULL; @@ -5191,6 +5201,12 @@ exit_frame: DEBUG_LEAVE (); } +static void +interp_exec_method (InterpFrame *frame, ThreadContext *context) +{ + interp_exec_method_full (frame, context, NULL, NULL, -1, NULL); +} + void mono_interp_parse_options (const char *options) { @@ -5385,7 +5401,7 @@ mono_interp_regression_list (int verbose, int count, char *images []) * Set the state the interpeter will continue to execute from after execution returns to the interpreter. */ void -mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip) +mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip) { ThreadContext *context; @@ -5397,6 +5413,9 @@ mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoIn context->handler_frame = interp_frame; /* This is on the stack, so it doesn't need a wbarrier */ context->handler_frame->ex = ex; + /* Ditto */ + if (ei) + *(MonoException**)(context->handler_frame->locals + ei->exvar_offset) = ex; context->handler_ip = handler_ip; } @@ -5409,10 +5428,38 @@ mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoIn void mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip) { - InterpFrame *iframe = frame->interp_frame; - ThreadContext *context = mono_native_tls_get_value (thread_context_id); + InterpFrame *iframe = frame->interp_frame; + ThreadContext *context = mono_native_tls_get_value (thread_context_id); - ves_exec_method_with_context (iframe, context, handler_ip, NULL, clause_index); + interp_exec_method_full (iframe, context, handler_ip, NULL, clause_index, NULL); +} + +/* + * mono_interp_run_filter: + * + * Run the filter clause identified by CLAUSE_INDEX in the intepreter frame given by + * frame->interp_frame. + */ +gboolean +mono_interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip) +{ + InterpFrame *iframe = frame->interp_frame; + ThreadContext *context = mono_native_tls_get_value (thread_context_id); + InterpFrame child_frame; + stackval retval; + + /* + * Have to run the clause in a new frame which is a copy of IFRAME, since + * during debugging, there are two copies of the frame on the stack. + */ + memset (&child_frame, 0, sizeof (InterpFrame)); + child_frame.imethod = iframe->imethod; + child_frame.retval = &retval; + child_frame.parent = iframe; + + interp_exec_method_full (&child_frame, context, handler_ip, ex, clause_index, iframe); + /* ENDFILTER stores the result into child_frame->retval */ + return child_frame.retval->data.i ? TRUE : FALSE; } typedef struct { @@ -5432,6 +5479,11 @@ mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_dat stack_iter->current = (InterpFrame*)interp_exit_data; } +/* + * mono_interp_frame_iter_next: + * + * Fill out FRAME with date for the next interpreter frame. + */ gboolean mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) { @@ -5440,7 +5492,7 @@ mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) memset (frame, 0, sizeof (StackFrameInfo)); /* pinvoke frames doesn't have imethod set */ - while (iframe && !(iframe->imethod && iframe->imethod->code)) + while (iframe && !(iframe->imethod && iframe->imethod->code && iframe->imethod->jinfo)) iframe = iframe->parent; if (!iframe) return FALSE; @@ -5541,6 +5593,14 @@ mono_interp_frame_get_this (MonoInterpFrameHandle frame) return iframe->args + arg_offset; } +MonoInterpFrameHandle +mono_interp_frame_get_parent (MonoInterpFrameHandle frame) +{ + InterpFrame *iframe = (InterpFrame*)frame; + + return iframe->parent; +} + void mono_interp_start_single_stepping (void) { diff --git a/mono/mini/interp/interp.h b/mono/mini/interp/interp.h index 8415c6f43fe..ad2ddc9703c 100644 --- a/mono/mini/interp/interp.h +++ b/mono/mini/interp/interp.h @@ -66,11 +66,14 @@ void interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data); void -mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip); +mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip); void mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip); +gboolean +mono_interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip); + void mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data); @@ -101,6 +104,9 @@ mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos); gpointer mono_interp_frame_get_this (MonoInterpFrameHandle frame); +MonoInterpFrameHandle +mono_interp_frame_get_parent (MonoInterpFrameHandle frame); + void mono_interp_start_single_stepping (void); diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index a3d0e60df75..5605a196b72 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -1656,6 +1656,15 @@ generate (MonoMethod *method, MonoMethodHeader *header, InterpMethod *rtm, unsig mono_bitset_set_fast (seq_point_locs, sps [i].il_offset); } g_free (sps); + + MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method); + if (asyncMethod) { + for (i = 0; asyncMethod != NULL && i < asyncMethod->num_awaits; i++) { + mono_bitset_set_fast (seq_point_locs, asyncMethod->resume_offsets [i]); + mono_bitset_set_fast (seq_point_locs, asyncMethod->yield_offsets [i]); + } + mono_debug_free_method_async_debug_info (asyncMethod); + } } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) { /* Methods without line number info like auto-generated property accessors */ seq_point_locs = mono_bitset_new (header->code_size, 0); diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 10fe33c2a2c..42a43d48ce7 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -98,6 +98,8 @@ typedef struct { gpointer ip; gpointer generic_info; + /* Only for interpreter frames */ + MonoJitInfo *ji; } ExceptionTraceIp; /* Number of words in trace_ips belonging to one entry */ @@ -701,10 +703,30 @@ unwinder_unwind_frame (Unwinder *unwinder, StackFrameInfo *frame) { if (unwinder->in_interp) { + gpointer parent; + memcpy (new_ctx, ctx, sizeof (MonoContext)); + + /* Process debugger invokes */ + /* The DEBUGGER_INVOKE should be returned before the first interpreter frame for the invoke */ + if ((gpointer)MONO_CONTEXT_GET_SP (ctx) > (gpointer)(*lmf)) { + if (((guint64)(*lmf)->previous_lmf) & 2) { + MonoLMFExt *ext = (MonoLMFExt*)(*lmf); + if (ext->debugger_invoke) { + *lmf = (MonoLMF *)(((guint64)(*lmf)->previous_lmf) & ~7); + frame->type = FRAME_TYPE_DEBUGGER_INVOKE; + return TRUE; + } + } + } + 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); + if (frame->type == FRAME_TYPE_INTERP) { + parent = mono_interp_frame_get_parent (frame->interp_frame); + /* This is needed so code which uses ctx->sp for frame ordering would work */ + MONO_CONTEXT_SET_SP (new_ctx, parent); } + 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, @@ -929,16 +951,20 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info gpointer generic_info = trace_ip.generic_info; MonoMethod *method; - ji = mono_jit_info_table_find (domain, (char *)ip); - if (ji == NULL) { - /* Unmanaged frame */ - mono_array_setref (res, i, sf); - continue; + if (trace_ip.ji) { + ji = trace_ip.ji; + } else { + ji = mono_jit_info_table_find (domain, (char *)ip); + if (ji == NULL) { + /* Unmanaged frame */ + mono_array_setref (res, i, sf); + continue; + } } g_assert (ji != NULL); - if (mono_llvm_only) + if (mono_llvm_only || !generic_info) /* Can't resolve actual method */ method = jinfo_get_method (ji); else @@ -1581,14 +1607,14 @@ setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, GList **trac } /* - * mono_handle_exception_internal_first_pass: + * handle_exception_first_pass: * * The first pass of exception handling. Unwind the stack until a catch clause which can catch - * OBJ is found. Run the index of the filter clause which caught the exception into + * OBJ is found. Store the index of the filter clause which caught the exception into * OUT_FILTER_IDX. Return TRUE if the exception is caught, FALSE otherwise. */ static gboolean -mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception) +handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception, StackFrameInfo *catch_frame) { MonoError error; MonoDomain *domain = mono_domain_get (); @@ -1704,8 +1730,9 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi if (method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) { // avoid giant stack traces during a stack overflow if (frame_count < 1000) { - trace_ips = g_list_prepend (trace_ips, MONO_CONTEXT_GET_IP (ctx)); + trace_ips = g_list_prepend (trace_ips, ip); trace_ips = g_list_prepend (trace_ips, get_generic_info_from_stack_frame (ji, ctx)); + trace_ips = g_list_prepend (trace_ips, ji); } } @@ -1747,33 +1774,39 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi mono_atomic_inc_i32 (&mono_perfcounters->exceptions_filters); #endif + if (!ji->is_interp) { #ifndef MONO_CROSS_COMPILE #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG - if (ji->from_llvm) - MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj); - else - /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */ - *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj; + if (ji->from_llvm) + MONO_CONTEXT_SET_LLVM_EXC_REG (ctx, ex_obj); + else + /* Can't pass the ex object in a register yet to filter clauses, because call_filter () might not support it */ + *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj; #else - g_assert (!ji->from_llvm); - /* store the exception object in bp + ei->exvar_offset */ - *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj; + g_assert (!ji->from_llvm); + /* store the exception object in bp + ei->exvar_offset */ + *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = ex_obj; #endif #endif #ifdef MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG - /* - * Pass the original il clause index to the landing pad so it can - * branch to the landing pad associated with the il clause. - * This is needed because llvm compiled code assumes that the EH - * code always branches to the innermost landing pad. - */ - if (ji->from_llvm) - MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index); + /* + * Pass the original il clause index to the landing pad so it can + * branch to the landing pad associated with the il clause. + * This is needed because llvm compiled code assumes that the EH + * code always branches to the innermost landing pad. + */ + if (ji->from_llvm) + MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG (ctx, ei->clause_index); #endif + } mono_debugger_agent_begin_exception_filter (mono_ex, ctx, &initial_ctx); - filtered = call_filter (ctx, ei->data.filter); + if (ji->is_interp) { + filtered = mono_interp_run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter); + } else { + filtered = call_filter (ctx, ei->data.filter); + } mono_debugger_agent_end_exception_filter (mono_ex, ctx, &initial_ctx); if (filtered && out_filter_idx) *out_filter_idx = filter_idx; @@ -1787,6 +1820,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi /* mono_debugger_agent_handle_exception () needs this */ mini_set_abort_threshold (ctx); MONO_CONTEXT_SET_IP (ctx, ei->handler_start); + frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start; + *catch_frame = frame; return TRUE; } } @@ -1803,6 +1838,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi /* mono_debugger_agent_handle_exception () needs this */ if (!in_interp) MONO_CONTEXT_SET_IP (ctx, ei->handler_start); + frame.native_offset = (char*)ei->handler_start - (char*)ji->code_start; + *catch_frame = frame; return TRUE; } mono_error_cleanup (&isinst_error); @@ -1969,12 +2006,13 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu 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); + StackFrameInfo catch_frame; + res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame); if (!res) { if (mini_get_debug_options ()->break_on_exc) G_BREAKPOINT (); - mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL); + mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL, NULL); if (mini_get_debug_options ()->suspend_on_unhandled) { mono_runtime_printf_err ("Unhandled exception, suspending..."); @@ -2002,9 +2040,9 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu } if (unhandled) - mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL); + mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, NULL, NULL); else - mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, &ctx_cp); + mono_debugger_agent_handle_exception ((MonoException *)obj, ctx, &ctx_cp, &catch_frame); } } @@ -2179,7 +2217,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu * 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); + mono_interp_set_resume_state (jit_tls, mono_ex, ei, frame.interp_frame, ei->handler_start); /* Undo the IP adjustment done by mono_arch_unwind_frame () */ #if defined(TARGET_AMD64) ctx->gregs [AMD64_RIP] ++; @@ -3234,6 +3272,7 @@ throw_exception (MonoObject *ex, gboolean rethrow) for (l = ips; l; l = l->next) { trace = g_list_append (trace, l->data); trace = g_list_append (trace, NULL); + trace = g_list_append (trace, NULL); } MonoArray *ips_arr = mono_glist_to_array (trace, mono_defaults.int_class, &error); mono_error_assert_ok (&error); |