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); }
void __darwin_objc_end_catch() { if (m_cxx) __cxa_end_catch(); }