| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #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) |
| | extern "C" void __asan_handle_no_return(void); |
| | #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); |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | 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); |
| | } |
| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | void |
| | __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { |
| | __cxa_eh_globals *globals = __cxa_get_globals(); |
| | __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); |
| |
|
| | 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->referenceCount = 1; |
| | globals->uncaughtExceptions += 1; |
| |
|
| | exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; |
| |
|
| | #if __has_feature(address_sanitizer) |
| | |
| | __asan_handle_no_return(); |
| | #endif |
| |
|
| | #ifdef __USING_SJLJ_EXCEPTIONS__ |
| | _Unwind_SjLj_RaiseException(&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" |
| | " push {r1, r2, r3, r4}\n" |
| | " bl __cxa_end_cleanup_impl\n" |
| | " pop {r1, r2, r3, r4}\n" |
| | " bl _Unwind_Resume\n" |
| | " bl abort\n" |
| | " .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 (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; |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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); |
| | #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); |
| | #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; |
| | } |
| |
|
| | } |
| |
|
| | } |
| |
|