// Check if we should stop due to flow control, breakpoints, and signals. bool DebuggerProxy::checkFlowBreak(CmdInterrupt &cmd) { TRACE(2, "DebuggerProxy::checkFlowBreak\n"); // If there is an outstanding Ctrl-C from the client, go ahead and break now. // Note: this stops any flow control command we might have in-flight. if (m_signum == CmdSignal::SignalBreak) { Lock lock(m_signumMutex); if (m_signum == CmdSignal::SignalBreak) { m_signum = CmdSignal::SignalNone; m_flow.reset(); return true; } } // Note that even if fcShouldBreak, we still need to test bpShouldBreak // so to correctly report breakpoint reached + evaluating watchpoints; // vice versa, so to decCount() on m_flow. bool fcShouldBreak = false; // should I break according to flow control? bool bpShouldBreak = false; // should I break according to breakpoints? if ((cmd.getInterruptType() == BreakPointReached || cmd.getInterruptType() == HardBreakPoint) && m_flow) { fcShouldBreak = breakByFlowControl(cmd); } bpShouldBreak = checkBreakPoints(cmd); if (!fcShouldBreak && !bpShouldBreak) { return false; // this is done before KindOfContinue testing } return true; }
// Waits until this thread is the one that the proxy considers the current // thread. // NB: if the thread is not the current thread, and we're asked to check // breakpoints, then if there are no breakpoints which could effect this // thread we simply return false and stop processing the current interrupt. bool DebuggerProxy::blockUntilOwn(CmdInterrupt &cmd, bool check) { int64_t self = cmd.getThreadId(); TRACE(2, "DebuggerProxy::blockUntilOwn for thread %" PRIx64 "\n", self); Lock lock(this); if (m_thread && m_thread != self) { if (check && (m_threadMode == Exclusive || !checkBreakPoints(cmd))) { // Flow control commands only belong to sticky thread TRACE(2, "No need to interrupt this thread\n"); return false; } m_threads[self] = createThreadInfo(cmd.desc()); while (!m_stopped && m_thread && m_thread != self) { TRACE(2, "Waiting...\n"); wait(1); // If for whatever reason, m_thread isn't debugging anymore (for example, // it runs in Sticky mode, but it finishes running), kick it out. if (m_thread && !Debugger::IsThreadDebugging(m_thread)) { TRACE(2, "Old thread abandoned debugging, taking over!\n"); m_threadMode = Normal; m_thread = 0; m_newThread.reset(); m_flow.reset(); } } TRACE(2, "Ready to become current thread for this proxy\n"); m_threads.erase(self); if (m_stopped) return false; if (!checkBreakPoints(cmd)) { // The breakpoint might have been removed while I'm waiting return false; } } // This thread is now the one the proxy considers the current thread. if (m_thread == 0) { TRACE(2, "Updating current thread\n"); m_thread = self; } TRACE(2, "Current thread for this proxy tid=%" PRIx64 "\n", self); return true; }
// Check if we should stop due to flow control, breakpoints, and signals. bool DebuggerProxy::checkFlowBreak(CmdInterrupt &cmd) { TRACE(2, "DebuggerProxy::checkFlowBreak\n"); // If there is an outstanding Ctrl-C from the client, go ahead and break now. // Note: this stops any flow control command we might have in-flight. if (m_signum == CmdSignal::SignalBreak) { Lock lock(m_signalMutex); if (m_signum == CmdSignal::SignalBreak) { m_signum = CmdSignal::SignalNone; m_flow.reset(); return true; } } // Note that even if fcShouldBreak, we still need to test bpShouldBreak // so to correctly report breakpoint reached + evaluating watchpoints; // vice versa, so to give a flow cmd a chance to react. // Note: a Continue cmd is a bit special. We need to process it _only_ if // we decide to break. bool fcShouldBreak = false; // should I break according to flow control? bool bpShouldBreak = false; // should I break according to breakpoints? if ((cmd.getInterruptType() == BreakPointReached || cmd.getInterruptType() == HardBreakPoint || cmd.getInterruptType() == ExceptionHandler) && m_flow) { if (!m_flow->is(DebuggerCommand::KindOfContinue)) { m_flow->onBeginInterrupt(*this, cmd); if (m_flow->complete()) { fcShouldBreak = true; m_flow.reset(); } } } // NB: this also checks whether we should be stopping at special interrupt // sites, like SessionStarted, RequestEnded, ExceptionThrown, etc. bpShouldBreak = checkBreakPoints(cmd); // This is done before KindOfContinue testing. if (!fcShouldBreak && !bpShouldBreak) { return false; } if ((cmd.getInterruptType() == BreakPointReached || cmd.getInterruptType() == HardBreakPoint) && m_flow) { if (m_flow->is(DebuggerCommand::KindOfContinue)) { m_flow->onBeginInterrupt(*this, cmd); if (m_flow->complete()) m_flow.reset(); return false; } } return true; }
// Waits until this thread is the one that the proxy considers the current // thread. This also check to see if the given cmd has any breakpoints or // flow control that we should stop for. Note: while stepping, pretty much all // of the stepping logic is handled below here and this will return false if // the stepping operation has not completed. bool DebuggerProxy::blockUntilOwn(CmdInterrupt &cmd, bool check) { TRACE(2, "DebuggerProxy::blockUntilOwn\n"); int64_t self = cmd.getThreadId(); Lock lock(this); if (m_thread && m_thread != self) { if (check && (m_threadMode == Exclusive || !checkBreakPoints(cmd))) { // Flow control commands only belong to sticky thread return false; } m_threads[self] = createThreadInfo(cmd.desc()); while (!m_stopped && m_thread && m_thread != self) { wait(1); // if for whatever reason, m_thread isn't debugging anymore (for example, // it runs in Sticky mode, but it finishes running), kick it out. if (!Debugger::IsThreadDebugging(m_thread)) { m_threadMode = Normal; m_thread = self; m_newThread.reset(); m_flow.reset(); } } m_threads.erase(self); if (m_stopped) return false; if (!checkBreakPoints(cmd)) { // The breakpoint might have been removed while I'm waiting return false; } } else if (check && !checkFlowBreak(cmd)) { return false; } if (m_thread == 0) { m_thread = self; } return true; }