aboutsummaryrefslogtreecommitdiff
path: root/gcc/ada/raise-gcc.c
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2018-05-24 13:05:59 +0000
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>2018-05-24 13:05:59 +0000
commit45c6d7849670dc3fd2dc4686c3c31dc6cb7bf49e (patch)
tree18927dc96d96e1b3480de2b1197b98748e575202 /gcc/ada/raise-gcc.c
parentb6784d9087199e43c77a626b3de277bec9f08088 (diff)
downloadgcc-45c6d7849670dc3fd2dc4686c3c31dc6cb7bf49e.zip
gcc-45c6d7849670dc3fd2dc4686c3c31dc6cb7bf49e.tar.gz
gcc-45c6d7849670dc3fd2dc4686c3c31dc6cb7bf49e.tar.bz2
[Ada] Handle version 2 of Windows unwinding information structures
2018-05-24 Eric Botcazou <ebotcazou@adacore.com> gcc/ada/ * raise-gcc.c (__gnat_SEH_error_handler): Remove prototype. (__gnat_personality_seh0): Adjust and beef up comments, and fix formatting throughout. (__gnat_adjust_context): Deal minimally with version 2. * seh_init.c (__gnat_map_SEH): Fix formatting. (_gnat_SEH_error_handler): Adjust comments. (__gnat_install_SEH_handler): Fix formatting. From-SVN: r260659
Diffstat (limited to 'gcc/ada/raise-gcc.c')
-rw-r--r--gcc/ada/raise-gcc.c81
1 files changed, 50 insertions, 31 deletions
diff --git a/gcc/ada/raise-gcc.c b/gcc/ada/raise-gcc.c
index 05d1a40..7558414 100644
--- a/gcc/ada/raise-gcc.c
+++ b/gcc/ada/raise-gcc.c
@@ -1457,9 +1457,6 @@ __gnat_Unwind_ForcedUnwind (_Unwind_Exception *e ATTRIBUTE_UNUSED,
(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);
@@ -1481,22 +1478,30 @@ __gnat_create_machine_occurrence_from_signal_handler (Exception_Id,
/* Modify the IP value saved in the machine frame. This is really a kludge,
that will be removed if we could propagate the Windows exception (and not
the GCC one).
+
What is very wrong is that the Windows unwinder will try to decode the
- instruction at IP, which isn't valid anymore after the adjust. */
+ instruction at IP, which isn't valid anymore after the adjustment. */
static void
__gnat_adjust_context (unsigned char *unw, ULONG64 rsp)
{
unsigned int len;
- /* Version = 1, no flags, no prologue. */
- if (unw[0] != 1 || unw[1] != 0)
+ /* Version 1 or 2. */
+ if (unw[0] != 1 && unw[0] != 2)
+ return;
+ /* No flags, no prologue. */
+ if (unw[1] != 0)
return;
len = unw[2];
- /* No frame pointer. */
+ /* No frame. */
if (unw[3] != 0)
return;
- unw += 4;
+ /* ??? Skip the first 2 undocumented opcodes for version 2. */
+ if (unw[0] == 2)
+ unw += 8;
+ else
+ unw += 4;
while (len > 0)
{
/* Offset in prologue = 0. */
@@ -1541,9 +1546,7 @@ __gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
PCONTEXT ms_orig_context,
PDISPATCHER_CONTEXT ms_disp)
{
- /* Possibly transform run-time errors into Ada exceptions. As a small
- optimization, we call __gnat_SEH_error_handler only on non-user
- exceptions. */
+ /* Possibly transform run-time errors into Ada exceptions. */
if (!(ms_exc->ExceptionCode & STATUS_USER_DEFINED))
{
struct Exception_Data *exception;
@@ -1557,13 +1560,21 @@ __gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
+ ms_disp->FunctionEntry->EndAddress))
{
/* This is a fault in this function. We need to adjust the return
- address before raising the GCC exception. */
+ address before raising the GCC exception. In order to do that,
+ we need to locate the machine frame that has been pushed onto
+ the stack in response to the hardware exception, so we will do
+ a private unwinding from here, i.e. the frame of the personality
+ routine, up to the frame immediately following the frame of this
+ function. This frame corresponds to a dummy prologue which is
+ never actually executed but instead appears before the real entry
+ point of an interrupt routine and exists only to provide a place
+ to simulate the push of a machine frame. */
CONTEXT context;
PRUNTIME_FUNCTION mf_func = NULL;
ULONG64 mf_imagebase;
ULONG64 mf_rsp = 0;
- /* Get the context. */
+ /* Get the current context. */
RtlCaptureContext (&context);
while (1)
@@ -1574,27 +1585,31 @@ __gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
ULONG64 EstablisherFrame;
/* Get function metadata. */
- RuntimeFunction = RtlLookupFunctionEntry
- (context.Rip, &ImageBase, ms_disp->HistoryTable);
+ RuntimeFunction
+ = RtlLookupFunctionEntry (context.Rip, &ImageBase,
+ ms_disp->HistoryTable);
+
+ /* Stop once we reached the frame of this function. */
if (RuntimeFunction == ms_disp->FunctionEntry)
break;
+
mf_func = RuntimeFunction;
mf_imagebase = ImageBase;
mf_rsp = context.Rsp;
- if (!RuntimeFunction)
- {
- /* In case of failure, assume this is a leaf function. */
- context.Rip = *(ULONG64 *) context.Rsp;
- context.Rsp += 8;
- }
- else
+ if (RuntimeFunction)
{
/* Unwind. */
RtlVirtualUnwind (0, ImageBase, context.Rip, RuntimeFunction,
&context, &HandlerData, &EstablisherFrame,
NULL);
}
+ else
+ {
+ /* In case of failure, assume this is a leaf function. */
+ context.Rip = *(ULONG64 *) context.Rsp;
+ context.Rsp += 8;
+ }
/* 0 means bottom of the stack. */
if (context.Rip == 0)
@@ -1603,6 +1618,8 @@ __gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
break;
}
}
+
+ /* If we have found the machine frame, adjust the return address. */
if (mf_func != NULL)
__gnat_adjust_context
((unsigned char *)(mf_imagebase + mf_func->UnwindData), mf_rsp);
@@ -1611,16 +1628,16 @@ __gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
exception = __gnat_map_SEH (ms_exc, &msg);
if (exception != NULL)
{
- struct _Unwind_Exception *exc;
+ /* Directly convert the system exception into a GCC one.
- /* 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);
+ which builds 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. */
+ struct _Unwind_Exception *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;
@@ -1629,9 +1646,11 @@ __gnat_personality_seh0 (PEXCEPTION_RECORD ms_exc, void *this_frame,
}
- return _GCC_specific_handler (ms_exc, this_frame, ms_orig_context,
- ms_disp, __gnat_personality_imp);
+ return
+ _GCC_specific_handler (ms_exc, this_frame, ms_orig_context, ms_disp,
+ __gnat_personality_imp);
}
+
#endif /* SEH */
#if !defined (__USING_SJLJ_EXCEPTIONS__)