unwind-seh.c revision 1.10 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