TCA emitEndCatchHelper(CodeBlock& cb, UniqueStubs& us) { auto const udrspo = rvmtl()[unwinderDebuggerReturnSPOff()]; auto const debuggerReturn = vwrap(cb, [&] (Vout& v) { v << load{udrspo, rvmsp()}; v << storeqi{0, udrspo}; }); svcreq::emit_persistent(cb, folly::none, REQ_POST_DEBUGGER_RET); auto const resumeCPPUnwind = vwrap(cb, [] (Vout& v) { static_assert(sizeof(tl_regState) == 1, "The following store must match the size of tl_regState."); auto const regstate = emitTLSAddr(v, tls_datum(tl_regState)); v << storebi{static_cast<int32_t>(VMRegState::CLEAN), regstate}; v << load{rvmtl()[unwinderExnOff()], rarg(0)}; v << call{TCA(_Unwind_Resume), arg_regs(1)}; }); us.endCatchHelperPast = cb.frontier(); vwrap(cb, [] (Vout& v) { v << ud2{}; }); alignJmpTarget(cb); return vwrap(cb, [&] (Vout& v) { auto const done1 = v.makeBlock(); auto const sf1 = v.makeReg(); v << cmpqim{0, udrspo, sf1}; v << jcci{CC_NE, sf1, done1, debuggerReturn}; v = done1; // Normal end catch situation: call back to tc_unwind_resume, which returns // the catch trace (or null) in %rax, and the new vmfp in %rdx. v << copy{rvmfp(), rarg(0)}; v << call{TCA(tc_unwind_resume)}; v << copy{reg::rdx, rvmfp()}; auto const done2 = v.makeBlock(); auto const sf2 = v.makeReg(); v << testq{reg::rax, reg::rax, sf2}; v << jcci{CC_Z, sf2, done2, resumeCPPUnwind}; v = done2; // We need to do a syncForLLVMCatch(), but vmfp is already in rdx. v << jmpr{reg::rax}; }); }
void addDbgGuardImpl(SrcKey sk, SrcRec* sr) { TCA realCode = sr->getTopTranslation(); if (!realCode) return; // No translations, nothing to do. auto& cb = mcg->code.main(); auto const dbgGuard = vwrap(cb, [&] (Vout& v) { if (!sk.resumed()) { auto const off = sr->nonResumedSPOff(); v << lea{rvmfp()[-cellsToBytes(off.offset)], rvmsp()}; } auto const tinfo = v.makeReg(); auto const attached = v.makeReg(); auto const sf = v.makeReg(); auto const done = v.makeBlock(); constexpr size_t dbgOff = offsetof(ThreadInfo, m_reqInjectionData) + RequestInjectionData::debuggerReadOnlyOffset(); v << ldimmq{reinterpret_cast<uintptr_t>(sk.pc()), rarg(0)}; emitTLSLoad(v, tls_datum(ThreadInfo::s_threadInfo), tinfo); v << loadb{tinfo[dbgOff], attached}; v << testbi{static_cast<int8_t>(0xffu), attached, sf}; v << jcci{CC_NZ, sf, done, mcg->ustubs().interpHelper}; v = done; v << fallthru{}; }, CodeKind::Helper); // Emit a jump to the actual code. auto const dbgBranchGuardSrc = emitSmashableJmp(cb, realCode); // Add the guard to the SrcRec. sr->addDebuggerGuard(dbgGuard, dbgBranchGuardSrc); }