Path: blob/main/contrib/llvm-project/libunwind/src/Unwind-sjlj.c
35148 views
//===----------------------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//7// Implements setjump-longjump based C++ exceptions8//9//===----------------------------------------------------------------------===//1011#include <unwind.h>1213#include <inttypes.h>14#include <stdint.h>15#include <stdbool.h>16#include <stdlib.h>1718#include "config.h"1920/// With SJLJ based exceptions, any function that has a catch clause or needs to21/// do any clean up when an exception propagates through it, needs to call22/// \c _Unwind_SjLj_Register at the start of the function and23/// \c _Unwind_SjLj_Unregister at the end. The register function is called with24/// the address of a block of memory in the function's stack frame. The runtime25/// keeps a linked list (stack) of these blocks - one per thread. The calling26/// function also sets the personality and lsda fields of the block.2728#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)2930struct _Unwind_FunctionContext {31// next function in stack of handlers32struct _Unwind_FunctionContext *prev;3334#if defined(__ve__)35// VE requires to store 64 bit pointers in the buffer for SjLj exception.36// We expand the size of values defined here. This size must be matched37// to the size returned by TargetMachine::getSjLjDataSize().3839// set by calling function before registering to be the landing pad40uint64_t resumeLocation;4142// set by personality handler to be parameters passed to landing pad function43uint64_t resumeParameters[4];44#else45// set by calling function before registering to be the landing pad46uint32_t resumeLocation;4748// set by personality handler to be parameters passed to landing pad function49uint32_t resumeParameters[4];50#endif5152// set by calling function before registering53_Unwind_Personality_Fn personality; // arm offset=2454uintptr_t lsda; // arm offset=285556// variable length array, contains registers to restore57// 0 = r7, 1 = pc, 2 = sp58void *jbuf[];59};6061#if defined(_LIBUNWIND_HAS_NO_THREADS)62# define _LIBUNWIND_THREAD_LOCAL63#else64# if __STDC_VERSION__ >= 201112L65# define _LIBUNWIND_THREAD_LOCAL _Thread_local66# elif defined(_MSC_VER)67# define _LIBUNWIND_THREAD_LOCAL __declspec(thread)68# elif defined(__GNUC__) || defined(__clang__)69# define _LIBUNWIND_THREAD_LOCAL __thread70# else71# error Unable to create thread local storage72# endif73#endif747576#if !defined(FOR_DYLD)7778#if defined(__APPLE__)79#include <System/pthread_machdep.h>80#else81static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL;82#endif8384static struct _Unwind_FunctionContext *85__Unwind_SjLj_GetTopOfFunctionStack(void) {86#if defined(__APPLE__)87return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);88#else89return stack;90#endif91}9293static void94__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {95#if defined(__APPLE__)96_pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);97#else98stack = fc;99#endif100}101102#endif103104105/// Called at start of each function that catches exceptions106_LIBUNWIND_EXPORT void107_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) {108fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();109__Unwind_SjLj_SetTopOfFunctionStack(fc);110}111112113/// Called at end of each function that catches exceptions114_LIBUNWIND_EXPORT void115_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {116__Unwind_SjLj_SetTopOfFunctionStack(fc->prev);117}118119120static _Unwind_Reason_Code121unwind_phase1(struct _Unwind_Exception *exception_object) {122_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();123_LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p",124(void *)c);125126// walk each frame looking for a place to stop127for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {128129// check for no more frames130if (c == NULL) {131_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "132"bottom => _URC_END_OF_STACK",133(void *)exception_object);134return _URC_END_OF_STACK;135}136137_LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c);138// if there is a personality routine, ask it if it will want to stop at this139// frame140if (c->personality != NULL) {141_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling "142"personality function %p",143(void *)exception_object,144(void *)c->personality);145_Unwind_Reason_Code personalityResult = (*c->personality)(1461, _UA_SEARCH_PHASE, exception_object->exception_class,147exception_object, (struct _Unwind_Context *)c);148switch (personalityResult) {149case _URC_HANDLER_FOUND:150// found a catch clause or locals that need destructing in this frame151// stop search and remember function context152handlerNotFound = false;153exception_object->private_2 = (uintptr_t) c;154_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "155"_URC_HANDLER_FOUND",156(void *)exception_object);157return _URC_NO_REASON;158159case _URC_CONTINUE_UNWIND:160_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "161"_URC_CONTINUE_UNWIND",162(void *)exception_object);163// continue unwinding164break;165166default:167// something went wrong168_LIBUNWIND_TRACE_UNWINDING(169"unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",170(void *)exception_object);171return _URC_FATAL_PHASE1_ERROR;172}173}174}175return _URC_NO_REASON;176}177178179static _Unwind_Reason_Code180unwind_phase2(struct _Unwind_Exception *exception_object) {181_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",182(void *)exception_object);183184// walk each frame until we reach where search phase said to stop185_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();186while (true) {187_LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p",188(void *)exception_object, (void *)c);189190// check for no more frames191if (c == NULL) {192_LIBUNWIND_TRACE_UNWINDING(193"unwind_phase2(ex_ojb=%p): __unw_step() reached "194"bottom => _URC_END_OF_STACK",195(void *)exception_object);196return _URC_END_OF_STACK;197}198199// if there is a personality routine, tell it we are unwinding200if (c->personality != NULL) {201_Unwind_Action action = _UA_CLEANUP_PHASE;202if ((uintptr_t) c == exception_object->private_2)203action = (_Unwind_Action)(204_UA_CLEANUP_PHASE |205_UA_HANDLER_FRAME); // tell personality this was the frame it marked206// in phase 1207_Unwind_Reason_Code personalityResult =208(*c->personality)(1, action, exception_object->exception_class,209exception_object, (struct _Unwind_Context *)c);210switch (personalityResult) {211case _URC_CONTINUE_UNWIND:212// continue unwinding213_LIBUNWIND_TRACE_UNWINDING(214"unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",215(void *)exception_object);216if ((uintptr_t) c == exception_object->private_2) {217// phase 1 said we would stop at this frame, but we did not...218_LIBUNWIND_ABORT("during phase1 personality function said it would "219"stop here, but now if phase2 it did not stop here");220}221break;222case _URC_INSTALL_CONTEXT:223_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "224"_URC_INSTALL_CONTEXT, will resume at "225"landing pad %p",226(void *)exception_object, c->jbuf[1]);227// personality routine says to transfer control to landing pad228// we may get control back if landing pad calls _Unwind_Resume()229__Unwind_SjLj_SetTopOfFunctionStack(c);230__builtin_longjmp(c->jbuf, 1);231// __unw_resume() only returns if there was an error232return _URC_FATAL_PHASE2_ERROR;233default:234// something went wrong235_LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",236personalityResult);237return _URC_FATAL_PHASE2_ERROR;238}239}240c = c->prev;241}242243// clean up phase did not resume at the frame that the search phase said it244// would245return _URC_FATAL_PHASE2_ERROR;246}247248249static _Unwind_Reason_Code250unwind_phase2_forced(struct _Unwind_Exception *exception_object,251_Unwind_Stop_Fn stop, void *stop_parameter) {252// walk each frame until we reach where search phase said to stop253_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();254while (true) {255256// get next frame (skip over first which is _Unwind_RaiseException)257if (c == NULL) {258_LIBUNWIND_TRACE_UNWINDING(259"unwind_phase2(ex_ojb=%p): __unw_step() reached "260"bottom => _URC_END_OF_STACK",261(void *)exception_object);262return _URC_END_OF_STACK;263}264265// call stop function at each frame266_Unwind_Action action =267(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);268_Unwind_Reason_Code stopResult =269(*stop)(1, action, exception_object->exception_class, exception_object,270(struct _Unwind_Context *)c, stop_parameter);271_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "272"stop function returned %d",273(void *)exception_object, stopResult);274if (stopResult != _URC_NO_REASON) {275_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "276"stopped by stop function",277(void *)exception_object);278return _URC_FATAL_PHASE2_ERROR;279}280281// if there is a personality routine, tell it we are unwinding282if (c->personality != NULL) {283_Unwind_Personality_Fn p = (_Unwind_Personality_Fn)c->personality;284_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "285"calling personality function %p",286(void *)exception_object, (void *)p);287_Unwind_Reason_Code personalityResult =288(*p)(1, action, exception_object->exception_class, exception_object,289(struct _Unwind_Context *)c);290switch (personalityResult) {291case _URC_CONTINUE_UNWIND:292_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "293"personality returned _URC_CONTINUE_UNWIND",294(void *)exception_object);295// destructors called, continue unwinding296break;297case _URC_INSTALL_CONTEXT:298_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "299"personality returned _URC_INSTALL_CONTEXT",300(void *)exception_object);301// we may get control back if landing pad calls _Unwind_Resume()302__Unwind_SjLj_SetTopOfFunctionStack(c);303__builtin_longjmp(c->jbuf, 1);304break;305default:306// something went wrong307_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "308"personality returned %d, "309"_URC_FATAL_PHASE2_ERROR",310(void *)exception_object, personalityResult);311return _URC_FATAL_PHASE2_ERROR;312}313}314c = c->prev;315}316317// call stop function one last time and tell it we've reached the end of the318// stack319_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "320"function with _UA_END_OF_STACK",321(void *)exception_object);322_Unwind_Action lastAction =323(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);324(*stop)(1, lastAction, exception_object->exception_class, exception_object,325(struct _Unwind_Context *)c, stop_parameter);326327// clean up phase did not resume at the frame that the search phase said it328// would329return _URC_FATAL_PHASE2_ERROR;330}331332333/// Called by __cxa_throw. Only returns if there is a fatal error334_LIBUNWIND_EXPORT _Unwind_Reason_Code335_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {336_LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)",337(void *)exception_object);338339// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right340// thing341exception_object->private_1 = 0;342exception_object->private_2 = 0;343344// phase 1: the search phase345_Unwind_Reason_Code phase1 = unwind_phase1(exception_object);346if (phase1 != _URC_NO_REASON)347return phase1;348349// phase 2: the clean up phase350return unwind_phase2(exception_object);351}352353354355/// When _Unwind_RaiseException() is in phase2, it hands control356/// to the personality function at each frame. The personality357/// may force a jump to a landing pad in that function, the landing358/// pad code may then call _Unwind_Resume() to continue with the359/// unwinding. Note: the call to _Unwind_Resume() is from compiler360/// generated user code. All other _Unwind_* routines are called361/// by the C++ runtime __cxa_* routines.362///363/// Re-throwing an exception is implemented by having the code call364/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()365_LIBUNWIND_EXPORT void366_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {367_LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)",368(void *)exception_object);369370if (exception_object->private_1 != 0)371unwind_phase2_forced(exception_object,372(_Unwind_Stop_Fn) exception_object->private_1,373(void *)exception_object->private_2);374else375unwind_phase2(exception_object);376377// clients assume _Unwind_Resume() does not return, so all we can do is abort.378_LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return");379}380381382/// Called by __cxa_rethrow().383_LIBUNWIND_EXPORT _Unwind_Reason_Code384_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {385_LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), "386"private_1=%" PRIuPTR,387(void *)exception_object, exception_object->private_1);388// If this is non-forced and a stopping place was found, then this is a389// re-throw.390// Call _Unwind_RaiseException() as if this was a new exception.391if (exception_object->private_1 == 0) {392return _Unwind_SjLj_RaiseException(exception_object);393// should return if there is no catch clause, so that __cxa_rethrow can call394// std::terminate()395}396397// Call through to _Unwind_Resume() which distinguishes between forced and398// regular exceptions.399_Unwind_SjLj_Resume(exception_object);400_LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "401"_Unwind_SjLj_Resume() which unexpectedly returned");402}403404405/// Called by personality handler during phase 2 to get LSDA for current frame.406_LIBUNWIND_EXPORT uintptr_t407_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {408_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;409_LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) "410"=> 0x%" PRIuPTR,411(void *)context, ufc->lsda);412return ufc->lsda;413}414415416/// Called by personality handler during phase 2 to get register values.417_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,418int index) {419_LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context,420index);421_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;422return ufc->resumeParameters[index];423}424425426/// Called by personality handler during phase 2 to alter register values.427_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,428uintptr_t new_value) {429_LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIxPTR430")",431(void *)context, index, new_value);432_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;433ufc->resumeParameters[index] = new_value;434}435436437/// Called by personality handler during phase 2 to get instruction pointer.438_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {439_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;440_LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,441(void *)context, ufc->resumeLocation + 1);442return ufc->resumeLocation + 1;443}444445446/// Called by personality handler during phase 2 to get instruction pointer.447/// ipBefore is a boolean that says if IP is already adjusted to be the call448/// site address. Normally IP is the return address.449_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,450int *ipBefore) {451_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;452*ipBefore = 0;453_LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIxPTR,454(void *)context, (void *)ipBefore,455ufc->resumeLocation + 1);456return ufc->resumeLocation + 1;457}458459460/// Called by personality handler during phase 2 to alter instruction pointer.461_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,462uintptr_t new_value) {463_LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIxPTR ")",464(void *)context, new_value);465_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;466ufc->resumeLocation = new_value - 1;467}468469470/// Called by personality handler during phase 2 to find the start of the471/// function.472_LIBUNWIND_EXPORT uintptr_t473_Unwind_GetRegionStart(struct _Unwind_Context *context) {474// Not supported or needed for sjlj based unwinding475(void)context;476_LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context);477return 0;478}479480481/// Called by personality handler during phase 2 if a foreign exception482/// is caught.483_LIBUNWIND_EXPORT void484_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {485_LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",486(void *)exception_object);487if (exception_object->exception_cleanup != NULL)488(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,489exception_object);490}491492493494/// Called by personality handler during phase 2 to get base address for data495/// relative encodings.496_LIBUNWIND_EXPORT uintptr_t497_Unwind_GetDataRelBase(struct _Unwind_Context *context) {498// Not supported or needed for sjlj based unwinding499(void)context;500_LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);501_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");502}503504505/// Called by personality handler during phase 2 to get base address for text506/// relative encodings.507_LIBUNWIND_EXPORT uintptr_t508_Unwind_GetTextRelBase(struct _Unwind_Context *context) {509// Not supported or needed for sjlj based unwinding510(void)context;511_LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);512_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");513}514515516/// Called by personality handler to get "Call Frame Area" for current frame.517_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {518_LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context);519if (context != NULL) {520_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;521// Setjmp/longjmp based exceptions don't have a true CFA.522// Instead, the SP in the jmpbuf is the closest approximation.523return (uintptr_t) ufc->jbuf[2];524}525return 0;526}527528#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)529530531