2007-06-10 Sanghyeon Seo <sanxiyn@gmail.com>
[mono.git] / mono / mini / mini-exceptions.c
index 7212707ad68d5427c9c359935c76fe3290d0dc96..022d6d4e295a0c196611a3c121127df34f292d2e 100644 (file)
 #include <execinfo.h>
 #endif
 
+#ifndef PLATFORM_WIN32
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/threads.h>
@@ -23,6 +28,7 @@
 #include <mono/metadata/exception.h>
 #include <mono/metadata/gc-internal.h>
 #include <mono/metadata/mono-debug.h>
+#include <mono/metadata/profiler.h>
 
 #include "mini.h"
 #include "trace.h"
@@ -253,7 +259,7 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
 void
 mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start_ctx, MonoStackFrameWalk func, gpointer user_data)
 {
-       MonoLMF *lmf = jit_tls->lmf;
+       MonoLMF *lmf = mono_get_lmf ();
        MonoJitInfo *ji, rji;
        gint native_offset;
        gboolean managed;
@@ -261,7 +267,7 @@ mono_walk_stack (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoContext *start
 
        ctx = *start_ctx;
 
-       while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
+       while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
                /* 
                 * FIXME: mono_find_jit_info () will need to be able to return a different
                 * MonoDomain when apddomain transitions are found on the stack.
@@ -284,7 +290,7 @@ mono_jit_walk_stack_from_ctx (MonoStackWalk func, MonoContext *start_ctx, gboole
 {
        MonoDomain *domain = mono_domain_get ();
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-       MonoLMF *lmf = jit_tls->lmf;
+       MonoLMF *lmf = mono_get_lmf ();
        MonoJitInfo *ji, rji;
        gint native_offset, il_offset;
        gboolean managed;
@@ -341,7 +347,7 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 {
        MonoDomain *domain = mono_domain_get ();
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-       MonoLMF *lmf = jit_tls->lmf;
+       MonoLMF *lmf = mono_get_lmf ();
        MonoJitInfo *ji, rji;
        MonoContext ctx, new_ctx;
        MonoDebugSourceLocation *location;
@@ -370,7 +376,7 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 
                ctx = new_ctx;
                
-               if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
+               if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_SP (&ctx) >= jit_tls->end_of_stack)
                        return FALSE;
 
                /* skip all wrappers ??*/
@@ -595,7 +601,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
        static void (*restore_context) (void *);
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-       MonoLMF *lmf = jit_tls->lmf;            
+       MonoLMF *lmf = mono_get_lmf ();
        MonoArray *initial_trace_ips = NULL;
        GList *trace_ips = NULL;
        MonoException *mono_ex;
@@ -718,7 +724,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                has_dynamic_methods = TRUE;
 
                        if (stack_overflow)
-                               free_stack = (guint8*)(MONO_CONTEXT_GET_BP (ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
+                               free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
                        else
                                free_stack = 0xffffff;
 
@@ -742,8 +748,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                                /* catch block */
 
                                                if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
-                                                       /* store the exception object in cfg->excvar */
-                                                       g_assert (ei->exvar_offset);
+                                                       /* store the exception object in bp + ei->exvar_offset */
                                                        *((gpointer *)(gpointer)((char *)MONO_CONTEXT_GET_BP (ctx) + ei->exvar_offset)) = obj;
                                                }
 
@@ -784,7 +789,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                                                g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
                                                        mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
                                                        MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
-                                                       jit_tls->lmf = lmf;
+                                                       *(mono_get_lmf_addr ()) = lmf;
 
                                                        if (gc_disabled)
                                                                mono_gc_enable ();
@@ -792,7 +797,15 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                                }
                                                if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
                                                    MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
-                                                   (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
+                                                   (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
+                                                       if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
+                                                               g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
+                                                       mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
+                                                       call_filter (ctx, ei->handler_start);
+                                               }
+                                               if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
+                                                   MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
+                                                   (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
                                                        if (mono_trace_is_enabled () && mono_trace_eval (ji->method))
                                                                g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
                                                        mono_debugger_handle_exception (ei->handler_start, MONO_CONTEXT_GET_SP (ctx), obj);
@@ -802,6 +815,9 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                        }
                                }
                        }
+                       if (!test_only)
+                               if (mono_profiler_get_events () && MONO_PROFILE_ENTER_LEAVE)
+                                       mono_profiler_method_leave (ji->method);
                }
 
                *ctx = new_ctx;
@@ -811,7 +827,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gpointer origina
                                mono_gc_enable ();
 
                        if (!test_only) {
-                               jit_tls->lmf = lmf;
+                               *(mono_get_lmf_addr ()) = lmf;
 
                                if (IS_ON_SIGALTSTACK (jit_tls)) {
                                        /* Switch back to normal stack */
@@ -865,7 +881,7 @@ mono_debugger_run_finally (MonoContext *start_ctx)
        static int (*call_filter) (MonoContext *, gpointer) = NULL;
        MonoDomain *domain = mono_domain_get ();
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-       MonoLMF *lmf = jit_tls->lmf;
+       MonoLMF *lmf = mono_get_lmf ();
        MonoContext ctx, new_ctx;
        MonoJitInfo *ji, rji;
        int i;
@@ -1012,28 +1028,12 @@ mono_handle_native_sigsegv (int signal, void *ctx)
 #ifndef PLATFORM_WIN32
        struct sigaction sa;
 #endif
-       const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
-
        if (handling_sigsegv)
                return;
 
        /* To prevent infinite loops when the stack walk causes a crash */
        handling_sigsegv = TRUE;
 
-       /*
-        * A SIGSEGV indicates something went very wrong so we can no longer depend
-        * on anything working. So try to print out lots of diagnostics, starting 
-        * with ones which have a greater chance of working.
-        */
-       fprintf (stderr,
-                        "\n"
-                        "=================================================================\n"
-                        "Got a %s while executing native code. This usually indicates\n"
-                        "a fatal error in the mono runtime or one of the native libraries \n"
-                        "used by your application.\n"
-                        "=================================================================\n"
-                        "\n", signal_str);
-
        fprintf (stderr, "Stacktrace:\n\n");
 
        mono_jit_walk_stack (print_stack_frame, TRUE, stderr);
@@ -1044,7 +1044,11 @@ mono_handle_native_sigsegv (int signal, void *ctx)
  {
        void *array [256];
        char **names;
+       char cmd [1024];
        int i, size;
+       gchar *out, *err;
+       gint exit_status;
+       const char *signal_str = (signal == SIGSEGV) ? "SIGSEGV" : "SIGABRT";
 
        fprintf (stderr, "\nNative stacktrace:\n\n");
 
@@ -1054,9 +1058,37 @@ mono_handle_native_sigsegv (int signal, void *ctx)
                fprintf (stderr, "\t%s\n", names [i]);
        }
        free (names);
- }
 
        fflush (stderr);
+
+       /* Try to get more meaningful information using gdb */
+
+#ifndef PLATFORM_WIN32
+       sprintf (cmd, "gdb --ex 'attach %ld' --ex 'info threads' --ex 'thread apply all bt' --batch", (long)getpid ());
+       {
+               int res = g_spawn_command_line_sync (cmd, &out, &err, &exit_status, NULL);
+
+               if (res) {
+                       fprintf (stderr, "\nDebug info from gdb:\n\n");
+                       fprintf (stderr, "%s\n", out);
+               }
+       }
+#endif
+       /*
+        * A SIGSEGV indicates something went very wrong so we can no longer depend
+        * on anything working. So try to print out lots of diagnostics, starting 
+        * with ones which have a greater chance of working.
+        */
+       fprintf (stderr,
+                        "\n"
+                        "=================================================================\n"
+                        "Got a %s while executing native code. This usually indicates\n"
+                        "a fatal error in the mono runtime or one of the native libraries \n"
+                        "used by your application.\n"
+                        "=================================================================\n"
+                        "\n", signal_str);
+
+ }
 #endif
 
 #ifndef PLATFORM_WIN32