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