diff options
author | Eric Botcazou <ebotcazou@adacore.com> | 2018-05-24 13:05:59 +0000 |
---|---|---|
committer | Pierre-Marie de Rodat <pmderodat@gcc.gnu.org> | 2018-05-24 13:05:59 +0000 |
commit | 45c6d7849670dc3fd2dc4686c3c31dc6cb7bf49e (patch) | |
tree | 18927dc96d96e1b3480de2b1197b98748e575202 /gcc/ada/raise-gcc.c | |
parent | b6784d9087199e43c77a626b3de277bec9f08088 (diff) | |
download | gcc-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.c | 81 |
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__) |