2006-06-04 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / exceptions-x86.c
index c0961c485d2861b4cf572dae98a7d95c17b2474f..c63f05cdc1541cad420d28cdc43eb2a497f0bd51 100644 (file)
@@ -25,6 +25,8 @@
 #include "mini-x86.h"
 
 #ifdef PLATFORM_WIN32
+static void (*restore_stack) (void *);
+
 static MonoW32ExceptionHandler fpe_handler;
 static MonoW32ExceptionHandler ill_handler;
 static MonoW32ExceptionHandler segv_handler;
@@ -34,6 +36,122 @@ static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
 #define W32_SEH_HANDLE_EX(_ex) \
        if (_ex##_handler) _ex##_handler((int)sctx)
 
+/*
+ * mono_win32_get_handle_stackoverflow (void):
+ *
+ * Returns a pointer to a method which restores the current context stack
+ * and calls handle_exceptions, when done restores the original stack.
+ */
+static gpointer
+mono_win32_get_handle_stackoverflow (void)
+{
+       static guint8 *start = NULL;
+       guint8 *code;
+
+       if (start)
+               return start;
+
+       /* restore_contect (void *sigctx) */
+       start = code = mono_global_codeman_reserve (128);
+
+       /* load context into ebx */
+       x86_mov_reg_membase (code, X86_EBX, X86_ESP, 4, 4);
+
+       /* move current stack into edi for later restore */
+       x86_mov_reg_reg (code, X86_EDI, X86_ESP, 4);
+
+       /* use the new freed stack from sigcontext */
+       x86_mov_reg_membase (code, X86_ESP, X86_EBX,  G_STRUCT_OFFSET (struct sigcontext, esp), 4);
+
+       /* get the current domain */
+       x86_call_code (code, mono_domain_get);
+
+       /* get stack overflow exception from domain object */
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoDomain, stack_overflow_ex), 4);
+
+       /* call mono_arch_handle_exception (sctx, stack_overflow_exception_obj, FALSE) */
+       x86_push_imm (code, 0);
+       x86_push_reg (code, X86_EAX);
+       x86_push_reg (code, X86_EBX);
+       x86_call_code (code, mono_arch_handle_exception);
+
+       /* restore the SEH handler stack */
+       x86_mov_reg_reg (code, X86_ESP, X86_EDI, 4);
+
+       /* return */
+       x86_ret (code);
+
+       return start;
+}
+
+/* Special hack to workaround the fact that the
+ * when the SEH handler is called the stack is
+ * to small to recover.
+ *
+ * Stack walking part of this method is from mono_handle_exception
+ *
+ * The idea is simple; 
+ *  - walk the stack to free some space (64k)
+ *  - set esp to new stack location
+ *  - call mono_arch_handle_exception with stack overflow exception
+ *  - set esp to SEH handlers stack
+ *  - done
+ */
+static void 
+win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) 
+{
+    SYSTEM_INFO si;
+    DWORD page_size;
+       MonoDomain *domain = mono_domain_get ();
+       MonoJitInfo *ji, rji;
+       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+       MonoLMF *lmf = jit_tls->lmf;            
+       MonoContext initial_ctx;
+       MonoContext ctx;
+       guint32 free_stack = 0;
+
+       /* convert sigcontext to MonoContext (due to reuse of stack walking helpers */
+       mono_arch_sigctx_to_monoctx (sctx, &ctx);
+       
+       /* get our os page size */
+    GetSystemInfo(&si);
+       page_size = si.dwPageSize;
+
+       /* Let's walk the stack to recover
+        * the needed stack space (if possible)
+        */
+       memset (&rji, 0, sizeof (rji));
+
+       initial_ctx = ctx;
+       free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
+
+       /* try to free 64kb from our stack */
+       do {
+               MonoContext new_ctx;
+
+               ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
+               if (!ji) {
+                       g_warning ("Exception inside function without unwind info");
+                       g_assert_not_reached ();
+               }
+
+               if (ji != (gpointer)-1) {
+                       free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
+               }
+
+               /* todo: we should call abort if ji is -1 */
+               ctx = new_ctx;
+       } while (free_stack < 64 * 1024 && ji != (gpointer) -1);
+
+       /* convert into sigcontext to be used in mono_arch_handle_exception */
+       mono_arch_monoctx_to_sigctx (&ctx, sctx);
+
+       /* todo: install new stack-guard page */
+
+       /* use the new stack and call mono_arch_handle_exception () */
+       restore_stack (sctx);
+}
+
 /*
  * Unhandled Exception Filter
  * Top-level per-process exception handler.
@@ -63,6 +181,9 @@ LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
        sctx->eip = ctx->Eip;
 
        switch (er->ExceptionCode) {
+       case EXCEPTION_STACK_OVERFLOW:
+               win32_handle_stack_overflow (ep, sctx);
+               break;
        case EXCEPTION_ACCESS_VIOLATION:
                W32_SEH_HANDLE_EX(segv);
                break;
@@ -97,6 +218,10 @@ LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
 
 void win32_seh_init()
 {
+       /* install restore stack helper */
+       if (!restore_stack)
+               restore_stack = mono_win32_get_handle_stackoverflow ();
+
        old_handler = SetUnhandledExceptionFilter(seh_handler);
 }
 
@@ -138,26 +263,26 @@ mono_arch_get_restore_context (void)
        if (start)
                return start;
 
-       /* restore_contect (struct sigcontext *ctx) */
+       /* restore_contect (MonoContext *ctx) */
        /* we do not restore X86_EAX, X86_EDX */
 
-       start = code = g_malloc (1024);
+       start = code = mono_global_codeman_reserve (128);
        
        /* load ctx */
        x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
 
        /* get return address, stored in EDX */
-       x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EIP), 4);
+       x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eip), 4);
        /* restore EBX */
-       x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
+       x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
        /* restore EDI */
-       x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
+       x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
        /* restore ESI */
-       x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
+       x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
        /* restore ESP */
-       x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESP), 4);
+       x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esp), 4);
        /* restore EBP */
-       x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
+       x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
 
        /* jump to the saved IP */
        x86_jump_reg (code, X86_EDX);
@@ -175,7 +300,7 @@ mono_arch_get_restore_context (void)
 gpointer
 mono_arch_get_call_filter (void)
 {
-       static guint8 start [64];
+       static guint8* start;
        static int inited = 0;
        guint8 *code;
 
@@ -183,8 +308,8 @@ mono_arch_get_call_filter (void)
                return start;
 
        inited = 1;
-       /* call_filter (struct sigcontext *ctx, unsigned long eip) */
-       code = start;
+       /* call_filter (MonoContext *ctx, unsigned long eip) */
+       start = code = mono_global_codeman_reserve (64);
 
        x86_push_reg (code, X86_EBP);
        x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
@@ -200,11 +325,11 @@ mono_arch_get_call_filter (void)
        x86_push_reg (code, X86_EBP);
 
        /* set new EBP */
-       x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
+       x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, 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);
+       x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
+       x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
+       x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
 
        /* call the handler */
        x86_call_reg (code, X86_ECX);
@@ -226,34 +351,77 @@ mono_arch_get_call_filter (void)
 static void
 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
                 unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
-                unsigned long eip,  unsigned long esp)
+                unsigned long eip,  unsigned long esp, gboolean rethrow)
 {
-       static void (*restore_context) (struct sigcontext *);
-       struct sigcontext ctx;
+       static void (*restore_context) (MonoContext *);
+       MonoContext ctx;
 
        if (!restore_context)
                restore_context = mono_arch_get_restore_context ();
 
+       /* Pop argument and return address */
+       ctx.esp = esp + (2 * sizeof (gpointer));
+       ctx.eip = eip;
+       ctx.ebp = ebp;
+       ctx.edi = edi;
+       ctx.esi = esi;
+       ctx.ebx = ebx;
+       ctx.edx = edx;
+       ctx.ecx = ecx;
+       ctx.eax = eax;
+
+       if (mono_debugger_throw_exception ((gpointer)(eip - 5), (gpointer)esp, exc)) {
+               /*
+                * The debugger wants us to stop on the `throw' instruction.
+                * By the time we get here, it already inserted a breakpoint on
+                * eip - 5 (which is the address of the call).
+                */
+               ctx.eip = eip - 5;
+               ctx.esp = esp + sizeof (gpointer);
+               restore_context (&ctx);
+               g_assert_not_reached ();
+       }
+
        /* adjust eip so that it point into the call instruction */
-       eip -= 1;
+       ctx.eip -= 1;
 
-       /* Pop argument and return address */
-       ctx.SC_ESP = esp + (2 * sizeof (gpointer));
-       ctx.SC_EIP = eip;
-       ctx.SC_EBP = ebp;
-       ctx.SC_EDI = edi;
-       ctx.SC_ESI = esi;
-       ctx.SC_EBX = ebx;
-       ctx.SC_EDX = edx;
-       ctx.SC_ECX = ecx;
-       ctx.SC_EAX = eax;
-       
-       mono_handle_exception (&ctx, exc, eip + 1, FALSE);
+       if (mono_object_isinst (exc, mono_defaults.exception_class)) {
+               MonoException *mono_ex = (MonoException*)exc;
+               if (!rethrow)
+                       mono_ex->stack_trace = NULL;
+       }
+       mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
        restore_context (&ctx);
 
        g_assert_not_reached ();
 }
 
+static guint8*
+get_throw_exception (gboolean rethrow)
+{
+       guint8 *start, *code;
+
+       start = code = mono_global_codeman_reserve (64);
+
+       x86_push_reg (code, X86_ESP);
+       x86_push_membase (code, X86_ESP, 4); /* IP */
+       x86_push_membase (code, X86_ESP, 12); /* exception */
+       x86_push_reg (code, X86_EBP);
+       x86_push_reg (code, X86_EDI);
+       x86_push_reg (code, X86_ESI);
+       x86_push_reg (code, X86_EBX);
+       x86_push_reg (code, X86_EDX);
+       x86_push_reg (code, X86_ECX);
+       x86_push_reg (code, X86_EAX);
+       x86_call_code (code, throw_exception);
+       /* we should never reach this breakpoint */
+       x86_breakpoint (code);
+
+       g_assert ((code - start) < 64);
+
+       return start;
+}
+
 /**
  * mono_arch_get_throw_exception:
  *
@@ -269,31 +437,32 @@ throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsign
 gpointer 
 mono_arch_get_throw_exception (void)
 {
-       static guint8 start [24];
+       static guint8 *start;
        static int inited = 0;
-       guint8 *code;
 
        if (inited)
                return start;
 
+       start = get_throw_exception (FALSE);
+
        inited = 1;
-       code = start;
 
-       x86_push_reg (code, X86_ESP);
-       x86_push_membase (code, X86_ESP, 4); /* IP */
-       x86_push_membase (code, X86_ESP, 12); /* exception */
-       x86_push_reg (code, X86_EBP);
-       x86_push_reg (code, X86_EDI);
-       x86_push_reg (code, X86_ESI);
-       x86_push_reg (code, X86_EBX);
-       x86_push_reg (code, X86_EDX);
-       x86_push_reg (code, X86_ECX);
-       x86_push_reg (code, X86_EAX);
-       x86_call_code (code, throw_exception);
-       /* we should never reach this breakpoint */
-       x86_breakpoint (code);
+       return start;
+}
+
+gpointer 
+mono_arch_get_rethrow_exception (void)
+{
+       static guint8 *start;
+       static int inited = 0;
+
+       if (inited)
+               return start;
+
+       start = get_throw_exception (TRUE);
+
+       inited = 1;
 
-       g_assert ((code - start) < 24);
        return start;
 }
 
@@ -302,17 +471,18 @@ mono_arch_get_throw_exception (void)
  *
  * Returns a function pointer which can be used to raise 
  * corlib exceptions. The returned function has the following 
- * signature: void (*func) (char *exc_name); 
+ * signature: void (*func) (gpointer ip, char *exc_name); 
  * For example to raise an arithmetic exception you can use:
  *
  * x86_push_imm (code, "ArithmeticException"); 
- * x86_call_code (code, arch_get_throw_exception_by_name ()); 
+ * x86_push_imm (code, <IP>)
+ * x86_jump_code (code, arch_get_throw_exception_by_name ()); 
  *
  */
 gpointer 
 mono_arch_get_throw_exception_by_name (void)
 {
-       static guint8 start [32];
+       static guint8* start;
        static int inited = 0;
        guint8 *code;
 
@@ -320,7 +490,7 @@ mono_arch_get_throw_exception_by_name (void)
                return start;
 
        inited = 1;
-       code = start;
+       code = start = mono_global_codeman_reserve (32);
 
        x86_push_membase (code, X86_ESP, 4); /* exception name */
        x86_push_imm (code, "System");
@@ -336,6 +506,50 @@ mono_arch_get_throw_exception_by_name (void)
        return start;
 }
 
+/**
+ * mono_arch_get_throw_corlib_exception:
+ *
+ * Returns a function pointer which can be used to raise 
+ * corlib exceptions. The returned function has the following 
+ * signature: void (*func) (guint32 ex_token, guint32 offset); 
+ * Here, offset is the offset which needs to be substracted from the caller IP 
+ * to get the IP of the throw. Passing the offset has the advantage that it 
+ * needs no relocations in the caller.
+ */
+gpointer 
+mono_arch_get_throw_corlib_exception (void)
+{
+       static guint8* start;
+       static int inited = 0;
+       guint8 *code;
+
+       if (inited)
+               return start;
+
+       inited = 1;
+       code = start = mono_global_codeman_reserve (64);
+
+       x86_push_membase (code, X86_ESP, 4); /* token */
+       x86_push_imm (code, mono_defaults.exception_class->image);
+       x86_call_code (code, mono_exception_from_token);
+       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
+       /* Compute caller ip */
+       x86_pop_reg (code, X86_ECX);
+       /* Pop token */
+       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+       x86_pop_reg (code, X86_EDX);
+       x86_alu_reg_reg (code, X86_SUB, X86_ECX, X86_EDX);
+       /* Push exception object */
+       x86_push_reg (code, X86_EAX);
+       /* Push throw IP */
+       x86_push_reg (code, X86_ECX);
+       x86_jump_code (code, mono_arch_get_throw_exception ());
+
+       g_assert ((code - start) < 64);
+
+       return start;
+}
+
 /* mono_arch_find_jit_info:
  *
  * This function is used to gather information from @ctx. It return the 
@@ -359,52 +573,18 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
        else
                ji = mono_jit_info_table_find (domain, ip);
 
-       if (trace)
-               *trace = NULL;
-
-       if (native_offset)
-               *native_offset = -1;
-
        if (managed)
                *managed = FALSE;
 
        if (ji != NULL) {
-               char *source_location, *tmpaddr, *fname;
-               gint32 address, iloffset;
                int offset;
 
                *new_ctx = *ctx;
 
-               address = (char *)ip - (char *)ji->code_start;
-
-               if (native_offset)
-                       *native_offset = address;
-
                if (managed)
                        if (!ji->method->wrapper_type)
                                *managed = TRUE;
 
-               if (trace) {
-                       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);
-                       else
-                               tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
-               
-                       fname = mono_method_full_name (ji->method, TRUE);
-
-                       if (source_location)
-                               *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
-                       else
-                               *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
-
-                       g_free (fname);
-                       g_free (source_location);
-                       g_free (tmpaddr);
-               }
-
                /*
                 * Some managed methods like pinvoke wrappers might have save_lmf set.
                 * In this case, register save/restore code is not generated by the 
@@ -416,24 +596,24 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                         * 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;
+                               new_ctx->esi = (*lmf)->esi;
+                               new_ctx->edi = (*lmf)->edi;
+                               new_ctx->ebx = (*lmf)->ebx;
                        }
                }
                else {
                        offset = -1;
                        /* restore caller saved registers */
                        if (ji->used_regs & X86_EBX_MASK) {
-                               new_ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
+                               new_ctx->ebx = *((int *)ctx->ebp + offset);
                                offset--;
                        }
                        if (ji->used_regs & X86_EDI_MASK) {
-                               new_ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
+                               new_ctx->edi = *((int *)ctx->ebp + offset);
                                offset--;
                        }
                        if (ji->used_regs & X86_ESI_MASK) {
-                               new_ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
+                               new_ctx->esi = *((int *)ctx->ebp + offset);
                        }
                }
 
@@ -443,18 +623,20 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                }
 
                /* Pop EBP and the return address */
-               new_ctx->SC_ESP = ctx->SC_EBP + (2 * sizeof (gpointer));
+               new_ctx->esp = ctx->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);
-
-               *res = *ji;
-               return res;
-#ifdef MONO_USE_EXC_TABLES
-       } else if ((ji = x86_unwind_native_frame (domain, jit_tls, ctx, new_ctx, *lmf, trace))) {
-               *res = *ji;             
-               return res;
-#endif
+               new_ctx->eip = *((int *)ctx->ebp + 1) - 1;
+               new_ctx->ebp = *((int *)ctx->ebp);
+
+               /* Pop arguments off the stack */
+               {
+                       MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
+
+                       guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
+                       new_ctx->esp += stack_to_pop;
+               }
+
+               return ji;
        } else if (*lmf) {
                
                *new_ctx = *ctx;
@@ -463,49 +645,122 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                        return (gpointer)-1;
 
                if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
-                       *res = *ji;
                } else {
                        memset (res, 0, sizeof (MonoJitInfo));
                        res->method = (*lmf)->method;
                }
 
-               if (trace)
-                       *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name (res->method, TRUE));
-               
-               new_ctx->SC_ESI = (*lmf)->esi;
-               new_ctx->SC_EDI = (*lmf)->edi;
-               new_ctx->SC_EBX = (*lmf)->ebx;
-               new_ctx->SC_EBP = (*lmf)->ebp;
-               new_ctx->SC_EIP = (*lmf)->eip;
+               new_ctx->esi = (*lmf)->esi;
+               new_ctx->edi = (*lmf)->edi;
+               new_ctx->ebx = (*lmf)->ebx;
+               new_ctx->ebp = (*lmf)->ebp;
+               new_ctx->eip = (*lmf)->eip;
                /* the lmf is always stored on the stack, so the following
                 * expression points to a stack location which can be used as ESP */
-               new_ctx->SC_ESP = (unsigned long)&((*lmf)->eip);
+               new_ctx->esp = (unsigned long)&((*lmf)->eip);
 
                *lmf = (*lmf)->previous_lmf;
 
-               return res;
-               
+               return ji ? ji : res;
        }
 
        return NULL;
 }
 
-/**
- * mono_arch_handle_exception:
- *
- * @ctx: saved processor state
- * @obj: the exception object
- */
-gboolean
-mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
+#ifdef __sun
+#define REG_EAX EAX
+#define REG_EBX EBX
+#define REG_ECX ECX
+#define REG_EDX EDX
+#define REG_EBP EBP
+#define REG_ESP ESP
+#define REG_ESI ESI
+#define REG_EDI EDI
+#define REG_EIP EIP
+#endif
+
+void
+mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
 {
-       return mono_handle_exception (sigctx, obj, mono_arch_ip_from_context (sigctx), test_only);
+#ifdef MONO_ARCH_USE_SIGACTION
+       ucontext_t *ctx = (ucontext_t*)sigctx;
+       
+       mctx->eax = UCONTEXT_REG_EAX (ctx);
+       mctx->ebx = UCONTEXT_REG_EBX (ctx);
+       mctx->ecx = UCONTEXT_REG_ECX (ctx);
+       mctx->edx = UCONTEXT_REG_EDX (ctx);
+       mctx->ebp = UCONTEXT_REG_EBP (ctx);
+       mctx->esp = UCONTEXT_REG_ESP (ctx);
+       mctx->esi = UCONTEXT_REG_ESI (ctx);
+       mctx->edi = UCONTEXT_REG_EDI (ctx);
+       mctx->eip = UCONTEXT_REG_EIP (ctx);
+#else  
+       struct sigcontext *ctx = (struct sigcontext *)sigctx;
+
+       mctx->eax = ctx->SC_EAX;
+       mctx->ebx = ctx->SC_EBX;
+       mctx->ecx = ctx->SC_ECX;
+       mctx->edx = ctx->SC_EDX;
+       mctx->ebp = ctx->SC_EBP;
+       mctx->esp = ctx->SC_ESP;
+       mctx->esi = ctx->SC_ESI;
+       mctx->edi = ctx->SC_EDI;
+       mctx->eip = ctx->SC_EIP;
+#endif
 }
 
+void
+mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
+{
+#ifdef MONO_ARCH_USE_SIGACTION
+       ucontext_t *ctx = (ucontext_t*)sigctx;
+
+       UCONTEXT_REG_EAX (ctx) = mctx->eax;
+       UCONTEXT_REG_EBX (ctx) = mctx->ebx;
+       UCONTEXT_REG_ECX (ctx) = mctx->ecx;
+       UCONTEXT_REG_EDX (ctx) = mctx->edx;
+       UCONTEXT_REG_EBP (ctx) = mctx->ebp;
+       UCONTEXT_REG_ESP (ctx) = mctx->esp;
+       UCONTEXT_REG_ESI (ctx) = mctx->esi;
+       UCONTEXT_REG_EDI (ctx) = mctx->edi;
+       UCONTEXT_REG_EIP (ctx) = mctx->eip;
+#else
+       struct sigcontext *ctx = (struct sigcontext *)sigctx;
+
+       ctx->SC_EAX = mctx->eax;
+       ctx->SC_EBX = mctx->ebx;
+       ctx->SC_ECX = mctx->ecx;
+       ctx->SC_EDX = mctx->edx;
+       ctx->SC_EBP = mctx->ebp;
+       ctx->SC_ESP = mctx->esp;
+       ctx->SC_ESI = mctx->esi;
+       ctx->SC_EDI = mctx->edi;
+       ctx->SC_EIP = mctx->eip;
+#endif
+}      
+
 gpointer
 mono_arch_ip_from_context (void *sigctx)
 {
+#ifdef MONO_ARCH_USE_SIGACTION
+       ucontext_t *ctx = (ucontext_t*)sigctx;
+       return (gpointer)UCONTEXT_REG_EIP (ctx);
+#else
        struct sigcontext *ctx = sigctx;
        return (gpointer)ctx->SC_EIP;
+#endif 
 }
 
+gboolean
+mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
+{
+       MonoContext mctx;
+
+       mono_arch_sigctx_to_monoctx (sigctx, &mctx);
+
+       mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
+
+       mono_arch_monoctx_to_sigctx (&mctx, sigctx);
+
+       return TRUE;
+}