+2010-03-03 Rolf Bjarne Kvinge <RKvinge@novell.com>
+
+ * mono.1: Document exception tracing.
+
2010-02-18 Marek Habersack <mhabersack@novell.com>
* mono-configuration-crypto.1: added
mono --trace=M:System.Console:WriteLine app.exe
+.fi
+Exceptions can also be traced, it will cause a stack trace to be
+printed every time an exception of the specified type is thrown.
+The exception type can be specified with or without the namespace,
+and to trace all exceptions, specify 'all' as the type name.
+.nf
+
+ mono --trace=E:System.Exception app.exe
+
.fi
As previously noted, various rules can be specified at once:
.nf
+2010-03-03 Rolf Bjarne Kvinge <RKvinge@novell.com>
+
+ * trace.c|h:
+ * mini-exceptions.c: Add support for printing stack traces when handling
+ exceptions, and when printing exceptions thrown while tracing also print
+ the exception message.
+
2010-03-03 Rolf Bjarne Kvinge <RKvinge@novell.com>
* trace.c: We need to parse exclude tokens ('-') before string tokens,
if (!test_only) {
MonoContext ctx_cp = *ctx;
- if (mono_trace_is_enabled ())
- g_print ("[%p:] EXCEPTION handling: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj)->name);
+ if (mono_trace_is_enabled ()) {
+ MonoMethod *system_exception_get_message = mono_class_get_method_from_name (mono_defaults.exception_class, "get_Message", 0);
+ MonoMethod *get_message = system_exception_get_message == NULL ? NULL : mono_object_get_virtual_method (obj, system_exception_get_message);
+ MonoObject *message;
+ const char *type_name = mono_class_get_name (mono_object_class (mono_ex));
+ char *msg = NULL;
+ MonoObject *exc = NULL;
+ if (get_message == NULL) {
+ message = NULL;
+ } else if (!strcmp (type_name, "OutOfMemoryException") || !strcmp (type_name, "StackOverflowException")) {
+ message = NULL;
+ msg = g_strdup_printf ("(No exception message for: %s)\n", type_name);
+ } else {
+ message = mono_runtime_invoke (get_message, obj, NULL, &exc);
+
+ }
+ if (msg == NULL) {
+ msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
+ }
+ g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
+ g_free (msg);
+ if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
+ mono_print_thread_dump_from_ctx (ctx);
+ }
mono_profiler_exception_thrown (obj);
if (!mono_handle_exception_internal (&ctx_cp, obj, original_ip, TRUE, FALSE, &first_filter_idx, out_ji)) {
if (mono_break_on_exc)
static MonoTraceSpec trace_spec;
+gboolean
+mono_trace_eval_exception (MonoClass *klass)
+{
+ int include = 0;
+ int i;
+
+ if (!klass)
+ return FALSE;
+
+ for (i = 0; i < trace_spec.len; i++) {
+ MonoTraceOperation *op = &trace_spec.ops [i];
+ int inc = 0;
+
+ switch (op->op){
+ case MONO_TRACEOP_EXCEPTION:
+ if (strcmp ("", op->data) == 0 && strcmp ("all", op->data2) == 0)
+ inc = 1;
+ else if (strcmp ("", op->data) == 0 || strcmp (klass->name_space, op->data) == 0)
+ if (strcmp (klass->name, op->data2) == 0)
+ inc = 1;
+ break;
+ default:
+ break;
+ }
+ if (op->exclude){
+ if (inc)
+ include = 0;
+ } else if (inc)
+ include = 1;
+ }
+
+ return include;
+}
+
gboolean
mono_trace_eval (MonoMethod *method)
{
case MONO_TRACEOP_NAMESPACE:
if (strcmp (method->klass->name_space, op->data) == 0)
inc = 1;
+ case MONO_TRACEOP_EXCEPTION:
+ break;
}
if (op->exclude){
if (inc)
TOKEN_CLASS,
TOKEN_ALL,
TOKEN_PROGRAM,
+ TOKEN_EXCEPTION,
TOKEN_NAMESPACE,
TOKEN_STRING,
TOKEN_EXCLUDE,
get_string ();
return TOKEN_CLASS;
}
+ if (input [0] == 'E' && input [1] == ':'){
+ input += 2;
+ get_string ();
+ return TOKEN_EXCEPTION;
+ }
if (*input == '-'){
input++;
return TOKEN_EXCLUDE;
else if (token == TOKEN_NAMESPACE){
trace_spec.ops [*last].op = MONO_TRACEOP_NAMESPACE;
trace_spec.ops [*last].data = g_strdup (value);
- } else if (token == TOKEN_CLASS){
+ } else if (token == TOKEN_CLASS || token == TOKEN_EXCEPTION){
char *p = strrchr (value, '.');
if (p) {
*p++ = 0;
trace_spec.ops [*last].data = g_strdup ("");
trace_spec.ops [*last].data2 = g_strdup (value);
}
- trace_spec.ops [*last].op = MONO_TRACEOP_CLASS;
+ trace_spec.ops [*last].op = token == TOKEN_CLASS ? MONO_TRACEOP_CLASS : MONO_TRACEOP_EXCEPTION;
} else if (token == TOKEN_STRING){
trace_spec.ops [*last].op = MONO_TRACEOP_ASSEMBLY;
trace_spec.ops [*last].data = g_strdup (value);
{
return trace_spec.enabled;
}
-
MONO_TRACEOP_METHOD,
MONO_TRACEOP_ASSEMBLY,
MONO_TRACEOP_CLASS,
- MONO_TRACEOP_NAMESPACE
+ MONO_TRACEOP_NAMESPACE,
+ MONO_TRACEOP_EXCEPTION,
} MonoTraceOpcode;
typedef struct {
void mono_trace_enable (gboolean enable) MONO_INTERNAL;
gboolean mono_trace_is_enabled (void) MONO_INTERNAL;
+gboolean mono_trace_eval_exception (MonoClass *klass) MONO_INTERNAL;
G_END_DECLS