Home | History | Annotate | Line # | Download | only in libgcc
      1   1.1  mrg /* Structured Exception Handling (SEH) runtime interface routines.
      2  1.10  mrg    Copyright (C) 2010-2022 Free Software Foundation, Inc.
      3   1.1  mrg 
      4   1.1  mrg    This file is part of GCC.
      5   1.1  mrg 
      6   1.1  mrg    GCC is free software; you can redistribute it and/or modify it
      7   1.1  mrg    under the terms of the GNU General Public License as published by
      8   1.1  mrg    the Free Software Foundation; either version 3, or (at your option)
      9   1.1  mrg    any later version.
     10   1.1  mrg 
     11   1.1  mrg    GCC is distributed in the hope that it will be useful, but WITHOUT
     12   1.1  mrg    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     13   1.1  mrg    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     14   1.1  mrg    License for more details.
     15   1.1  mrg 
     16   1.1  mrg    Under Section 7 of GPL version 3, you are granted additional
     17   1.1  mrg    permissions described in the GCC Runtime Library Exception, version
     18   1.1  mrg    3.1, as published by the Free Software Foundation.
     19   1.1  mrg 
     20   1.1  mrg    You should have received a copy of the GNU General Public License and
     21   1.1  mrg    a copy of the GCC Runtime Library Exception along with this program;
     22   1.1  mrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23   1.1  mrg    <http://www.gnu.org/licenses/>.  */
     24   1.1  mrg 
     25   1.1  mrg #include "tconfig.h"
     26   1.1  mrg #include "tsystem.h"
     27   1.1  mrg #include "coretypes.h"
     28   1.1  mrg #include "tm.h"
     29   1.1  mrg #include "unwind.h"
     30   1.1  mrg 
     31   1.1  mrg #if defined (__SEH__) && !defined (__USING_SJLJ_EXCEPTIONS__)
     32   1.1  mrg 
     33   1.1  mrg /* At the moment everything is written for x64, but in theory this could
     34   1.1  mrg    also be used for i386, arm, mips and other extant embedded Windows.  */
     35   1.1  mrg #ifndef __x86_64__
     36   1.1  mrg #error "Unsupported architecture."
     37   1.1  mrg #endif
     38   1.1  mrg 
     39   1.1  mrg /* Define GCC's exception codes.  See
     41   1.1  mrg      http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx
     42   1.1  mrg    In particular, MS defines bits:
     43   1.1  mrg      [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
     44   1.1  mrg      [29]    = 1 (user-defined)
     45   1.1  mrg      [28]    = 0 (reserved)
     46   1.1  mrg    We define bits:
     47   1.1  mrg      [24:27] = type
     48   1.1  mrg      [0:23]  = magic
     49   1.1  mrg    We set "magic" to "GCC", which is similar to MVC++ which uses "msc"
     50   1.1  mrg    as the low 3 bytes of its user-defined codes for C++ exceptions.
     51   1.1  mrg 
     52   1.1  mrg    We define the ExceptionInformation entries as follows:
     53   1.1  mrg      [0] = _Unwind_Exception pointer
     54   1.1  mrg      [1] = target frame
     55   1.1  mrg      [2] = target ip
     56   1.1  mrg      [3] = target rdx
     57   1.1  mrg */
     58   1.1  mrg 
     59   1.1  mrg #define STATUS_USER_DEFINED		(1U << 29)
     60   1.1  mrg 
     61   1.1  mrg #define GCC_MAGIC			(('G' << 16) | ('C' << 8) | 'C')
     62   1.1  mrg #define GCC_EXCEPTION(TYPE)		\
     63   1.1  mrg        (STATUS_USER_DEFINED | ((TYPE) << 24) | GCC_MAGIC)
     64   1.1  mrg 
     65   1.1  mrg #define STATUS_GCC_THROW		GCC_EXCEPTION (0)
     66   1.1  mrg #define STATUS_GCC_UNWIND		GCC_EXCEPTION (1)
     67   1.1  mrg #define STATUS_GCC_FORCED		GCC_EXCEPTION (2)
     68   1.1  mrg 
     69   1.1  mrg 
     70   1.1  mrg struct _Unwind_Context
     72   1.1  mrg {
     73   1.1  mrg   _Unwind_Word cfa;
     74   1.1  mrg   _Unwind_Word ra;
     75   1.1  mrg   _Unwind_Word reg[2];
     76   1.1  mrg   PDISPATCHER_CONTEXT disp;
     77   1.1  mrg };
     78   1.1  mrg 
     79   1.1  mrg /* Get the value of register INDEX as saved in CONTEXT.  */
     80   1.1  mrg 
     81   1.1  mrg _Unwind_Word
     82   1.3  mrg _Unwind_GetGR (struct _Unwind_Context *c, int index)
     83   1.1  mrg {
     84   1.1  mrg   if (index < 0 || index >= 2)
     85   1.1  mrg     abort ();
     86   1.1  mrg   return c->reg[index];
     87   1.1  mrg }
     88   1.1  mrg 
     89   1.1  mrg /* Overwrite the saved value for register INDEX in CONTEXT with VAL.  */
     90   1.1  mrg 
     91   1.1  mrg void
     92   1.3  mrg _Unwind_SetGR (struct _Unwind_Context *c, int index, _Unwind_Word val)
     93   1.1  mrg {
     94   1.1  mrg   if (index < 0 || index >= 2)
     95   1.1  mrg     abort ();
     96   1.1  mrg   c->reg[index] = val;
     97   1.1  mrg }
     98   1.1  mrg 
     99   1.1  mrg /* Get the value of the CFA as saved in CONTEXT.  */
    100   1.1  mrg 
    101   1.1  mrg _Unwind_Word
    102   1.1  mrg _Unwind_GetCFA (struct _Unwind_Context *c)
    103   1.1  mrg {
    104   1.1  mrg   return c->cfa;
    105   1.1  mrg }
    106   1.1  mrg 
    107   1.1  mrg /* Retrieve the return address for CONTEXT.  */
    108   1.1  mrg 
    109   1.1  mrg _Unwind_Ptr
    110   1.1  mrg _Unwind_GetIP (struct _Unwind_Context *c)
    111   1.1  mrg {
    112   1.1  mrg   return c->ra;
    113   1.1  mrg }
    114   1.1  mrg 
    115   1.1  mrg /* Retrieve the return address and flag whether that IP is before
    116   1.1  mrg    or after first not yet fully executed instruction.  */
    117   1.1  mrg 
    118   1.1  mrg _Unwind_Ptr
    119   1.1  mrg _Unwind_GetIPInfo (struct _Unwind_Context *c, int *ip_before_insn)
    120   1.1  mrg {
    121   1.1  mrg   /* ??? Is there a concept of a signal context properly?  There's
    122   1.1  mrg      obviously an UNWP_PUSH_MACHFRAME opcode, but the runtime might
    123   1.1  mrg      have arranged for that not to matter, really.  */
    124   1.1  mrg   *ip_before_insn = 0;
    125   1.1  mrg   return c->ra;
    126   1.1  mrg }
    127   1.1  mrg 
    128   1.1  mrg /* Overwrite the return address for CONTEXT with VAL.  */
    129   1.1  mrg 
    130   1.1  mrg void
    131   1.1  mrg _Unwind_SetIP (struct _Unwind_Context *c, _Unwind_Ptr val)
    132   1.1  mrg {
    133   1.1  mrg   c->ra = val;
    134   1.1  mrg }
    135   1.4  mrg 
    136   1.1  mrg _Unwind_Ptr
    137   1.1  mrg _Unwind_GetLanguageSpecificData (struct _Unwind_Context *c)
    138   1.1  mrg {
    139   1.1  mrg   return c->disp->HandlerData;
    140   1.1  mrg }
    141   1.1  mrg 
    142   1.1  mrg _Unwind_Ptr
    143   1.1  mrg _Unwind_GetRegionStart (struct _Unwind_Context *c)
    144   1.1  mrg {
    145   1.1  mrg   return c->disp->FunctionEntry->BeginAddress + c->disp->ImageBase;
    146   1.1  mrg }
    147   1.1  mrg 
    148   1.1  mrg void *
    149   1.1  mrg _Unwind_FindEnclosingFunction (void *pc)
    150   1.1  mrg {
    151   1.1  mrg   PRUNTIME_FUNCTION entry;
    152   1.1  mrg   ULONG64 ImageBase;
    153   1.1  mrg 
    154   1.1  mrg   entry = RtlLookupFunctionEntry ((ULONG64)pc, &ImageBase, NULL);
    155   1.1  mrg 
    156   1.1  mrg   return (entry ? (void *)(entry->BeginAddress + ImageBase) : NULL);
    157   1.1  mrg }
    158   1.1  mrg 
    159   1.1  mrg _Unwind_Ptr
    160   1.1  mrg _Unwind_GetDataRelBase (struct _Unwind_Context *c ATTRIBUTE_UNUSED)
    161   1.1  mrg {
    162   1.1  mrg   return 0;
    163   1.1  mrg }
    164   1.1  mrg 
    165   1.1  mrg _Unwind_Ptr
    166   1.1  mrg _Unwind_GetTextRelBase (struct _Unwind_Context *c)
    167   1.1  mrg {
    168   1.1  mrg   return c->disp->ImageBase;
    169   1.1  mrg }
    170   1.1  mrg 
    171   1.1  mrg 
    172   1.1  mrg /* The two-phase unwind process that GCC uses is ordered differently
    174   1.1  mrg    from the two-phase unwind process that SEH uses.  The mechansism
    175   1.1  mrg    that GCC uses is to have the filter return _URC_HANDER_FOUND; the
    176   1.1  mrg    mechanism that SEH uses is for the filter function call back into
    177   1.1  mrg    the unwinder.
    178   1.1  mrg 
    179   1.1  mrg    An Ideal port to SEH would have GCC emit handler functions that
    180   1.1  mrg    can be called, given a pointer to the "EstablisherFrame" (i.e.
    181   1.1  mrg    the frame pointer base of the user-level function) can manipulate
    182   1.1  mrg    the user-level variables within the user-level function's stack
    183   1.1  mrg    frame.  Once done manipulating the variables, it would return
    184   1.1  mrg    a ExceptionContinueSearch, and the unwind process would continue.
    185   1.1  mrg 
    186   1.1  mrg    GCC has always done things a bit differently.  We continue to
    187   1.1  mrg    transfer control back into the user-level function which, once
    188   1.1  mrg    done manipulating the user-level variables, re-throws the exception.  */
    189   1.1  mrg 
    190   1.1  mrg /* The "real" language-specific personality handler forwards to here
    191   1.1  mrg    where we handle the MS SEH state and transforms it into the GCC
    192   1.1  mrg    unwind state as per GCC's <unwind.h>, at which point we defer to
    193   1.1  mrg    the regular language-specfic exception handler, which is passed in.  */
    194   1.1  mrg 
    195   1.1  mrg EXCEPTION_DISPOSITION
    196   1.1  mrg _GCC_specific_handler (PEXCEPTION_RECORD ms_exc, void *this_frame,
    197   1.1  mrg 		       PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp,
    198   1.1  mrg 		       _Unwind_Personality_Fn gcc_per)
    199   1.1  mrg {
    200   1.1  mrg   DWORD ms_flags = ms_exc->ExceptionFlags;
    201   1.1  mrg   DWORD ms_code = ms_exc->ExceptionCode;
    202   1.1  mrg 
    203   1.1  mrg   struct _Unwind_Exception *gcc_exc
    204   1.1  mrg     = (struct _Unwind_Exception *) ms_exc->ExceptionInformation[0];
    205   1.1  mrg   struct _Unwind_Context gcc_context;
    206   1.1  mrg   _Unwind_Action gcc_action;
    207   1.1  mrg   _Unwind_Reason_Code gcc_reason;
    208   1.1  mrg 
    209   1.1  mrg   if (ms_flags & EXCEPTION_TARGET_UNWIND)
    210   1.1  mrg     {
    211   1.1  mrg       /* This frame is known to be the target frame.  We've already
    212   1.1  mrg          "installed" the target_ip and RAX value via the arguments
    213   1.1  mrg          to RtlUnwindEx.  All that's left is to set the RDX value
    214   1.1  mrg          and "continue" to have the context installed.  */
    215   1.1  mrg       ms_disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3];
    216   1.1  mrg       return ExceptionContinueSearch;
    217   1.1  mrg     }
    218   1.1  mrg 
    219   1.1  mrg   if (ms_code == STATUS_GCC_UNWIND)
    220   1.1  mrg     {
    221   1.1  mrg       /* This is a colliding exception that we threw so that we could
    222   1.1  mrg          cancel the already in-flight exception and stop in a frame
    223   1.1  mrg 	 that wanted to perform some unwind action.  The only relevant
    224   1.6  mrg 	 test is that we're the target frame.  */
    225   1.1  mrg       if (ms_exc->ExceptionInformation[1] == (_Unwind_Ptr) this_frame)
    226   1.1  mrg 	{
    227   1.1  mrg 	  RtlUnwindEx (this_frame, (PVOID) ms_exc->ExceptionInformation[2],
    228   1.1  mrg 		       ms_exc, gcc_exc, ms_orig_context,
    229   1.1  mrg 		       ms_disp->HistoryTable);
    230   1.1  mrg 	  abort ();
    231   1.1  mrg 	}
    232   1.1  mrg       return ExceptionContinueSearch;
    233   1.1  mrg     }
    234   1.1  mrg 
    235   1.1  mrg   gcc_context.cfa = ms_disp->ContextRecord->Rsp;
    236   1.1  mrg   gcc_context.ra = ms_disp->ControlPc;
    237   1.1  mrg   gcc_context.reg[0] = 0xdeadbeef;	/* These are write-only.  */
    238   1.1  mrg   gcc_context.reg[1] = 0xdeadbeef;
    239   1.1  mrg   gcc_context.disp = ms_disp;
    240   1.1  mrg 
    241   1.1  mrg   if (ms_code == STATUS_GCC_FORCED)
    242   1.1  mrg     {
    243   1.1  mrg        _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) gcc_exc->private_[0];
    244   1.1  mrg        void *stop_argument = (void *) gcc_exc->private_[4];
    245   1.1  mrg 
    246   1.1  mrg        gcc_action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE;
    247   1.1  mrg 
    248   1.1  mrg        stop (1, gcc_action, gcc_exc->exception_class, gcc_exc,
    249   1.1  mrg              &gcc_context, stop_argument);
    250   1.1  mrg 
    251   1.1  mrg        goto phase2;
    252   1.1  mrg     }
    253   1.1  mrg 
    254   1.1  mrg   /* ??? TODO: handling non-gcc user-defined exceptions as foreign.  */
    255   1.1  mrg   if (ms_code != STATUS_GCC_THROW)
    256   1.1  mrg     return ExceptionContinueSearch;
    257   1.1  mrg 
    258   1.1  mrg   if (ms_flags & (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND))
    259   1.1  mrg     {
    260   1.1  mrg       /* This is Phase 2.  */
    261   1.1  mrg       /* We know this isn't the target frame because we've already tested
    262   1.1  mrg 	 EXCEPTION_TARGET_UNWIND.  The remaining possibility is that the
    263   1.1  mrg 	 gcc personality has unwind code to run.  */
    264   1.1  mrg 
    265   1.1  mrg       gcc_action = _UA_CLEANUP_PHASE;
    266   1.1  mrg     phase2:
    267   1.1  mrg       gcc_reason = gcc_per (1, gcc_action, gcc_exc->exception_class,
    268   1.1  mrg 			    gcc_exc, &gcc_context);
    269   1.1  mrg 
    270   1.1  mrg       if (gcc_reason == _URC_CONTINUE_UNWIND)
    271   1.1  mrg 	return ExceptionContinueSearch;
    272   1.1  mrg 
    273   1.1  mrg       if (gcc_reason == _URC_INSTALL_CONTEXT)
    274   1.1  mrg 	{
    275   1.1  mrg 	  /* Scratch space for the bits for the unwind catch.  */
    276   1.1  mrg 	  ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame;
    277   1.1  mrg 	  ms_exc->ExceptionInformation[2] = gcc_context.ra;
    278   1.1  mrg 	  ms_exc->ExceptionInformation[3] = gcc_context.reg[1];
    279   1.1  mrg 
    280   1.1  mrg 	  /* Cancel the current exception by raising another.  */
    281   1.1  mrg 	  RaiseException (STATUS_GCC_UNWIND, EXCEPTION_NONCONTINUABLE,
    282   1.1  mrg 			  4, ms_exc->ExceptionInformation);
    283   1.1  mrg 
    284   1.1  mrg 	  /* Is RaiseException declared noreturn?  */
    285   1.1  mrg 	}
    286   1.1  mrg 
    287   1.1  mrg       /* In _Unwind_RaiseException_Phase2 we return _URC_FATAL_PHASE2_ERROR. */
    288   1.1  mrg     }
    289   1.1  mrg   else
    290   1.1  mrg     {
    291   1.1  mrg       /* This is Phase 1.  */
    292   1.1  mrg       gcc_reason = gcc_per (1, _UA_SEARCH_PHASE, gcc_exc->exception_class,
    293   1.1  mrg 			    gcc_exc, &gcc_context);
    294   1.1  mrg 
    295   1.1  mrg       if (gcc_reason == _URC_CONTINUE_UNWIND)
    296   1.1  mrg 	return ExceptionContinueSearch;
    297   1.1  mrg 
    298   1.1  mrg       if (gcc_reason == _URC_HANDLER_FOUND)
    299   1.1  mrg 	{
    300   1.1  mrg 	  /* We really need some of the information that GCC's personality
    301   1.1  mrg 	     routines compute during phase 2 right now, like the target IP.
    302   1.1  mrg 	     Go ahead and ask for it now, and cache it.  */
    303   1.1  mrg 	  gcc_reason = gcc_per (1, _UA_CLEANUP_PHASE | _UA_HANDLER_FRAME,
    304   1.1  mrg 				gcc_exc->exception_class, gcc_exc,
    305   1.1  mrg 				&gcc_context);
    306   1.1  mrg 	  if (gcc_reason != _URC_INSTALL_CONTEXT)
    307   1.1  mrg 	    abort ();
    308   1.1  mrg 
    309   1.1  mrg 	  gcc_exc->private_[1] = (_Unwind_Ptr) this_frame;
    310   1.1  mrg 	  gcc_exc->private_[2] = gcc_context.ra;
    311   1.1  mrg 	  gcc_exc->private_[3] = gcc_context.reg[1];
    312   1.1  mrg 
    313   1.1  mrg 	  ms_exc->NumberParameters = 4;
    314   1.1  mrg 	  ms_exc->ExceptionInformation[1] = (_Unwind_Ptr) this_frame;
    315   1.1  mrg 	  ms_exc->ExceptionInformation[2] = gcc_context.ra;
    316   1.6  mrg 	  ms_exc->ExceptionInformation[3] = gcc_context.reg[1];
    317   1.1  mrg 
    318   1.1  mrg 	  /* Begin phase 2.  Perform the unwinding.  */
    319   1.1  mrg 	  RtlUnwindEx (this_frame, (PVOID)gcc_context.ra, ms_exc,
    320   1.1  mrg 		       (PVOID)gcc_context.reg[0], ms_orig_context,
    321   1.1  mrg 		       ms_disp->HistoryTable);
    322   1.1  mrg 	}
    323   1.1  mrg 
    324   1.1  mrg       /* In _Unwind_RaiseException we return _URC_FATAL_PHASE1_ERROR.  */
    325   1.1  mrg     }
    326   1.1  mrg   abort ();
    327   1.1  mrg }
    328   1.1  mrg 
    329   1.1  mrg /* Raise an exception, passing along the given exception object.  */
    330   1.1  mrg 
    331   1.1  mrg _Unwind_Reason_Code
    332   1.1  mrg _Unwind_RaiseException (struct _Unwind_Exception *exc)
    333   1.1  mrg {
    334   1.1  mrg   memset (exc->private_, 0, sizeof (exc->private_));
    335   1.1  mrg 
    336   1.1  mrg   /* The ExceptionInformation array will have only 1 element, EXC.  */
    337   1.1  mrg   RaiseException (STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exc);
    338   1.1  mrg 
    339   1.1  mrg   /* The exception handler installed in crt0 will continue any GCC
    340   1.1  mrg      exception that reaches there (and isn't marked non-continuable).
    341   1.1  mrg      Returning allows the C++ runtime to call std::terminate.  */
    342   1.1  mrg   return _URC_END_OF_STACK;
    343   1.1  mrg }
    344   1.1  mrg 
    345   1.1  mrg /* Resume propagation of an existing exception.  This is used after
    346   1.1  mrg    e.g. executing cleanup code, and not to implement rethrowing.  */
    347   1.1  mrg 
    348   1.1  mrg void
    349   1.1  mrg _Unwind_Resume (struct _Unwind_Exception *gcc_exc)
    350   1.1  mrg {
    351   1.1  mrg   UNWIND_HISTORY_TABLE ms_history;
    352   1.1  mrg   EXCEPTION_RECORD ms_exc;
    353   1.1  mrg   CONTEXT ms_context;
    354   1.1  mrg 
    355   1.1  mrg   memset (&ms_exc, 0, sizeof(ms_exc));
    356   1.1  mrg   memset (&ms_history, 0, sizeof(ms_history));
    357   1.1  mrg 
    358   1.1  mrg   /* ??? Not 100% perfect, since we aren't passing on the *original*
    359   1.1  mrg      exception context, but should be good enough.  */
    360   1.1  mrg   ms_exc.ExceptionCode = STATUS_GCC_THROW;
    361   1.1  mrg   ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
    362   1.1  mrg   ms_exc.NumberParameters = 4;
    363   1.1  mrg   ms_exc.ExceptionInformation[0] = (ULONG_PTR) gcc_exc;
    364   1.1  mrg   ms_exc.ExceptionInformation[1] = gcc_exc->private_[1];
    365   1.1  mrg   ms_exc.ExceptionInformation[2] = gcc_exc->private_[2];
    366   1.1  mrg   ms_exc.ExceptionInformation[3] = gcc_exc->private_[3];
    367   1.1  mrg 
    368   1.6  mrg   ms_context.ContextFlags = CONTEXT_ALL;
    369   1.1  mrg   RtlCaptureContext (&ms_context);
    370   1.1  mrg 
    371   1.1  mrg   RtlUnwindEx ((void *) gcc_exc->private_[1], (PVOID)gcc_exc->private_[2],
    372   1.1  mrg 	       &ms_exc, gcc_exc, &ms_context, &ms_history);
    373   1.1  mrg 
    374   1.1  mrg   /* Is RtlUnwindEx declared noreturn?  */
    375   1.1  mrg   abort ();
    376   1.1  mrg }
    377   1.1  mrg 
    378   1.1  mrg static _Unwind_Reason_Code
    379   1.1  mrg _Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc)
    380   1.1  mrg {
    381   1.1  mrg   _Unwind_Stop_Fn stop;
    382   1.1  mrg   void * stop_argument;
    383   1.1  mrg 
    384   1.1  mrg   RaiseException (STATUS_GCC_FORCED, 0, 1, (ULONG_PTR *)&exc);
    385   1.1  mrg 
    386   1.1  mrg   /* If we get here, we got to top-of-stack.  */
    387   1.1  mrg   /* ??? We no longer have a context pointer to pass in.  */
    388   1.1  mrg 
    389   1.1  mrg   stop = (_Unwind_Stop_Fn) exc->private_[0];
    390   1.1  mrg   stop_argument = (void *) exc->private_[4];
    391   1.1  mrg   stop (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK,
    392   1.1  mrg 	exc->exception_class, exc, NULL, stop_argument);
    393   1.1  mrg 
    394   1.1  mrg   return _UA_END_OF_STACK;
    395   1.1  mrg }
    396   1.1  mrg 
    397   1.1  mrg _Unwind_Reason_Code
    398   1.1  mrg _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc)
    399   1.1  mrg {
    400   1.1  mrg   if (exc->private_[0] == 0)
    401   1.1  mrg     _Unwind_RaiseException (exc);
    402   1.1  mrg   else
    403   1.1  mrg     _Unwind_ForcedUnwind_Phase2 (exc);
    404   1.1  mrg   abort ();
    405   1.1  mrg }
    406   1.1  mrg 
    407   1.1  mrg /* Raise an exception for forced unwinding.  */
    408   1.1  mrg 
    409   1.1  mrg _Unwind_Reason_Code
    410   1.1  mrg _Unwind_ForcedUnwind (struct _Unwind_Exception *exc,
    411   1.1  mrg 		      _Unwind_Stop_Fn stop, void * stop_argument)
    412   1.1  mrg {
    413   1.1  mrg   /* ??? This is a hack that only works with _GCC_specific_handler.
    414   1.1  mrg      There's no way to invoke STOP within frames that use a different
    415   1.1  mrg      exception handler.  This is essentially just good enough to run
    416   1.1  mrg      the code within the gcc testsuite.  */
    417   1.1  mrg 
    418   1.1  mrg   memset (exc->private_, 0, sizeof (exc->private_));
    419   1.1  mrg   exc->private_[0] = (_Unwind_Ptr) stop;
    420   1.1  mrg   exc->private_[4] = (_Unwind_Ptr) stop_argument;
    421   1.1  mrg 
    422   1.1  mrg   return _Unwind_ForcedUnwind_Phase2 (exc);
    423   1.1  mrg }
    424   1.1  mrg 
    425   1.1  mrg /* A convenience function that calls the exception_cleanup field.  */
    426   1.1  mrg 
    427   1.1  mrg void
    428   1.1  mrg _Unwind_DeleteException (struct _Unwind_Exception *exc)
    429   1.1  mrg {
    430   1.1  mrg   if (exc->exception_cleanup)
    431   1.1  mrg     (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc);
    432   1.1  mrg }
    433   1.1  mrg 
    434   1.3  mrg /* Perform stack backtrace through unwind data.  */
    435   1.3  mrg 
    436   1.1  mrg _Unwind_Reason_Code
    437   1.1  mrg _Unwind_Backtrace(_Unwind_Trace_Fn trace,
    438   1.1  mrg 		  void *trace_argument)
    439   1.1  mrg {
    440   1.3  mrg   UNWIND_HISTORY_TABLE ms_history;
    441   1.1  mrg   CONTEXT ms_context;
    442   1.1  mrg   struct _Unwind_Context gcc_context;
    443   1.1  mrg   DISPATCHER_CONTEXT disp_context;
    444   1.3  mrg 
    445   1.1  mrg   memset (&ms_history, 0, sizeof(ms_history));
    446   1.1  mrg   memset (&gcc_context, 0, sizeof(gcc_context));
    447   1.1  mrg   memset (&disp_context, 0, sizeof(disp_context));
    448   1.1  mrg 
    449   1.3  mrg   ms_context.ContextFlags = CONTEXT_ALL;
    450   1.3  mrg   RtlCaptureContext (&ms_context);
    451   1.3  mrg 
    452   1.1  mrg   gcc_context.disp = &disp_context;
    453   1.1  mrg   gcc_context.disp->ContextRecord = &ms_context;
    454   1.1  mrg   gcc_context.disp->HistoryTable = &ms_history;
    455   1.3  mrg 
    456   1.3  mrg   while (1)
    457   1.3  mrg     {
    458   1.1  mrg       gcc_context.disp->ControlPc = ms_context.Rip;
    459   1.1  mrg       gcc_context.disp->FunctionEntry
    460   1.3  mrg 	= RtlLookupFunctionEntry (ms_context.Rip, &gcc_context.disp->ImageBase,
    461   1.3  mrg 				  &ms_history);
    462   1.3  mrg 
    463   1.3  mrg       if (!gcc_context.disp->FunctionEntry)
    464   1.3  mrg 	return _URC_END_OF_STACK;
    465   1.3  mrg 
    466   1.3  mrg       gcc_context.disp->LanguageHandler
    467   1.3  mrg 	= RtlVirtualUnwind (0, gcc_context.disp->ImageBase, ms_context.Rip,
    468   1.1  mrg 			    gcc_context.disp->FunctionEntry, &ms_context,
    469  1.10  mrg 			    &gcc_context.disp->HandlerData,
    470  1.10  mrg 			    &gcc_context.disp->EstablisherFrame, NULL);
    471  1.10  mrg 
    472  1.10  mrg       /* Set values that the callback can inspect via _Unwind_GetIP
    473  1.10  mrg        * and _Unwind_GetCFA. */
    474   1.1  mrg       gcc_context.ra = ms_context.Rip;
    475   1.1  mrg       gcc_context.cfa = ms_context.Rsp;
    476   1.1  mrg 
    477   1.1  mrg       /* Call trace function.  */
    478   1.1  mrg       if (trace (&gcc_context, trace_argument) != _URC_NO_REASON)
    479   1.1  mrg 	return _URC_FATAL_PHASE1_ERROR;
    480   1.1  mrg 
    481   1.1  mrg       /* ??? Check for invalid stack pointer.  */
    482   1.1  mrg       if (ms_context.Rip == 0)
    483   1.1  mrg 	return _URC_END_OF_STACK;
    484                }
    485            }
    486            #endif /* __SEH__  && !defined (__USING_SJLJ_EXCEPTIONS__)  */
    487