Patchwork [Ada] Improve support of Storage_Error for Windows 64 SEH

login
register
mail settings
Submitter Arnaud Charlet
Date July 16, 2012, 12:52 p.m.
Message ID <20120716125206.GA22621@adacore.com>
Download mbox | patch
Permalink /patch/171182/
State New
Headers show

Comments

Arnaud Charlet - July 16, 2012, 12:52 p.m.
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  <gingold@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).

Patch

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).  */