Wed Jun 11 18:01:06 CEST 2003 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / exceptions-x86.c
index 5e00f88cb5d7661c271c898dfbe8f9a62e356326..fcea3156e86f7d8b441eca565f2d5c1bd751edc3 100644 (file)
 #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);
+
+static MonoW32ExceptionHandler fpe_handler;
+static MonoW32ExceptionHandler ill_handler;
+static MonoW32ExceptionHandler segv_handler;
+
+static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
+
+#define W32_SEH_COPY_CONTEXT \
+       sctx->eax = ctx->Eax;\
+       sctx->ebx = ctx->Ebx;\
+       sctx->ecx = ctx->Ecx;\
+       sctx->edx = ctx->Edx;\
+       sctx->ebp = ctx->Ebp;\
+       sctx->esp = ctx->Esp;\
+       sctx->esi = ctx->Esi;\
+       sctx->edi = ctx->Edi;\
+       sctx->eip = ctx->Eip;
+
+#define W32_SEH_HANDLE_EX(_ex) \
+       if (_ex##_handler) _ex##_handler((int)sctx)
+
+/*
+ * Unhandled Exception Filter
+ * Top-level per-process exception handler.
+ */
+LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
+{
+       EXCEPTION_RECORD* er;
+       CONTEXT* ctx;
+       struct sigcontext* sctx;
+       LONG res;
+
+       res = EXCEPTION_CONTINUE_SEARCH;
+
+       er = ep->ExceptionRecord;
+       ctx = ep->ContextRecord;
+       sctx = g_malloc(sizeof(struct sigcontext));
+       W32_SEH_COPY_CONTEXT
+
+       switch (er->ExceptionCode) {
+       case EXCEPTION_ACCESS_VIOLATION:
+               W32_SEH_HANDLE_EX(segv);
+               break;
+       case EXCEPTION_ILLEGAL_INSTRUCTION:
+               W32_SEH_HANDLE_EX(ill);
+               break;
+       case EXCEPTION_INT_DIVIDE_BY_ZERO:
+       case EXCEPTION_INT_OVERFLOW:
+       case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+       case EXCEPTION_FLT_OVERFLOW:
+       case EXCEPTION_FLT_UNDERFLOW:
+       case EXCEPTION_FLT_INEXACT_RESULT:
+               W32_SEH_HANDLE_EX(fpe);
+               break;
+       default:
+               break;
+       }
+
+       return res;
+}
+
+void win32_seh_init()
+{
+       old_handler = SetUnhandledExceptionFilter(seh_handler);
+}
+
+void win32_seh_cleanup()
+{
+       if (old_handler) SetUnhandledExceptionFilter(old_handler);
+}
+
+void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
+{
+       switch (type) {
+       case SIGFPE:
+               fpe_handler = handler;
+               break;
+       case SIGILL:
+               ill_handler = handler;
+               break;
+       case SIGSEGV:
+               segv_handler = handler;
+               break;
+       default:
+               break;
+       }
+}
+
+#endif /* PLATFORM_WIN32 */
+
 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
 # define SC_EAX sc_eax
 # define SC_EBX sc_ebx
 # 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); 
@@ -378,7 +511,7 @@ arch_get_call_filter (void)
                return start;
 
        inited = 1;
-       /* call_filter (struct sigcontext *ctx, unsigned long eip, gpointer exc) */
+       /* call_filter (struct sigcontext *ctx, unsigned long eip) */
        code = start;
 
        x86_push_reg (code, X86_EBP);
@@ -393,21 +526,20 @@ arch_get_call_filter (void)
        x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
        /* save EBP */
        x86_push_reg (code, X86_EBP);
-       /* push exc */
-       x86_push_membase (code, X86_EBP, 16);
+
        /* set new EBP */
        x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBP), 4);
        /* restore registers used by global register allocation (EBX & ESI) */
        x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EBX), 4);
        x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_ESI), 4);
        x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, SC_EDI), 4);
-       /* save the ESP - this is used by endfinally */
-       x86_mov_membase_reg (code, X86_EBP, mono_exc_esp_offset, X86_ESP, 4);
+
        /* call the handler */
        x86_call_reg (code, X86_ECX);
-       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
+
        /* restore EBP */
        x86_pop_reg (code, X86_EBP);
+
        /* restore saved regs */
        x86_pop_reg (code, X86_ESI);
        x86_pop_reg (code, X86_EDI);
@@ -600,8 +732,8 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                                *managed = TRUE;
 
                if (trace) {
-                       source_location = mono_debug_source_location_from_address (ji->method, address, NULL);
-                       iloffset = mono_debug_il_offset_from_address (ji->method, address);
+                       source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
+                       iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
 
                        if (iloffset < 0)
                                tmpaddr = g_strdup_printf ("<0x%05x>", address);
@@ -715,12 +847,12 @@ ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info
                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 = filename? mono_string_new (domain, filename): NULL;
                        sf->column = 0;
@@ -756,7 +888,7 @@ mono_jit_walk_stack (MonoStackWalk func, gpointer user_data) {
                if (ji == (gpointer)-1)
                        return;
 
-               il_offset = mono_debug_il_offset_from_address (ji->method, native_offset);
+               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;
@@ -790,7 +922,10 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
                if (!ji || ji == (gpointer)-1 || MONO_CONTEXT_GET_BP (&ctx) >= jit_tls->end_of_stack)
                        return FALSE;
 
-               if (ji->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)
+               /* 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--;
@@ -798,12 +933,12 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
        } while (skip >= 0);
 
        *method = mono_method_get_object (domain, ji->method, NULL);
-       *iloffset = mono_debug_il_offset_from_address (ji->method, *native_offset);
+       *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);
+               filename = mono_debug_source_location_from_address (ji->method, *native_offset, line, domain);
 
                *file = filename? mono_string_new (domain, filename): NULL;
                *column = 0;
@@ -827,7 +962,7 @@ mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
 {
        MonoDomain *domain = mono_domain_get ();
        MonoJitInfo *ji, rji;
-       static int (*call_filter) (MonoContext *, gpointer, gpointer) = NULL;
+       static int (*call_filter) (MonoContext *, gpointer) = NULL;
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
        MonoLMF *lmf = jit_tls->lmf;            
        GList *trace_ips = NULL;
@@ -901,20 +1036,28 @@ mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
                                        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, obj)))) {
+                                                     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)
                                                                g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
                                                        MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
-                                                       *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
                                                        jit_tls->lmf = lmf;
+                                                       g_free (trace);
                                                        return 0;
                                                }
                                                if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
@@ -922,7 +1065,7 @@ mono_arch_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
                                                    (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
                                                        if (mono_jit_trace_calls)
                                                                g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
-                                                       call_filter (ctx, ei->handler_start, NULL);
+                                                       call_filter (ctx, ei->handler_start);
                                                }
                                                
                                        }