Skip to content

Commit

Permalink
Improve exception handling when running in mdb: check whether an exce…
Browse files Browse the repository at this point in the history
…ption is caught inside a runtime-invoked method or the runtime-invoke wrapper.

2009-06-08  Martin Baulig  <martin@ximian.com>

	* debug-mini.c
	(MonoDebuggerExceptionAction): Moved into debug-mini.h.
	(_mono_debugger_throw_exception): Don't make this static.
	(_mono_debugger_unhandled_exception): Likewise.
	(mono_debugger_handle_exception): Moved to mini-exceptions.c

	* debug-mini.c
	(MonoDebuggerExceptionAction): Moved here from debug-mini.c.
	(_mono_debugger_throw_exception): Add function prototype.
	(_mono_debugger_unhandled_exception): Likewise.

	* mini-exceptions.c
	(mono_handle_exception_internal): Added `MonoJitInfo **out_ji'
	arg; return the first exception handler if the exception is caught
	and we're running inside the debugger.
	(mono_debugger_handle_exception): Moved here from debug-mini.c;
	improve exception handle inside runtime-invoke, check whether the
	exception is actually caught in the method being invoked and not
	by the runtime-invoke-wrapper.

svn path=/branches/mono-2-4/mono/; revision=135636
  • Loading branch information
Martin Baulig committed Jun 8, 2009
1 parent 8c11b0c commit aa667d9
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 67 deletions.
44 changes: 44 additions & 0 deletions mono/mini/ChangeLog
@@ -1,3 +1,25 @@
2009-06-08 Martin Baulig <martin@ximian.com>

* debug-mini.c
(MonoDebuggerExceptionAction): Moved into debug-mini.h.
(_mono_debugger_throw_exception): Don't make this static.
(_mono_debugger_unhandled_exception): Likewise.
(mono_debugger_handle_exception): Moved to mini-exceptions.c

* debug-mini.c
(MonoDebuggerExceptionAction): Moved here from debug-mini.c.
(_mono_debugger_throw_exception): Add function prototype.
(_mono_debugger_unhandled_exception): Likewise.

* mini-exceptions.c
(mono_handle_exception_internal): Added `MonoJitInfo **out_ji'
arg; return the first exception handler if the exception is caught
and we're running inside the debugger.
(mono_debugger_handle_exception): Moved here from debug-mini.c;
improve exception handle inside runtime-invoke, check whether the
exception is actually caught in the method being invoked and not
by the runtime-invoke-wrapper.

2009-05-26 Zoltan Varga <vargaz@gmail.com>

* mini-sparc.c (add_outarg_load): Fix the sparc build.
Expand Down Expand Up @@ -56,6 +78,28 @@
* aot-compiler.c (add_wrappers): Add remoting-invoke-with-check wrappers
for virtual methods too.

2009-06-08 Martin Baulig <martin@ximian.com>

* debug-mini.c
(MonoDebuggerExceptionAction): Moved into debug-mini.h.
(_mono_debugger_throw_exception): Don't make this static.
(_mono_debugger_unhandled_exception): Likewise.
(mono_debugger_handle_exception): Moved to mini-exceptions.c

* debug-mini.c
(MonoDebuggerExceptionAction): Moved here from debug-mini.c.
(_mono_debugger_throw_exception): Add function prototype.
(_mono_debugger_unhandled_exception): Likewise.

* mini-exceptions.c
(mono_handle_exception_internal): Added `MonoJitInfo **out_ji'
arg; return the first exception handler if the exception is caught
and we're running inside the debugger.
(mono_debugger_handle_exception): Moved here from debug-mini.c;
improve exception handle inside runtime-invoke, check whether the
exception is actually caught in the method being invoked and not
by the runtime-invoke-wrapper.

2009-05-06 Zoltan Varga <vargaz@gmail.com>

Backport of r133651.
Expand Down
65 changes: 2 additions & 63 deletions mono/mini/debug-mini.c
Expand Up @@ -81,12 +81,6 @@ typedef struct {
guint32 stop_unhandled;
} MonoDebuggerExceptionInfo;

typedef enum {
MONO_DEBUGGER_EXCEPTION_ACTION_NONE = 0,
MONO_DEBUGGER_EXCEPTION_ACTION_STOP = 1,
MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED = 2
} MonoDebuggerExceptionAction;

MonoDebuggerThreadInfo *mono_debugger_thread_table = NULL;

static inline void
Expand Down Expand Up @@ -887,7 +881,7 @@ find_debugger_thread_info (MonoThread *thread)
}
#endif

static MonoDebuggerExceptionAction
MonoDebuggerExceptionAction
_mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
{
#ifdef MONO_DEBUGGER_SUPPORTED
Expand Down Expand Up @@ -952,7 +946,7 @@ _mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
return MONO_DEBUGGER_EXCEPTION_ACTION_NONE;
}

static gboolean
gboolean
_mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
{
#ifdef MONO_DEBUGGER_SUPPORTED
Expand Down Expand Up @@ -1036,61 +1030,6 @@ mono_debugger_call_exception_handler (gpointer addr, gpointer stack, MonoObject
#endif
}

/*
* mono_debugger_handle_exception:
*
* Notify the debugger about exceptions. Returns TRUE if the debugger wants us to stop
* at the exception and FALSE to resume with the normal exception handling.
*
* The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
* MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
* `callq throw' instruction.
*/
gboolean
mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
{
MonoDebuggerExceptionAction action;

if (!mono_debug_using_mono_debugger ())
return FALSE;

if (!obj) {
MonoException *ex = mono_get_exception_null_reference ();
MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
obj = (MonoObject *)ex;
}

action = _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);

if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
/*
* The debugger wants us to stop on the `throw' instruction.
* By the time we get here, it already inserted a breakpoint there.
*/
return TRUE;
} else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
MonoContext ctx_cp = *ctx;

/*
* The debugger wants us to stop only if this exception is user-unhandled.
*/

if (!mono_handle_exception (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), TRUE)) {
/*
* The exception is user-unhandled - tell the debugger to stop.
*/
return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
}

/*
* The exception is catched somewhere - resume with the normal exception handling and don't
* stop in the debugger.
*/
}

return FALSE;
}

#ifdef MONO_DEBUGGER_SUPPORTED

static gchar *
Expand Down
16 changes: 16 additions & 0 deletions mono/mini/debug-mini.h
Expand Up @@ -30,6 +30,22 @@ mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj);
MonoObject *
mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc);

/*
* Internal exception API.
*/

typedef enum {
MONO_DEBUGGER_EXCEPTION_ACTION_NONE = 0,
MONO_DEBUGGER_EXCEPTION_ACTION_STOP = 1,
MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED = 2
} MonoDebuggerExceptionAction;

MonoDebuggerExceptionAction
_mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc);

gboolean
_mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc);

/*
* This is the old breakpoint interface.
* It isn't used by the debugger anymore, but still when using the `--break' command
Expand Down
78 changes: 74 additions & 4 deletions mono/mini/mini-exceptions.c
Expand Up @@ -850,7 +850,7 @@ get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContex
* the first filter clause which caught the exception.
*/
static gboolean
mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only, gint32 *out_filter_idx)
mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer original_ip, gboolean test_only, gint32 *out_filter_idx, MonoJitInfo **out_ji)
{
MonoDomain *domain = mono_domain_get ();
MonoJitInfo *ji, rji;
Expand Down Expand Up @@ -919,7 +919,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
if (mono_trace_is_enabled ())
g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
mono_profiler_exception_thrown (obj);
if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, &first_filter_idx)) {
if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, &first_filter_idx, out_ji)) {
if (mono_break_on_exc)
G_BREAKPOINT ();
// FIXME: This runs managed code so it might cause another stack overflow when
Expand All @@ -930,6 +930,8 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina

if (out_filter_idx)
*out_filter_idx = -1;
if (out_ji)
*out_ji = NULL;
filter_idx = 0;
initial_ctx = *ctx;
memset (&rji, 0, sizeof (rji));
Expand Down Expand Up @@ -1014,12 +1016,14 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
}

if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
// mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
if (test_only) {
mono_perfcounters->exceptions_filters++;
mono_debugger_call_exception_handler (ei->data.filter, MONO_CONTEXT_GET_SP (ctx), obj);
filtered = call_filter (ctx, ei->data.filter);
if (filtered && out_filter_idx)
*out_filter_idx = filter_idx;
if (out_ji)
*out_ji = ji;
}
else {
/*
Expand Down Expand Up @@ -1110,6 +1114,72 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
g_assert_not_reached ();
}

/*
* mono_debugger_handle_exception:
*
* Notify the debugger about exceptions. Returns TRUE if the debugger wants us to stop
* at the exception and FALSE to resume with the normal exception handling.
*
* The arch code is responsible to setup @ctx in a way that MONO_CONTEXT_GET_IP () and
* MONO_CONTEXT_GET_SP () point to the throw instruction; ie. before executing the
* `callq throw' instruction.
*/
gboolean
mono_debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
{
MonoDebuggerExceptionAction action;

if (!mono_debug_using_mono_debugger ())
return FALSE;

if (!obj) {
MonoException *ex = mono_get_exception_null_reference ();
MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
obj = (MonoObject *)ex;
}

action = _mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);

if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
/*
* The debugger wants us to stop on the `throw' instruction.
* By the time we get here, it already inserted a breakpoint there.
*/
return TRUE;
} else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
MonoContext ctx_cp = *ctx;
MonoJitInfo *ji = NULL;
gboolean ret;

/*
* The debugger wants us to stop only if this exception is user-unhandled.
*/

ret = mono_handle_exception_internal (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), TRUE, NULL, &ji);
if (ret && (ji != NULL) && (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
/*
* The exception is handled in a runtime-invoke wrapper, that means that it's unhandled
* inside the method being invoked, so we handle it like a user-unhandled exception.
*/
ret = FALSE;
}

if (!ret) {
/*
* The exception is user-unhandled - tell the debugger to stop.
*/
return _mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
}

/*
* The exception is catched somewhere - resume with the normal exception handling and don't
* stop in the debugger.
*/
}

return FALSE;
}

/**
* mono_debugger_run_finally:
* @start_ctx: saved processor state
Expand Down Expand Up @@ -1163,7 +1233,7 @@ mono_handle_exception (MonoContext *ctx, gpointer obj, gpointer original_ip, gbo
{
if (!test_only)
mono_perfcounters->exceptions_thrown++;
return mono_handle_exception_internal (ctx, obj, original_ip, test_only, NULL);
return mono_handle_exception_internal (ctx, obj, original_ip, test_only, NULL, NULL);
}

#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
Expand Down

0 comments on commit aa667d9

Please sign in to comment.