| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "cxxabi.h" |
|
|
| #include <exception> |
| #include <string.h> |
| #include "cxa_exception.h" |
| #include "cxa_handlers.h" |
| #include "fallback_malloc.h" |
| #include "include/atomic_support.h" |
|
|
| #if __has_feature(address_sanitizer) |
| #include <sanitizer/asan_interface.h> |
| #endif |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| namespace __cxxabiv1 { |
|
|
| |
| static |
| inline |
| __cxa_exception* |
| cxa_exception_from_thrown_object(void* thrown_object) |
| { |
| return static_cast<__cxa_exception*>(thrown_object) - 1; |
| } |
|
|
| |
| |
| static |
| inline |
| void* |
| thrown_object_from_cxa_exception(__cxa_exception* exception_header) |
| { |
| return static_cast<void*>(exception_header + 1); |
| } |
|
|
| |
| |
| |
| static |
| inline |
| __cxa_exception* |
| cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception) |
| { |
| return cxa_exception_from_thrown_object(unwind_exception + 1 ); |
| } |
|
|
| |
| static inline |
| size_t aligned_allocation_size(size_t s, size_t a) { |
| return (s + a - 1) & ~(a - 1); |
| } |
|
|
| static inline |
| size_t cxa_exception_size_from_exception_thrown_size(size_t size) { |
| return aligned_allocation_size(size + sizeof (__cxa_exception), |
| alignof(__cxa_exception)); |
| } |
|
|
| void __setExceptionClass(_Unwind_Exception* unwind_exception, uint64_t newValue) { |
| ::memcpy(&unwind_exception->exception_class, &newValue, sizeof(newValue)); |
| } |
|
|
|
|
| static void setOurExceptionClass(_Unwind_Exception* unwind_exception) { |
| __setExceptionClass(unwind_exception, kOurExceptionClass); |
| } |
|
|
| static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) { |
| __setExceptionClass(unwind_exception, kOurDependentExceptionClass); |
| } |
|
|
| |
| uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) { |
| |
| |
| |
| |
| uint64_t exClass; |
| ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass)); |
| return exClass; |
| } |
|
|
| bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) { |
| return (__getExceptionClass(unwind_exception) & get_vendor_and_language) == |
| (kOurExceptionClass & get_vendor_and_language); |
| } |
|
|
| static bool isDependentException(_Unwind_Exception* unwind_exception) { |
| return (__getExceptionClass(unwind_exception) & 0xFF) == 0x01; |
| } |
|
|
| |
| static inline int incrementHandlerCount(__cxa_exception *exception) { |
| return ++exception->handlerCount; |
| } |
|
|
| |
| static inline int decrementHandlerCount(__cxa_exception *exception) { |
| return --exception->handlerCount; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static |
| void |
| exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) |
| { |
| __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception); |
| if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) |
| std::__terminate(exception_header->terminateHandler); |
| |
| |
| __cxa_decrement_exception_refcount(unwind_exception + 1); |
| } |
|
|
| static _LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { |
| |
| |
| |
| |
| |
| |
| |
| (void) __cxa_begin_catch(&exception_header->unwindHeader); |
| std::__terminate(exception_header->terminateHandler); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static size_t get_cxa_exception_offset() { |
| struct S { |
| } __attribute__((aligned)); |
|
|
| |
| constexpr size_t alignment = alignof(S); |
| constexpr size_t excp_size = sizeof(__cxa_exception); |
| constexpr size_t aligned_size = |
| (excp_size + alignment - 1) / alignment * alignment; |
| constexpr size_t offset = aligned_size - excp_size; |
| static_assert((offset == 0 || alignof(_Unwind_Exception) < alignment), |
| "offset is non-zero only if _Unwind_Exception isn't aligned"); |
| return offset; |
| } |
|
|
| extern "C" { |
|
|
| |
| |
| |
| |
| |
| void *__cxa_allocate_exception(size_t thrown_size) throw() { |
| size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); |
|
|
| |
| |
| size_t header_offset = get_cxa_exception_offset(); |
| char *raw_buffer = |
| (char *)__aligned_malloc_with_fallback(header_offset + actual_size); |
| if (NULL == raw_buffer) |
| std::terminate(); |
| __cxa_exception *exception_header = |
| static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset)); |
| ::memset(exception_header, 0, actual_size); |
| return thrown_object_from_cxa_exception(exception_header); |
| } |
|
|
|
|
| |
| void __cxa_free_exception(void *thrown_object) throw() { |
| |
| size_t header_offset = get_cxa_exception_offset(); |
| char *raw_buffer = |
| ((char *)cxa_exception_from_thrown_object(thrown_object)) - header_offset; |
| __aligned_free_with_fallback((void *)raw_buffer); |
| } |
|
|
| __cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo, |
| #ifdef __wasm__ |
| |
| void *(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() { |
| #else |
| void(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() { |
| #endif |
| __cxa_exception* exception_header = cxa_exception_from_thrown_object(object); |
| exception_header->referenceCount = 0; |
| exception_header->unexpectedHandler = std::get_unexpected(); |
| exception_header->terminateHandler = std::get_terminate(); |
| exception_header->exceptionType = tinfo; |
| exception_header->exceptionDestructor = dest; |
| setOurExceptionClass(&exception_header->unwindHeader); |
| exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; |
|
|
| return exception_header; |
| } |
|
|
| |
| |
| |
| void * __cxa_allocate_dependent_exception () { |
| size_t actual_size = sizeof(__cxa_dependent_exception); |
| void *ptr = __aligned_malloc_with_fallback(actual_size); |
| if (NULL == ptr) |
| std::terminate(); |
| ::memset(ptr, 0, actual_size); |
| return ptr; |
| } |
|
|
|
|
| |
| |
| void __cxa_free_dependent_exception (void * dependent_exception) { |
| __aligned_free_with_fallback(dependent_exception); |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #if defined(__EMSCRIPTEN__) && defined(__WASM_EXCEPTIONS__) && !defined(NDEBUG) |
| extern "C" { |
| void __throw_exception_with_stack_trace(_Unwind_Exception*); |
| } |
| #endif |
|
|
| void |
| #ifdef __wasm__ |
| |
| __cxa_throw(void *thrown_object, std::type_info *tinfo, void *(_LIBCXXABI_DTOR_FUNC *dest)(void *)) { |
| #else |
| __cxa_throw(void *thrown_object, std::type_info *tinfo, void (_LIBCXXABI_DTOR_FUNC *dest)(void *)) { |
| #endif |
| __cxa_eh_globals* globals = __cxa_get_globals(); |
| globals->uncaughtExceptions += 1; |
|
|
| __cxa_exception* exception_header = __cxa_init_primary_exception(thrown_object, tinfo, dest); |
| exception_header->referenceCount = 1; |
|
|
| #if __has_feature(address_sanitizer) |
| |
| __asan_handle_no_return(); |
| #endif |
|
|
| #ifdef __USING_SJLJ_EXCEPTIONS__ |
| _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); |
| #elif defined(__EMSCRIPTEN__) && defined(__WASM_EXCEPTIONS__) && !defined(NDEBUG) |
| |
| |
| __throw_exception_with_stack_trace(&exception_header->unwindHeader); |
| #else |
| _Unwind_RaiseException(&exception_header->unwindHeader); |
| #endif |
| |
| |
| failed_throw(exception_header); |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| void *__cxa_get_exception_ptr(void *unwind_exception) throw() { |
| #if defined(_LIBCXXABI_ARM_EHABI) |
| return reinterpret_cast<void*>( |
| static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); |
| #else |
| return cxa_exception_from_exception_unwind_exception( |
| static_cast<_Unwind_Exception*>(unwind_exception))->adjustedPtr; |
| #endif |
| } |
|
|
| #if defined(_LIBCXXABI_ARM_EHABI) |
| |
| |
| |
| |
| bool __cxa_begin_cleanup(void *unwind_arg) throw() { |
| _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); |
| __cxa_eh_globals* globals = __cxa_get_globals(); |
| __cxa_exception* exception_header = |
| cxa_exception_from_exception_unwind_exception(unwind_exception); |
|
|
| if (__isOurExceptionClass(unwind_exception)) |
| { |
| if (0 == exception_header->propagationCount) |
| { |
| exception_header->nextPropagatingException = globals->propagatingExceptions; |
| globals->propagatingExceptions = exception_header; |
| } |
| ++exception_header->propagationCount; |
| } |
| else |
| { |
| |
| |
| if (NULL != globals->propagatingExceptions) |
| std::terminate(); |
| globals->propagatingExceptions = exception_header; |
| } |
| return true; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| __attribute__((used)) static _Unwind_Exception * |
| __cxa_end_cleanup_impl() |
| { |
| __cxa_eh_globals* globals = __cxa_get_globals(); |
| __cxa_exception* exception_header = globals->propagatingExceptions; |
| if (NULL == exception_header) |
| { |
| |
| |
| std::terminate(); |
| } |
|
|
| if (__isOurExceptionClass(&exception_header->unwindHeader)) |
| { |
| --exception_header->propagationCount; |
| if (0 == exception_header->propagationCount) |
| { |
| globals->propagatingExceptions = exception_header->nextPropagatingException; |
| exception_header->nextPropagatingException = NULL; |
| } |
| } |
| else |
| { |
| globals->propagatingExceptions = NULL; |
| } |
| return &exception_header->unwindHeader; |
| } |
|
|
| asm(" .pushsection .text.__cxa_end_cleanup,\"ax\",%progbits\n" |
| " .globl __cxa_end_cleanup\n" |
| " .type __cxa_end_cleanup,%function\n" |
| "__cxa_end_cleanup:\n" |
| #if defined(__ARM_FEATURE_BTI_DEFAULT) |
| " bti\n" |
| #endif |
| " push {r1, r2, r3, r4}\n" |
| " mov r4, lr\n" |
| " bl __cxa_end_cleanup_impl\n" |
| " mov lr, r4\n" |
| #if defined(LIBCXXABI_BAREMETAL) |
| " ldr r4, =_Unwind_Resume\n" |
| " mov ip, r4\n" |
| #endif |
| " pop {r1, r2, r3, r4}\n" |
| #if defined(LIBCXXABI_BAREMETAL) |
| " bx ip\n" |
| #else |
| " b _Unwind_Resume\n" |
| #endif |
| " .popsection"); |
| #endif |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void* |
| __cxa_begin_catch(void* unwind_arg) throw() |
| { |
| _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); |
| bool native_exception = __isOurExceptionClass(unwind_exception); |
| __cxa_eh_globals* globals = __cxa_get_globals(); |
| |
| |
| |
| __cxa_exception* exception_header = |
| cxa_exception_from_exception_unwind_exception |
| ( |
| static_cast<_Unwind_Exception*>(unwind_exception) |
| ); |
|
|
| #if defined(__MVS__) |
| |
| |
| |
| _UnwindZOS_PopException(); |
| #endif |
|
|
| if (native_exception) |
| { |
| |
| exception_header->handlerCount = exception_header->handlerCount < 0 ? |
| -exception_header->handlerCount + 1 : exception_header->handlerCount + 1; |
| |
| |
| if (exception_header != globals->caughtExceptions) |
| { |
| exception_header->nextException = globals->caughtExceptions; |
| globals->caughtExceptions = exception_header; |
| } |
| globals->uncaughtExceptions -= 1; |
| #if defined(_LIBCXXABI_ARM_EHABI) |
| return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]); |
| #else |
| return exception_header->adjustedPtr; |
| #endif |
| } |
| |
| |
| if (globals->caughtExceptions != 0) |
| std::terminate(); |
| |
| globals->caughtExceptions = exception_header; |
| return unwind_exception + 1; |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void __cxa_end_catch() { |
| static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception), |
| "sizeof(__cxa_exception) must be equal to " |
| "sizeof(__cxa_dependent_exception)"); |
| static_assert(__builtin_offsetof(__cxa_exception, referenceCount) == |
| __builtin_offsetof(__cxa_dependent_exception, |
| primaryException), |
| "the layout of __cxa_exception must match the layout of " |
| "__cxa_dependent_exception"); |
| static_assert(__builtin_offsetof(__cxa_exception, handlerCount) == |
| __builtin_offsetof(__cxa_dependent_exception, handlerCount), |
| "the layout of __cxa_exception must match the layout of " |
| "__cxa_dependent_exception"); |
| __cxa_eh_globals* globals = __cxa_get_globals_fast(); |
| __cxa_exception* exception_header = globals->caughtExceptions; |
| |
| |
| |
| if (NULL != exception_header) |
| { |
| bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); |
| if (native_exception) |
| { |
| |
| if (exception_header->handlerCount < 0) |
| { |
| |
| if (0 == incrementHandlerCount(exception_header)) |
| { |
| |
| globals->caughtExceptions = exception_header->nextException; |
| |
| } |
| |
| |
| |
| } |
| else |
| { |
| |
| if (0 == decrementHandlerCount(exception_header)) |
| { |
| |
| globals->caughtExceptions = exception_header->nextException; |
| |
| |
| if (isDependentException(&exception_header->unwindHeader)) |
| { |
| |
| __cxa_dependent_exception* dep_exception_header = |
| reinterpret_cast<__cxa_dependent_exception*>(exception_header); |
| exception_header = |
| cxa_exception_from_thrown_object(dep_exception_header->primaryException); |
| __cxa_free_dependent_exception(dep_exception_header); |
| } |
| |
| |
| __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header)); |
| } |
| } |
| } |
| else |
| { |
| |
| |
| |
| |
| |
| _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader); |
| globals->caughtExceptions = 0; |
| } |
| } |
| } |
|
|
| void __cxa_call_terminate(void* unwind_arg) throw() { |
| __cxa_begin_catch(unwind_arg); |
| std::terminate(); |
| } |
|
|
| |
| |
| |
| std::type_info *__cxa_current_exception_type() { |
| |
| __cxa_eh_globals *globals = __cxa_get_globals_fast(); |
| if (NULL == globals) |
| return NULL; |
| __cxa_exception *exception_header = globals->caughtExceptions; |
| if (NULL == exception_header) |
| return NULL; |
| if (!__isOurExceptionClass(&exception_header->unwindHeader)) |
| return NULL; |
| return exception_header->exceptionType; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void __cxa_rethrow() { |
| __cxa_eh_globals* globals = __cxa_get_globals(); |
| __cxa_exception* exception_header = globals->caughtExceptions; |
| if (NULL == exception_header) |
| std::terminate(); |
| bool native_exception = __isOurExceptionClass(&exception_header->unwindHeader); |
| if (native_exception) |
| { |
| |
| exception_header->handlerCount = -exception_header->handlerCount; |
| globals->uncaughtExceptions += 1; |
| |
| } |
| else |
| { |
| |
| |
| |
| |
| globals->caughtExceptions = 0; |
| } |
| #ifdef __USING_SJLJ_EXCEPTIONS__ |
| _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); |
| #elif defined(__EMSCRIPTEN__) && defined(__WASM_EXCEPTIONS__) && !defined(NDEBUG) |
| |
| |
| __throw_exception_with_stack_trace(&exception_header->unwindHeader); |
| #else |
| _Unwind_RaiseException(&exception_header->unwindHeader); |
| #endif |
|
|
| |
| |
| |
| |
| __cxa_begin_catch(&exception_header->unwindHeader); |
| if (native_exception) |
| std::__terminate(exception_header->terminateHandler); |
| |
| std::terminate(); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| void |
| __cxa_increment_exception_refcount(void *thrown_object) throw() { |
| if (thrown_object != NULL ) |
| { |
| __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); |
| std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| _LIBCXXABI_NO_CFI |
| void __cxa_decrement_exception_refcount(void *thrown_object) throw() { |
| if (thrown_object != NULL ) |
| { |
| __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); |
| if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0) |
| { |
| if (NULL != exception_header->exceptionDestructor) |
| exception_header->exceptionDestructor(thrown_object); |
| __cxa_free_exception(thrown_object); |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void *__cxa_current_primary_exception() throw() { |
| |
| __cxa_eh_globals* globals = __cxa_get_globals_fast(); |
| if (NULL == globals) |
| return NULL; |
| __cxa_exception* exception_header = globals->caughtExceptions; |
| if (NULL == exception_header) |
| return NULL; |
| if (!__isOurExceptionClass(&exception_header->unwindHeader)) |
| return NULL; |
| if (isDependentException(&exception_header->unwindHeader)) { |
| __cxa_dependent_exception* dep_exception_header = |
| reinterpret_cast<__cxa_dependent_exception*>(exception_header); |
| exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); |
| } |
| void* thrown_object = thrown_object_from_cxa_exception(exception_header); |
| __cxa_increment_exception_refcount(thrown_object); |
| return thrown_object; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static |
| void |
| dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) |
| { |
| __cxa_dependent_exception* dep_exception_header = |
| reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1; |
| if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) |
| std::__terminate(dep_exception_header->terminateHandler); |
| __cxa_decrement_exception_refcount(dep_exception_header->primaryException); |
| __cxa_free_dependent_exception(dep_exception_header); |
| } |
|
|
| |
| |
| |
| |
| void |
| __cxa_rethrow_primary_exception(void* thrown_object) |
| { |
| if ( thrown_object != NULL ) |
| { |
| |
| |
| __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); |
| __cxa_dependent_exception* dep_exception_header = |
| static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception()); |
| dep_exception_header->primaryException = thrown_object; |
| __cxa_increment_exception_refcount(thrown_object); |
| dep_exception_header->exceptionType = exception_header->exceptionType; |
| dep_exception_header->unexpectedHandler = std::get_unexpected(); |
| dep_exception_header->terminateHandler = std::get_terminate(); |
| setDependentExceptionClass(&dep_exception_header->unwindHeader); |
| __cxa_get_globals()->uncaughtExceptions += 1; |
| dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup; |
| #ifdef __USING_SJLJ_EXCEPTIONS__ |
| _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader); |
| #elif defined(__EMSCRIPTEN__) && defined(__WASM_EXCEPTIONS__) && !defined(NDEBUG) |
| |
| |
| |
| __throw_exception_with_stack_trace(&dep_exception_header->unwindHeader); |
| #else |
| _Unwind_RaiseException(&dep_exception_header->unwindHeader); |
| #endif |
| |
| __cxa_begin_catch(&dep_exception_header->unwindHeader); |
| } |
| |
| } |
|
|
| bool |
| __cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; } |
|
|
| unsigned int |
| __cxa_uncaught_exceptions() throw() |
| { |
| |
| __cxa_eh_globals* globals = __cxa_get_globals_fast(); |
| if (globals == 0) |
| return 0; |
| return globals->uncaughtExceptions; |
| } |
|
|
| } |
|
|
| } |
|
|