UnwindAction checkHandlers(const EHEnt* eh, const ActRec* const fp, PC& pc, Fault& fault) { auto const func = fp->m_func; FTRACE(1, "checkHandlers: func {} ({})\n", func->fullName()->data(), func->unit()->filepath()->data()); // Always blindly propagate on fatal exception since those are // unrecoverable anyway. if (fault.m_faultType == Fault::Type::CppException) { return UnwindAction::Propagate; } for (int i = 0;; ++i) { // Skip the initial m_handledCount - 1 handlers that were // considered before. if (fault.m_handledCount <= i) { fault.m_handledCount++; switch (eh->m_type) { case EHEnt::Type::Fault: FTRACE(1, "checkHandlers: entering fault at {}: save {}\n", eh->m_fault, func->unit()->offsetOf(pc)); pc = func->unit()->entry() + eh->m_fault; DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook()); return UnwindAction::ResumeVM; case EHEnt::Type::Catch: // Note: we skip catch clauses if we have a pending C++ exception // as part of our efforts to avoid running more PHP code in the // face of such exceptions. if (fault.m_faultType == Fault::Type::UserException && ThreadInfo::s_threadInfo->m_pendingException == nullptr) { auto const obj = fault.m_userException; for (auto& idOff : eh->m_catches) { FTRACE(1, "checkHandlers: catch candidate {}\n", idOff.second); auto handler = func->unit()->at(idOff.second); auto const cls = Unit::lookupClass( func->unit()->lookupNamedEntityId(idOff.first) ); if (!cls || !obj->instanceof(cls)) continue; FTRACE(1, "checkHandlers: entering catch at {}\n", idOff.second); pc = handler; DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook()); return UnwindAction::ResumeVM; } } break; } } if (eh->m_parentIndex != -1) { eh = &func->ehtab()[eh->m_parentIndex]; } else { break; } } return UnwindAction::Propagate; }
UnwindAction checkHandlers(const EHEnt* eh, const ActRec* const fp, PC& pc, Fault& fault) { auto const func = fp->m_func; ITRACE(1, "checkHandlers: func {} ({})\n", func->fullName()->data(), func->unit()->filepath()->data()); for (int i = 0;; ++i) { // Skip the initial m_handledCount - 1 handlers that were // considered before. if (fault.m_handledCount <= i) { fault.m_handledCount++; switch (eh->m_type) { case EHEnt::Type::Fault: ITRACE(1, "checkHandlers: entering fault at {}: save {}\n", eh->m_handler, func->unit()->offsetOf(pc)); pc = func->unit()->at(eh->m_handler); DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook()); return UnwindAction::ResumeVM; case EHEnt::Type::Catch: ITRACE(1, "checkHandlers: entering catch at {}\n", eh->m_handler); pc = func->unit()->at(eh->m_handler); DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook()); return UnwindAction::ResumeVM; } } if (eh->m_parentIndex != -1) { eh = &func->ehtab()[eh->m_parentIndex]; } else { break; } } return UnwindAction::Propagate; }
UnwindAction checkHandlers(const EHEnt* eh, const ActRec* const fp, PC& pc, Fault& fault) { auto const func = fp->m_func; FTRACE(1, "checkHandlers: func {} ({})\n", func->fullName()->data(), func->unit()->filepath()->data()); /* * This code is repeatedly called with the same offset when an * exception is raised and rethrown by fault handlers. The * `faultNest' iterator is here to skip the EHEnt handlers that have * already been run for this in-flight exception. */ int faultNest = 0; for (;;) { assert(faultNest <= fault.m_handledCount); if (faultNest == fault.m_handledCount) { ++fault.m_handledCount; switch (eh->m_type) { case EHEnt::Type::Fault: FTRACE(1, "checkHandlers: entering fault at {}: save {}\n", eh->m_fault, func->unit()->offsetOf(pc)); fault.m_savedRaiseOffset = func->unit()->offsetOf(pc); pc = func->unit()->entry() + eh->m_fault; DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook()); return UnwindAction::ResumeVM; case EHEnt::Type::Catch: // Note: we skip catch clauses if we have a pending C++ exception // as part of our efforts to avoid running more PHP code in the // face of such exceptions. if (fault.m_faultType == Fault::Type::UserException && ThreadInfo::s_threadInfo->m_pendingException == nullptr) { auto const obj = fault.m_userException; for (auto& idOff : eh->m_catches) { FTRACE(1, "checkHandlers: catch candidate {}\n", idOff.second); auto handler = func->unit()->at(idOff.second); auto const cls = Unit::lookupClass( func->unit()->lookupNamedEntityId(idOff.first) ); if (!cls || !obj->instanceof(cls)) continue; FTRACE(1, "checkHandlers: entering catch at {}\n", idOff.second); pc = handler; DEBUGGER_ATTACHED_ONLY(phpDebuggerExceptionHandlerHook()); return UnwindAction::ResumeVM; } } break; } } if (eh->m_parentIndex != -1) { eh = &func->ehtab()[eh->m_parentIndex]; } else { break; } ++faultNest; } return UnwindAction::Propagate; }