Add exception handler basic routines.
SEH support experimental.



git-svn-id: svn+ssh://svn.code.sf.net/p/mingw-w64/code/trunk@158 4407c894-4637-0410-b4f5-ada5f102cad1
diff --git a/mingw-w64-crt/ChangeLog b/mingw-w64-crt/ChangeLog
index 6947eb6..03ec856 100755
--- a/mingw-w64-crt/ChangeLog
+++ b/mingw-w64-crt/ChangeLog
@@ -1,3 +1,8 @@
+2007-10-22  Kai Tietz  <kai.tietz@onevision.com>
+
+	* crtexe.c: Add exception handler basic routines.
+	SEH support experimental.
+
 2007-10-19  Kai Tietz  <kai.tietz@onevision.com>
 
 	* fseeko64.c: (_flush): New method.
diff --git a/mingw-w64-crt/crtexe.c b/mingw-w64-crt/crtexe.c
index 187932b..451090a 100755
--- a/mingw-w64-crt/crtexe.c
+++ b/mingw-w64-crt/crtexe.c
@@ -6,6 +6,7 @@
 #include <oscalls.h>
 #include <internal.h>
 #include <process.h>
+#include <signal.h>
 #include <math.h>
 #include <stdlib.h>
 #include <tchar.h>
@@ -70,6 +71,9 @@
 static int has_cctor = 0;
 static _startupinfo startinfo;
 
+static CALLBACK long _gnu_exception_handler (EXCEPTION_POINTERS * exception_data);
+static LONG __mingw_vex(EXCEPTION_POINTERS * exception_data);
+
 static int __cdecl pre_c_init (void);
 static void __cdecl pre_cpp_init (void);
 
@@ -190,6 +194,12 @@
       __dyn_tls_init_callback (NULL, DLL_THREAD_ATTACH, NULL);
     
     _CrtSetCheckCount (FALSE);
+    
+    __asm__ __volatile__ (
+	"xorq %rax,%rax\n\t"
+	"movq %rax,%gs:0" "\n");
+    AddVectoredExceptionHandler (0, (PVECTORED_EXCEPTION_HANDLER)__mingw_vex);
+    SetUnhandledExceptionFilter (_gnu_exception_handler);
 
     if (mingw_app_type)
       {
@@ -289,3 +299,96 @@
 }
 
 int __defaultmatherr;
+
+static CALLBACK long
+_gnu_exception_handler (EXCEPTION_POINTERS * exception_data)
+{
+  void (*old_handler) (int);
+  long action = EXCEPTION_CONTINUE_SEARCH;
+  int reset_fpu = 0;
+
+  switch (exception_data->ExceptionRecord->ExceptionCode)
+    {
+    case EXCEPTION_ACCESS_VIOLATION:
+      /* test if the user has set SIGSEGV */
+      old_handler = signal (SIGSEGV, SIG_DFL);
+      if (old_handler == SIG_IGN)
+	{
+	  /* this is undefined if the signal was raised by anything other
+	     than raise ().  */
+	  signal (SIGSEGV, SIG_IGN);
+	  action = EXCEPTION_CONTINUE_EXECUTION;
+	}
+      else if (old_handler != SIG_DFL)
+	{
+	  /* This means 'old' is a user defined function. Call it */
+	  (*old_handler) (SIGSEGV);
+	  action = EXCEPTION_CONTINUE_EXECUTION;
+	}
+      break;
+
+    case EXCEPTION_ILLEGAL_INSTRUCTION:
+    case EXCEPTION_PRIV_INSTRUCTION:
+      /* test if the user has set SIGILL */
+      old_handler = signal (SIGILL, SIG_DFL);
+      if (old_handler == SIG_IGN)
+	{
+	  /* this is undefined if the signal was raised by anything other
+	     than raise ().  */
+	  signal (SIGILL, SIG_IGN);
+	  action = EXCEPTION_CONTINUE_EXECUTION;
+	}
+      else if (old_handler != SIG_DFL)
+	{
+	  /* This means 'old' is a user defined function. Call it */
+	  (*old_handler) (SIGILL);
+	  action = EXCEPTION_CONTINUE_EXECUTION;
+	}
+      break;
+
+    case EXCEPTION_FLT_INVALID_OPERATION:
+    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+    case EXCEPTION_FLT_DENORMAL_OPERAND:
+    case EXCEPTION_FLT_OVERFLOW:
+    case EXCEPTION_FLT_UNDERFLOW:
+    case EXCEPTION_FLT_INEXACT_RESULT:
+      reset_fpu = 1;
+      /* fall through. */
+
+    case EXCEPTION_INT_DIVIDE_BY_ZERO:
+      /* test if the user has set SIGFPE */
+      old_handler = signal (SIGFPE, SIG_DFL);
+      if (old_handler == SIG_IGN)
+	{
+	  signal (SIGFPE, SIG_IGN);
+	  if (reset_fpu)
+	    _fpreset ();
+	  action = EXCEPTION_CONTINUE_EXECUTION;
+	}
+      else if (old_handler != SIG_DFL)
+	{
+	  /* This means 'old' is a user defined function. Call it */
+	  (*old_handler) (SIGFPE);
+	  action = EXCEPTION_CONTINUE_EXECUTION;
+	}
+      break;
+
+    default:
+      break;
+    }
+  return action;
+}
+
+static LONG __mingw_vex(EXCEPTION_POINTERS * exception_data)
+{
+  /* TODO this is not chainablem, therefore need rewrite. */
+  __asm__ __volatile__ (
+      "movq %gs:0,%rax" "\n\t"
+      "orq %rax,%rax\n\t"
+      "jz l1\n\t"
+      "jmp *8(%rax)\n\r"
+      "l1:\n\t"
+      "nop\n");
+
+  return _gnu_exception_handler(exception_data);
+}