brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.2 KiB · a3551b3 Raw
530 lines · c
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//8//  Implements setjump-longjump based C++ exceptions9//10//===----------------------------------------------------------------------===//11 12#include <unwind.h>13 14#include <inttypes.h>15#include <stdint.h>16#include <stdbool.h>17#include <stdlib.h>18 19#include "config.h"20 21/// With SJLJ based exceptions, any function that has a catch clause or needs to22/// do any clean up when an exception propagates through it, needs to call23/// \c _Unwind_SjLj_Register at the start of the function and24/// \c _Unwind_SjLj_Unregister at the end.  The register function is called with25/// the address of a block of memory in the function's stack frame.  The runtime26/// keeps a linked list (stack) of these blocks - one per thread.  The calling27/// function also sets the personality and lsda fields of the block.28 29#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)30 31struct _Unwind_FunctionContext {32  // next function in stack of handlers33  struct _Unwind_FunctionContext *prev;34 35#if defined(__ve__)36  // VE requires to store 64 bit pointers in the buffer for SjLj exception.37  // We expand the size of values defined here.  This size must be matched38  // to the size returned by TargetMachine::getSjLjDataSize().39 40  // set by calling function before registering to be the landing pad41  uint64_t                        resumeLocation;42 43  // set by personality handler to be parameters passed to landing pad function44  uint64_t                        resumeParameters[4];45#else46  // set by calling function before registering to be the landing pad47  uint32_t                        resumeLocation;48 49  // set by personality handler to be parameters passed to landing pad function50  uint32_t                        resumeParameters[4];51#endif52 53  // set by calling function before registering54  _Unwind_Personality_Fn personality;          // arm offset=2455  uintptr_t                       lsda;        // arm offset=2856 57  // variable length array, contains registers to restore58  // 0 = r7, 1 = pc, 2 = sp59  void                           *jbuf[];60};61 62#if defined(_LIBUNWIND_HAS_NO_THREADS)63# define _LIBUNWIND_THREAD_LOCAL64#else65# if __STDC_VERSION__ >= 201112L66#  define _LIBUNWIND_THREAD_LOCAL _Thread_local67# elif defined(_MSC_VER)68#  define _LIBUNWIND_THREAD_LOCAL __declspec(thread)69# elif defined(__GNUC__) || defined(__clang__)70#  define _LIBUNWIND_THREAD_LOCAL __thread71# else72#  error Unable to create thread local storage73# endif74#endif75 76 77#if !defined(FOR_DYLD)78 79#if defined(__APPLE__)80#include <System/pthread_machdep.h>81#else82static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL;83#endif84 85static struct _Unwind_FunctionContext *86__Unwind_SjLj_GetTopOfFunctionStack(void) {87#if defined(__APPLE__)88  return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);89#else90  return stack;91#endif92}93 94static void95__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {96#if defined(__APPLE__)97  _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);98#else99  stack = fc;100#endif101}102 103#endif104 105 106/// Called at start of each function that catches exceptions107_LIBUNWIND_EXPORT void108_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) {109  fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();110  __Unwind_SjLj_SetTopOfFunctionStack(fc);111}112 113 114/// Called at end of each function that catches exceptions115_LIBUNWIND_EXPORT void116_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {117  __Unwind_SjLj_SetTopOfFunctionStack(fc->prev);118}119 120 121static _Unwind_Reason_Code122unwind_phase1(struct _Unwind_Exception *exception_object) {123  _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();124  _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p",125                             (void *)c);126 127  // walk each frame looking for a place to stop128  for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {129 130    // check for no more frames131    if (c == NULL) {132      _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "133                                 "bottom => _URC_END_OF_STACK",134                                 (void *)exception_object);135      return _URC_END_OF_STACK;136    }137 138    _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", (void *)c);139    // if there is a personality routine, ask it if it will want to stop at this140    // frame141    if (c->personality != NULL) {142      _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling "143                                 "personality function %p",144                                 (void *)exception_object,145                                 (void *)c->personality);146      _Unwind_Reason_Code personalityResult = (*c->personality)(147          1, _UA_SEARCH_PHASE, exception_object->exception_class,148          exception_object, (struct _Unwind_Context *)c);149      switch (personalityResult) {150      case _URC_HANDLER_FOUND:151        // found a catch clause or locals that need destructing in this frame152        // stop search and remember function context153        handlerNotFound = false;154        exception_object->private_2 = (uintptr_t) c;155        _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "156                                   "_URC_HANDLER_FOUND",157                                   (void *)exception_object);158        return _URC_NO_REASON;159 160      case _URC_CONTINUE_UNWIND:161        _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "162                                   "_URC_CONTINUE_UNWIND",163                                   (void *)exception_object);164        // continue unwinding165        break;166 167      default:168        // something went wrong169        _LIBUNWIND_TRACE_UNWINDING(170            "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",171            (void *)exception_object);172        return _URC_FATAL_PHASE1_ERROR;173      }174    }175  }176  return _URC_NO_REASON;177}178 179 180static _Unwind_Reason_Code181unwind_phase2(struct _Unwind_Exception *exception_object) {182  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",183                             (void *)exception_object);184 185  // walk each frame until we reach where search phase said to stop186  _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();187  while (true) {188    _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p",189                               (void *)exception_object, (void *)c);190 191    // check for no more frames192    if (c == NULL) {193      _LIBUNWIND_TRACE_UNWINDING(194          "unwind_phase2(ex_ojb=%p): __unw_step() reached "195          "bottom => _URC_END_OF_STACK",196          (void *)exception_object);197      return _URC_END_OF_STACK;198    }199 200    // if there is a personality routine, tell it we are unwinding201    if (c->personality != NULL) {202      _Unwind_Action action = _UA_CLEANUP_PHASE;203      if ((uintptr_t) c == exception_object->private_2)204        action = (_Unwind_Action)(205            _UA_CLEANUP_PHASE |206            _UA_HANDLER_FRAME); // tell personality this was the frame it marked207                                // in phase 1208      _Unwind_Reason_Code personalityResult =209          (*c->personality)(1, action, exception_object->exception_class,210                            exception_object, (struct _Unwind_Context *)c);211      switch (personalityResult) {212      case _URC_CONTINUE_UNWIND:213        // continue unwinding214        _LIBUNWIND_TRACE_UNWINDING(215            "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",216            (void *)exception_object);217        if ((uintptr_t) c == exception_object->private_2) {218          // phase 1 said we would stop at this frame, but we did not...219          _LIBUNWIND_ABORT("during phase1 personality function said it would "220                           "stop here, but now if phase2 it did not stop here");221        }222        break;223      case _URC_INSTALL_CONTEXT:224        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "225                                   "_URC_INSTALL_CONTEXT, will resume at "226                                   "landing pad %p",227                                   (void *)exception_object, c->jbuf[1]);228        // personality routine says to transfer control to landing pad229        // we may get control back if landing pad calls _Unwind_Resume()230        __Unwind_SjLj_SetTopOfFunctionStack(c);231        __builtin_longjmp(c->jbuf, 1);232        // __unw_resume() only returns if there was an error233        return _URC_FATAL_PHASE2_ERROR;234      default:235        // something went wrong236        _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",237                      personalityResult);238        return _URC_FATAL_PHASE2_ERROR;239      }240    }241    c = c->prev;242  }243 244  // clean up phase did not resume at the frame that the search phase said it245  // would246  return _URC_FATAL_PHASE2_ERROR;247}248 249 250static _Unwind_Reason_Code251unwind_phase2_forced(struct _Unwind_Exception *exception_object,252                     _Unwind_Stop_Fn stop, void *stop_parameter) {253  // walk each frame until we reach where search phase said to stop254  _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();255  while (true) {256 257    // get next frame (skip over first which is _Unwind_RaiseException)258    if (c == NULL) {259      _LIBUNWIND_TRACE_UNWINDING(260          "unwind_phase2(ex_ojb=%p): __unw_step() reached "261          "bottom => _URC_END_OF_STACK",262          (void *)exception_object);263      return _URC_END_OF_STACK;264    }265 266    // call stop function at each frame267    _Unwind_Action action =268        (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);269    _Unwind_Reason_Code stopResult =270        (*stop)(1, action, exception_object->exception_class, exception_object,271                (struct _Unwind_Context *)c, stop_parameter);272    _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "273                               "stop function returned %d",274                               (void *)exception_object, stopResult);275    if (stopResult != _URC_NO_REASON) {276      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "277                                 "stopped by stop function",278                                 (void *)exception_object);279      return _URC_FATAL_PHASE2_ERROR;280    }281 282    // if there is a personality routine, tell it we are unwinding283    if (c->personality != NULL) {284      _Unwind_Personality_Fn p = (_Unwind_Personality_Fn)c->personality;285      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "286                                 "calling personality function %p",287                                 (void *)exception_object, (void *)p);288      _Unwind_Reason_Code personalityResult =289          (*p)(1, action, exception_object->exception_class, exception_object,290               (struct _Unwind_Context *)c);291      switch (personalityResult) {292      case _URC_CONTINUE_UNWIND:293        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p):  "294                                   "personality returned _URC_CONTINUE_UNWIND",295                                   (void *)exception_object);296        // destructors called, continue unwinding297        break;298      case _URC_INSTALL_CONTEXT:299        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "300                                   "personality returned _URC_INSTALL_CONTEXT",301                                   (void *)exception_object);302        // we may get control back if landing pad calls _Unwind_Resume()303        __Unwind_SjLj_SetTopOfFunctionStack(c);304        __builtin_longjmp(c->jbuf, 1);305        break;306      default:307        // something went wrong308        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "309                                   "personality returned %d, "310                                   "_URC_FATAL_PHASE2_ERROR",311                                   (void *)exception_object, personalityResult);312        return _URC_FATAL_PHASE2_ERROR;313      }314    }315    c = c->prev;316  }317 318  // call stop function one last time and tell it we've reached the end of the319  // stack320  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "321                             "function with _UA_END_OF_STACK",322                             (void *)exception_object);323  _Unwind_Action lastAction =324      (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);325  (*stop)(1, lastAction, exception_object->exception_class, exception_object,326          (struct _Unwind_Context *)c, stop_parameter);327 328  // clean up phase did not resume at the frame that the search phase said it329  // would330  return _URC_FATAL_PHASE2_ERROR;331}332 333 334/// Called by __cxa_throw.  Only returns if there is a fatal error335_LIBUNWIND_EXPORT _Unwind_Reason_Code336_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {337  _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)",338                       (void *)exception_object);339 340  // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right341  // thing342  exception_object->private_1 = 0;343  exception_object->private_2 = 0;344 345  // phase 1: the search phase346  _Unwind_Reason_Code phase1 = unwind_phase1(exception_object);347  if (phase1 != _URC_NO_REASON)348    return phase1;349 350  // phase 2: the clean up phase351  return unwind_phase2(exception_object);352}353 354 355 356/// When _Unwind_RaiseException() is in phase2, it hands control357/// to the personality function at each frame.  The personality358/// may force a jump to a landing pad in that function, the landing359/// pad code may then call _Unwind_Resume() to continue with the360/// unwinding.  Note: the call to _Unwind_Resume() is from compiler361/// generated user code.  All other _Unwind_* routines are called362/// by the C++ runtime __cxa_* routines.363///364/// Re-throwing an exception is implemented by having the code call365/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()366_LIBUNWIND_EXPORT void367_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {368  _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)",369                       (void *)exception_object);370 371  if (exception_object->private_1 != 0)372    unwind_phase2_forced(exception_object,373                         (_Unwind_Stop_Fn) exception_object->private_1,374                         (void *)exception_object->private_2);375  else376    unwind_phase2(exception_object);377 378  // clients assume _Unwind_Resume() does not return, so all we can do is abort.379  _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return");380}381 382 383///  Called by __cxa_rethrow().384_LIBUNWIND_EXPORT _Unwind_Reason_Code385_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {386  _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), "387                       "private_1=%" PRIuPTR,388                       (void *)exception_object, exception_object->private_1);389  // If this is non-forced and a stopping place was found, then this is a390  // re-throw.391  // Call _Unwind_RaiseException() as if this was a new exception.392  if (exception_object->private_1 == 0) {393    return _Unwind_SjLj_RaiseException(exception_object);394    // should return if there is no catch clause, so that __cxa_rethrow can call395    // std::terminate()396  }397 398  // Call through to _Unwind_Resume() which distinguishes between forced and399  // regular exceptions.400  _Unwind_SjLj_Resume(exception_object);401  _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "402                    "_Unwind_SjLj_Resume() which unexpectedly returned");403}404 405 406/// Called by personality handler during phase 2 to get LSDA for current frame.407_LIBUNWIND_EXPORT uintptr_t408_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {409  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;410  _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) "411                       "=> 0x%" PRIxPTR,412                       (void *)context, ufc->lsda);413  return ufc->lsda;414}415 416 417/// Called by personality handler during phase 2 to get register values.418_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,419                                          int index) {420  _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context,421                       index);422  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;423  return ufc->resumeParameters[index];424}425 426 427/// Called by personality handler during phase 2 to alter register values.428_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,429                                     uintptr_t new_value) {430  _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%" PRIxPTR431                       ")",432                       (void *)context, index, new_value);433  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;434  ufc->resumeParameters[index] = new_value;435}436 437 438/// Called by personality handler during phase 2 to get instruction pointer.439_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {440  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;441  _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,442                       (void *)context, ufc->resumeLocation + 1);443  return ufc->resumeLocation + 1;444}445 446 447/// Called by personality handler during phase 2 to get instruction pointer.448/// ipBefore is a boolean that says if IP is already adjusted to be the call449/// site address.  Normally IP is the return address.450_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,451                                              int *ipBefore) {452  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;453  *ipBefore = 0;454  _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIxPTR,455                       (void *)context, (void *)ipBefore,456                       ufc->resumeLocation + 1);457  return ufc->resumeLocation + 1;458}459 460 461/// Called by personality handler during phase 2 to alter instruction pointer.462_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,463                                     uintptr_t new_value) {464  _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIxPTR ")",465                       (void *)context, new_value);466  _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;467  ufc->resumeLocation = new_value - 1;468}469 470 471/// Called by personality handler during phase 2 to find the start of the472/// function.473_LIBUNWIND_EXPORT uintptr_t474_Unwind_GetRegionStart(struct _Unwind_Context *context) {475  // Not supported or needed for sjlj based unwinding476  (void)context;477  _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", (void *)context);478  return 0;479}480 481 482/// Called by personality handler during phase 2 if a foreign exception483/// is caught.484_LIBUNWIND_EXPORT void485_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {486  _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",487                       (void *)exception_object);488  if (exception_object->exception_cleanup != NULL)489    (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,490                                           exception_object);491}492 493 494 495/// Called by personality handler during phase 2 to get base address for data496/// relative encodings.497_LIBUNWIND_EXPORT uintptr_t498_Unwind_GetDataRelBase(struct _Unwind_Context *context) {499  // Not supported or needed for sjlj based unwinding500  (void)context;501  _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);502  _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");503}504 505 506/// Called by personality handler during phase 2 to get base address for text507/// relative encodings.508_LIBUNWIND_EXPORT uintptr_t509_Unwind_GetTextRelBase(struct _Unwind_Context *context) {510  // Not supported or needed for sjlj based unwinding511  (void)context;512  _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);513  _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");514}515 516 517/// Called by personality handler to get "Call Frame Area" for current frame.518_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {519  _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", (void *)context);520  if (context != NULL) {521    _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;522    // Setjmp/longjmp based exceptions don't have a true CFA.523    // Instead, the SP in the jmpbuf is the closest approximation.524    return (uintptr_t) ufc->jbuf[2];525  }526  return 0;527}528 529#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)530