1*0faf1914Srobert //===----------------------------------------------------------------------===//
2f6c50668Spatrick //
3f6c50668Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f6c50668Spatrick // See https://llvm.org/LICENSE.txt for license information.
5f6c50668Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f6c50668Spatrick //
7f6c50668Spatrick //
8f6c50668Spatrick // Implements setjump-longjump based C++ exceptions
9f6c50668Spatrick //
10f6c50668Spatrick //===----------------------------------------------------------------------===//
11f6c50668Spatrick
12f6c50668Spatrick #include <unwind.h>
13f6c50668Spatrick
14f6c50668Spatrick #include <inttypes.h>
15f6c50668Spatrick #include <stdint.h>
16f6c50668Spatrick #include <stdbool.h>
17f6c50668Spatrick #include <stdlib.h>
18f6c50668Spatrick
19f6c50668Spatrick #include "config.h"
20f6c50668Spatrick
21f6c50668Spatrick /// With SJLJ based exceptions, any function that has a catch clause or needs to
22f6c50668Spatrick /// do any clean up when an exception propagates through it, needs to call
23f6c50668Spatrick /// \c _Unwind_SjLj_Register at the start of the function and
24f6c50668Spatrick /// \c _Unwind_SjLj_Unregister at the end. The register function is called with
25f6c50668Spatrick /// the address of a block of memory in the function's stack frame. The runtime
26f6c50668Spatrick /// keeps a linked list (stack) of these blocks - one per thread. The calling
27f6c50668Spatrick /// function also sets the personality and lsda fields of the block.
28f6c50668Spatrick
29f6c50668Spatrick #if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
30f6c50668Spatrick
31f6c50668Spatrick struct _Unwind_FunctionContext {
32f6c50668Spatrick // next function in stack of handlers
33f6c50668Spatrick struct _Unwind_FunctionContext *prev;
34f6c50668Spatrick
35b3056a3bSpatrick #if defined(__ve__)
36*0faf1914Srobert // VE requires to store 64 bit pointers in the buffer for SjLj exception.
37b3056a3bSpatrick // We expand the size of values defined here. This size must be matched
38b3056a3bSpatrick // to the size returned by TargetMachine::getSjLjDataSize().
39b3056a3bSpatrick
40b3056a3bSpatrick // set by calling function before registering to be the landing pad
41b3056a3bSpatrick uint64_t resumeLocation;
42b3056a3bSpatrick
43b3056a3bSpatrick // set by personality handler to be parameters passed to landing pad function
44b3056a3bSpatrick uint64_t resumeParameters[4];
45b3056a3bSpatrick #else
46f6c50668Spatrick // set by calling function before registering to be the landing pad
47f6c50668Spatrick uint32_t resumeLocation;
48f6c50668Spatrick
49f6c50668Spatrick // set by personality handler to be parameters passed to landing pad function
50f6c50668Spatrick uint32_t resumeParameters[4];
51b3056a3bSpatrick #endif
52f6c50668Spatrick
53f6c50668Spatrick // set by calling function before registering
54f6c50668Spatrick _Unwind_Personality_Fn personality; // arm offset=24
55f6c50668Spatrick uintptr_t lsda; // arm offset=28
56f6c50668Spatrick
57f6c50668Spatrick // variable length array, contains registers to restore
58f6c50668Spatrick // 0 = r7, 1 = pc, 2 = sp
59f6c50668Spatrick void *jbuf[];
60f6c50668Spatrick };
61f6c50668Spatrick
62f6c50668Spatrick #if defined(_LIBUNWIND_HAS_NO_THREADS)
63f6c50668Spatrick # define _LIBUNWIND_THREAD_LOCAL
64f6c50668Spatrick #else
65f6c50668Spatrick # if __STDC_VERSION__ >= 201112L
66f6c50668Spatrick # define _LIBUNWIND_THREAD_LOCAL _Thread_local
67f6c50668Spatrick # elif defined(_MSC_VER)
68f6c50668Spatrick # define _LIBUNWIND_THREAD_LOCAL __declspec(thread)
69f6c50668Spatrick # elif defined(__GNUC__) || defined(__clang__)
70f6c50668Spatrick # define _LIBUNWIND_THREAD_LOCAL __thread
71f6c50668Spatrick # else
72f6c50668Spatrick # error Unable to create thread local storage
73f6c50668Spatrick # endif
74f6c50668Spatrick #endif
75f6c50668Spatrick
76f6c50668Spatrick
77f6c50668Spatrick #if !defined(FOR_DYLD)
78f6c50668Spatrick
79f6c50668Spatrick #if defined(__APPLE__)
80f6c50668Spatrick #include <System/pthread_machdep.h>
81f6c50668Spatrick #else
82f6c50668Spatrick static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL;
83f6c50668Spatrick #endif
84f6c50668Spatrick
__Unwind_SjLj_GetTopOfFunctionStack()85f6c50668Spatrick static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() {
86f6c50668Spatrick #if defined(__APPLE__)
87f6c50668Spatrick return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
88f6c50668Spatrick #else
89f6c50668Spatrick return stack;
90f6c50668Spatrick #endif
91f6c50668Spatrick }
92f6c50668Spatrick
93f6c50668Spatrick static void
__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext * fc)94f6c50668Spatrick __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {
95f6c50668Spatrick #if defined(__APPLE__)
96f6c50668Spatrick _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
97f6c50668Spatrick #else
98f6c50668Spatrick stack = fc;
99f6c50668Spatrick #endif
100f6c50668Spatrick }
101f6c50668Spatrick
102f6c50668Spatrick #endif
103f6c50668Spatrick
104f6c50668Spatrick
105f6c50668Spatrick /// Called at start of each function that catches exceptions
106f6c50668Spatrick _LIBUNWIND_EXPORT void
_Unwind_SjLj_Register(struct _Unwind_FunctionContext * fc)107f6c50668Spatrick _Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) {
108f6c50668Spatrick fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
109f6c50668Spatrick __Unwind_SjLj_SetTopOfFunctionStack(fc);
110f6c50668Spatrick }
111f6c50668Spatrick
112f6c50668Spatrick
113f6c50668Spatrick /// Called at end of each function that catches exceptions
114f6c50668Spatrick _LIBUNWIND_EXPORT void
_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext * fc)115f6c50668Spatrick _Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {
116f6c50668Spatrick __Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
117f6c50668Spatrick }
118f6c50668Spatrick
119f6c50668Spatrick
120f6c50668Spatrick static _Unwind_Reason_Code
unwind_phase1(struct _Unwind_Exception * exception_object)121f6c50668Spatrick unwind_phase1(struct _Unwind_Exception *exception_object) {
122f6c50668Spatrick _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
123f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p",
124f6c50668Spatrick (void *)c);
125f6c50668Spatrick
126f6c50668Spatrick // walk each frame looking for a place to stop
127f6c50668Spatrick for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
128f6c50668Spatrick
129f6c50668Spatrick // check for no more frames
130f6c50668Spatrick if (c == NULL) {
131f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "
132f6c50668Spatrick "bottom => _URC_END_OF_STACK",
133f6c50668Spatrick (void *)exception_object);
134f6c50668Spatrick return _URC_END_OF_STACK;
135f6c50668Spatrick }
136f6c50668Spatrick
137f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c);
138f6c50668Spatrick // if there is a personality routine, ask it if it will want to stop at this
139f6c50668Spatrick // frame
140f6c50668Spatrick if (c->personality != NULL) {
141f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling "
142f6c50668Spatrick "personality function %p",
143f6c50668Spatrick (void *)exception_object,
144f6c50668Spatrick (void *)c->personality);
145f6c50668Spatrick _Unwind_Reason_Code personalityResult = (*c->personality)(
146f6c50668Spatrick 1, _UA_SEARCH_PHASE, exception_object->exception_class,
147f6c50668Spatrick exception_object, (struct _Unwind_Context *)c);
148f6c50668Spatrick switch (personalityResult) {
149f6c50668Spatrick case _URC_HANDLER_FOUND:
150f6c50668Spatrick // found a catch clause or locals that need destructing in this frame
151f6c50668Spatrick // stop search and remember function context
152f6c50668Spatrick handlerNotFound = false;
153f6c50668Spatrick exception_object->private_2 = (uintptr_t) c;
154f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
155f6c50668Spatrick "_URC_HANDLER_FOUND",
156f6c50668Spatrick (void *)exception_object);
157f6c50668Spatrick return _URC_NO_REASON;
158f6c50668Spatrick
159f6c50668Spatrick case _URC_CONTINUE_UNWIND:
160f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
161f6c50668Spatrick "_URC_CONTINUE_UNWIND",
162f6c50668Spatrick (void *)exception_object);
163f6c50668Spatrick // continue unwinding
164f6c50668Spatrick break;
165f6c50668Spatrick
166f6c50668Spatrick default:
167f6c50668Spatrick // something went wrong
168f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING(
169f6c50668Spatrick "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
170f6c50668Spatrick (void *)exception_object);
171f6c50668Spatrick return _URC_FATAL_PHASE1_ERROR;
172f6c50668Spatrick }
173f6c50668Spatrick }
174f6c50668Spatrick }
175f6c50668Spatrick return _URC_NO_REASON;
176f6c50668Spatrick }
177f6c50668Spatrick
178f6c50668Spatrick
179f6c50668Spatrick static _Unwind_Reason_Code
unwind_phase2(struct _Unwind_Exception * exception_object)180f6c50668Spatrick unwind_phase2(struct _Unwind_Exception *exception_object) {
181f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
182f6c50668Spatrick (void *)exception_object);
183f6c50668Spatrick
184f6c50668Spatrick // walk each frame until we reach where search phase said to stop
185f6c50668Spatrick _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
186f6c50668Spatrick while (true) {
187f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p",
188f6c50668Spatrick (void *)exception_object, (void *)c);
189f6c50668Spatrick
190f6c50668Spatrick // check for no more frames
191f6c50668Spatrick if (c == NULL) {
192f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING(
193f6c50668Spatrick "unwind_phase2(ex_ojb=%p): __unw_step() reached "
194f6c50668Spatrick "bottom => _URC_END_OF_STACK",
195f6c50668Spatrick (void *)exception_object);
196f6c50668Spatrick return _URC_END_OF_STACK;
197f6c50668Spatrick }
198f6c50668Spatrick
199f6c50668Spatrick // if there is a personality routine, tell it we are unwinding
200f6c50668Spatrick if (c->personality != NULL) {
201f6c50668Spatrick _Unwind_Action action = _UA_CLEANUP_PHASE;
202f6c50668Spatrick if ((uintptr_t) c == exception_object->private_2)
203f6c50668Spatrick action = (_Unwind_Action)(
204f6c50668Spatrick _UA_CLEANUP_PHASE |
205f6c50668Spatrick _UA_HANDLER_FRAME); // tell personality this was the frame it marked
206f6c50668Spatrick // in phase 1
207f6c50668Spatrick _Unwind_Reason_Code personalityResult =
208f6c50668Spatrick (*c->personality)(1, action, exception_object->exception_class,
209f6c50668Spatrick exception_object, (struct _Unwind_Context *)c);
210f6c50668Spatrick switch (personalityResult) {
211f6c50668Spatrick case _URC_CONTINUE_UNWIND:
212f6c50668Spatrick // continue unwinding
213f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING(
214f6c50668Spatrick "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
215f6c50668Spatrick (void *)exception_object);
216f6c50668Spatrick if ((uintptr_t) c == exception_object->private_2) {
217f6c50668Spatrick // phase 1 said we would stop at this frame, but we did not...
218f6c50668Spatrick _LIBUNWIND_ABORT("during phase1 personality function said it would "
219f6c50668Spatrick "stop here, but now if phase2 it did not stop here");
220f6c50668Spatrick }
221f6c50668Spatrick break;
222f6c50668Spatrick case _URC_INSTALL_CONTEXT:
223f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "
224f6c50668Spatrick "_URC_INSTALL_CONTEXT, will resume at "
225f6c50668Spatrick "landing pad %p",
226f6c50668Spatrick (void *)exception_object, c->jbuf[1]);
227f6c50668Spatrick // personality routine says to transfer control to landing pad
228f6c50668Spatrick // we may get control back if landing pad calls _Unwind_Resume()
229f6c50668Spatrick __Unwind_SjLj_SetTopOfFunctionStack(c);
230f6c50668Spatrick __builtin_longjmp(c->jbuf, 1);
231f6c50668Spatrick // __unw_resume() only returns if there was an error
232f6c50668Spatrick return _URC_FATAL_PHASE2_ERROR;
233f6c50668Spatrick default:
234f6c50668Spatrick // something went wrong
235f6c50668Spatrick _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
236f6c50668Spatrick personalityResult);
237f6c50668Spatrick return _URC_FATAL_PHASE2_ERROR;
238f6c50668Spatrick }
239f6c50668Spatrick }
240f6c50668Spatrick c = c->prev;
241f6c50668Spatrick }
242f6c50668Spatrick
243f6c50668Spatrick // clean up phase did not resume at the frame that the search phase said it
244f6c50668Spatrick // would
245f6c50668Spatrick return _URC_FATAL_PHASE2_ERROR;
246f6c50668Spatrick }
247f6c50668Spatrick
248f6c50668Spatrick
249f6c50668Spatrick static _Unwind_Reason_Code
unwind_phase2_forced(struct _Unwind_Exception * exception_object,_Unwind_Stop_Fn stop,void * stop_parameter)250f6c50668Spatrick unwind_phase2_forced(struct _Unwind_Exception *exception_object,
251f6c50668Spatrick _Unwind_Stop_Fn stop, void *stop_parameter) {
252f6c50668Spatrick // walk each frame until we reach where search phase said to stop
253f6c50668Spatrick _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
254f6c50668Spatrick while (true) {
255f6c50668Spatrick
256f6c50668Spatrick // get next frame (skip over first which is _Unwind_RaiseException)
257f6c50668Spatrick if (c == NULL) {
258f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING(
259f6c50668Spatrick "unwind_phase2(ex_ojb=%p): __unw_step() reached "
260f6c50668Spatrick "bottom => _URC_END_OF_STACK",
261f6c50668Spatrick (void *)exception_object);
262f6c50668Spatrick return _URC_END_OF_STACK;
263f6c50668Spatrick }
264f6c50668Spatrick
265f6c50668Spatrick // call stop function at each frame
266f6c50668Spatrick _Unwind_Action action =
267f6c50668Spatrick (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
268f6c50668Spatrick _Unwind_Reason_Code stopResult =
269f6c50668Spatrick (*stop)(1, action, exception_object->exception_class, exception_object,
270f6c50668Spatrick (struct _Unwind_Context *)c, stop_parameter);
271f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
272f6c50668Spatrick "stop function returned %d",
273f6c50668Spatrick (void *)exception_object, stopResult);
274f6c50668Spatrick if (stopResult != _URC_NO_REASON) {
275f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
276f6c50668Spatrick "stopped by stop function",
277f6c50668Spatrick (void *)exception_object);
278f6c50668Spatrick return _URC_FATAL_PHASE2_ERROR;
279f6c50668Spatrick }
280f6c50668Spatrick
281f6c50668Spatrick // if there is a personality routine, tell it we are unwinding
282f6c50668Spatrick if (c->personality != NULL) {
283f6c50668Spatrick _Unwind_Personality_Fn p = (_Unwind_Personality_Fn)c->personality;
284f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
285f6c50668Spatrick "calling personality function %p",
286f6c50668Spatrick (void *)exception_object, (void *)p);
287f6c50668Spatrick _Unwind_Reason_Code personalityResult =
288f6c50668Spatrick (*p)(1, action, exception_object->exception_class, exception_object,
289f6c50668Spatrick (struct _Unwind_Context *)c);
290f6c50668Spatrick switch (personalityResult) {
291f6c50668Spatrick case _URC_CONTINUE_UNWIND:
292f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
293f6c50668Spatrick "personality returned _URC_CONTINUE_UNWIND",
294f6c50668Spatrick (void *)exception_object);
295f6c50668Spatrick // destructors called, continue unwinding
296f6c50668Spatrick break;
297f6c50668Spatrick case _URC_INSTALL_CONTEXT:
298f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
299f6c50668Spatrick "personality returned _URC_INSTALL_CONTEXT",
300f6c50668Spatrick (void *)exception_object);
301f6c50668Spatrick // we may get control back if landing pad calls _Unwind_Resume()
302f6c50668Spatrick __Unwind_SjLj_SetTopOfFunctionStack(c);
303f6c50668Spatrick __builtin_longjmp(c->jbuf, 1);
304f6c50668Spatrick break;
305f6c50668Spatrick default:
306f6c50668Spatrick // something went wrong
307f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
308f6c50668Spatrick "personality returned %d, "
309f6c50668Spatrick "_URC_FATAL_PHASE2_ERROR",
310f6c50668Spatrick (void *)exception_object, personalityResult);
311f6c50668Spatrick return _URC_FATAL_PHASE2_ERROR;
312f6c50668Spatrick }
313f6c50668Spatrick }
314f6c50668Spatrick c = c->prev;
315f6c50668Spatrick }
316f6c50668Spatrick
317f6c50668Spatrick // call stop function one last time and tell it we've reached the end of the
318f6c50668Spatrick // stack
319f6c50668Spatrick _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
320f6c50668Spatrick "function with _UA_END_OF_STACK",
321f6c50668Spatrick (void *)exception_object);
322f6c50668Spatrick _Unwind_Action lastAction =
323f6c50668Spatrick (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
324f6c50668Spatrick (*stop)(1, lastAction, exception_object->exception_class, exception_object,
325f6c50668Spatrick (struct _Unwind_Context *)c, stop_parameter);
326f6c50668Spatrick
327f6c50668Spatrick // clean up phase did not resume at the frame that the search phase said it
328f6c50668Spatrick // would
329f6c50668Spatrick return _URC_FATAL_PHASE2_ERROR;
330f6c50668Spatrick }
331f6c50668Spatrick
332f6c50668Spatrick
333f6c50668Spatrick /// Called by __cxa_throw. Only returns if there is a fatal error
334f6c50668Spatrick _LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_SjLj_RaiseException(struct _Unwind_Exception * exception_object)335f6c50668Spatrick _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {
336f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)",
337f6c50668Spatrick (void *)exception_object);
338f6c50668Spatrick
339f6c50668Spatrick // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right
340f6c50668Spatrick // thing
341f6c50668Spatrick exception_object->private_1 = 0;
342f6c50668Spatrick exception_object->private_2 = 0;
343f6c50668Spatrick
344f6c50668Spatrick // phase 1: the search phase
345f6c50668Spatrick _Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
346f6c50668Spatrick if (phase1 != _URC_NO_REASON)
347f6c50668Spatrick return phase1;
348f6c50668Spatrick
349f6c50668Spatrick // phase 2: the clean up phase
350f6c50668Spatrick return unwind_phase2(exception_object);
351f6c50668Spatrick }
352f6c50668Spatrick
353f6c50668Spatrick
354f6c50668Spatrick
355f6c50668Spatrick /// When _Unwind_RaiseException() is in phase2, it hands control
356f6c50668Spatrick /// to the personality function at each frame. The personality
357f6c50668Spatrick /// may force a jump to a landing pad in that function, the landing
358f6c50668Spatrick /// pad code may then call _Unwind_Resume() to continue with the
359f6c50668Spatrick /// unwinding. Note: the call to _Unwind_Resume() is from compiler
360*0faf1914Srobert /// generated user code. All other _Unwind_* routines are called
361f6c50668Spatrick /// by the C++ runtime __cxa_* routines.
362f6c50668Spatrick ///
363f6c50668Spatrick /// Re-throwing an exception is implemented by having the code call
364f6c50668Spatrick /// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
365f6c50668Spatrick _LIBUNWIND_EXPORT void
_Unwind_SjLj_Resume(struct _Unwind_Exception * exception_object)366f6c50668Spatrick _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {
367f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)",
368f6c50668Spatrick (void *)exception_object);
369f6c50668Spatrick
370f6c50668Spatrick if (exception_object->private_1 != 0)
371f6c50668Spatrick unwind_phase2_forced(exception_object,
372f6c50668Spatrick (_Unwind_Stop_Fn) exception_object->private_1,
373f6c50668Spatrick (void *)exception_object->private_2);
374f6c50668Spatrick else
375f6c50668Spatrick unwind_phase2(exception_object);
376f6c50668Spatrick
377f6c50668Spatrick // clients assume _Unwind_Resume() does not return, so all we can do is abort.
378f6c50668Spatrick _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return");
379f6c50668Spatrick }
380f6c50668Spatrick
381f6c50668Spatrick
382f6c50668Spatrick /// Called by __cxa_rethrow().
383f6c50668Spatrick _LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception * exception_object)384f6c50668Spatrick _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
385f6c50668Spatrick _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), "
386f6c50668Spatrick "private_1=%" PRIuPTR,
387f6c50668Spatrick (void *)exception_object, exception_object->private_1);
388f6c50668Spatrick // If this is non-forced and a stopping place was found, then this is a
389f6c50668Spatrick // re-throw.
390f6c50668Spatrick // Call _Unwind_RaiseException() as if this was a new exception.
391f6c50668Spatrick if (exception_object->private_1 == 0) {
392f6c50668Spatrick return _Unwind_SjLj_RaiseException(exception_object);
393f6c50668Spatrick // should return if there is no catch clause, so that __cxa_rethrow can call
394f6c50668Spatrick // std::terminate()
395f6c50668Spatrick }
396f6c50668Spatrick
397*0faf1914Srobert // Call through to _Unwind_Resume() which distinguishes between forced and
398f6c50668Spatrick // regular exceptions.
399f6c50668Spatrick _Unwind_SjLj_Resume(exception_object);
400f6c50668Spatrick _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "
401f6c50668Spatrick "_Unwind_SjLj_Resume() which unexpectedly returned");
402f6c50668Spatrick }
403f6c50668Spatrick
404f6c50668Spatrick
405f6c50668Spatrick /// Called by personality handler during phase 2 to get LSDA for current frame.
406f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetLanguageSpecificData(struct _Unwind_Context * context)407f6c50668Spatrick _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
408f6c50668Spatrick _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
409f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) "
410f6c50668Spatrick "=> 0x%" PRIuPTR,
411f6c50668Spatrick (void *)context, ufc->lsda);
412f6c50668Spatrick return ufc->lsda;
413f6c50668Spatrick }
414f6c50668Spatrick
415f6c50668Spatrick
416f6c50668Spatrick /// Called by personality handler during phase 2 to get register values.
_Unwind_GetGR(struct _Unwind_Context * context,int index)417f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
418f6c50668Spatrick int index) {
419f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context,
420f6c50668Spatrick index);
421f6c50668Spatrick _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
422f6c50668Spatrick return ufc->resumeParameters[index];
423f6c50668Spatrick }
424f6c50668Spatrick
425f6c50668Spatrick
426f6c50668Spatrick /// Called by personality handler during phase 2 to alter register values.
_Unwind_SetGR(struct _Unwind_Context * context,int index,uintptr_t new_value)427f6c50668Spatrick _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
428f6c50668Spatrick uintptr_t new_value) {
429f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIuPTR
430f6c50668Spatrick ")",
431f6c50668Spatrick (void *)context, index, new_value);
432f6c50668Spatrick _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
433f6c50668Spatrick ufc->resumeParameters[index] = new_value;
434f6c50668Spatrick }
435f6c50668Spatrick
436f6c50668Spatrick
437f6c50668Spatrick /// Called by personality handler during phase 2 to get instruction pointer.
_Unwind_GetIP(struct _Unwind_Context * context)438f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
439f6c50668Spatrick _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
440f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIu32,
441f6c50668Spatrick (void *)context, ufc->resumeLocation + 1);
442f6c50668Spatrick return ufc->resumeLocation + 1;
443f6c50668Spatrick }
444f6c50668Spatrick
445f6c50668Spatrick
446f6c50668Spatrick /// Called by personality handler during phase 2 to get instruction pointer.
447f6c50668Spatrick /// ipBefore is a boolean that says if IP is already adjusted to be the call
448f6c50668Spatrick /// site address. Normally IP is the return address.
_Unwind_GetIPInfo(struct _Unwind_Context * context,int * ipBefore)449f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
450f6c50668Spatrick int *ipBefore) {
451f6c50668Spatrick _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
452f6c50668Spatrick *ipBefore = 0;
453f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIu32,
454f6c50668Spatrick (void *)context, (void *)ipBefore,
455f6c50668Spatrick ufc->resumeLocation + 1);
456f6c50668Spatrick return ufc->resumeLocation + 1;
457f6c50668Spatrick }
458f6c50668Spatrick
459f6c50668Spatrick
460f6c50668Spatrick /// Called by personality handler during phase 2 to alter instruction pointer.
_Unwind_SetIP(struct _Unwind_Context * context,uintptr_t new_value)461f6c50668Spatrick _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
462f6c50668Spatrick uintptr_t new_value) {
463f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIuPTR ")",
464f6c50668Spatrick (void *)context, new_value);
465f6c50668Spatrick _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
466f6c50668Spatrick ufc->resumeLocation = new_value - 1;
467f6c50668Spatrick }
468f6c50668Spatrick
469f6c50668Spatrick
470f6c50668Spatrick /// Called by personality handler during phase 2 to find the start of the
471f6c50668Spatrick /// function.
472f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetRegionStart(struct _Unwind_Context * context)473f6c50668Spatrick _Unwind_GetRegionStart(struct _Unwind_Context *context) {
474f6c50668Spatrick // Not supported or needed for sjlj based unwinding
475f6c50668Spatrick (void)context;
476f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context);
477f6c50668Spatrick return 0;
478f6c50668Spatrick }
479f6c50668Spatrick
480f6c50668Spatrick
481f6c50668Spatrick /// Called by personality handler during phase 2 if a foreign exception
482f6c50668Spatrick /// is caught.
483f6c50668Spatrick _LIBUNWIND_EXPORT void
_Unwind_DeleteException(struct _Unwind_Exception * exception_object)484f6c50668Spatrick _Unwind_DeleteException(struct _Unwind_Exception *exception_object) {
485f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
486f6c50668Spatrick (void *)exception_object);
487f6c50668Spatrick if (exception_object->exception_cleanup != NULL)
488f6c50668Spatrick (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
489f6c50668Spatrick exception_object);
490f6c50668Spatrick }
491f6c50668Spatrick
492f6c50668Spatrick
493f6c50668Spatrick
494f6c50668Spatrick /// Called by personality handler during phase 2 to get base address for data
495f6c50668Spatrick /// relative encodings.
496f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetDataRelBase(struct _Unwind_Context * context)497f6c50668Spatrick _Unwind_GetDataRelBase(struct _Unwind_Context *context) {
498f6c50668Spatrick // Not supported or needed for sjlj based unwinding
499f6c50668Spatrick (void)context;
500f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
501f6c50668Spatrick _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
502f6c50668Spatrick }
503f6c50668Spatrick
504f6c50668Spatrick
505f6c50668Spatrick /// Called by personality handler during phase 2 to get base address for text
506f6c50668Spatrick /// relative encodings.
507f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetTextRelBase(struct _Unwind_Context * context)508f6c50668Spatrick _Unwind_GetTextRelBase(struct _Unwind_Context *context) {
509f6c50668Spatrick // Not supported or needed for sjlj based unwinding
510f6c50668Spatrick (void)context;
511f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
512f6c50668Spatrick _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
513f6c50668Spatrick }
514f6c50668Spatrick
515f6c50668Spatrick
516f6c50668Spatrick /// Called by personality handler to get "Call Frame Area" for current frame.
_Unwind_GetCFA(struct _Unwind_Context * context)517f6c50668Spatrick _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
518f6c50668Spatrick _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context);
519f6c50668Spatrick if (context != NULL) {
520f6c50668Spatrick _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
521f6c50668Spatrick // Setjmp/longjmp based exceptions don't have a true CFA.
522f6c50668Spatrick // Instead, the SP in the jmpbuf is the closest approximation.
523f6c50668Spatrick return (uintptr_t) ufc->jbuf[2];
524f6c50668Spatrick }
525f6c50668Spatrick return 0;
526f6c50668Spatrick }
527f6c50668Spatrick
528f6c50668Spatrick #endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
529