1349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric // 80b57cec5SDimitry Andric // Implements setjump-longjump based C++ exceptions 90b57cec5SDimitry Andric // 100b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include <unwind.h> 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include <inttypes.h> 150b57cec5SDimitry Andric #include <stdint.h> 160b57cec5SDimitry Andric #include <stdbool.h> 170b57cec5SDimitry Andric #include <stdlib.h> 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #include "config.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric /// With SJLJ based exceptions, any function that has a catch clause or needs to 220b57cec5SDimitry Andric /// do any clean up when an exception propagates through it, needs to call 230b57cec5SDimitry Andric /// \c _Unwind_SjLj_Register at the start of the function and 240b57cec5SDimitry Andric /// \c _Unwind_SjLj_Unregister at the end. The register function is called with 250b57cec5SDimitry Andric /// the address of a block of memory in the function's stack frame. The runtime 260b57cec5SDimitry Andric /// keeps a linked list (stack) of these blocks - one per thread. The calling 270b57cec5SDimitry Andric /// function also sets the personality and lsda fields of the block. 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #if defined(_LIBUNWIND_BUILD_SJLJ_APIS) 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric struct _Unwind_FunctionContext { 320b57cec5SDimitry Andric // next function in stack of handlers 330b57cec5SDimitry Andric struct _Unwind_FunctionContext *prev; 340b57cec5SDimitry Andric 35e8d8bef9SDimitry Andric #if defined(__ve__) 36bdd1243dSDimitry Andric // VE requires to store 64 bit pointers in the buffer for SjLj exception. 37e8d8bef9SDimitry Andric // We expand the size of values defined here. This size must be matched 38e8d8bef9SDimitry Andric // to the size returned by TargetMachine::getSjLjDataSize(). 39e8d8bef9SDimitry Andric 40e8d8bef9SDimitry Andric // set by calling function before registering to be the landing pad 41e8d8bef9SDimitry Andric uint64_t resumeLocation; 42e8d8bef9SDimitry Andric 43e8d8bef9SDimitry Andric // set by personality handler to be parameters passed to landing pad function 44e8d8bef9SDimitry Andric uint64_t resumeParameters[4]; 45e8d8bef9SDimitry Andric #else 460b57cec5SDimitry Andric // set by calling function before registering to be the landing pad 470b57cec5SDimitry Andric uint32_t resumeLocation; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric // set by personality handler to be parameters passed to landing pad function 500b57cec5SDimitry Andric uint32_t resumeParameters[4]; 51e8d8bef9SDimitry Andric #endif 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric // set by calling function before registering 545ffd83dbSDimitry Andric _Unwind_Personality_Fn personality; // arm offset=24 550b57cec5SDimitry Andric uintptr_t lsda; // arm offset=28 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // variable length array, contains registers to restore 580b57cec5SDimitry Andric // 0 = r7, 1 = pc, 2 = sp 590b57cec5SDimitry Andric void *jbuf[]; 600b57cec5SDimitry Andric }; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric #if defined(_LIBUNWIND_HAS_NO_THREADS) 630b57cec5SDimitry Andric # define _LIBUNWIND_THREAD_LOCAL 640b57cec5SDimitry Andric #else 650b57cec5SDimitry Andric # if __STDC_VERSION__ >= 201112L 660b57cec5SDimitry Andric # define _LIBUNWIND_THREAD_LOCAL _Thread_local 670b57cec5SDimitry Andric # elif defined(_MSC_VER) 680b57cec5SDimitry Andric # define _LIBUNWIND_THREAD_LOCAL __declspec(thread) 690b57cec5SDimitry Andric # elif defined(__GNUC__) || defined(__clang__) 700b57cec5SDimitry Andric # define _LIBUNWIND_THREAD_LOCAL __thread 710b57cec5SDimitry Andric # else 720b57cec5SDimitry Andric # error Unable to create thread local storage 730b57cec5SDimitry Andric # endif 740b57cec5SDimitry Andric #endif 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric #if !defined(FOR_DYLD) 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric #if defined(__APPLE__) 800b57cec5SDimitry Andric #include <System/pthread_machdep.h> 810b57cec5SDimitry Andric #else 820b57cec5SDimitry Andric static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL; 830b57cec5SDimitry Andric #endif 840b57cec5SDimitry Andric 85*5f757f3fSDimitry Andric static struct _Unwind_FunctionContext * 86*5f757f3fSDimitry Andric __Unwind_SjLj_GetTopOfFunctionStack(void) { 870b57cec5SDimitry Andric #if defined(__APPLE__) 880b57cec5SDimitry Andric return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); 890b57cec5SDimitry Andric #else 900b57cec5SDimitry Andric return stack; 910b57cec5SDimitry Andric #endif 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric static void 950b57cec5SDimitry Andric __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) { 960b57cec5SDimitry Andric #if defined(__APPLE__) 970b57cec5SDimitry Andric _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); 980b57cec5SDimitry Andric #else 990b57cec5SDimitry Andric stack = fc; 1000b57cec5SDimitry Andric #endif 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric #endif 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric /// Called at start of each function that catches exceptions 1070b57cec5SDimitry Andric _LIBUNWIND_EXPORT void 1080b57cec5SDimitry Andric _Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) { 1090b57cec5SDimitry Andric fc->prev = __Unwind_SjLj_GetTopOfFunctionStack(); 1100b57cec5SDimitry Andric __Unwind_SjLj_SetTopOfFunctionStack(fc); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric /// Called at end of each function that catches exceptions 1150b57cec5SDimitry Andric _LIBUNWIND_EXPORT void 1160b57cec5SDimitry Andric _Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) { 1170b57cec5SDimitry Andric __Unwind_SjLj_SetTopOfFunctionStack(fc->prev); 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric static _Unwind_Reason_Code 1220b57cec5SDimitry Andric unwind_phase1(struct _Unwind_Exception *exception_object) { 1230b57cec5SDimitry Andric _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); 1240b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p", 1250b57cec5SDimitry Andric (void *)c); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric // walk each frame looking for a place to stop 1280b57cec5SDimitry Andric for (bool handlerNotFound = true; handlerNotFound; c = c->prev) { 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric // check for no more frames 1310b57cec5SDimitry Andric if (c == NULL) { 1320b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached " 1330b57cec5SDimitry Andric "bottom => _URC_END_OF_STACK", 1340b57cec5SDimitry Andric (void *)exception_object); 1350b57cec5SDimitry Andric return _URC_END_OF_STACK; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c); 1390b57cec5SDimitry Andric // if there is a personality routine, ask it if it will want to stop at this 1400b57cec5SDimitry Andric // frame 1410b57cec5SDimitry Andric if (c->personality != NULL) { 1420b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling " 1430b57cec5SDimitry Andric "personality function %p", 1440b57cec5SDimitry Andric (void *)exception_object, 1450b57cec5SDimitry Andric (void *)c->personality); 1460b57cec5SDimitry Andric _Unwind_Reason_Code personalityResult = (*c->personality)( 1470b57cec5SDimitry Andric 1, _UA_SEARCH_PHASE, exception_object->exception_class, 1480b57cec5SDimitry Andric exception_object, (struct _Unwind_Context *)c); 1490b57cec5SDimitry Andric switch (personalityResult) { 1500b57cec5SDimitry Andric case _URC_HANDLER_FOUND: 1510b57cec5SDimitry Andric // found a catch clause or locals that need destructing in this frame 1520b57cec5SDimitry Andric // stop search and remember function context 1530b57cec5SDimitry Andric handlerNotFound = false; 1540b57cec5SDimitry Andric exception_object->private_2 = (uintptr_t) c; 1550b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " 1560b57cec5SDimitry Andric "_URC_HANDLER_FOUND", 1570b57cec5SDimitry Andric (void *)exception_object); 1580b57cec5SDimitry Andric return _URC_NO_REASON; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric case _URC_CONTINUE_UNWIND: 1610b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " 1620b57cec5SDimitry Andric "_URC_CONTINUE_UNWIND", 1630b57cec5SDimitry Andric (void *)exception_object); 1640b57cec5SDimitry Andric // continue unwinding 1650b57cec5SDimitry Andric break; 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric default: 1680b57cec5SDimitry Andric // something went wrong 1690b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 1700b57cec5SDimitry Andric "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR", 1710b57cec5SDimitry Andric (void *)exception_object); 1720b57cec5SDimitry Andric return _URC_FATAL_PHASE1_ERROR; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric return _URC_NO_REASON; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric 1800b57cec5SDimitry Andric static _Unwind_Reason_Code 1810b57cec5SDimitry Andric unwind_phase2(struct _Unwind_Exception *exception_object) { 1820b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", 1830b57cec5SDimitry Andric (void *)exception_object); 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric // walk each frame until we reach where search phase said to stop 1860b57cec5SDimitry Andric _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); 1870b57cec5SDimitry Andric while (true) { 1880b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p", 1890b57cec5SDimitry Andric (void *)exception_object, (void *)c); 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric // check for no more frames 1920b57cec5SDimitry Andric if (c == NULL) { 1930b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 1940b57cec5SDimitry Andric "unwind_phase2(ex_ojb=%p): __unw_step() reached " 1950b57cec5SDimitry Andric "bottom => _URC_END_OF_STACK", 1960b57cec5SDimitry Andric (void *)exception_object); 1970b57cec5SDimitry Andric return _URC_END_OF_STACK; 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric // if there is a personality routine, tell it we are unwinding 2010b57cec5SDimitry Andric if (c->personality != NULL) { 2020b57cec5SDimitry Andric _Unwind_Action action = _UA_CLEANUP_PHASE; 2030b57cec5SDimitry Andric if ((uintptr_t) c == exception_object->private_2) 2040b57cec5SDimitry Andric action = (_Unwind_Action)( 2050b57cec5SDimitry Andric _UA_CLEANUP_PHASE | 2060b57cec5SDimitry Andric _UA_HANDLER_FRAME); // tell personality this was the frame it marked 2070b57cec5SDimitry Andric // in phase 1 2080b57cec5SDimitry Andric _Unwind_Reason_Code personalityResult = 2090b57cec5SDimitry Andric (*c->personality)(1, action, exception_object->exception_class, 2100b57cec5SDimitry Andric exception_object, (struct _Unwind_Context *)c); 2110b57cec5SDimitry Andric switch (personalityResult) { 2120b57cec5SDimitry Andric case _URC_CONTINUE_UNWIND: 2130b57cec5SDimitry Andric // continue unwinding 2140b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 2150b57cec5SDimitry Andric "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND", 2160b57cec5SDimitry Andric (void *)exception_object); 2170b57cec5SDimitry Andric if ((uintptr_t) c == exception_object->private_2) { 2180b57cec5SDimitry Andric // phase 1 said we would stop at this frame, but we did not... 2190b57cec5SDimitry Andric _LIBUNWIND_ABORT("during phase1 personality function said it would " 2200b57cec5SDimitry Andric "stop here, but now if phase2 it did not stop here"); 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric break; 2230b57cec5SDimitry Andric case _URC_INSTALL_CONTEXT: 2240b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): " 2250b57cec5SDimitry Andric "_URC_INSTALL_CONTEXT, will resume at " 2260b57cec5SDimitry Andric "landing pad %p", 2270b57cec5SDimitry Andric (void *)exception_object, c->jbuf[1]); 2280b57cec5SDimitry Andric // personality routine says to transfer control to landing pad 2290b57cec5SDimitry Andric // we may get control back if landing pad calls _Unwind_Resume() 2300b57cec5SDimitry Andric __Unwind_SjLj_SetTopOfFunctionStack(c); 2310b57cec5SDimitry Andric __builtin_longjmp(c->jbuf, 1); 2320b57cec5SDimitry Andric // __unw_resume() only returns if there was an error 2330b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 2340b57cec5SDimitry Andric default: 2350b57cec5SDimitry Andric // something went wrong 2360b57cec5SDimitry Andric _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", 2370b57cec5SDimitry Andric personalityResult); 2380b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric c = c->prev; 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric // clean up phase did not resume at the frame that the search phase said it 2450b57cec5SDimitry Andric // would 2460b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric static _Unwind_Reason_Code 2510b57cec5SDimitry Andric unwind_phase2_forced(struct _Unwind_Exception *exception_object, 2520b57cec5SDimitry Andric _Unwind_Stop_Fn stop, void *stop_parameter) { 2530b57cec5SDimitry Andric // walk each frame until we reach where search phase said to stop 2540b57cec5SDimitry Andric _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); 2550b57cec5SDimitry Andric while (true) { 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric // get next frame (skip over first which is _Unwind_RaiseException) 2580b57cec5SDimitry Andric if (c == NULL) { 2590b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING( 2600b57cec5SDimitry Andric "unwind_phase2(ex_ojb=%p): __unw_step() reached " 2610b57cec5SDimitry Andric "bottom => _URC_END_OF_STACK", 2620b57cec5SDimitry Andric (void *)exception_object); 2630b57cec5SDimitry Andric return _URC_END_OF_STACK; 2640b57cec5SDimitry Andric } 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric // call stop function at each frame 2670b57cec5SDimitry Andric _Unwind_Action action = 2680b57cec5SDimitry Andric (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); 2690b57cec5SDimitry Andric _Unwind_Reason_Code stopResult = 2700b57cec5SDimitry Andric (*stop)(1, action, exception_object->exception_class, exception_object, 2710b57cec5SDimitry Andric (struct _Unwind_Context *)c, stop_parameter); 2720b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 2730b57cec5SDimitry Andric "stop function returned %d", 2740b57cec5SDimitry Andric (void *)exception_object, stopResult); 2750b57cec5SDimitry Andric if (stopResult != _URC_NO_REASON) { 2760b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 2770b57cec5SDimitry Andric "stopped by stop function", 2780b57cec5SDimitry Andric (void *)exception_object); 2790b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 2800b57cec5SDimitry Andric } 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric // if there is a personality routine, tell it we are unwinding 2830b57cec5SDimitry Andric if (c->personality != NULL) { 2845ffd83dbSDimitry Andric _Unwind_Personality_Fn p = (_Unwind_Personality_Fn)c->personality; 2850b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 2860b57cec5SDimitry Andric "calling personality function %p", 2870b57cec5SDimitry Andric (void *)exception_object, (void *)p); 2880b57cec5SDimitry Andric _Unwind_Reason_Code personalityResult = 2890b57cec5SDimitry Andric (*p)(1, action, exception_object->exception_class, exception_object, 2900b57cec5SDimitry Andric (struct _Unwind_Context *)c); 2910b57cec5SDimitry Andric switch (personalityResult) { 2920b57cec5SDimitry Andric case _URC_CONTINUE_UNWIND: 2930b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 2940b57cec5SDimitry Andric "personality returned _URC_CONTINUE_UNWIND", 2950b57cec5SDimitry Andric (void *)exception_object); 2960b57cec5SDimitry Andric // destructors called, continue unwinding 2970b57cec5SDimitry Andric break; 2980b57cec5SDimitry Andric case _URC_INSTALL_CONTEXT: 2990b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 3000b57cec5SDimitry Andric "personality returned _URC_INSTALL_CONTEXT", 3010b57cec5SDimitry Andric (void *)exception_object); 3020b57cec5SDimitry Andric // we may get control back if landing pad calls _Unwind_Resume() 3030b57cec5SDimitry Andric __Unwind_SjLj_SetTopOfFunctionStack(c); 3040b57cec5SDimitry Andric __builtin_longjmp(c->jbuf, 1); 3050b57cec5SDimitry Andric break; 3060b57cec5SDimitry Andric default: 3070b57cec5SDimitry Andric // something went wrong 3080b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " 3090b57cec5SDimitry Andric "personality returned %d, " 3100b57cec5SDimitry Andric "_URC_FATAL_PHASE2_ERROR", 3110b57cec5SDimitry Andric (void *)exception_object, personalityResult); 3120b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric c = c->prev; 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // call stop function one last time and tell it we've reached the end of the 3190b57cec5SDimitry Andric // stack 3200b57cec5SDimitry Andric _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " 3210b57cec5SDimitry Andric "function with _UA_END_OF_STACK", 3220b57cec5SDimitry Andric (void *)exception_object); 3230b57cec5SDimitry Andric _Unwind_Action lastAction = 3240b57cec5SDimitry Andric (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); 3250b57cec5SDimitry Andric (*stop)(1, lastAction, exception_object->exception_class, exception_object, 3260b57cec5SDimitry Andric (struct _Unwind_Context *)c, stop_parameter); 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric // clean up phase did not resume at the frame that the search phase said it 3290b57cec5SDimitry Andric // would 3300b57cec5SDimitry Andric return _URC_FATAL_PHASE2_ERROR; 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric /// Called by __cxa_throw. Only returns if there is a fatal error 3350b57cec5SDimitry Andric _LIBUNWIND_EXPORT _Unwind_Reason_Code 3360b57cec5SDimitry Andric _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) { 3370b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)", 3380b57cec5SDimitry Andric (void *)exception_object); 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right 3410b57cec5SDimitry Andric // thing 3420b57cec5SDimitry Andric exception_object->private_1 = 0; 3430b57cec5SDimitry Andric exception_object->private_2 = 0; 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric // phase 1: the search phase 3460b57cec5SDimitry Andric _Unwind_Reason_Code phase1 = unwind_phase1(exception_object); 3470b57cec5SDimitry Andric if (phase1 != _URC_NO_REASON) 3480b57cec5SDimitry Andric return phase1; 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric // phase 2: the clean up phase 3510b57cec5SDimitry Andric return unwind_phase2(exception_object); 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric /// When _Unwind_RaiseException() is in phase2, it hands control 3570b57cec5SDimitry Andric /// to the personality function at each frame. The personality 3580b57cec5SDimitry Andric /// may force a jump to a landing pad in that function, the landing 3590b57cec5SDimitry Andric /// pad code may then call _Unwind_Resume() to continue with the 3600b57cec5SDimitry Andric /// unwinding. Note: the call to _Unwind_Resume() is from compiler 361bdd1243dSDimitry Andric /// generated user code. All other _Unwind_* routines are called 3620b57cec5SDimitry Andric /// by the C++ runtime __cxa_* routines. 3630b57cec5SDimitry Andric /// 3640b57cec5SDimitry Andric /// Re-throwing an exception is implemented by having the code call 3650b57cec5SDimitry Andric /// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow() 3660b57cec5SDimitry Andric _LIBUNWIND_EXPORT void 3670b57cec5SDimitry Andric _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) { 3680b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)", 3690b57cec5SDimitry Andric (void *)exception_object); 3700b57cec5SDimitry Andric 3710b57cec5SDimitry Andric if (exception_object->private_1 != 0) 3720b57cec5SDimitry Andric unwind_phase2_forced(exception_object, 3730b57cec5SDimitry Andric (_Unwind_Stop_Fn) exception_object->private_1, 3740b57cec5SDimitry Andric (void *)exception_object->private_2); 3750b57cec5SDimitry Andric else 3760b57cec5SDimitry Andric unwind_phase2(exception_object); 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric // clients assume _Unwind_Resume() does not return, so all we can do is abort. 3790b57cec5SDimitry Andric _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return"); 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric 3830b57cec5SDimitry Andric /// Called by __cxa_rethrow(). 3840b57cec5SDimitry Andric _LIBUNWIND_EXPORT _Unwind_Reason_Code 3850b57cec5SDimitry Andric _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) { 3860b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), " 3870b57cec5SDimitry Andric "private_1=%" PRIuPTR, 3880b57cec5SDimitry Andric (void *)exception_object, exception_object->private_1); 3890b57cec5SDimitry Andric // If this is non-forced and a stopping place was found, then this is a 3900b57cec5SDimitry Andric // re-throw. 3910b57cec5SDimitry Andric // Call _Unwind_RaiseException() as if this was a new exception. 3920b57cec5SDimitry Andric if (exception_object->private_1 == 0) { 3930b57cec5SDimitry Andric return _Unwind_SjLj_RaiseException(exception_object); 3940b57cec5SDimitry Andric // should return if there is no catch clause, so that __cxa_rethrow can call 3950b57cec5SDimitry Andric // std::terminate() 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric 398bdd1243dSDimitry Andric // Call through to _Unwind_Resume() which distinguishes between forced and 3990b57cec5SDimitry Andric // regular exceptions. 4000b57cec5SDimitry Andric _Unwind_SjLj_Resume(exception_object); 4010b57cec5SDimitry Andric _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called " 4020b57cec5SDimitry Andric "_Unwind_SjLj_Resume() which unexpectedly returned"); 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric /// Called by personality handler during phase 2 to get LSDA for current frame. 4070b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t 4080b57cec5SDimitry Andric _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { 4090b57cec5SDimitry Andric _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; 4100b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) " 4110b57cec5SDimitry Andric "=> 0x%" PRIuPTR, 4120b57cec5SDimitry Andric (void *)context, ufc->lsda); 4130b57cec5SDimitry Andric return ufc->lsda; 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric /// Called by personality handler during phase 2 to get register values. 4180b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, 4190b57cec5SDimitry Andric int index) { 4200b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context, 4210b57cec5SDimitry Andric index); 4220b57cec5SDimitry Andric _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; 4230b57cec5SDimitry Andric return ufc->resumeParameters[index]; 4240b57cec5SDimitry Andric } 4250b57cec5SDimitry Andric 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric /// Called by personality handler during phase 2 to alter register values. 4280b57cec5SDimitry Andric _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, 4290b57cec5SDimitry Andric uintptr_t new_value) { 430*5f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIxPTR 4310b57cec5SDimitry Andric ")", 4320b57cec5SDimitry Andric (void *)context, index, new_value); 4330b57cec5SDimitry Andric _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; 4340b57cec5SDimitry Andric ufc->resumeParameters[index] = new_value; 4350b57cec5SDimitry Andric } 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric /// Called by personality handler during phase 2 to get instruction pointer. 4390b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { 4400b57cec5SDimitry Andric _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; 441*5f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, 4420b57cec5SDimitry Andric (void *)context, ufc->resumeLocation + 1); 4430b57cec5SDimitry Andric return ufc->resumeLocation + 1; 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric /// Called by personality handler during phase 2 to get instruction pointer. 4480b57cec5SDimitry Andric /// ipBefore is a boolean that says if IP is already adjusted to be the call 4490b57cec5SDimitry Andric /// site address. Normally IP is the return address. 4500b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, 4510b57cec5SDimitry Andric int *ipBefore) { 4520b57cec5SDimitry Andric _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; 4530b57cec5SDimitry Andric *ipBefore = 0; 454*5f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIxPTR, 4550b57cec5SDimitry Andric (void *)context, (void *)ipBefore, 4560b57cec5SDimitry Andric ufc->resumeLocation + 1); 4570b57cec5SDimitry Andric return ufc->resumeLocation + 1; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric /// Called by personality handler during phase 2 to alter instruction pointer. 4620b57cec5SDimitry Andric _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, 4630b57cec5SDimitry Andric uintptr_t new_value) { 464*5f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIxPTR ")", 4650b57cec5SDimitry Andric (void *)context, new_value); 4660b57cec5SDimitry Andric _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; 4670b57cec5SDimitry Andric ufc->resumeLocation = new_value - 1; 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric /// Called by personality handler during phase 2 to find the start of the 4720b57cec5SDimitry Andric /// function. 4730b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t 4740b57cec5SDimitry Andric _Unwind_GetRegionStart(struct _Unwind_Context *context) { 4750b57cec5SDimitry Andric // Not supported or needed for sjlj based unwinding 4760b57cec5SDimitry Andric (void)context; 4770b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context); 4780b57cec5SDimitry Andric return 0; 4790b57cec5SDimitry Andric } 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric /// Called by personality handler during phase 2 if a foreign exception 4830b57cec5SDimitry Andric /// is caught. 4840b57cec5SDimitry Andric _LIBUNWIND_EXPORT void 4850b57cec5SDimitry Andric _Unwind_DeleteException(struct _Unwind_Exception *exception_object) { 4860b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", 4870b57cec5SDimitry Andric (void *)exception_object); 4880b57cec5SDimitry Andric if (exception_object->exception_cleanup != NULL) 4890b57cec5SDimitry Andric (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, 4900b57cec5SDimitry Andric exception_object); 4910b57cec5SDimitry Andric } 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric 4950b57cec5SDimitry Andric /// Called by personality handler during phase 2 to get base address for data 4960b57cec5SDimitry Andric /// relative encodings. 4970b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t 4980b57cec5SDimitry Andric _Unwind_GetDataRelBase(struct _Unwind_Context *context) { 4990b57cec5SDimitry Andric // Not supported or needed for sjlj based unwinding 5000b57cec5SDimitry Andric (void)context; 5010b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context); 5020b57cec5SDimitry Andric _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); 5030b57cec5SDimitry Andric } 5040b57cec5SDimitry Andric 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric /// Called by personality handler during phase 2 to get base address for text 5070b57cec5SDimitry Andric /// relative encodings. 5080b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t 5090b57cec5SDimitry Andric _Unwind_GetTextRelBase(struct _Unwind_Context *context) { 5100b57cec5SDimitry Andric // Not supported or needed for sjlj based unwinding 5110b57cec5SDimitry Andric (void)context; 5120b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context); 5130b57cec5SDimitry Andric _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric /// Called by personality handler to get "Call Frame Area" for current frame. 5180b57cec5SDimitry Andric _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { 5190b57cec5SDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context); 5200b57cec5SDimitry Andric if (context != NULL) { 5210b57cec5SDimitry Andric _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; 5220b57cec5SDimitry Andric // Setjmp/longjmp based exceptions don't have a true CFA. 5230b57cec5SDimitry Andric // Instead, the SP in the jmpbuf is the closest approximation. 5240b57cec5SDimitry Andric return (uintptr_t) ufc->jbuf[2]; 5250b57cec5SDimitry Andric } 5260b57cec5SDimitry Andric return 0; 5270b57cec5SDimitry Andric } 5280b57cec5SDimitry Andric 5290b57cec5SDimitry Andric #endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS) 530