1*8f1d5724Srobert //===----------------------------------------------------------------------===// 279c2e3e6Spatrick // 379c2e3e6Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 479c2e3e6Spatrick // See https://llvm.org/LICENSE.txt for license information. 579c2e3e6Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 679c2e3e6Spatrick // 779c2e3e6Spatrick // 879c2e3e6Spatrick // This file implements the storage for the "Caught Exception Stack" 979c2e3e6Spatrick // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-exc-stack 1079c2e3e6Spatrick // 1179c2e3e6Spatrick //===----------------------------------------------------------------------===// 1279c2e3e6Spatrick 1379c2e3e6Spatrick #include "cxa_exception.h" 1479c2e3e6Spatrick 1579c2e3e6Spatrick #include <__threading_support> 1679c2e3e6Spatrick 1779c2e3e6Spatrick #if defined(_LIBCXXABI_HAS_NO_THREADS) 1879c2e3e6Spatrick 1979c2e3e6Spatrick namespace __cxxabiv1 { 2079c2e3e6Spatrick extern "C" { 2179c2e3e6Spatrick static __cxa_eh_globals eh_globals; __cxa_get_globals()2279c2e3e6Spatrick __cxa_eh_globals *__cxa_get_globals() { return &eh_globals; } __cxa_get_globals_fast()2379c2e3e6Spatrick __cxa_eh_globals *__cxa_get_globals_fast() { return &eh_globals; } 24*8f1d5724Srobert } // extern "C" 25*8f1d5724Srobert } // namespace __cxxabiv1 2679c2e3e6Spatrick 2779c2e3e6Spatrick #elif defined(HAS_THREAD_LOCAL) 2879c2e3e6Spatrick 2979c2e3e6Spatrick namespace __cxxabiv1 { 3079c2e3e6Spatrick namespace { __globals()3179c2e3e6Spatrick __cxa_eh_globals *__globals() { 3279c2e3e6Spatrick static thread_local __cxa_eh_globals eh_globals; 3379c2e3e6Spatrick return &eh_globals; 3479c2e3e6Spatrick } 35*8f1d5724Srobert } // namespace 3679c2e3e6Spatrick 3779c2e3e6Spatrick extern "C" { __cxa_get_globals()3879c2e3e6Spatrick __cxa_eh_globals *__cxa_get_globals() { return __globals(); } __cxa_get_globals_fast()3979c2e3e6Spatrick __cxa_eh_globals *__cxa_get_globals_fast() { return __globals(); } 40*8f1d5724Srobert } // extern "C" 41*8f1d5724Srobert } // namespace __cxxabiv1 4279c2e3e6Spatrick 4379c2e3e6Spatrick #else 4479c2e3e6Spatrick 4579c2e3e6Spatrick #include "abort_message.h" 4679c2e3e6Spatrick #include "fallback_malloc.h" 4779c2e3e6Spatrick 4879c2e3e6Spatrick #if defined(__ELF__) && defined(_LIBCXXABI_LINK_PTHREAD_LIB) 4979c2e3e6Spatrick #pragma comment(lib, "pthread") 5079c2e3e6Spatrick #endif 5179c2e3e6Spatrick 5279c2e3e6Spatrick // In general, we treat all threading errors as fatal. 5379c2e3e6Spatrick // We cannot call std::terminate() because that will in turn 5479c2e3e6Spatrick // call __cxa_get_globals() and cause infinite recursion. 5579c2e3e6Spatrick 5679c2e3e6Spatrick namespace __cxxabiv1 { 5779c2e3e6Spatrick namespace { 5879c2e3e6Spatrick std::__libcpp_tls_key key_; 5979c2e3e6Spatrick std::__libcpp_exec_once_flag flag_ = _LIBCPP_EXEC_ONCE_INITIALIZER; 6079c2e3e6Spatrick destruct_(void * p)6179c2e3e6Spatrick void _LIBCPP_TLS_DESTRUCTOR_CC destruct_(void *p) { 6279c2e3e6Spatrick __free_with_fallback(p); 6379c2e3e6Spatrick if (0 != std::__libcpp_tls_set(key_, NULL)) 6479c2e3e6Spatrick abort_message("cannot zero out thread value for __cxa_get_globals()"); 6579c2e3e6Spatrick } 6679c2e3e6Spatrick construct_()6779c2e3e6Spatrick void construct_() { 6879c2e3e6Spatrick if (0 != std::__libcpp_tls_create(&key_, destruct_)) 6979c2e3e6Spatrick abort_message("cannot create thread specific key for __cxa_get_globals()"); 7079c2e3e6Spatrick } 71*8f1d5724Srobert } // namespace 7279c2e3e6Spatrick 7379c2e3e6Spatrick extern "C" { __cxa_get_globals()7479c2e3e6Spatrick __cxa_eh_globals *__cxa_get_globals() { 7579c2e3e6Spatrick // Try to get the globals for this thread 7679c2e3e6Spatrick __cxa_eh_globals *retVal = __cxa_get_globals_fast(); 7779c2e3e6Spatrick 7879c2e3e6Spatrick // If this is the first time we've been asked for these globals, create them 7979c2e3e6Spatrick if (NULL == retVal) { 80*8f1d5724Srobert retVal = static_cast<__cxa_eh_globals*>( 81*8f1d5724Srobert __calloc_with_fallback(1, sizeof(__cxa_eh_globals))); 8279c2e3e6Spatrick if (NULL == retVal) 8379c2e3e6Spatrick abort_message("cannot allocate __cxa_eh_globals"); 8479c2e3e6Spatrick if (0 != std::__libcpp_tls_set(key_, retVal)) 8579c2e3e6Spatrick abort_message("std::__libcpp_tls_set failure in __cxa_get_globals()"); 8679c2e3e6Spatrick } 8779c2e3e6Spatrick return retVal; 8879c2e3e6Spatrick } 8979c2e3e6Spatrick 9079c2e3e6Spatrick // Note that this implementation will reliably return NULL if not 9179c2e3e6Spatrick // preceded by a call to __cxa_get_globals(). This is an extension 9279c2e3e6Spatrick // to the Itanium ABI and is taken advantage of in several places in 9379c2e3e6Spatrick // libc++abi. __cxa_get_globals_fast()9479c2e3e6Spatrick __cxa_eh_globals *__cxa_get_globals_fast() { 9579c2e3e6Spatrick // First time through, create the key. 9679c2e3e6Spatrick if (0 != std::__libcpp_execute_once(&flag_, construct_)) 9779c2e3e6Spatrick abort_message("execute once failure in __cxa_get_globals_fast()"); 9879c2e3e6Spatrick return static_cast<__cxa_eh_globals*>(std::__libcpp_tls_get(key_)); 9979c2e3e6Spatrick } 100*8f1d5724Srobert } // extern "C" 101*8f1d5724Srobert } // namespace __cxxabiv1 10279c2e3e6Spatrick 10379c2e3e6Spatrick #endif 104