2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / jit / exception.c
index 60af8de1aaff1f24e9dc48adfcb6ea0a1bed13b0..59b4c811a9ce0504d699148e13b69c429478a932 100644 (file)
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/threads.h>
 #include <mono/metadata/debug-helpers.h>
+#include <mono/metadata/mono-debug.h>
 
 #include "jit.h"
 #include "codegen.h"
-#include "debug.h"
 
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
 # define SC_EAX sc_eax
 # define SC_EBX sc_ebx
 # define SC_ECX sc_ecx
 # define SC_ESI esi
 #endif
 
+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_SET_EXCREG(ctx,exc) do { (ctx)->SC_ECX = (long)exc; } 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->eax;
+       case X86_EBX:
+               return ctx->ebx;
+       case X86_ECX:
+               return ctx->ecx;
+       case X86_EDX:
+               return ctx->edx;
+       case X86_ESI:
+               return ctx->esi;
+       case X86_EDI:
+               return ctx->edi;
+       case X86_EBP:
+               return ctx->ebp;
+       case X86_ESP:
+               return ctx->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->eax = value;
+               break;
+       case X86_EBX:
+               ctx->ebx = value;
+               break;
+       case X86_ECX:
+               ctx->ecx = value;
+               break;
+       case X86_EDX:
+               ctx->edx = value;
+               break;
+       case X86_ESI:
+               ctx->esi = value;
+               break;
+       case X86_EDI:
+               ctx->edi = value;
+               break;
+       case X86_EBP:
+               ctx->ebp = value;
+               break;
+       case X86_ESP:
+               ctx->esp = value;
+               break;
+       case 8:
+               ctx->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_has_unwind_info:
+ *
+ * Tests if a function has an DWARF exception table able to restore
+ * all caller saved registers. 
+ */
+gboolean
+mono_has_unwind_info (MonoMethod *method)
+{
+       struct frame_state state_in;
+       struct frame_state *res;
+
+       if (!inited) 
+               init_frame_state_for ();
+       
+       if (!frame_state_for)
+               return FALSE;
+
+       g_assert (method->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 *)method->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;
+}
+
+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->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:
  *
@@ -89,7 +363,9 @@ arch_get_restore_context (void)
 /*
  * arch_get_call_filter:
  *
- * Returns a pointer to a method which calls an exception 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)
@@ -102,7 +378,7 @@ arch_get_call_filter (void)
                return start;
 
        inited = 1;
-       /* call_finally (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
+       /* call_filter (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
        code = start;
 
        x86_push_reg (code, X86_EBP);
@@ -142,15 +418,52 @@ arch_get_call_filter (void)
        return start;
 }
 
-/*
- * arch_get_call_finally:
+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)
+{
+       static void (*restore_context) (struct sigcontext *);
+       struct sigcontext ctx;
+
+       if (!restore_context)
+               restore_context = arch_get_restore_context ();
+
+       /* adjust eip so that it point into the call instruction */
+       eip -= 1;
+
+       ctx.SC_ESP = esp;
+       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;
+       
+       arch_handle_exception (&ctx, exc, FALSE);
+       restore_context (&ctx);
+
+       g_assert_not_reached ();
+}
+
+/**
+ * arch_get_throw_exception:
+ *
+ * Returns a function pointer which can be used to raise 
+ * exceptions. The returned function has the following 
+ * signature: void (*func) (MonoException *exc); 
+ * For example to raise an arithmetic exception you can use:
+ *
+ * x86_push_imm (code, mono_get_exception_arithmetic ()); 
+ * x86_call_code (code, arch_get_throw_exception ()); 
  *
- * Returns a pointer to a method which calls a finally handler.
  */
-static gpointer
-arch_get_call_finally (void)
+gpointer 
+arch_get_throw_exception (void)
 {
-       static guint8 start [64];
+       static guint8 start [24];
        static int inited = 0;
        guint8 *code;
 
@@ -158,43 +471,67 @@ arch_get_call_finally (void)
                return start;
 
        inited = 1;
-       /* call_finally (struct sigcontext *ctx, unsigned long eip) */
        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_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
-       x86_push_reg (code, X86_EBX);
        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);
 
-       /* load ctx */
-       x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
-       /* load eip */
-       x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
-       /* save EBP */
-       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);
-       /* 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);
-       /* 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);
-       /* restore EBP */
-       x86_pop_reg (code, X86_EBP);
-       /* restore saved regs */
-       x86_pop_reg (code, X86_ESI);
-       x86_pop_reg (code, X86_EDI);
-       x86_pop_reg (code, X86_EBX);
-       x86_leave (code);
-       x86_ret (code);
-
-       g_assert ((code - start) < 64);
+       g_assert ((code - start) < 24);
        return start;
 }
 
+/**
+ * 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); 
+ * For example to raise an arithmetic exception you can use:
+ *
+ * x86_push_imm (code, "ArithmeticException"); 
+ * x86_call_code (code, arch_get_throw_exception ()); 
+ *
+ */
+gpointer 
+arch_get_throw_exception_by_name ()
+{
+       static guint8 start [32];
+       static int inited = 0;
+       guint8 *code;
+
+       if (inited)
+               return start;
+
+       inited = 1;
+       code = start;
+
+       /* fixme: we do not save EAX, EDX, ECD - unsure if we need that */
+
+       x86_push_membase (code, X86_ESP, 4); /* exception name */
+       x86_push_imm (code, "System");
+       x86_push_imm (code, mono_defaults.exception_class->image);
+       x86_call_code (code, mono_exception_from_name);
+       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
+       /* save the newly create object (overwrite exception name)*/
+       x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
+       x86_jump_code (code, arch_get_throw_exception ());
+
+       g_assert ((code - start) < 32);
+
+       return start;
+}      
+
 static MonoArray *
 glist_to_array (GList *list) 
 {
@@ -214,6 +551,138 @@ glist_to_array (GList *list)
        return res;
 }
 
+/* mono_arch_find_jit_info:
+ *
+ * This function is used to gather information from @ctx. It return the 
+ * MonoJitInfo of the corresponding function, unwinds one stack frame and
+ * stores the resulting context into @new_ctx. It also stores a string 
+ * describing the stack location into @trace (if not NULL), and modifies
+ * 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, 
+                        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;
+
+       if (managed)
+               *managed = FALSE;
+
+       if (ji != NULL) {
+               char *source_location, *tmpaddr, *fname;
+               gint32 address, iloffset;
+               int offset;
+
+               *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)
+                       *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);
+               }
+                               
+               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);
+               }
+
+               new_ctx->SC_ESP = ctx->SC_EBP;
+               /* 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
+       } else if (*lmf) {
+               
+               *new_ctx = *ctx;
+
+               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;
+               /* 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);
+
+               *lmf = (*lmf)->previous_lmf;
+
+               return res;
+               
+       }
+
+       return NULL;
+}
+
 MonoArray *
 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
 {
@@ -221,6 +690,11 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
        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);
 
@@ -232,16 +706,22 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
                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);
+               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);
+                       filename = mono_debug_source_location_from_address (ji->method, sf->native_offset, &sf->line, domain);
 
                        sf->filename = mono_string_new (domain, filename ? filename : "<unknown>");
                        sf->column = 0;
@@ -260,36 +740,29 @@ 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;
-       MonoMethod *m;
-       gpointer ip;
-       gpointer *bp;
+       MonoJitInfo *ji, rji;
        gint native_offset, il_offset;
+       gboolean managed;
 
-       bp = (gpointer *)&func;
-       ip = bp [-1];
-       bp = &ip;
-
-       while ((unsigned)bp < (unsigned)jit_tls->end_of_stack) {
-               if ((ji = mono_jit_info_table_find (domain, ip))) {
-                       m = ji->method;
-                       native_offset = (char *)ip - (char *)ji->code_start;
-                       ip = (gpointer)((char *)bp [1] - 5);
-                       bp = bp [0];
-                       il_offset = mono_debug_il_offset_from_address (m, native_offset);
-               } else {
-                       if (!lmf)
-                               break;
-                       m = lmf->method;
+       MonoContext ctx, new_ctx;
 
-                       bp = (gpointer)lmf->ebp;
-                       ip = (gpointer)lmf->eip;
-                       lmf = lmf->previous_lmf;
+       MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
+       MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (1));
 
-                       native_offset = il_offset = -1;
-               }
-               if (func (m, native_offset, il_offset, user_data))
+       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;
        }
 }
 
@@ -302,48 +775,35 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
        MonoDomain *domain = mono_domain_get ();
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
        MonoLMF *lmf = jit_tls->lmf;
-       gpointer *sf = (gpointer *)&skip;
-       gpointer ip = sf [-1];
-       int addr;
-       gpointer *bp = sf [-2];
-       MonoMethod *m = NULL;
+       MonoJitInfo *ji, rji;
+       MonoContext ctx, new_ctx;
 
-       do {
-               MonoJitInfo *ji;
-               addr = -1; /* unknown */
+       MONO_CONTEXT_SET_IP (&ctx, ves_icall_get_frame_info);
+       MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
 
-               if ((ji = mono_jit_info_table_find (domain, ip))) {
-                       m = ji->method;
-                       addr = (char *)ip - (char *)ji->code_start;
-                       ip = (gpointer)((char *)bp [1] - 5);
-                       bp = bp [0];
-               } else {
-                       if (!lmf)
-                               return FALSE;
-                       
-                       m = lmf->method;
-
-                       bp = (gpointer)lmf->ebp;
-                       ip = (gpointer)lmf->eip;
+       skip++;
 
-                       lmf = lmf->previous_lmf;
-               }
-
-               if ((unsigned)bp >= (unsigned)jit_tls->end_of_stack)
+       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;
 
-       } while (skip-- > 0);
+               if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)
+                       continue;
+               
+               skip--;
 
-       g_assert (m);
+       } while (skip >= 0);
 
-       *method = mono_method_get_object (domain, m, NULL);
-       *iloffset = mono_debug_il_offset_from_address (m, addr);
-       *native_offset = addr;
+       *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 (m, addr, line);
+               filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
 
                *file = mono_string_new (domain, filename ? filename : "<unknown>");
                *column = 0;
@@ -357,23 +817,20 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
 /**
  * arch_handle_exception:
  * @ctx: saved processor state
- * @obj:
+ * @obj: the exception object
+ * @test_only: only test if the exception is caught, but dont call handlers
+ *
+ *
  */
 gboolean
-arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only)
+arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
 {
        MonoDomain *domain = mono_domain_get ();
-       MonoJitInfo *ji;
-       static void (*restore_context) (struct sigcontext *);
-       static void (*call_finally) (struct sigcontext *, unsigned long);
-       static int (*call_filter) (struct sigcontext *, gpointer, gpointer);
-       void (*cleanup) (MonoObject *exc);
+       MonoJitInfo *ji, rji;
+       static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-       gpointer end_of_stack;
-       struct sigcontext ctx_cp;
        MonoLMF *lmf = jit_tls->lmf;            
        GList *trace_ips = NULL;
-       MonoMethod *m;
 
        g_assert (ctx != NULL);
        if (!obj) {
@@ -385,96 +842,52 @@ arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only)
 
        g_assert (mono_object_isinst (obj, mono_defaults.exception_class));
 
-       ((MonoException *)obj)->stack_trace = NULL;
-
-       if (!restore_context)
-               restore_context = arch_get_restore_context ();
-       
-       if (!call_finally)
-               call_finally = arch_get_call_finally ();
-
        if (!call_filter)
                call_filter = arch_get_call_filter ();
 
-       end_of_stack = jit_tls->end_of_stack;
-       g_assert (end_of_stack);
+       g_assert (jit_tls->end_of_stack);
+       g_assert (jit_tls->abort_func);
 
-       cleanup = jit_tls->abort_func;
-       g_assert (cleanup);
-       
        if (!test_only) {
-               ctx_cp = *ctx;
+               MonoContext ctx_cp = *ctx;
                if (!arch_handle_exception (&ctx_cp, obj, TRUE)) {
-                       if (mono_break_on_exc) {
-                               if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
-                                       mono_debug_make_symbols ();
+                       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 ();
+               }
 
-               ji = mono_jit_info_table_find (domain, (gpointer)ctx->SC_EIP);
-       
-               /* we are inside managed code if ji != NULL */
-               if (ji != NULL) {
-                       int offset;
-                       m = ji->method;
-
-                       if (m == mono_start_method) {
-                               if (!test_only) {
-                                       jit_tls->lmf = lmf;
-                                       cleanup (obj);
-                                       g_assert_not_reached ();
-                               } else {
-                                       ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
-                                       g_list_free (trace_ips);
-                                       return FALSE;
-                               }
-                       }
-                       
-                       if (test_only) {
-                               char    *strace;
-                               char    *tmp, *source_location, *tmpaddr, *fname;
-                               gint32   address, iloffset;
+               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, (gpointer)ctx->SC_EIP);
+                               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);
-
-                               address = (char *)ctx->SC_EIP - (char *)ji->code_start;
-
-                               source_location = mono_debug_source_location_from_address (m, address, NULL);
-                               iloffset = mono_debug_il_offset_from_address (m, address);
-
-                               if (iloffset < 0)
-                                       tmpaddr = g_strdup_printf ("<0x%05x>", address);
-                               else
-                                       tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
-
-                               fname = mono_method_full_name (m, TRUE);
-
-                               if (source_location)
-                                       tmp = g_strdup_printf ("%sin %s (at %s) %s\n", strace, tmpaddr,
-                                                              source_location, fname);
-                               else
-                                       tmp = g_strdup_printf ("%sin %s %s\n", strace, tmpaddr,
-                                                              fname);
-                               g_free (fname);
-                               g_free (source_location);
+                       
+                               tmp = g_strdup_printf ("%s%s\n", strace, trace);
                                g_free (strace);
-                               g_free (tmpaddr);
 
                                ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
 
                                g_free (tmp);
                        }
-                       
+
                        if (ji->num_clauses) {
                                int i;
                                
@@ -483,11 +896,11 @@ arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only)
                                for (i = 0; i < ji->num_clauses; i++) {
                                        MonoJitExceptionInfo *ei = &ji->clauses [i];
 
-                                       if (ei->try_start <= (gpointer)ctx->SC_EIP && 
-                                           (gpointer)ctx->SC_EIP <= ei->try_end) { 
+                                       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 (m->klass->image, ei->data.token))) ||
+                                                    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) {
@@ -495,15 +908,10 @@ arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only)
                                                                g_list_free (trace_ips);
                                                                return TRUE;
                                                        }
-                                                       ctx->SC_EIP = (unsigned long)ei->handler_start;
-                                                       ctx->SC_ECX = (unsigned long)obj;
+                                                       MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
+                                                       MONO_CONTEXT_SET_EXCREG (ctx, obj);
                                                        jit_tls->lmf = lmf;
-#if 1
                                                        return 0;
-#else
-                                                       restore_context (ctx);
-                                                       g_assert_not_reached ();
-#endif
                                                }
                                        }
                                }
@@ -512,101 +920,30 @@ arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only)
                                if (!test_only) {
                                        for (i = 0; i < ji->num_clauses; i++) {
                                                MonoJitExceptionInfo *ei = &ji->clauses [i];
-
-                                               if (ei->try_start <= (gpointer)ctx->SC_EIP && 
-                                                   (gpointer)ctx->SC_EIP < ei->try_end &&
+                                               
+                                               if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
+                                                   MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
                                                    (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
-                                                       call_finally (ctx, (unsigned long)ei->handler_start);
+                                                       call_filter (ctx, ei->handler_start, NULL);
                                                }
                                        }
                                }
                        }
+               }
 
-                       /* continue unwinding */
-
-                       offset = -1;
-                       /* restore caller saved registers */
-                       if (ji->used_regs & X86_EBX_MASK) {
-                               ctx->SC_EBX = *((int *)ctx->SC_EBP + offset);
-                               offset--;
-                       }
-                       if (ji->used_regs & X86_EDI_MASK) {
-                               ctx->SC_EDI = *((int *)ctx->SC_EBP + offset);
-                               offset--;
-                       }
-                       if (ji->used_regs & X86_ESI_MASK) {
-                               ctx->SC_ESI = *((int *)ctx->SC_EBP + offset);
-                       }
-
-                       ctx->SC_ESP = ctx->SC_EBP;
-                       ctx->SC_EIP = *((int *)ctx->SC_EBP + 1) - 5;
-                       ctx->SC_EBP = *((int *)ctx->SC_EBP);
-
-                       if (ctx->SC_EBP > (unsigned)end_of_stack) {
-                               if (!test_only) {
-                                       jit_tls->lmf = lmf;
-                                       cleanup (obj);
-                                       g_assert_not_reached ();
-                               } else {
-                                       ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
-                                       g_list_free (trace_ips);
-                                       return FALSE;
-                               }
-                       }
-       
-               } else {
-                       if (!lmf) {
-                               if (!test_only) {
-                                       jit_tls->lmf = lmf;
-                                       cleanup (obj);
-                                       g_assert_not_reached ();
-                               } else {
-                                       ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
-                                       g_list_free (trace_ips);
-                                       return FALSE;
-                               }
-                       }
+               g_free (trace);
                        
-                       m = lmf->method;
-
-                       if (test_only) {
-                               char  *strace; 
-                               char  *tmp;
-
-                               trace_ips = g_list_append (trace_ips, lmf->method->info);
-
-                               if (!((MonoException*)obj)->stack_trace)
-                                       strace = g_strdup ("");
-                               else
-                                       strace = mono_string_to_utf8 (((MonoException*)obj)->stack_trace);
-
-                               tmp = g_strdup_printf ("%sin (unmanaged) %s\n", strace, mono_method_full_name (m, TRUE));
-
-                               g_free (strace);
-
-                               ((MonoException*)obj)->stack_trace = mono_string_new (domain, tmp);
-                               g_free (tmp);
-                       }
-
-                       ctx->SC_ESI = lmf->esi;
-                       ctx->SC_EDI = lmf->edi;
-                       ctx->SC_EBX = lmf->ebx;
-                       ctx->SC_EBP = lmf->ebp;
-                       ctx->SC_EIP = lmf->eip;
-                       ctx->SC_ESP = (unsigned long)&lmf->eip;
-
-                       lmf = lmf->previous_lmf;
-
-                       if (ctx->SC_EBP >= (unsigned)end_of_stack) {
-                               if (!test_only) {
-                                       jit_tls->lmf = lmf;
-                                       cleanup (obj);
-                                       g_assert_not_reached ();
-                               } else {
-                                       ((MonoException*)obj)->trace_ips = glist_to_array (trace_ips);
-                                       g_list_free (trace_ips);
-                                       return FALSE;
-                               }
+               *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;
                        }
                }
        }
@@ -614,116 +951,4 @@ arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only)
        g_assert_not_reached ();
 }
 
-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)
-{
-       static void (*restore_context) (struct sigcontext *);
-       struct sigcontext ctx;
-
-       if (!restore_context)
-               restore_context = arch_get_restore_context ();
-
-       /* adjust eip so that it point to the call instruction */
-       eip -= 5;
-
-       ctx.SC_ESP = esp;
-       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;
-       
-       arch_handle_exception (&ctx, exc, FALSE);
-       restore_context (&ctx);
-
-       g_assert_not_reached ();
-}
-
-/**
- * arch_get_throw_exception:
- *
- * Returns a function pointer which can be used to raise 
- * exceptions. The returned function has the following 
- * signature: void (*func) (MonoException *exc); 
- * For example to raise an arithmetic exception you can use:
- *
- * x86_push_imm (code, mono_get_exception_arithmetic ()); 
- * x86_call_code (code, arch_get_throw_exception ()); 
- *
- */
-gpointer 
-arch_get_throw_exception (void)
-{
-       static guint8 start [24];
-       static int inited = 0;
-       guint8 *code;
-
-       if (inited)
-               return start;
-
-       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);
-
-       g_assert ((code - start) < 24);
-       return start;
-}
 
-/**
- * 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); 
- * For example to raise an arithmetic exception you can use:
- *
- * x86_push_imm (code, "ArithmeticException"); 
- * x86_call_code (code, arch_get_throw_exception ()); 
- *
- */
-gpointer 
-arch_get_throw_exception_by_name ()
-{
-       static guint8 start [32];
-       static int inited = 0;
-       guint8 *code;
-
-       if (inited)
-               return start;
-
-       inited = 1;
-       code = start;
-
-       /* fixme: we do not save EAX, EDX, ECD - unsure if we need that */
-
-       x86_push_membase (code, X86_ESP, 4); /* exception name */
-       x86_push_imm (code, "System");
-       x86_push_imm (code, mono_defaults.exception_class->image);
-       x86_call_code (code, mono_exception_from_name);
-       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
-       /* save the newly create object (overwrite exception name)*/
-       x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
-       x86_jump_code (code, arch_get_throw_exception ());
-
-       g_assert ((code - start) < 32);
-
-       return start;
-}