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