2004-04-29 Gonzalo Paniagua Javier <gonzalo@ximian.com>
[mono.git] / mono / mini / exceptions-x86.c
index 5e00f88cb5d7661c271c898dfbe8f9a62e356326..39412d20cd35ec58603aacfd1a6cfe42ae53ecc6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * exception.c: exception support
+ * exceptions-x86.c: exception support for x86
  *
  * Authors:
  *   Dietmar Maurer (dietmar@ximian.com)
 #include <mono/metadata/threads.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/exception.h>
+#include <mono/metadata/gc-internal.h>
 #include <mono/metadata/mono-debug.h>
 
 #include "mini.h"
 #include "mini-x86.h"
 
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
-# define SC_EAX sc_eax
-# define SC_EBX sc_ebx
-# define SC_ECX sc_ecx
-# define SC_EDX sc_edx
-# define SC_EBP sc_ebp
-# define SC_EIP sc_eip
-# define SC_ESP sc_esp
-# define SC_EDI sc_edi
-# define SC_ESI sc_esi
-#else
-# define SC_EAX eax
-# define SC_EBX ebx
-# define SC_ECX ecx
-# define SC_EDX edx
-# define SC_EBP ebp
-# define SC_EIP eip
-# define SC_ESP esp
-# define SC_EDI edi
-# define SC_ESI esi
-#endif
+#ifdef PLATFORM_WIN32
+static MonoW32ExceptionHandler fpe_handler;
+static MonoW32ExceptionHandler ill_handler;
+static MonoW32ExceptionHandler segv_handler;
+
+static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
+
+#define W32_SEH_HANDLE_EX(_ex) \
+       if (_ex##_handler) _ex##_handler((int)sctx)
+
+/*
+ * Unhandled Exception Filter
+ * Top-level per-process exception handler.
+ */
+LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
+{
+       EXCEPTION_RECORD* er;
+       CONTEXT* ctx;
+       struct sigcontext* sctx;
+       LONG res;
+
+       res = EXCEPTION_CONTINUE_EXECUTION;
+
+       er = ep->ExceptionRecord;
+       ctx = ep->ContextRecord;
+       sctx = g_malloc(sizeof(struct sigcontext));
+
+       /* Copy Win32 context to UNIX style context */
+       sctx->eax = ctx->Eax;
+       sctx->ebx = ctx->Ebx;
+       sctx->ecx = ctx->Ecx;
+       sctx->edx = ctx->Edx;
+       sctx->ebp = ctx->Ebp;
+       sctx->esp = ctx->Esp;
+       sctx->esi = ctx->Esi;
+       sctx->edi = ctx->Edi;
+       sctx->eip = ctx->Eip;
+
+       switch (er->ExceptionCode) {
+       case EXCEPTION_ACCESS_VIOLATION:
+               W32_SEH_HANDLE_EX(segv);
+               break;
+       case EXCEPTION_ILLEGAL_INSTRUCTION:
+               W32_SEH_HANDLE_EX(ill);
+               break;
+       case EXCEPTION_INT_DIVIDE_BY_ZERO:
+       case EXCEPTION_INT_OVERFLOW:
+       case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+       case EXCEPTION_FLT_OVERFLOW:
+       case EXCEPTION_FLT_UNDERFLOW:
+       case EXCEPTION_FLT_INEXACT_RESULT:
+               W32_SEH_HANDLE_EX(fpe);
+               break;
+       default:
+               break;
+       }
+
+       /* Copy context back */
+       ctx->Eax = sctx->eax;
+       ctx->Ebx = sctx->ebx;
+       ctx->Ecx = sctx->ecx;
+       ctx->Edx = sctx->edx;
+       ctx->Ebp = sctx->ebp;
+       ctx->Esp = sctx->esp;
+       ctx->Esi = sctx->esi;
+       ctx->Edi = sctx->edi;
+       ctx->Eip = sctx->eip;
+
+       return res;
+}
+
+void win32_seh_init()
+{
+       old_handler = SetUnhandledExceptionFilter(seh_handler);
+}
+
+void win32_seh_cleanup()
+{
+       if (old_handler) SetUnhandledExceptionFilter(old_handler);
+}
 
-typedef struct sigcontext MonoContext;
+void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
+{
+       switch (type) {
+       case SIGFPE:
+               fpe_handler = handler;
+               break;
+       case SIGILL:
+               ill_handler = handler;
+               break;
+       case SIGSEGV:
+               segv_handler = handler;
+               break;
+       default:
+               break;
+       }
+}
 
-#define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->SC_EIP = (long)ip; } while (0); 
-#define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->SC_EBP = (long)bp; } while (0); 
+#endif /* PLATFORM_WIN32 */
 
-#define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->SC_EIP))
-#define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->SC_EBP))
 
 #ifdef MONO_USE_EXC_TABLES
 
@@ -200,16 +272,14 @@ mono_arch_has_unwind_info (gconstpointer addr)
        /* offset 10 is just a guess, but it works for all methods tested */
        if ((res = frame_state_for ((char *)addr + 10, &state_in))) {
 
-               if (res->saved [X86_EBX] != 1 ||
-                   res->saved [X86_EDI] != 1 ||
-                   res->saved [X86_EBP] != 1 ||
-                   res->saved [X86_ESI] != 1) {
-                       return FALSE;
-               }
-               return TRUE;
-       } else {
-               return FALSE;
+               if (res->saved [X86_EBX] == 1 &&
+                   res->saved [X86_EDI] == 1 &&
+                   res->saved [X86_EBP] == 1 &&
+                   res->saved [X86_ESI] == 1)
+                       return TRUE;
        }
+
+       return FALSE;
 }
 
 struct stack_frame
@@ -320,12 +390,12 @@ x86_unwind_native_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, struct sig
 #endif
 
 /*
- * arch_get_restore_context:
+ * mono_arch_get_restore_context:
  *
  * Returns a pointer to a method which restores a previously saved sigcontext.
  */
-static gpointer
-arch_get_restore_context (void)
+gpointer
+mono_arch_get_restore_context (void)
 {
        static guint8 *start = NULL;
        guint8 *code;
@@ -361,14 +431,14 @@ arch_get_restore_context (void)
 }
 
 /*
- * arch_get_call_filter:
+ * mono_arch_get_call_filter:
  *
  * Returns a pointer to a method which calls an exception filter. We
  * also use this function to call finally handlers (we pass NULL as 
  * @exc object in this case).
  */
-static gpointer
-arch_get_call_filter (void)
+gpointer
+mono_arch_get_call_filter (void)
 {
        static guint8 start [64];
        static int inited = 0;
@@ -378,7 +448,7 @@ arch_get_call_filter (void)
                return start;
 
        inited = 1;
-       /* call_filter (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
+       /* call_filter (struct sigcontext *ctx, unsigned long eip) */
        code = start;
 
        x86_push_reg (code, X86_EBP);
@@ -393,21 +463,20 @@ arch_get_call_filter (void)
        x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
        /* save EBP */
        x86_push_reg (code, X86_EBP);
-       /* push exc */
-       x86_push_membase (code, X86_EBP, 16);
+
        /* set new EBP */
        x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
        /* restore registers used by global register allocation (EBX & ESI) */
        x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
        x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
        x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
-       /* save the ESP - this is used by endfinally */
-       x86_mov_membase_reg (code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
+
        /* call the handler */
        x86_call_reg (code, X86_ECX);
-       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+
        /* restore EBP */
        x86_pop_reg (code, X86_EBP);
+
        /* restore saved regs */
        x86_pop_reg (code, X86_ESI);
        x86_pop_reg (code, X86_EDI);
@@ -428,12 +497,13 @@ throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsign
        struct sigcontext ctx;
 
        if (!restore_context)
-               restore_context = arch_get_restore_context ();
+               restore_context = mono_arch_get_restore_context ();
 
        /* adjust eip so that it point into the call instruction */
        eip -= 1;
 
-       ctx.SC_ESP = esp;
+       /* Pop argument and return address */
+       ctx.SC_ESP = esp + (2 * sizeof (gpointer));
        ctx.SC_EIP = eip;
        ctx.SC_EBP = ebp;
        ctx.SC_EDI = edi;
@@ -450,7 +520,7 @@ throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsign
 }
 
 /**
- * arch_get_throw_exception:
+ * mono_arch_get_throw_exception:
  *
  * Returns a function pointer which can be used to raise 
  * exceptions. The returned function has the following 
@@ -493,7 +563,7 @@ mono_arch_get_throw_exception (void)
 }
 
 /**
- * arch_get_throw_exception_by_name:
+ * mono_arch_get_throw_exception_by_name:
  *
  * Returns a function pointer which can be used to raise 
  * corlib exceptions. The returned function has the following 
@@ -529,25 +599,6 @@ mono_arch_get_throw_exception_by_name (void)
        g_assert ((code - start) < 32);
 
        return start;
-}      
-
-static MonoArray *
-glist_to_array (GList *list) 
-{
-       MonoDomain *domain = mono_domain_get ();
-       MonoArray *res;
-       int len, i;
-
-       if (!list)
-               return NULL;
-
-       len = g_list_length (list);
-       res = mono_array_new (domain, mono_defaults.int_class, len);
-
-       for (i = 0; list; list = list->next, i++)
-               mono_array_set (res, gpointer, i, list->data);
-
-       return res;
 }
 
 /* mono_arch_find_jit_info:
@@ -559,15 +610,19 @@ glist_to_array (GList *list)
  * the @lmf if necessary. @native_offset return the IP offset from the 
  * start of the function or -1 if that info is not available.
  */
-static MonoJitInfo *
-mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoContext *ctx, 
+MonoJitInfo *
+mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
                         MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
                         gboolean *managed)
 {
        MonoJitInfo *ji;
        gpointer ip = MONO_CONTEXT_GET_IP (ctx);
 
-       ji = mono_jit_info_table_find (domain, ip);
+       /* Avoid costly table lookup during stack overflow */
+       if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
+               ji = prev_ji;
+       else
+               ji = mono_jit_info_table_find (domain, ip);
 
        if (trace)
                *trace = NULL;
@@ -585,11 +640,6 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
 
                *new_ctx = *ctx;
 
-               if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
-                       /* remove any unused lmf */
-                       *lmf = (*lmf)->previous_lmf;
-               }
-
                address = (char *)ip - (char *)ji->code_start;
 
                if (native_offset)
@@ -600,8 +650,8 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                                *managed = TRUE;
 
                if (trace) {
-                       source_location = mono_debug_source_location_from_address (ji->method, address, NULL);
-                       iloffset = mono_debug_il_offset_from_address (ji->method, address);
+                       source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
+                       iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
 
                        if (iloffset < 0)
                                tmpaddr = g_strdup_printf ("<0x%05x>", address);
@@ -619,22 +669,46 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                        g_free (source_location);
                        g_free (tmpaddr);
                }
-                               
-               offset = -1;
-               /* restore caller saved registers */
-               if (ji->used_regs & X86_EBX_MASK) {
-                       new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
-                       offset--;
+
+               /*
+                * Some managed methods like pinvoke wrappers might have save_lmf set.
+                * In this case, register save/restore code is not generated by the 
+                * JIT, so we have to restore callee saved registers from the lmf.
+                */
+               if (ji->method->save_lmf) {
+                       /* 
+                        * We only need to do this if the exception was raised in managed
+                        * code, since otherwise the lmf was already popped of the stack.
+                        */
+                       if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+                               new_ctx->SC_ESI = (*lmf)->esi;
+                               new_ctx->SC_EDI = (*lmf)->edi;
+                               new_ctx->SC_EBX = (*lmf)->ebx;
+                       }
                }
-               if (ji->used_regs & X86_EDI_MASK) {
-                       new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
-                       offset--;
+               else {
+                       offset = -1;
+                       /* restore caller saved registers */
+                       if (ji->used_regs & X86_EBX_MASK) {
+                               new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
+                               offset--;
+                       }
+                       if (ji->used_regs & X86_EDI_MASK) {
+                               new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
+                               offset--;
+                       }
+                       if (ji->used_regs & X86_ESI_MASK) {
+                               new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
+                       }
                }
-               if (ji->used_regs & X86_ESI_MASK) {
-                       new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
+
+               if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
+                       /* remove any unused lmf */
+                       *lmf = (*lmf)->previous_lmf;
                }
 
-               new_ctx->SC_ESP = ctx->SC_EBP;
+               /* Pop EBP and the return address */
+               new_ctx->SC_ESP = ctx->SC_EBP + (2 * sizeof (gpointer));
                /* we substract 1, so that the IP points into the call instruction */
                new_ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 1;
                new_ctx->SC_EBP = *((int *)ctx->SC_EBP);
@@ -681,273 +755,14 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
        return NULL;
 }
 
-MonoArray *
-ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
-{
-       MonoDomain *domain = mono_domain_get ();
-       MonoArray *res;
-       MonoArray *ta = exc->trace_ips;
-       int i, len;
-
-       if (ta == NULL) {
-               /* Exception is not thrown yet */
-               return mono_array_new (domain, mono_defaults.stack_frame_class, 0);
-       }
-       
-       len = mono_array_length (ta);
-
-       res = mono_array_new (domain, mono_defaults.stack_frame_class, len > skip ? len - skip : 0);
-
-       for (i = skip; i < len; i++) {
-               MonoJitInfo *ji;
-               MonoStackFrame *sf = (MonoStackFrame *)mono_object_new (domain, mono_defaults.stack_frame_class);
-               gpointer ip = mono_array_get (ta, gpointer, i);
-
-               ji = mono_jit_info_table_find (domain, ip);
-               if (ji == NULL) {
-                       /* Unmanaged frame */
-                       mono_array_set (res, gpointer, i, sf);
-                       continue;
-               }
-
-               g_assert (ji != NULL);
-
-               sf->method = mono_method_get_object (domain, ji->method, NULL);
-               sf->native_offset = (char *)ip - (char *)ji->code_start;
-
-               sf->il_offset = mono_debug_il_offset_from_address (ji->method, sf->native_offset);
-
-               if (need_file_info) {
-                       gchar *filename;
-                       
-                       filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line);
-
-                       sf->filename = filename? mono_string_new (domain, filename): NULL;
-                       sf->column = 0;
-
-                       g_free (filename);
-               }
-
-               mono_array_set (res, gpointer, i, sf);
-       }
-
-       return res;
-}
-
-void
-mono_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
-       MonoDomain *domain = mono_domain_get ();
-       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-       MonoLMF *lmf = jit_tls->lmf;
-       MonoJitInfo *ji, rji;
-       gint native_offset, il_offset;
-       gboolean managed;
-
-       MonoContext ctx, new_ctx;
-
-       MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
-       MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
-
-       while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
-               
-               ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
-               g_assert (ji);
-
-               if (ji == (gpointer)-1)
-                       return;
-
-               il_offset = mono_debug_il_offset_from_address (ji->method, native_offset);
-
-               if (func (ji->method, native_offset, il_offset, managed, user_data))
-                       return;
-               
-               ctx = new_ctx;
-       }
-}
-
-MonoBoolean
-ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
-                         MonoReflectionMethod **method, 
-                         gint32 *iloffset, gint32 *native_offset,
-                         MonoString **file, gint32 *line, gint32 *column)
-{
-       MonoDomain *domain = mono_domain_get ();
-       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-       MonoLMF *lmf = jit_tls->lmf;
-       MonoJitInfo *ji, rji;
-       MonoContext ctx, new_ctx;
-
-       MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
-       MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
-
-       skip++;
-
-       do {
-               ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, NULL, &lmf, native_offset, NULL);
-
-               ctx = new_ctx;
-               
-               if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
-                       return FALSE;
-
-               if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)
-                       continue;
-
-               skip--;
-
-       } while (skip >= 0);
-
-       *method = mono_method_get_object (domain, ji->method, NULL);
-       *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset);
-
-       if (need_file_info) {
-               gchar *filename;
-
-               filename = mono_debug_source_location_from_address (ji->method, *native_offset, line);
-
-               *file = filename? mono_string_new (domain, filename): NULL;
-               *column = 0;
-
-               g_free (filename);
-       }
-
-       return TRUE;
-}
-
 /**
- * arch_handle_exception:
+ * mono_arch_handle_exception:
+ *
  * @ctx: saved processor state
  * @obj: the exception object
- * @test_only: only test if the exception is caught, but dont call handlers
- *
- *
  */
 gboolean
-mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
+mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
 {
-       MonoDomain *domain = mono_domain_get ();
-       MonoJitInfo *ji, rji;
-       static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
-       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-       MonoLMF *lmf = jit_tls->lmf;            
-       GList *trace_ips = NULL;
-
-       g_assert (ctx != NULL);
-       if (!obj) {
-               MonoException *ex = mono_get_exception_null_reference ();
-               ex->message = mono_string_new (domain, 
-                       "Object reference not set to an instance of an object");
-               obj = (MonoObject *)ex;
-       } 
-
-       g_assert (mono_object_isinst (obj, mono_defaults.exception_class));
-
-       if (!call_filter)
-               call_filter = arch_get_call_filter ();
-
-       g_assert (jit_tls->end_of_stack);
-       g_assert (jit_tls->abort_func);
-
-       if (!test_only) {
-               MonoContext ctx_cp = *ctx;
-               if (mono_jit_trace_calls)
-                       g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
-               if (!mono_arch_handle_exception (&ctx_cp, obj, TRUE)) {
-                       if (mono_break_on_exc)
-                               G_BREAKPOINT ();
-                       mono_unhandled_exception (obj);
-               }
-       }
-
-       while (1) {
-               MonoContext new_ctx;
-               char *trace = NULL;
-               
-               ji = mono_arch_find_jit_info (domain, jit_tls, &rji, ctx, &new_ctx, 
-                                             test_only ? &trace : NULL, &lmf, NULL, NULL);
-               if (!ji) {
-                       g_warning ("Exception inside function without unwind info");
-                       g_assert_not_reached ();
-               }
-
-               if (ji != (gpointer)-1) {
-                       
-                       if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE) {
-                               char *tmp, *strace;
-
-                               trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
-
-                               if (!((MonoException*)obj)->stack_trace)
-                                       strace = g_strdup ("");
-                               else
-                                       strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
-                       
-                               tmp = g_strdup_printf ("%s%s\n", strace, trace);
-                               g_free (strace);
-
-                               ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
-
-                               g_free (tmp);
-                       }
-
-                       if (ji->num_clauses) {
-                               int i;
-                               
-                               g_assert (ji->clauses);
-                       
-                               for (i = 0; i < ji->num_clauses; i++) {
-                                       MonoJitExceptionInfo *ei = &ji->clauses [i];
-
-                                       if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
-                                           MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
-                                               /* catch block */
-                                               if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
-                                                    mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
-                                                   ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
-                                                     call_filter (ctx, ei->data.filter, obj)))) {
-                                                       if (test_only) {
-                                                               ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
-                                                               g_list_free (trace_ips);
-                                                               return TRUE;
-                                                       }
-                                                       if (mono_jit_trace_calls)
-                                                               g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
-                                                       MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
-                                                       *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
-                                                       jit_tls->lmf = lmf;
-                                                       return 0;
-                                               }
-                                               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_jit_trace_calls)
-                                                               g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
-                                                       call_filter (ctx, ei->handler_start, NULL);
-                                               }
-                                               
-                                       }
-                               }
-                       }
-               }
-
-               g_free (trace);
-                       
-               *ctx = new_ctx;
-
-               if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
-                       if (!test_only) {
-                               jit_tls->lmf = lmf;
-                               jit_tls->abort_func (obj);
-                               g_assert_not_reached ();
-                       } else {
-                               ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
-                               g_list_free (trace_ips);
-                               return FALSE;
-                       }
-               }
-       }
-
-       g_assert_not_reached ();
+       return mono_handle_exception (sigctx, obj, test_only);
 }
-
-