/* If thrown_object is not null, allocate, initialize and throw a dependent exception. */ void __cxa_rethrow_primary_exception(void* thrown_object) { if ( thrown_object != NULL ) { // thrown_object guaranteed to be native because // __cxa_current_primary_exception returns NULL for foreign exceptions __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; #if __arm__ _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader); #else _Unwind_RaiseException(&dep_exception_header->unwindHeader); #endif // Some sort of unwinding error. Note that terminate is a handler. __cxa_begin_catch(&dep_exception_header->unwindHeader); } // If we return client will call terminate() }
static LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { // Section 2.5.3 says: // * For purposes of this ABI, several things are considered exception handlers: // ** A terminate() call due to a throw. // and // * Upon entry, Following initialization of the catch parameter, // a handler must call: // * void *__cxa_begin_catch(void *exceptionObject ); (void) __cxa_begin_catch(&exception_header->unwindHeader); std::__terminate(exception_header->terminateHandler); }
static void call_terminate(bool native_exception, _Unwind_Exception* unwind_exception) { __cxa_begin_catch(unwind_exception); if (native_exception) { // Use the stored terminate_handler if possible __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; std::__terminate(exception_header->terminateHandler); } std::terminate(); }
void* __darwin_objc_begin_catch(void* p) { void *rv = returnReturn(); void* cpp = __cxa_begin_catch(p); if (cpp) { m_cxx = true; return cpp; } else { m_cxx = false; return rv; } }
/* This routine can rethrow native or foreign exceptions. If the exception is native: * marks the exception object on top of the caughtExceptions stack (in an implementation-defined way) as being rethrown. * If the caughtExceptions stack is empty, it calls terminate() (see [C++FDIS] [except.throw], 15.1.8). * It then calls _Unwind_RaiseException which should not return (terminate if it does). Note: exception_header may be masquerading as a __cxa_dependent_exception and that's ok. */ LIBCXXABI_NORETURN void __cxa_rethrow() { __cxa_eh_globals* globals = __cxa_get_globals(); __cxa_exception* exception_header = globals->caughtExceptions; if (NULL == exception_header) std::terminate(); // throw; called outside of a exception handler bool native_exception = isOurExceptionClass(&exception_header->unwindHeader); if (native_exception) { // Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch) exception_header->handlerCount = -exception_header->handlerCount; globals->uncaughtExceptions += 1; // __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary } else // this is a foreign exception { // The only way to communicate to __cxa_end_catch that we've rethrown // a foreign exception, so don't delete us, is to pop the stack here // which must be empty afterwards. Then __cxa_end_catch will do // nothing globals->caughtExceptions = 0; } #if __arm__ _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); #else _Unwind_RaiseException(&exception_header->unwindHeader); #endif // If we get here, some kind of unwinding error has occurred. // There is some weird code generation bug happening with // Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn) // If we call failed_throw here. Turns up with -O2 or higher, and -Os. __cxa_begin_catch(&exception_header->unwindHeader); if (native_exception) std::__terminate(exception_header->terminateHandler); // Foreign exception: can't get exception_header->terminateHandler std::terminate(); }
void __cxa_call_unexpected(void* arg) { _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg); if (unwind_exception == 0) call_terminate(false, unwind_exception); __cxa_begin_catch(unwind_exception); bool native_old_exception = (reinterpret_cast<uint64_t>(unwind_exception->exception_class) & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language); std::unexpected_handler u_handler; std::terminate_handler t_handler; __cxa_exception* old_exception_header = 0; int64_t ttypeIndex; const uint8_t* lsda; if (native_old_exception) { old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1; t_handler = old_exception_header->terminateHandler; u_handler = old_exception_header->unexpectedHandler; // If std::__unexpected(u_handler) rethrows the same exception, // these values get overwritten by the rethrow. So save them now: #ifndef __ARM_EABI_UNWINDER__ ttypeIndex = old_exception_header->handlerSwitchValue; lsda = old_exception_header->languageSpecificData; #endif } else { t_handler = std::get_terminate(); u_handler = std::get_unexpected(); } try { std::__unexpected(u_handler); } catch (...) { // If the old exception is foreign, then all we can do is terminate. // We have no way to recover the needed old exception spec. There's // no way to pass that information here. And the personality routine // can't call us directly and do anything but terminate() if we throw // from here. if (native_old_exception) { // Have: // old_exception_header->languageSpecificData // old_exception_header->actionRecord // Need // const uint8_t* classInfo // uint8_t ttypeEncoding uint8_t lpStartEncoding = *lsda++; const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); (void)lpStart; // purposefully unused. Just needed to increment lsda. uint8_t ttypeEncoding = *lsda++; if (ttypeEncoding == DW_EH_PE_omit) std::__terminate(t_handler); uintptr_t classInfoOffset = readULEB128(&lsda); const uint8_t* classInfo = lsda + classInfoOffset; // Is this new exception catchable by the exception spec at ttypeIndex? // The answer is obviously yes if the new and old exceptions are the same exception // If no // throw; __cxa_eh_globals* globals = __cxa_get_globals_fast(); __cxa_exception* new_exception_header = globals->caughtExceptions; if (new_exception_header == 0) // This shouldn't be able to happen! std::__terminate(t_handler); bool native_new_exception = (reinterpret_cast<uint64_t>(new_exception_header->unwindHeader.exception_class) & get_vendor_and_language) == (kOurExceptionClass & get_vendor_and_language); void* adjustedPtr; if (native_new_exception && (new_exception_header != old_exception_header)) { const __shim_type_info* excpType = static_cast<const __shim_type_info*>(new_exception_header->exceptionType); adjustedPtr = reinterpret_cast<uint64_t>(new_exception_header->unwindHeader.exception_class) == kOurDependentExceptionClass ? ((__cxa_dependent_exception*)new_exception_header)->primaryException : new_exception_header + 1; if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, excpType, adjustedPtr, unwind_exception)) { // We need to __cxa_end_catch, but for the old exception, // not the new one. This is a little tricky ... // Disguise new_exception_header as a rethrown exception, but // don't actually rethrow it. This means you can temporarily // end the catch clause enclosing new_exception_header without // __cxa_end_catch destroying new_exception_header. new_exception_header->handlerCount = -new_exception_header->handlerCount; globals->uncaughtExceptions += 1; // Call __cxa_end_catch for new_exception_header __cxa_end_catch(); // Call __cxa_end_catch for old_exception_header __cxa_end_catch(); // Renter this catch clause with new_exception_header __cxa_begin_catch(&new_exception_header->unwindHeader); // Rethrow new_exception_header throw; } } // Will a std::bad_exception be catchable by the exception spec at // ttypeIndex? // If no // throw std::bad_exception(); const __shim_type_info* excpType = static_cast<const __shim_type_info*>(&typeid(std::bad_exception)); std::bad_exception be; adjustedPtr = &be; if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, excpType, adjustedPtr, unwind_exception)) { // We need to __cxa_end_catch for both the old exception and the // new exception. Technically we should do it in that order. // But it is expedient to do it in the opposite order: // Call __cxa_end_catch for new_exception_header __cxa_end_catch(); // Throw std::bad_exception will __cxa_end_catch for // old_exception_header throw be; } } } std::__terminate(t_handler); }