Work to support Windows 64 SEH: allow to convert an exception code
to an Ada exception ID and message; Optimize the propagation of Storage_Error
on Windows 64 SEH to avoid requiring a too large stack area.

2012-07-16  Tristan Gingold  <ging...@adacore.com>

        * seh_init.c (__gnat_map_SEH): New function extracted from
        __gnat_SEH_error_handler.
        * raise-gcc.c: __gnat_personality_seh0: Directly transforms
        Windows system exception into GCC one when possible, in order
        to save stack room (particularly useful when Storage_Error will
        be propagated).

Index: raise-gcc.c
===================================================================
--- raise-gcc.c (revision 189524)
+++ raise-gcc.c (working copy)
@@ -1213,9 +1213,23 @@
 #ifdef __SEH__
 
 #define STATUS_USER_DEFINED            (1U << 29)
+
+/* From unwind-seh.c.  */
+#define GCC_MAGIC                      (('G' << 16) | ('C' << 8) | 'C')
+#define GCC_EXCEPTION(TYPE)            \
+       (STATUS_USER_DEFINED | ((TYPE) << 24) | GCC_MAGIC)
+#define STATUS_GCC_THROW               GCC_EXCEPTION (0)
+
 EXCEPTION_DISPOSITION __gnat_SEH_error_handler
  (struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);
 
+struct Exception_Data *
+__gnat_map_SEH (EXCEPTION_RECORD* ExceptionRecord, const char **msg);
+
+struct _Unwind_Exception *
+__gnat_create_machine_occurrence_from_signal_handler (Exception_Id,
+                                                     const char *);
+
 /* Unwind opcodes.  */
 #define UWOP_PUSH_NONVOL 0
 #define UWOP_ALLOC_LARGE 1
@@ -1295,7 +1309,10 @@
      exceptions.  */
   if (!(ms_exc->ExceptionCode & STATUS_USER_DEFINED))
     {
+      struct Exception_Data *exception;
+      const char *msg;
       ULONG64 excpip = (ULONG64) ms_exc->ExceptionAddress;
+
       if (excpip != 0
          && excpip >= (ms_disp->ImageBase
                        + ms_disp->FunctionEntry->BeginAddress)
@@ -1353,7 +1370,26 @@
            __gnat_adjust_context
              ((unsigned char *)(mf_imagebase + mf_func->UnwindData), mf_rsp);
        }
-      __gnat_SEH_error_handler (ms_exc, this_frame, ms_orig_context, ms_disp);
+
+      exception = __gnat_map_SEH (ms_exc, &msg);
+      if (exception != NULL)
+       {
+         struct _Unwind_Exception *exc;
+
+         /* Directly convert the system exception to a GCC one.
+            This is really breaking the API, but is necessary for stack size
+            reasons: the normal way is to call Raise_From_Signal_Handler,
+            which build the exception and calls _Unwind_RaiseException, which
+            unwinds the stack and will call this personality routine. But
+            the Windows unwinder needs about 2KB of stack.  */
+         exc = __gnat_create_machine_occurrence_from_signal_handler
+           (exception, msg);
+         memset (exc->private_, 0, sizeof (exc->private_));
+         ms_exc->ExceptionCode = STATUS_GCC_THROW;
+         ms_exc->NumberParameters = 1;
+         ms_exc->ExceptionInformation[0] = (ULONG_PTR)exc;
+       }
+
     }
 
   return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
Index: seh_init.c
===================================================================
--- seh_init.c  (revision 189524)
+++ seh_init.c  (working copy)
@@ -68,20 +68,21 @@
 #include <windows.h>
 #include <excpt.h>
 
+/* Prototypes.  */
 extern void _global_unwind2 (void *);
 
 EXCEPTION_DISPOSITION __gnat_SEH_error_handler
 (struct _EXCEPTION_RECORD*, void*, struct _CONTEXT*, void*);
 
-EXCEPTION_DISPOSITION
-__gnat_SEH_error_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
-                         void *EstablisherFrame,
-                         struct _CONTEXT* ContextRecord ATTRIBUTE_UNUSED,
-                         void *DispatcherContext ATTRIBUTE_UNUSED)
+struct Exception_Data *
+__gnat_map_SEH (EXCEPTION_RECORD* ExceptionRecord, const char **msg);
+
+/* Convert an SEH exception to an Ada one.  Return the exception ID
+   and set MSG with the corresponding message.  */
+
+struct Exception_Data *
+__gnat_map_SEH (EXCEPTION_RECORD* ExceptionRecord, const char **msg)
 {
-  struct Exception_Data *exception;
-  const char *msg;
-
   switch (ExceptionRecord->ExceptionCode)
     {
     case EXCEPTION_ACCESS_VIOLATION:
@@ -92,93 +93,95 @@
          || IsBadCodePtr
          ((void *)(ExceptionRecord->ExceptionInformation[1] + 4096)))
        {
-         exception = &program_error;
-         msg = "EXCEPTION_ACCESS_VIOLATION";
+         *msg = "EXCEPTION_ACCESS_VIOLATION";
+         return &program_error;
        }
       else
        {
          /* otherwise it is a stack overflow  */
-         exception = &storage_error;
-         msg = "stack overflow or erroneous memory access";
+         *msg = "stack overflow or erroneous memory access";
+         return &storage_error;
        }
-      break;
 
     case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
-      exception = &constraint_error;
-      msg = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
-      break;
+      *msg = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
+      return &constraint_error;
 
     case EXCEPTION_DATATYPE_MISALIGNMENT:
-      exception = &constraint_error;
-      msg = "EXCEPTION_DATATYPE_MISALIGNMENT";
-      break;
+      *msg = "EXCEPTION_DATATYPE_MISALIGNMENT";
+      return &constraint_error;
 
     case EXCEPTION_FLT_DENORMAL_OPERAND:
-      exception = &constraint_error;
-      msg = "EXCEPTION_FLT_DENORMAL_OPERAND";
-      break;
+      *msg = "EXCEPTION_FLT_DENORMAL_OPERAND";
+      return &constraint_error;
 
     case EXCEPTION_FLT_DIVIDE_BY_ZERO:
-      exception = &constraint_error;
-      msg = "EXCEPTION_FLT_DENORMAL_OPERAND";
-      break;
+      *msg = "EXCEPTION_FLT_DENORMAL_OPERAND";
+      return &constraint_error;
 
     case EXCEPTION_FLT_INVALID_OPERATION:
-      exception = &constraint_error;
-      msg = "EXCEPTION_FLT_INVALID_OPERATION";
-      break;
+      *msg = "EXCEPTION_FLT_INVALID_OPERATION";
+      return &constraint_error;
 
     case EXCEPTION_FLT_OVERFLOW:
-      exception = &constraint_error;
-      msg = "EXCEPTION_FLT_OVERFLOW";
-      break;
+      *msg = "EXCEPTION_FLT_OVERFLOW";
+      return &constraint_error;
 
     case EXCEPTION_FLT_STACK_CHECK:
-      exception = &program_error;
-      msg = "EXCEPTION_FLT_STACK_CHECK";
-      break;
+      *msg = "EXCEPTION_FLT_STACK_CHECK";
+      return &program_error;
 
     case EXCEPTION_FLT_UNDERFLOW:
-      exception = &constraint_error;
-      msg = "EXCEPTION_FLT_UNDERFLOW";
-      break;
+      *msg = "EXCEPTION_FLT_UNDERFLOW";
+      return &constraint_error;
 
     case EXCEPTION_INT_DIVIDE_BY_ZERO:
-      exception = &constraint_error;
-      msg = "EXCEPTION_INT_DIVIDE_BY_ZERO";
-      break;
+      *msg = "EXCEPTION_INT_DIVIDE_BY_ZERO";
+      return &constraint_error;
 
     case EXCEPTION_INT_OVERFLOW:
-      exception = &constraint_error;
-      msg = "EXCEPTION_INT_OVERFLOW";
-      break;
+      *msg = "EXCEPTION_INT_OVERFLOW";
+      return &constraint_error;
 
     case EXCEPTION_INVALID_DISPOSITION:
-      exception = &program_error;
-      msg = "EXCEPTION_INVALID_DISPOSITION";
-      break;
+      *msg = "EXCEPTION_INVALID_DISPOSITION";
+      return &program_error;
 
     case EXCEPTION_NONCONTINUABLE_EXCEPTION:
-      exception = &program_error;
-      msg = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
-      break;
+      *msg = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
+      return &program_error;
 
     case EXCEPTION_PRIV_INSTRUCTION:
-      exception = &program_error;
-      msg = "EXCEPTION_PRIV_INSTRUCTION";
-      break;
+      *msg = "EXCEPTION_PRIV_INSTRUCTION";
+      return &program_error;
 
     case EXCEPTION_SINGLE_STEP:
-      exception = &program_error;
-      msg = "EXCEPTION_SINGLE_STEP";
-      break;
+      *msg = "EXCEPTION_SINGLE_STEP";
+      return &program_error;
 
     case EXCEPTION_STACK_OVERFLOW:
-      exception = &storage_error;
-      msg = "EXCEPTION_STACK_OVERFLOW";
-      break;
+      *msg = "EXCEPTION_STACK_OVERFLOW";
+      return &storage_error;
 
     default:
+      *msg = NULL;
+      return NULL;
+    }
+}
+
+EXCEPTION_DISPOSITION
+__gnat_SEH_error_handler (struct _EXCEPTION_RECORD* ExceptionRecord,
+                         void *EstablisherFrame,
+                         struct _CONTEXT* ContextRecord ATTRIBUTE_UNUSED,
+                         void *DispatcherContext ATTRIBUTE_UNUSED)
+{
+  struct Exception_Data *exception;
+  const char *msg;
+
+  exception = __gnat_map_SEH (ExceptionRecord, &msg);
+
+  if (exception == NULL)
+    {
 #if defined (_WIN64) && defined (__SEH__)
       /* On Windows x64, do not transform other exception as they could
         be caught by user (when SEH is used to propagate exceptions).  */

Reply via email to