Browse Source

Improve exception handling when running in mdb: check whether an exception is caught inside a runtime-invoked method or the runtime-invoke wrapper.
2009-06-08 Martin Baulig <[email protected]>

* 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=/trunk/mono/; revision=135635

Martin Baulig 16 years ago
parent
commit
bf16cb052d
4 changed files with 114 additions and 67 deletions
  1. 22 0
      mono/mini/ChangeLog
  2. 2 63
      mono/mini/debug-mini.c
  3. 16 0
      mono/mini/debug-mini.h
  4. 74 4
      mono/mini/mini-exceptions.c

+ 22 - 0
mono/mini/ChangeLog

@@ -1,3 +1,25 @@
+2009-06-08  Martin Baulig  <[email protected]>
+
+	* 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-06-08  Zoltan Varga  <[email protected]>
 
 	* image-writer.c: Improve support for the osx assembler.

+ 2 - 63
mono/mini/debug-mini.c

@@ -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
@@ -888,7 +882,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
@@ -953,7 +947,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
@@ -1037,61 +1031,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 *

+ 16 - 0
mono/mini/debug-mini.h

@@ -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

+ 74 - 4
mono/mini/mini-exceptions.c

@@ -854,7 +854,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;
@@ -923,7 +923,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
 		if (mono_trace_is_enabled ())
 			g_print ("[%p:] EXCEPTION handling: %s\n", (void*)GetCurrentThreadId (), 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
@@ -934,6 +934,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));
@@ -1018,12 +1020,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 {
 								/* 
@@ -1114,6 +1118,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
@@ -1167,7 +1237,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