xref: /openbsd-src/gnu/llvm/libunwind/src/Unwind-sjlj.c (revision 0faf1914bfa030ea6c1d961758e08514a79ff73a)
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