[Ada] Improve support of Storage_Error for Windows 64 SEH
Arnaud Charlet
charlet@adacore.com
Mon Jul 16 12:52:00 GMT 2012
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).
-------------- next part --------------
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). */
More information about the Gcc-patches
mailing list