* main.c (dis_nt_header): New. Dump pe_stack_reserve if different from the
[mono.git] / mono / mini / exceptions-x86.c
index 7c0e853f265b8a0cc2644bde08d4547fe262e7a0..c0699aa167917d7374296e600a9cb50a23838be3 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 <mono/metadata/mono-debug-debugger.h>
 
 #include "mini.h"
 #include "mini-x86.h"
 
-#ifdef PLATFORM_WIN32
-
-#include <windows.h>
-
-/* use SIG* defines if possible */
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-
-/* sigcontext surrogate */
-struct sigcontext {
-       unsigned int eax;
-       unsigned int ebx;
-       unsigned int ecx;
-       unsigned int edx;
-       unsigned int ebp;
-       unsigned int esp;
-       unsigned int esi;
-       unsigned int edi;
-       unsigned int eip;
-};
-
-
-typedef void (* MonoW32ExceptionHandler) (int);
-void win32_seh_init(void);
-void win32_seh_cleanup(void);
-void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler);
-
-#ifndef SIGFPE
-#define SIGFPE 4
-#endif
-
-#ifndef SIGILL
-#define SIGILL 8
-#endif
-
-#ifndef        SIGSEGV
-#define        SIGSEGV 11
-#endif
-
-LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep);
+#if defined(__FreeBSD__)
+#include <ucontext.h>
+#endif 
 
+#ifdef PLATFORM_WIN32
 static MonoW32ExceptionHandler fpe_handler;
 static MonoW32ExceptionHandler ill_handler;
 static MonoW32ExceptionHandler segv_handler;
@@ -164,309 +129,13 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
 
 #endif /* PLATFORM_WIN32 */
 
-#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
-
-gboolean  mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
-
-typedef struct sigcontext MonoContext;
-
-#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); 
-
-#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
-
-/*************************************/
-/*    STACK UNWINDING STUFF          */
-/*************************************/
-
-/* These definitions are from unwind-dw2.c in glibc 2.2.5 */
-
-/* For x86 */
-#define DWARF_FRAME_REGISTERS 17
-
-typedef struct frame_state
-{
-  void *cfa;
-  void *eh_ptr;
-  long cfa_offset;
-  long args_size;
-  long reg_or_offset[DWARF_FRAME_REGISTERS+1];
-  unsigned short cfa_reg;
-  unsigned short retaddr_column;
-  char saved[DWARF_FRAME_REGISTERS+1];
-} frame_state;
-
-static long
-get_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum)
-{
-       switch (dwarf_regnum) {
-       case X86_EAX:
-               return ctx->SC_EAX;
-       case X86_EBX:
-               return ctx->SC_EBX;
-       case X86_ECX:
-               return ctx->SC_ECX;
-       case X86_EDX:
-               return ctx->SC_EDX;
-       case X86_ESI:
-               return ctx->SC_ESI;
-       case X86_EDI:
-               return ctx->SC_EDI;
-       case X86_EBP:
-               return ctx->SC_EBP;
-       case X86_ESP:
-               return ctx->SC_ESP;
-       default:
-               g_assert_not_reached ();
-       }
-
-       return 0;
-}
-
-static void
-set_sigcontext_reg (struct sigcontext *ctx, int dwarf_regnum, long value)
-{
-       switch (dwarf_regnum) {
-       case X86_EAX:
-               ctx->SC_EAX = value;
-               break;
-       case X86_EBX:
-               ctx->SC_EBX = value;
-               break;
-       case X86_ECX:
-               ctx->SC_ECX = value;
-               break;
-       case X86_EDX:
-               ctx->SC_EDX = value;
-               break;
-       case X86_ESI:
-               ctx->SC_ESI = value;
-               break;
-       case X86_EDI:
-               ctx->SC_EDI = value;
-               break;
-       case X86_EBP:
-               ctx->SC_EBP = value;
-               break;
-       case X86_ESP:
-               ctx->SC_ESP = value;
-               break;
-       case 8:
-               ctx->SC_EIP = value;
-               break;
-       default:
-               g_assert_not_reached ();
-       }
-}
-
-typedef struct frame_state * (*framesf) (void *, struct frame_state *);
-
-static framesf frame_state_for = NULL;
-
-static gboolean inited = FALSE;
-
-typedef char ** (*get_backtrace_symbols_type) (void *__const *__array, int __size);
-
-static get_backtrace_symbols_type get_backtrace_symbols = NULL;
-
-static void
-init_frame_state_for (void)
-{
-       GModule *module;
-
-       /*
-        * There are two versions of __frame_state_for: one in libgcc.a and the
-        * other in glibc.so. We need the version from glibc.
-        * For more info, see this:
-        * http://gcc.gnu.org/ml/gcc/2002-08/msg00192.html
-        */
-       if ((module = g_module_open ("libc.so.6", G_MODULE_BIND_LAZY))) {
-       
-               if (!g_module_symbol (module, "__frame_state_for", (gpointer*)&frame_state_for))
-                       frame_state_for = NULL;
-
-               if (!g_module_symbol (module, "backtrace_symbols", (gpointer*)&get_backtrace_symbols)) {
-                       get_backtrace_symbols = NULL;
-                       frame_state_for = NULL;
-               }
-
-               g_module_close (module);
-       }
-
-       inited = TRUE;
-}
-
-/* mono_arch_has_unwind_info:
- *
- * Tests if a function has an DWARF exception table able to restore
- * all caller saved registers. 
- */
-gboolean
-mono_arch_has_unwind_info (gconstpointer addr)
-{
-       struct frame_state state_in;
-       struct frame_state *res;
-
-       if (!inited) 
-               init_frame_state_for ();
-       
-       if (!frame_state_for)
-               return FALSE;
-
-       g_assert (addr);
-
-       memset (&state_in, 0, sizeof (state_in));
-
-       /* 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 TRUE;
-       }
-
-       return FALSE;
-}
-
-struct stack_frame
-{
-  void *next;
-  void *return_address;
-};
-
-static MonoJitInfo *
-x86_unwind_native_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, struct sigcontext *ctx, 
-                        struct sigcontext *new_ctx, MonoLMF *lmf, char **trace)
-{
-       struct stack_frame *frame;
-       gpointer max_stack;
-       MonoJitInfo *ji;
-       struct frame_state state_in;
-       struct frame_state *res;
-
-       if (trace)
-               *trace = NULL;
-
-       if (!inited) 
-               init_frame_state_for ();
-
-       if (!frame_state_for)
-               return FALSE;
-
-       frame = MONO_CONTEXT_GET_BP (ctx);
-
-       max_stack = lmf && lmf->method ? lmf : jit_tls->end_of_stack;
-
-       *new_ctx = *ctx;
-
-       memset (&state_in, 0, sizeof (state_in));
-
-       while ((gpointer)frame->next < (gpointer)max_stack) {
-               gpointer ip, addr = frame->return_address;
-               void *cfa;
-               char *tmp, **symbols;
-
-               if (trace) {
-                       ip = MONO_CONTEXT_GET_IP (new_ctx);
-                       symbols = get_backtrace_symbols (&ip, 1);
-                       if (*trace)
-                               tmp = g_strdup_printf ("%s\nin (unmanaged) %s", *trace, symbols [0]);
-                       else
-                               tmp = g_strdup_printf ("in (unmanaged) %s", symbols [0]);
-
-                       free (symbols);
-                       g_free (*trace);
-                       *trace = tmp;
-               }
-
-               if ((res = frame_state_for (addr, &state_in))) {        
-                       int i;
-
-                       cfa = (gint8*) (get_sigcontext_reg (new_ctx, res->cfa_reg) + res->cfa_offset);
-                       frame = (struct stack_frame *)((gint8*)cfa - 8);
-                       for (i = 0; i < DWARF_FRAME_REGISTERS + 1; i++) {
-                               int how = res->saved[i];
-                               long val;
-                               g_assert ((how == 0) || (how == 1));
-                       
-                               if (how == 1) {
-                                       val = * (long*) ((gint8*)cfa + res->reg_or_offset[i]);
-                                       set_sigcontext_reg (new_ctx, i, val);
-                               }
-                       }
-                       new_ctx->SC_ESP = (long)cfa;
-
-                       if (res->saved [X86_EBX] == 1 &&
-                           res->saved [X86_EDI] == 1 &&
-                           res->saved [X86_EBP] == 1 &&
-                           res->saved [X86_ESI] == 1 &&
-                           (ji = mono_jit_info_table_find (domain, frame->return_address))) {
-                               //printf ("FRAME CFA %s\n", mono_method_full_name (ji->method, TRUE));
-                               return ji;
-                       }
-
-               } else {
-                       //printf ("FRAME %p %p %p\n", frame, MONO_CONTEXT_GET_IP (new_ctx), mono_jit_info_table_find (domain, MONO_CONTEXT_GET_IP (new_ctx)));
-
-                       MONO_CONTEXT_SET_IP (new_ctx, frame->return_address);
-                       frame = frame->next;
-                       MONO_CONTEXT_SET_BP (new_ctx, frame);
-
-                       /* stop if !frame or when we detect an unexpected managed frame */
-                       if (!frame || mono_jit_info_table_find (domain, frame->return_address)) {
-                               if (trace) {
-                                       g_free (*trace);
-                                       *trace = NULL;
-                               }
-                               return NULL;
-                       }
-               }
-       }
-
-       //if (!lmf)
-       //g_assert_not_reached ();
-
-       if (trace) {
-               g_free (*trace);
-               *trace = NULL;
-       }
-       return NULL;
-}
-
-#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;
@@ -474,26 +143,26 @@ 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);
@@ -502,16 +171,16 @@ 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 guint8* start;
        static int inited = 0;
        guint8 *code;
 
@@ -519,8 +188,8 @@ 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);
@@ -536,11 +205,11 @@ 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);
@@ -562,36 +231,79 @@ 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 = arch_get_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_arch_handle_exception (&ctx, exc, 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;
+}
+
 /**
- * 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 
@@ -605,50 +317,52 @@ 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;
 }
 
 /**
- * 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 
- * 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;
 
@@ -656,7 +370,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");
@@ -670,25 +384,50 @@ mono_arch_get_throw_exception_by_name (void)
        g_assert ((code - start) < 32);
 
        return start;
-}      
+}
 
-static MonoArray *
-glist_to_array (GList *list) 
+/**
+ * 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)
 {
-       MonoDomain *domain = mono_domain_get ();
-       MonoArray *res;
-       int len, i;
+       static guint8* start;
+       static int inited = 0;
+       guint8 *code;
 
-       if (!list)
-               return NULL;
+       if (inited)
+               return start;
 
-       len = g_list_length (list);
-       res = mono_array_new (domain, mono_defaults.int_class, len);
+       inited = 1;
+       code = start = mono_global_codeman_reserve (64);
 
-       for (i = 0; list; list = list->next, i++)
-               mono_array_set (res, gpointer, i, list->data);
+       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 ());
 
-       return res;
+       g_assert ((code - start) < 64);
+
+       return start;
 }
 
 /* mono_arch_find_jit_info:
@@ -700,62 +439,32 @@ 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);
-
-       if (trace)
-               *trace = NULL;
-
-       if (native_offset)
-               *native_offset = -1;
+       /* 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 (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 
@@ -767,24 +476,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);
                        }
                }
 
@@ -794,18 +503,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;
@@ -813,312 +524,140 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                if (!(*lmf)->method)
                        return (gpointer)-1;
 
-               if (trace)
-                       *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
-               
                if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
-                       *res = *ji;
                } else {
                        memset (res, 0, sizeof (MonoJitInfo));
                        res->method = (*lmf)->method;
                }
 
-               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;
 }
 
-MonoArray *
-ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
+void
+mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
 {
-       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);
-       }
+#ifdef MONO_ARCH_USE_SIGACTION
+       ucontext_t *ctx = (ucontext_t*)sigctx;
        
-       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, domain);
-
-               if (need_file_info) {
-                       gchar *filename;
-                       
-                       filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
-
-                       sf->filename = filename? mono_string_new (domain, filename): NULL;
-                       sf->column = 0;
-
-                       g_free (filename);
-               }
-
-               mono_array_set (res, gpointer, i, sf);
-       }
-
-       return res;
+#if defined(__FreeBSD__)
+       mctx->eax = ctx->uc_mcontext.mc_eax;
+       mctx->ebx = ctx->uc_mcontext.mc_ebx;
+       mctx->ecx = ctx->uc_mcontext.mc_ecx;
+       mctx->edx = ctx->uc_mcontext.mc_edx;
+       mctx->ebp = ctx->uc_mcontext.mc_ebp;
+       mctx->esp = ctx->uc_mcontext.mc_esp;
+       mctx->esi = ctx->uc_mcontext.mc_esi;
+       mctx->edi = ctx->uc_mcontext.mc_edi;
+       mctx->eip = ctx->uc_mcontext.mc_eip;
+#else
+       mctx->eax = ctx->uc_mcontext.gregs [REG_EAX];
+       mctx->ebx = ctx->uc_mcontext.gregs [REG_EBX];
+       mctx->ecx = ctx->uc_mcontext.gregs [REG_ECX];
+       mctx->edx = ctx->uc_mcontext.gregs [REG_EDX];
+       mctx->ebp = ctx->uc_mcontext.gregs [REG_EBP];
+       mctx->esp = ctx->uc_mcontext.gregs [REG_ESP];
+       mctx->esi = ctx->uc_mcontext.gregs [REG_ESI];
+       mctx->edi = ctx->uc_mcontext.gregs [REG_EDI];
+       mctx->eip = ctx->uc_mcontext.gregs [REG_EIP];
+#endif
+#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_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, domain);
-
-               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)
+mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
 {
-       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;
-
-               /* skip all wrappers ??*/
-               if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE ||
-                   ji->method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK ||
-                   ji->method->wrapper_type == MONO_WRAPPER_REMOTING_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, domain);
-
-       if (need_file_info) {
-               gchar *filename;
-
-               filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
+#ifdef MONO_ARCH_USE_SIGACTION
+       ucontext_t *ctx = (ucontext_t*)sigctx;
+
+#if defined(__FreeBSD__)
+       ctx->uc_mcontext.mc_eax = mctx->eax;
+       ctx->uc_mcontext.mc_ebx = mctx->ebx;
+       ctx->uc_mcontext.mc_ecx = mctx->ecx;
+       ctx->uc_mcontext.mc_edx = mctx->edx;
+       ctx->uc_mcontext.mc_ebp  = mctx->ebp;
+       ctx->uc_mcontext.mc_esp = mctx->esp;
+       ctx->uc_mcontext.mc_esi = mctx->esi;
+       ctx->uc_mcontext.mc_edi = mctx->edi;
+       ctx->uc_mcontext.mc_eip = mctx->eip;
 
-               *file = filename? mono_string_new (domain, filename): NULL;
-               *column = 0;
-
-               g_free (filename);
-       }
+#else
+       ctx->uc_mcontext.gregs [REG_EAX] = mctx->eax;
+       ctx->uc_mcontext.gregs [REG_EBX] = mctx->ebx;
+       ctx->uc_mcontext.gregs [REG_ECX] = mctx->ecx;
+       ctx->uc_mcontext.gregs [REG_EDX] = mctx->edx;
+       ctx->uc_mcontext.gregs [REG_EBP] = mctx->ebp;
+       ctx->uc_mcontext.gregs [REG_ESP] = mctx->esp;
+       ctx->uc_mcontext.gregs [REG_ESI] = mctx->esi;
+       ctx->uc_mcontext.gregs [REG_EDI] = mctx->edi;
+       ctx->uc_mcontext.gregs [REG_EIP] = mctx->eip;
+#endif
+#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
+}      
 
-       return TRUE;
+gpointer
+mono_arch_ip_from_context (void *sigctx)
+{
+#ifdef MONO_ARCH_USE_SIGACTION
+       ucontext_t *ctx = (ucontext_t*)sigctx;
+#if defined(__FreeBSD__)
+       return (gpointer)ctx->uc_mcontext.mc_eip;
+#else
+       return (gpointer)ctx->uc_mcontext.gregs [REG_EIP];
+#endif
+#else
+       struct sigcontext *ctx = sigctx;
+       return (gpointer)ctx->SC_EIP;
+#endif 
 }
 
-/**
- * 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) = 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 != NULL)
-                       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);
-               }
-       }
+       MonoContext mctx;
 
-       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);
+       mono_arch_sigctx_to_monoctx (sigctx, &mctx);
 
-                               ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
+       mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
 
-                               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) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
-                                                       /* store the exception object int cfg->excvar */
-                                                       g_assert (ji->exvar_offset);
-                                                       *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
-                                               }
-
-                                               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)))) {
-                                                       if (test_only) {
-                                                               ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
-                                                               g_list_free (trace_ips);
-                                                               g_free (trace);
-                                                               return TRUE;
-                                                       }
-                                                       if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
-                                                               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);
-                                                       jit_tls->lmf = lmf;
-                                                       g_free (trace);
-                                                       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 != NULL && mono_trace_eval (ji->method))
-                                                               g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
-                                                       call_filter (ctx, ei->handler_start);
-                                               }
-                                               
-                                       }
-                               }
-                       }
-               }
+       mono_arch_monoctx_to_sigctx (&mctx, sigctx);
 
-               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 TRUE;
 }
-
-