annotate libunwind/src/Unwind-seh.cpp @ 266:00f31e85ec16 default tip

Added tag current for changeset 31d058e83c98
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Sat, 14 Oct 2023 10:13:55 +0900
parents 1f2b6ac9f198
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
1 //===----------------------------------------------------------------------===//
150
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // Implements SEH-based Itanium C++ exceptions.
anatofuz
parents:
diff changeset
10 //
anatofuz
parents:
diff changeset
11 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
12
anatofuz
parents:
diff changeset
13 #include "config.h"
anatofuz
parents:
diff changeset
14
anatofuz
parents:
diff changeset
15 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
anatofuz
parents:
diff changeset
16
anatofuz
parents:
diff changeset
17 #include <unwind.h>
anatofuz
parents:
diff changeset
18
anatofuz
parents:
diff changeset
19 #include <stdint.h>
anatofuz
parents:
diff changeset
20 #include <stdbool.h>
anatofuz
parents:
diff changeset
21 #include <stdlib.h>
anatofuz
parents:
diff changeset
22
anatofuz
parents:
diff changeset
23 #include <windef.h>
anatofuz
parents:
diff changeset
24 #include <excpt.h>
anatofuz
parents:
diff changeset
25 #include <winnt.h>
anatofuz
parents:
diff changeset
26 #include <ntstatus.h>
anatofuz
parents:
diff changeset
27
anatofuz
parents:
diff changeset
28 #include "libunwind_ext.h"
anatofuz
parents:
diff changeset
29 #include "UnwindCursor.hpp"
anatofuz
parents:
diff changeset
30
anatofuz
parents:
diff changeset
31 using namespace libunwind;
anatofuz
parents:
diff changeset
32
anatofuz
parents:
diff changeset
33 #define STATUS_USER_DEFINED (1u << 29)
anatofuz
parents:
diff changeset
34
anatofuz
parents:
diff changeset
35 #define STATUS_GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C')
anatofuz
parents:
diff changeset
36
anatofuz
parents:
diff changeset
37 #define MAKE_CUSTOM_STATUS(s, c) \
anatofuz
parents:
diff changeset
38 ((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c)))
anatofuz
parents:
diff changeset
39 #define MAKE_GCC_EXCEPTION(c) \
anatofuz
parents:
diff changeset
40 MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24))
anatofuz
parents:
diff changeset
41
anatofuz
parents:
diff changeset
42 /// SEH exception raised by libunwind when the program calls
anatofuz
parents:
diff changeset
43 /// \c _Unwind_RaiseException.
anatofuz
parents:
diff changeset
44 #define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343
anatofuz
parents:
diff changeset
45 /// SEH exception raised by libunwind to initiate phase 2 of exception
anatofuz
parents:
diff changeset
46 /// handling.
anatofuz
parents:
diff changeset
47 #define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343
anatofuz
parents:
diff changeset
48
anatofuz
parents:
diff changeset
49 static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx);
anatofuz
parents:
diff changeset
50 static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor);
anatofuz
parents:
diff changeset
51 static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
anatofuz
parents:
diff changeset
52 DISPATCHER_CONTEXT *disp);
anatofuz
parents:
diff changeset
53
anatofuz
parents:
diff changeset
54 /// Common implementation of SEH-style handler functions used by Itanium-
anatofuz
parents:
diff changeset
55 /// style frames. Depending on how and why it was called, it may do one of:
anatofuz
parents:
diff changeset
56 /// a) Delegate to the given Itanium-style personality function; or
anatofuz
parents:
diff changeset
57 /// b) Initiate a collided unwind to halt unwinding.
anatofuz
parents:
diff changeset
58 _LIBUNWIND_EXPORT EXCEPTION_DISPOSITION
anatofuz
parents:
diff changeset
59 _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
anatofuz
parents:
diff changeset
60 DISPATCHER_CONTEXT *disp, _Unwind_Personality_Fn pers) {
anatofuz
parents:
diff changeset
61 unw_cursor_t cursor;
anatofuz
parents:
diff changeset
62 _Unwind_Exception *exc;
anatofuz
parents:
diff changeset
63 _Unwind_Action action;
anatofuz
parents:
diff changeset
64 struct _Unwind_Context *ctx = nullptr;
anatofuz
parents:
diff changeset
65 _Unwind_Reason_Code urc;
anatofuz
parents:
diff changeset
66 uintptr_t retval, target;
anatofuz
parents:
diff changeset
67 bool ours = false;
anatofuz
parents:
diff changeset
68
anatofuz
parents:
diff changeset
69 _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010lx(%lx), %p)",
anatofuz
parents:
diff changeset
70 ms_exc->ExceptionCode, ms_exc->ExceptionFlags,
anatofuz
parents:
diff changeset
71 (void *)frame);
anatofuz
parents:
diff changeset
72 if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) {
anatofuz
parents:
diff changeset
73 if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) {
anatofuz
parents:
diff changeset
74 // Set up the upper return value (the lower one and the target PC
anatofuz
parents:
diff changeset
75 // were set in the call to RtlUnwindEx()) for the landing pad.
anatofuz
parents:
diff changeset
76 #ifdef __x86_64__
anatofuz
parents:
diff changeset
77 disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3];
anatofuz
parents:
diff changeset
78 #elif defined(__arm__)
anatofuz
parents:
diff changeset
79 disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3];
anatofuz
parents:
diff changeset
80 #elif defined(__aarch64__)
anatofuz
parents:
diff changeset
81 disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3];
anatofuz
parents:
diff changeset
82 #endif
anatofuz
parents:
diff changeset
83 }
anatofuz
parents:
diff changeset
84 // This is the collided unwind to the landing pad. Nothing to do.
anatofuz
parents:
diff changeset
85 return ExceptionContinueSearch;
anatofuz
parents:
diff changeset
86 }
anatofuz
parents:
diff changeset
87
anatofuz
parents:
diff changeset
88 if (ms_exc->ExceptionCode == STATUS_GCC_THROW) {
anatofuz
parents:
diff changeset
89 // This is (probably) a libunwind-controlled exception/unwind. Recover the
anatofuz
parents:
diff changeset
90 // parameters which we set below, and pass them to the personality function.
anatofuz
parents:
diff changeset
91 ours = true;
anatofuz
parents:
diff changeset
92 exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0];
anatofuz
parents:
diff changeset
93 if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) {
anatofuz
parents:
diff changeset
94 ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1];
anatofuz
parents:
diff changeset
95 action = (_Unwind_Action)ms_exc->ExceptionInformation[2];
anatofuz
parents:
diff changeset
96 }
anatofuz
parents:
diff changeset
97 } else {
anatofuz
parents:
diff changeset
98 // Foreign exception.
221
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
99 // We can't interact with them (we don't know the original target frame
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
100 // that we should pass on to RtlUnwindEx in _Unwind_Resume), so just
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
101 // pass without calling our destructors here.
79ff65ed7e25 LLVM12 Original
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
102 return ExceptionContinueSearch;
150
anatofuz
parents:
diff changeset
103 }
anatofuz
parents:
diff changeset
104 if (!ctx) {
anatofuz
parents:
diff changeset
105 __unw_init_seh(&cursor, disp->ContextRecord);
anatofuz
parents:
diff changeset
106 __unw_seh_set_disp_ctx(&cursor, disp);
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
107 __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc);
150
anatofuz
parents:
diff changeset
108 ctx = (struct _Unwind_Context *)&cursor;
anatofuz
parents:
diff changeset
109
anatofuz
parents:
diff changeset
110 if (!IS_UNWINDING(ms_exc->ExceptionFlags)) {
anatofuz
parents:
diff changeset
111 if (ours && ms_exc->NumberParameters > 1)
anatofuz
parents:
diff changeset
112 action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND);
anatofuz
parents:
diff changeset
113 else
anatofuz
parents:
diff changeset
114 action = _UA_SEARCH_PHASE;
anatofuz
parents:
diff changeset
115 } else {
anatofuz
parents:
diff changeset
116 if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame)
anatofuz
parents:
diff changeset
117 action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
anatofuz
parents:
diff changeset
118 else
anatofuz
parents:
diff changeset
119 action = _UA_CLEANUP_PHASE;
anatofuz
parents:
diff changeset
120 }
anatofuz
parents:
diff changeset
121 }
anatofuz
parents:
diff changeset
122
anatofuz
parents:
diff changeset
123 _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality "
anatofuz
parents:
diff changeset
124 "function %p(1, %d, %llx, %p, %p)",
anatofuz
parents:
diff changeset
125 (void *)pers, action, exc->exception_class,
anatofuz
parents:
diff changeset
126 (void *)exc, (void *)ctx);
anatofuz
parents:
diff changeset
127 urc = pers(1, action, exc->exception_class, exc, ctx);
anatofuz
parents:
diff changeset
128 _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc);
anatofuz
parents:
diff changeset
129 switch (urc) {
anatofuz
parents:
diff changeset
130 case _URC_CONTINUE_UNWIND:
anatofuz
parents:
diff changeset
131 // If we're in phase 2, and the personality routine said to continue
anatofuz
parents:
diff changeset
132 // at the target frame, we're in real trouble.
anatofuz
parents:
diff changeset
133 if (action & _UA_HANDLER_FRAME)
anatofuz
parents:
diff changeset
134 _LIBUNWIND_ABORT("Personality continued unwind at the target frame!");
anatofuz
parents:
diff changeset
135 return ExceptionContinueSearch;
anatofuz
parents:
diff changeset
136 case _URC_HANDLER_FOUND:
anatofuz
parents:
diff changeset
137 // If we were called by __libunwind_seh_personality(), indicate that
anatofuz
parents:
diff changeset
138 // a handler was found; otherwise, initiate phase 2 by unwinding.
anatofuz
parents:
diff changeset
139 if (ours && ms_exc->NumberParameters > 1)
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
140 return 4 /* ExceptionExecuteHandler in mingw */;
150
anatofuz
parents:
diff changeset
141 // This should never happen in phase 2.
anatofuz
parents:
diff changeset
142 if (IS_UNWINDING(ms_exc->ExceptionFlags))
anatofuz
parents:
diff changeset
143 _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!");
anatofuz
parents:
diff changeset
144 exc->private_[1] = (ULONG_PTR)frame;
anatofuz
parents:
diff changeset
145 if (ours) {
anatofuz
parents:
diff changeset
146 ms_exc->NumberParameters = 4;
anatofuz
parents:
diff changeset
147 ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame;
anatofuz
parents:
diff changeset
148 }
anatofuz
parents:
diff changeset
149 // FIXME: Indicate target frame in foreign case!
anatofuz
parents:
diff changeset
150 // phase 2: the clean up phase
anatofuz
parents:
diff changeset
151 RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable);
anatofuz
parents:
diff changeset
152 _LIBUNWIND_ABORT("RtlUnwindEx() failed");
anatofuz
parents:
diff changeset
153 case _URC_INSTALL_CONTEXT: {
anatofuz
parents:
diff changeset
154 // If we were called by __libunwind_seh_personality(), indicate that
anatofuz
parents:
diff changeset
155 // a handler was found; otherwise, it's time to initiate a collided
anatofuz
parents:
diff changeset
156 // unwind to the target.
anatofuz
parents:
diff changeset
157 if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1)
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
158 return 4 /* ExceptionExecuteHandler in mingw */;
150
anatofuz
parents:
diff changeset
159 // This should never happen in phase 1.
anatofuz
parents:
diff changeset
160 if (!IS_UNWINDING(ms_exc->ExceptionFlags))
anatofuz
parents:
diff changeset
161 _LIBUNWIND_ABORT("Personality installed context during phase 1!");
anatofuz
parents:
diff changeset
162 #ifdef __x86_64__
anatofuz
parents:
diff changeset
163 exc->private_[2] = disp->TargetIp;
anatofuz
parents:
diff changeset
164 __unw_get_reg(&cursor, UNW_X86_64_RAX, &retval);
anatofuz
parents:
diff changeset
165 __unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]);
anatofuz
parents:
diff changeset
166 #elif defined(__arm__)
anatofuz
parents:
diff changeset
167 exc->private_[2] = disp->TargetPc;
anatofuz
parents:
diff changeset
168 __unw_get_reg(&cursor, UNW_ARM_R0, &retval);
anatofuz
parents:
diff changeset
169 __unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]);
anatofuz
parents:
diff changeset
170 #elif defined(__aarch64__)
anatofuz
parents:
diff changeset
171 exc->private_[2] = disp->TargetPc;
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
172 __unw_get_reg(&cursor, UNW_AARCH64_X0, &retval);
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
173 __unw_get_reg(&cursor, UNW_AARCH64_X1, &exc->private_[3]);
150
anatofuz
parents:
diff changeset
174 #endif
anatofuz
parents:
diff changeset
175 __unw_get_reg(&cursor, UNW_REG_IP, &target);
anatofuz
parents:
diff changeset
176 ms_exc->ExceptionCode = STATUS_GCC_UNWIND;
anatofuz
parents:
diff changeset
177 #ifdef __x86_64__
anatofuz
parents:
diff changeset
178 ms_exc->ExceptionInformation[2] = disp->TargetIp;
anatofuz
parents:
diff changeset
179 #elif defined(__arm__) || defined(__aarch64__)
anatofuz
parents:
diff changeset
180 ms_exc->ExceptionInformation[2] = disp->TargetPc;
anatofuz
parents:
diff changeset
181 #endif
anatofuz
parents:
diff changeset
182 ms_exc->ExceptionInformation[3] = exc->private_[3];
anatofuz
parents:
diff changeset
183 // Give NTRTL some scratch space to keep track of the collided unwind.
anatofuz
parents:
diff changeset
184 // Don't use the one that was passed in; we don't want to overwrite the
anatofuz
parents:
diff changeset
185 // context in the DISPATCHER_CONTEXT.
anatofuz
parents:
diff changeset
186 CONTEXT new_ctx;
anatofuz
parents:
diff changeset
187 RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable);
anatofuz
parents:
diff changeset
188 _LIBUNWIND_ABORT("RtlUnwindEx() failed");
anatofuz
parents:
diff changeset
189 }
anatofuz
parents:
diff changeset
190 // Anything else indicates a serious problem.
anatofuz
parents:
diff changeset
191 default: return ExceptionContinueExecution;
anatofuz
parents:
diff changeset
192 }
anatofuz
parents:
diff changeset
193 }
anatofuz
parents:
diff changeset
194
anatofuz
parents:
diff changeset
195 /// Personality function returned by \c __unw_get_proc_info() in SEH contexts.
anatofuz
parents:
diff changeset
196 /// This is a wrapper that calls the real SEH handler function, which in
anatofuz
parents:
diff changeset
197 /// turn (at least, for Itanium-style frames) calls the real Itanium
anatofuz
parents:
diff changeset
198 /// personality function (see \c _GCC_specific_handler()).
anatofuz
parents:
diff changeset
199 extern "C" _Unwind_Reason_Code
anatofuz
parents:
diff changeset
200 __libunwind_seh_personality(int version, _Unwind_Action state,
anatofuz
parents:
diff changeset
201 uint64_t klass, _Unwind_Exception *exc,
anatofuz
parents:
diff changeset
202 struct _Unwind_Context *context) {
anatofuz
parents:
diff changeset
203 (void)version;
anatofuz
parents:
diff changeset
204 (void)klass;
anatofuz
parents:
diff changeset
205 EXCEPTION_RECORD ms_exc;
anatofuz
parents:
diff changeset
206 bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE;
anatofuz
parents:
diff changeset
207 ms_exc.ExceptionCode = STATUS_GCC_THROW;
anatofuz
parents:
diff changeset
208 ms_exc.ExceptionFlags = 0;
anatofuz
parents:
diff changeset
209 ms_exc.NumberParameters = 3;
anatofuz
parents:
diff changeset
210 ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc;
anatofuz
parents:
diff changeset
211 ms_exc.ExceptionInformation[1] = (ULONG_PTR)context;
anatofuz
parents:
diff changeset
212 ms_exc.ExceptionInformation[2] = state;
anatofuz
parents:
diff changeset
213 DISPATCHER_CONTEXT *disp_ctx =
anatofuz
parents:
diff changeset
214 __unw_seh_get_disp_ctx((unw_cursor_t *)context);
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
215 _LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() calling "
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
216 "LanguageHandler %p(%p, %p, %p, %p)",
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
217 (void *)disp_ctx->LanguageHandler, (void *)&ms_exc,
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
218 (void *)disp_ctx->EstablisherFrame,
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
219 (void *)disp_ctx->ContextRecord, (void *)disp_ctx);
150
anatofuz
parents:
diff changeset
220 EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc,
anatofuz
parents:
diff changeset
221 (PVOID)disp_ctx->EstablisherFrame,
anatofuz
parents:
diff changeset
222 disp_ctx->ContextRecord,
anatofuz
parents:
diff changeset
223 disp_ctx);
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
224 _LIBUNWIND_TRACE_UNWINDING("__libunwind_seh_personality() LanguageHandler "
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
225 "returned %d",
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
226 (int)ms_act);
150
anatofuz
parents:
diff changeset
227 switch (ms_act) {
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
228 case ExceptionContinueExecution: return _URC_END_OF_STACK;
150
anatofuz
parents:
diff changeset
229 case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND;
anatofuz
parents:
diff changeset
230 case 4 /*ExceptionExecuteHandler*/:
anatofuz
parents:
diff changeset
231 return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND;
anatofuz
parents:
diff changeset
232 default:
anatofuz
parents:
diff changeset
233 return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR;
anatofuz
parents:
diff changeset
234 }
anatofuz
parents:
diff changeset
235 }
anatofuz
parents:
diff changeset
236
anatofuz
parents:
diff changeset
237 static _Unwind_Reason_Code
anatofuz
parents:
diff changeset
238 unwind_phase2_forced(unw_context_t *uc,
anatofuz
parents:
diff changeset
239 _Unwind_Exception *exception_object,
anatofuz
parents:
diff changeset
240 _Unwind_Stop_Fn stop, void *stop_parameter) {
anatofuz
parents:
diff changeset
241 unw_cursor_t cursor2;
anatofuz
parents:
diff changeset
242 __unw_init_local(&cursor2, uc);
anatofuz
parents:
diff changeset
243
anatofuz
parents:
diff changeset
244 // Walk each frame until we reach where search phase said to stop
anatofuz
parents:
diff changeset
245 while (__unw_step(&cursor2) > 0) {
anatofuz
parents:
diff changeset
246
anatofuz
parents:
diff changeset
247 // Update info about this frame.
anatofuz
parents:
diff changeset
248 unw_proc_info_t frameInfo;
anatofuz
parents:
diff changeset
249 if (__unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
250 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_get_proc_info "
150
anatofuz
parents:
diff changeset
251 "failed => _URC_END_OF_STACK",
anatofuz
parents:
diff changeset
252 (void *)exception_object);
anatofuz
parents:
diff changeset
253 return _URC_FATAL_PHASE2_ERROR;
anatofuz
parents:
diff changeset
254 }
anatofuz
parents:
diff changeset
255
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
256 #ifndef NDEBUG
150
anatofuz
parents:
diff changeset
257 // When tracing, print state information.
anatofuz
parents:
diff changeset
258 if (_LIBUNWIND_TRACING_UNWINDING) {
anatofuz
parents:
diff changeset
259 char functionBuf[512];
anatofuz
parents:
diff changeset
260 const char *functionName = functionBuf;
anatofuz
parents:
diff changeset
261 unw_word_t offset;
anatofuz
parents:
diff changeset
262 if ((__unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf),
anatofuz
parents:
diff changeset
263 &offset) != UNW_ESUCCESS) ||
anatofuz
parents:
diff changeset
264 (frameInfo.start_ip + offset > frameInfo.end_ip))
anatofuz
parents:
diff changeset
265 functionName = ".anonymous.";
anatofuz
parents:
diff changeset
266 _LIBUNWIND_TRACE_UNWINDING(
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
267 "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
268 ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
150
anatofuz
parents:
diff changeset
269 (void *)exception_object, frameInfo.start_ip, functionName,
anatofuz
parents:
diff changeset
270 frameInfo.lsda, frameInfo.handler);
anatofuz
parents:
diff changeset
271 }
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
272 #endif
150
anatofuz
parents:
diff changeset
273
anatofuz
parents:
diff changeset
274 // Call stop function at each frame.
anatofuz
parents:
diff changeset
275 _Unwind_Action action =
anatofuz
parents:
diff changeset
276 (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
anatofuz
parents:
diff changeset
277 _Unwind_Reason_Code stopResult =
anatofuz
parents:
diff changeset
278 (*stop)(1, action, exception_object->exception_class, exception_object,
anatofuz
parents:
diff changeset
279 (struct _Unwind_Context *)(&cursor2), stop_parameter);
anatofuz
parents:
diff changeset
280 _LIBUNWIND_TRACE_UNWINDING(
anatofuz
parents:
diff changeset
281 "unwind_phase2_forced(ex_ojb=%p): stop function returned %d",
anatofuz
parents:
diff changeset
282 (void *)exception_object, stopResult);
anatofuz
parents:
diff changeset
283 if (stopResult != _URC_NO_REASON) {
anatofuz
parents:
diff changeset
284 _LIBUNWIND_TRACE_UNWINDING(
anatofuz
parents:
diff changeset
285 "unwind_phase2_forced(ex_ojb=%p): stopped by stop function",
anatofuz
parents:
diff changeset
286 (void *)exception_object);
anatofuz
parents:
diff changeset
287 return _URC_FATAL_PHASE2_ERROR;
anatofuz
parents:
diff changeset
288 }
anatofuz
parents:
diff changeset
289
anatofuz
parents:
diff changeset
290 // If there is a personality routine, tell it we are unwinding.
anatofuz
parents:
diff changeset
291 if (frameInfo.handler != 0) {
anatofuz
parents:
diff changeset
292 _Unwind_Personality_Fn p =
anatofuz
parents:
diff changeset
293 (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);
anatofuz
parents:
diff changeset
294 _LIBUNWIND_TRACE_UNWINDING(
anatofuz
parents:
diff changeset
295 "unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
anatofuz
parents:
diff changeset
296 (void *)exception_object, (void *)(uintptr_t)p);
anatofuz
parents:
diff changeset
297 _Unwind_Reason_Code personalityResult =
anatofuz
parents:
diff changeset
298 (*p)(1, action, exception_object->exception_class, exception_object,
anatofuz
parents:
diff changeset
299 (struct _Unwind_Context *)(&cursor2));
anatofuz
parents:
diff changeset
300 switch (personalityResult) {
anatofuz
parents:
diff changeset
301 case _URC_CONTINUE_UNWIND:
anatofuz
parents:
diff changeset
302 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
anatofuz
parents:
diff changeset
303 "personality returned "
anatofuz
parents:
diff changeset
304 "_URC_CONTINUE_UNWIND",
anatofuz
parents:
diff changeset
305 (void *)exception_object);
anatofuz
parents:
diff changeset
306 // Destructors called, continue unwinding
anatofuz
parents:
diff changeset
307 break;
anatofuz
parents:
diff changeset
308 case _URC_INSTALL_CONTEXT:
anatofuz
parents:
diff changeset
309 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
anatofuz
parents:
diff changeset
310 "personality returned "
anatofuz
parents:
diff changeset
311 "_URC_INSTALL_CONTEXT",
anatofuz
parents:
diff changeset
312 (void *)exception_object);
anatofuz
parents:
diff changeset
313 // We may get control back if landing pad calls _Unwind_Resume().
anatofuz
parents:
diff changeset
314 __unw_resume(&cursor2);
anatofuz
parents:
diff changeset
315 break;
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
316 case _URC_END_OF_STACK:
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
317 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
318 "personality returned "
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
319 "_URC_END_OF_STACK",
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
320 (void *)exception_object);
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
321 break;
150
anatofuz
parents:
diff changeset
322 default:
anatofuz
parents:
diff changeset
323 // Personality routine returned an unknown result code.
anatofuz
parents:
diff changeset
324 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
anatofuz
parents:
diff changeset
325 "personality returned %d, "
anatofuz
parents:
diff changeset
326 "_URC_FATAL_PHASE2_ERROR",
anatofuz
parents:
diff changeset
327 (void *)exception_object, personalityResult);
anatofuz
parents:
diff changeset
328 return _URC_FATAL_PHASE2_ERROR;
anatofuz
parents:
diff changeset
329 }
252
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
330 if (personalityResult == _URC_END_OF_STACK)
1f2b6ac9f198 LLVM16-1
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 236
diff changeset
331 break;
150
anatofuz
parents:
diff changeset
332 }
anatofuz
parents:
diff changeset
333 }
anatofuz
parents:
diff changeset
334
anatofuz
parents:
diff changeset
335 // Call stop function one last time and tell it we've reached the end
anatofuz
parents:
diff changeset
336 // of the stack.
anatofuz
parents:
diff changeset
337 _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
anatofuz
parents:
diff changeset
338 "function with _UA_END_OF_STACK",
anatofuz
parents:
diff changeset
339 (void *)exception_object);
anatofuz
parents:
diff changeset
340 _Unwind_Action lastAction =
anatofuz
parents:
diff changeset
341 (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
anatofuz
parents:
diff changeset
342 (*stop)(1, lastAction, exception_object->exception_class, exception_object,
anatofuz
parents:
diff changeset
343 (struct _Unwind_Context *)(&cursor2), stop_parameter);
anatofuz
parents:
diff changeset
344
anatofuz
parents:
diff changeset
345 // Clean up phase did not resume at the frame that the search phase said it
anatofuz
parents:
diff changeset
346 // would.
anatofuz
parents:
diff changeset
347 return _URC_FATAL_PHASE2_ERROR;
anatofuz
parents:
diff changeset
348 }
anatofuz
parents:
diff changeset
349
anatofuz
parents:
diff changeset
350 /// Called by \c __cxa_throw(). Only returns if there is a fatal error.
anatofuz
parents:
diff changeset
351 _LIBUNWIND_EXPORT _Unwind_Reason_Code
anatofuz
parents:
diff changeset
352 _Unwind_RaiseException(_Unwind_Exception *exception_object) {
anatofuz
parents:
diff changeset
353 _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
anatofuz
parents:
diff changeset
354 (void *)exception_object);
anatofuz
parents:
diff changeset
355
anatofuz
parents:
diff changeset
356 // Mark that this is a non-forced unwind, so _Unwind_Resume()
anatofuz
parents:
diff changeset
357 // can do the right thing.
anatofuz
parents:
diff changeset
358 memset(exception_object->private_, 0, sizeof(exception_object->private_));
anatofuz
parents:
diff changeset
359
anatofuz
parents:
diff changeset
360 // phase 1: the search phase
anatofuz
parents:
diff changeset
361 // We'll let the system do that for us.
anatofuz
parents:
diff changeset
362 RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object);
anatofuz
parents:
diff changeset
363
anatofuz
parents:
diff changeset
364 // If we get here, either something went horribly wrong or we reached the
anatofuz
parents:
diff changeset
365 // top of the stack. Either way, let libc++abi call std::terminate().
anatofuz
parents:
diff changeset
366 return _URC_END_OF_STACK;
anatofuz
parents:
diff changeset
367 }
anatofuz
parents:
diff changeset
368
anatofuz
parents:
diff changeset
369 /// When \c _Unwind_RaiseException() is in phase2, it hands control
anatofuz
parents:
diff changeset
370 /// to the personality function at each frame. The personality
anatofuz
parents:
diff changeset
371 /// may force a jump to a landing pad in that function; the landing
anatofuz
parents:
diff changeset
372 /// pad code may then call \c _Unwind_Resume() to continue with the
anatofuz
parents:
diff changeset
373 /// unwinding. Note: the call to \c _Unwind_Resume() is from compiler
236
c4bab56944e8 LLVM 16
kono
parents: 221
diff changeset
374 /// generated user code. All other \c _Unwind_* routines are called
150
anatofuz
parents:
diff changeset
375 /// by the C++ runtime \c __cxa_* routines.
anatofuz
parents:
diff changeset
376 ///
anatofuz
parents:
diff changeset
377 /// Note: re-throwing an exception (as opposed to continuing the unwind)
anatofuz
parents:
diff changeset
378 /// is implemented by having the code call \c __cxa_rethrow() which
anatofuz
parents:
diff changeset
379 /// in turn calls \c _Unwind_Resume_or_Rethrow().
anatofuz
parents:
diff changeset
380 _LIBUNWIND_EXPORT void
anatofuz
parents:
diff changeset
381 _Unwind_Resume(_Unwind_Exception *exception_object) {
anatofuz
parents:
diff changeset
382 _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object);
anatofuz
parents:
diff changeset
383
anatofuz
parents:
diff changeset
384 if (exception_object->private_[0] != 0) {
anatofuz
parents:
diff changeset
385 unw_context_t uc;
anatofuz
parents:
diff changeset
386
anatofuz
parents:
diff changeset
387 __unw_getcontext(&uc);
anatofuz
parents:
diff changeset
388 unwind_phase2_forced(&uc, exception_object,
anatofuz
parents:
diff changeset
389 (_Unwind_Stop_Fn) exception_object->private_[0],
anatofuz
parents:
diff changeset
390 (void *)exception_object->private_[4]);
anatofuz
parents:
diff changeset
391 } else {
anatofuz
parents:
diff changeset
392 // Recover the parameters for the unwind from the exception object
anatofuz
parents:
diff changeset
393 // so we can start unwinding again.
anatofuz
parents:
diff changeset
394 EXCEPTION_RECORD ms_exc;
anatofuz
parents:
diff changeset
395 CONTEXT ms_ctx;
anatofuz
parents:
diff changeset
396 UNWIND_HISTORY_TABLE hist;
anatofuz
parents:
diff changeset
397
anatofuz
parents:
diff changeset
398 memset(&ms_exc, 0, sizeof(ms_exc));
anatofuz
parents:
diff changeset
399 memset(&hist, 0, sizeof(hist));
anatofuz
parents:
diff changeset
400 ms_exc.ExceptionCode = STATUS_GCC_THROW;
anatofuz
parents:
diff changeset
401 ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
anatofuz
parents:
diff changeset
402 ms_exc.NumberParameters = 4;
anatofuz
parents:
diff changeset
403 ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object;
anatofuz
parents:
diff changeset
404 ms_exc.ExceptionInformation[1] = exception_object->private_[1];
anatofuz
parents:
diff changeset
405 ms_exc.ExceptionInformation[2] = exception_object->private_[2];
anatofuz
parents:
diff changeset
406 ms_exc.ExceptionInformation[3] = exception_object->private_[3];
anatofuz
parents:
diff changeset
407 RtlUnwindEx((PVOID)exception_object->private_[1],
anatofuz
parents:
diff changeset
408 (PVOID)exception_object->private_[2], &ms_exc,
anatofuz
parents:
diff changeset
409 exception_object, &ms_ctx, &hist);
anatofuz
parents:
diff changeset
410 }
anatofuz
parents:
diff changeset
411
anatofuz
parents:
diff changeset
412 // Clients assume _Unwind_Resume() does not return, so all we can do is abort.
anatofuz
parents:
diff changeset
413 _LIBUNWIND_ABORT("_Unwind_Resume() can't return");
anatofuz
parents:
diff changeset
414 }
anatofuz
parents:
diff changeset
415
anatofuz
parents:
diff changeset
416 /// Not used by C++.
anatofuz
parents:
diff changeset
417 /// Unwinds stack, calling "stop" function at each frame.
anatofuz
parents:
diff changeset
418 /// Could be used to implement \c longjmp().
anatofuz
parents:
diff changeset
419 _LIBUNWIND_EXPORT _Unwind_Reason_Code
anatofuz
parents:
diff changeset
420 _Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
anatofuz
parents:
diff changeset
421 _Unwind_Stop_Fn stop, void *stop_parameter) {
anatofuz
parents:
diff changeset
422 _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",
anatofuz
parents:
diff changeset
423 (void *)exception_object, (void *)(uintptr_t)stop);
anatofuz
parents:
diff changeset
424 unw_context_t uc;
anatofuz
parents:
diff changeset
425 __unw_getcontext(&uc);
anatofuz
parents:
diff changeset
426
anatofuz
parents:
diff changeset
427 // Mark that this is a forced unwind, so _Unwind_Resume() can do
anatofuz
parents:
diff changeset
428 // the right thing.
anatofuz
parents:
diff changeset
429 exception_object->private_[0] = (uintptr_t) stop;
anatofuz
parents:
diff changeset
430 exception_object->private_[4] = (uintptr_t) stop_parameter;
anatofuz
parents:
diff changeset
431
anatofuz
parents:
diff changeset
432 // do it
anatofuz
parents:
diff changeset
433 return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
anatofuz
parents:
diff changeset
434 }
anatofuz
parents:
diff changeset
435
anatofuz
parents:
diff changeset
436 /// Called by personality handler during phase 2 to get LSDA for current frame.
anatofuz
parents:
diff changeset
437 _LIBUNWIND_EXPORT uintptr_t
anatofuz
parents:
diff changeset
438 _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
anatofuz
parents:
diff changeset
439 uintptr_t result =
anatofuz
parents:
diff changeset
440 (uintptr_t)__unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData;
anatofuz
parents:
diff changeset
441 _LIBUNWIND_TRACE_API(
anatofuz
parents:
diff changeset
442 "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
anatofuz
parents:
diff changeset
443 (void *)context, result);
anatofuz
parents:
diff changeset
444 return result;
anatofuz
parents:
diff changeset
445 }
anatofuz
parents:
diff changeset
446
anatofuz
parents:
diff changeset
447 /// Called by personality handler during phase 2 to find the start of the
anatofuz
parents:
diff changeset
448 /// function.
anatofuz
parents:
diff changeset
449 _LIBUNWIND_EXPORT uintptr_t
anatofuz
parents:
diff changeset
450 _Unwind_GetRegionStart(struct _Unwind_Context *context) {
anatofuz
parents:
diff changeset
451 DISPATCHER_CONTEXT *disp = __unw_seh_get_disp_ctx((unw_cursor_t *)context);
anatofuz
parents:
diff changeset
452 uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase;
anatofuz
parents:
diff changeset
453 _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR,
anatofuz
parents:
diff changeset
454 (void *)context, result);
anatofuz
parents:
diff changeset
455 return result;
anatofuz
parents:
diff changeset
456 }
anatofuz
parents:
diff changeset
457
anatofuz
parents:
diff changeset
458 static int __unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) {
anatofuz
parents:
diff changeset
459 #ifdef _LIBUNWIND_TARGET_X86_64
anatofuz
parents:
diff changeset
460 new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor))
anatofuz
parents:
diff changeset
461 UnwindCursor<LocalAddressSpace, Registers_x86_64>(
anatofuz
parents:
diff changeset
462 context, LocalAddressSpace::sThisAddressSpace);
anatofuz
parents:
diff changeset
463 auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
anatofuz
parents:
diff changeset
464 co->setInfoBasedOnIPRegister();
anatofuz
parents:
diff changeset
465 return UNW_ESUCCESS;
anatofuz
parents:
diff changeset
466 #elif defined(_LIBUNWIND_TARGET_ARM)
anatofuz
parents:
diff changeset
467 new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor))
anatofuz
parents:
diff changeset
468 UnwindCursor<LocalAddressSpace, Registers_arm>(
anatofuz
parents:
diff changeset
469 context, LocalAddressSpace::sThisAddressSpace);
anatofuz
parents:
diff changeset
470 auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
anatofuz
parents:
diff changeset
471 co->setInfoBasedOnIPRegister();
anatofuz
parents:
diff changeset
472 return UNW_ESUCCESS;
anatofuz
parents:
diff changeset
473 #elif defined(_LIBUNWIND_TARGET_AARCH64)
anatofuz
parents:
diff changeset
474 new (reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor))
anatofuz
parents:
diff changeset
475 UnwindCursor<LocalAddressSpace, Registers_arm64>(
anatofuz
parents:
diff changeset
476 context, LocalAddressSpace::sThisAddressSpace);
anatofuz
parents:
diff changeset
477 auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
anatofuz
parents:
diff changeset
478 co->setInfoBasedOnIPRegister();
anatofuz
parents:
diff changeset
479 return UNW_ESUCCESS;
anatofuz
parents:
diff changeset
480 #else
anatofuz
parents:
diff changeset
481 return UNW_EINVAL;
anatofuz
parents:
diff changeset
482 #endif
anatofuz
parents:
diff changeset
483 }
anatofuz
parents:
diff changeset
484
anatofuz
parents:
diff changeset
485 static DISPATCHER_CONTEXT *__unw_seh_get_disp_ctx(unw_cursor_t *cursor) {
anatofuz
parents:
diff changeset
486 #ifdef _LIBUNWIND_TARGET_X86_64
anatofuz
parents:
diff changeset
487 return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext();
anatofuz
parents:
diff changeset
488 #elif defined(_LIBUNWIND_TARGET_ARM)
anatofuz
parents:
diff changeset
489 return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext();
anatofuz
parents:
diff changeset
490 #elif defined(_LIBUNWIND_TARGET_AARCH64)
anatofuz
parents:
diff changeset
491 return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->getDispatcherContext();
anatofuz
parents:
diff changeset
492 #else
anatofuz
parents:
diff changeset
493 return nullptr;
anatofuz
parents:
diff changeset
494 #endif
anatofuz
parents:
diff changeset
495 }
anatofuz
parents:
diff changeset
496
anatofuz
parents:
diff changeset
497 static void __unw_seh_set_disp_ctx(unw_cursor_t *cursor,
anatofuz
parents:
diff changeset
498 DISPATCHER_CONTEXT *disp) {
anatofuz
parents:
diff changeset
499 #ifdef _LIBUNWIND_TARGET_X86_64
anatofuz
parents:
diff changeset
500 reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp);
anatofuz
parents:
diff changeset
501 #elif defined(_LIBUNWIND_TARGET_ARM)
anatofuz
parents:
diff changeset
502 reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp);
anatofuz
parents:
diff changeset
503 #elif defined(_LIBUNWIND_TARGET_AARCH64)
anatofuz
parents:
diff changeset
504 reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp);
anatofuz
parents:
diff changeset
505 #endif
anatofuz
parents:
diff changeset
506 }
anatofuz
parents:
diff changeset
507
anatofuz
parents:
diff changeset
508 #endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)