// Setup the last location filter on the VM context for all offsets covered by // the current source line. This will short-circuit the work done in // phpDebuggerOpcodeHook() and ensure we don't interrupt on this source line. // We exclude continuation opcodes which transfer control out of the function, // which allows cmds to get a chance to alter their behavior when those opcodes // are encountered. void CmdFlowControl::installLocationFilterForLine(InterruptSite *site) { // We may be stopped at a place with no source info. if (!site || !site->valid()) return; if (g_context->m_lastLocFilter) { g_context->m_lastLocFilter->clear(); } else { g_context->m_lastLocFilter = new PCFilter(); } TRACE(3, "Prepare location filter for %s:%d, unit %p:\n", site->getFile(), site->getLine0(), site->getUnit()); OffsetRangeVec ranges; const auto unit = site->getUnit(); if (m_smallStep) { // Get offset range for the pc only. OffsetRange range; if (unit->getOffsetRange(site->getCurOffset(), range)) { ranges.push_back(range); } } else { // Get offset ranges for the whole line. // We use line1 here because it seems to be working better than line0 // in a handful of cases for our bytecode-source mapping. if (!unit->getOffsetRanges(site->getLine1(), ranges)) { ranges.clear(); } } auto excludeContinuationReturns = [] (Op op) { return (op != OpContSuspend) && (op != OpContSuspendK) && (op != OpAsyncESuspend) && (op != OpContRetC); }; g_context->m_lastLocFilter->addRanges(unit, ranges, excludeContinuationReturns); }
void phpDebuggerStepIn() { // If this is called in the middle of a flow command we short-circuit the // other commands auto& req_data = RID(); req_data.setDebuggerStepIn(true); req_data.setDebuggerStepOut(StepOutState::NONE); req_data.setDebuggerNext(false); // Ensure the flow filter is fresh auto flow_filter = getFlowFilter(); flow_filter->clear(); // Check if the site is valid. VMRegAnchor _; ActRec* fp = vmfp(); PC pc = vmpc(); if (fp == nullptr || pc == nullptr) { TRACE(5, "Could not grab stack or program counter\n"); return; } // Try to get needed context info. Bail if we can't const Func* func = fp->func(); const Unit* unit = func != nullptr ? func->unit() : nullptr; if (func == nullptr || func == nullptr) { TRACE(5, "Could not grab the current unit or function\n"); return; } // We use line1 here because it works better than line0 in our // bytecode-source mapping. int line; SourceLoc source_loc; if (unit->getSourceLoc(unit->offsetOf(pc), source_loc)) { line = source_loc.line1; } else { TRACE(5, "Could not grab the current line number\n"); return; } TRACE(3, "Prepare location filter for %s:%d, unit %p:\n", unit->filepath()->data(), line, unit); // Get offset ranges for the whole line. OffsetRangeVec ranges; if (!unit->getOffsetRanges(line, ranges)) { ranges.clear(); } flow_filter->addRanges(unit, ranges); }