// Do not allow further breaks on the site of cmd, except during // calls made from the current site. void DebuggerProxy::unsetBreakableForBreakpointsMatching(CmdInterrupt& cmd) { TRACE(2, "DebuggerProxy::unsetBreakableForBreakpointsMatching\n"); auto stackDepth = getRealStackDepth(); for (unsigned int i = 0; i < m_breakpoints.size(); ++i) { BreakPointInfoPtr bp = m_breakpoints[i]; if (bp != nullptr && bp->m_state != BreakPointInfo::Disabled && bp->match(*this, cmd.getInterruptType(), *cmd.getSite())) { bp->unsetBreakable(stackDepth); } } }
// Handle an interrupt from the VM. void DebuggerProxy::interrupt(CmdInterrupt &cmd) { TRACE(2, "DebuggerProxy::interrupt\n"); changeBreakPointDepth(cmd); if (cmd.getInterruptType() == BreakPointReached) { if (!needInterrupt()) return; // NB: stepping is represented as a BreakPointReached interrupt. // Modify m_lastLocFilter to save current location. This will short-circuit // the work done up in phpDebuggerOpcodeHook() and ensure we don't break on // this line until we're completely off of it. InterruptSite *site = cmd.getSite(); if (g_vmContext->m_lastLocFilter) { g_vmContext->m_lastLocFilter->clear(); } else { g_vmContext->m_lastLocFilter = new VM::PCFilter(); } if (debug && Trace::moduleEnabled(Trace::bcinterp, 5)) { Trace::trace("prepare source loc filter\n"); const VM::OffsetRangeVec& offsets = site->getCurOffsetRange(); for (VM::OffsetRangeVec::const_iterator it = offsets.begin(); it != offsets.end(); ++it) { Trace::trace("block source loc in %s:%d: unit %p offset [%d, %d)\n", site->getFile(), site->getLine0(), site->getUnit(), it->m_base, it->m_past); } } g_vmContext->m_lastLocFilter->addRanges(site->getUnit(), site->getCurOffsetRange()); // If the breakpoint is not to be processed, we should continue execution. BreakPointInfoPtr bp = getBreakPointAtCmd(cmd); if (bp) { if (!bp->breakable(getRealStackDepth())) { return; } else { bp->unsetBreakable(getRealStackDepth()); } } } // Wait until this thread is the thread this proxy wants to debug. // NB: breakpoints and control flow checks happen here, too, and return false // if we're not done with the flow, or not at a breakpoint, etc. if (!blockUntilOwn(cmd, true)) { return; } if (processFlowBreak(cmd)) { while (true) { try { Lock lock(m_signalMutex); m_signum = CmdSignal::SignalNone; processInterrupt(cmd); } catch (const DebuggerException &e) { switchThreadMode(Normal); throw; } catch (...) { assert(false); // no other exceptions should be seen here switchThreadMode(Normal); throw; } if (cmd.getInterruptType() == PSPEnded) { switchThreadMode(Normal); return; // we are done with this thread } if (!m_newThread) { break; // we're not switching threads } switchThreadMode(Normal, m_newThread->m_id); blockUntilOwn(cmd, false); } } if (m_threadMode == Normal) { Lock lock(this); m_thread = 0; notify(); } else if (cmd.getInterruptType() == PSPEnded) { switchThreadMode(Normal); // we are done with this thread } }