void DebuggerProxy::setBreakPoints( std::vector<BreakPointInfoPtr>& breakpoints ) { TRACE(2, "DebuggerProxy::setBreakPoints\n"); // Hold the break mutex while we update the proxy's state. There's no need to // hold it over the longer operation to set breakpoints in each file later. { WriteLock lock(m_breakMutex); // breakpoints holds a list of fresh new BreakPointInfo objects that // have been deserialized from the client's list of breakpoints. // The existing BreakPointInfo objects may include non empty values // for m_stack. If these get thrown away, breakpoints that are temporarily // disabled will suddenly fire again, which is not what we want to // happen if we create a new breakpoint or just even list breakpoints. auto it = m_breakpoints.begin(); for (auto it1 = breakpoints.begin(); it1 != breakpoints.end(); ++it1) { BreakPointInfoPtr newBreakPoint = *it1; do { for (auto it2 = it; it2 != m_breakpoints.end(); ) { BreakPointInfoPtr oldBreakPoint = *it2++; if (oldBreakPoint->same(newBreakPoint)) { newBreakPoint->transferStack(oldBreakPoint); it = it2; goto next_breakpoint; } } if (it == m_breakpoints.begin()) goto next_breakpoint; // Only searched a part of m_breakpoints. Reset it and try again. it = m_breakpoints.begin(); } while (true); next_breakpoint: continue; } m_breakpoints = breakpoints; m_hasBreakPoints = !m_breakpoints.empty(); } proxySetBreakPoints(this); }
bool CmdBreak::processUpdate(DebuggerClient *client) { m_breakpoints = client->getBreakPoints(); if (m_breakpoints->empty()) { client->error("There is no breakpoint to clear or toggle."); client->tutorial( "Use '[b]reak ?|[h]elp' to read how to set breakpoints. " ); return true; } if (client->argCount() == 1) { BreakPointInfoPtrVec *matched = client->getMatchedBreakPoints(); BreakPointInfoPtrVec *bps = client->getBreakPoints(); bool found = false; for (unsigned int i = 0; i < matched->size(); i++) { BreakPointInfoPtr bpm = (*matched)[i]; BreakPointInfoPtr bp; int index = 0; for (; index < (int)bps->size(); index++) { if (bpm->same((*bps)[index])) { bp = (*bps)[index]; break; } } if (bp) { const char *action; if (hasClearArg(client)) { action = "cleared"; bps->erase(bps->begin() + index); } else if (hasEnableArg(client)) { action = "updated"; bp->setState(BreakPointInfo::Always); } else if (hasDisableArg(client)) { action = "updated"; bp->setState(BreakPointInfo::Disabled); } else { assert(hasToggleArg(client)); action = "updated"; bp->toggle(); } client->info("Breakpoint %d is %s %s", bp->index(), action, bp->site().c_str()); found = true; } } if (found) { updateImpl(client); return true; } client->error("There is no current breakpoint to clear or toggle."); return true; } if (client->arg(2, "all")) { if (hasClearArg(client)) { m_breakpoints->clear(); updateImpl(client); client->info("All breakpoints are cleared."); return true; } for (unsigned int i = 0; i < m_breakpoints->size(); i++) { BreakPointInfoPtr bpi = (*m_breakpoints)[i]; if (hasEnableArg(client)) { bpi->setState(BreakPointInfo::Always); } else if (hasDisableArg(client)) { bpi->setState(BreakPointInfo::Disabled); } else { assert(hasToggleArg(client)); bpi->toggle(); } } updateImpl(client); return processList(client); } string snum = client->argValue(2); if (!DebuggerClient::IsValidNumber(snum)) { client->error("'[b]reak [c]lear|[t]oggle' needs an {index} argument."); client->tutorial( "You will have to run '[b]reak [l]ist' first to see a list of valid " "numbers or indices to specify." ); return true; } int index = -1; int num = atoi(snum.c_str()); for (unsigned int i = 0; i < m_breakpoints->size(); i++) { if (m_breakpoints->at(i)->index() == num) { index = i; break; } } if (index < 0) { client->error("\"%s\" is not a valid breakpoint index. Choose one from " "this list:", snum.c_str()); processList(client); return true; } BreakPointInfoPtr bpi = (*m_breakpoints)[index]; if (hasClearArg(client)) { m_breakpoints->erase(m_breakpoints->begin() + index); updateImpl(client); client->info("Breakpoint %d cleared %s", bpi->index(), bpi->desc().c_str()); } else if (hasEnableArg(client)) { bpi->setState(BreakPointInfo::Always); updateImpl(client); client->info("Breakpoint %d's state is changed to %s.", bpi->index(), bpi->state(false).c_str()); } else if (hasDisableArg(client)) { bpi->setState(BreakPointInfo::Disabled); updateImpl(client); client->info("Breakpoint %d's state is changed to %s.", bpi->index(), bpi->state(false).c_str()); } else { assert(hasToggleArg(client)); bpi->toggle(); updateImpl(client); client->info("Breakpoint %d's state is changed to %s.", bpi->index(), bpi->state(false).c_str()); } return true; }
void CmdInterrupt::onClient(DebuggerClient &client) { client.setCurrentLocation(m_threadId, m_bpi); if (!client.getDebuggerClientSmallStep()) { // Adjust line and char if it's not small stepping if (m_bpi->m_line1 == m_bpi->m_line2) { m_bpi->m_char1 = 1; m_bpi->m_char2 = 100; } } client.setMatchedBreakPoints(m_matched); switch (m_interrupt) { case SessionStarted: if (!m_program.empty()) { client.info("Program %s loaded. Type '[r]un' or '[c]ontinue' to go.", m_program.c_str()); m_bpi->m_file = m_program; } break; case SessionEnded: if (!m_program.empty()) { client.info("Program %s exited normally.", m_program.c_str()); } break; case RequestStarted: if (!m_program.empty()) { client.info("Web request %s started.", m_program.c_str()); } break; case RequestEnded: if (!m_program.empty()) { client.info("Web request %s ended.", m_program.c_str()); } break; case PSPEnded: if (!m_program.empty()) { client.info("Post-Send Processing for %s was ended.", m_program.c_str()); } break; case HardBreakPoint: case BreakPointReached: case ExceptionThrown: { bool found = false; bool toggled = false; auto *bps = client.getBreakPoints(); for (unsigned int i = 0; i < m_matched.size(); i++) { BreakPointInfoPtr bpm = m_matched[i]; BreakPointInfoPtr bp; int index = 0; for (; index < (int)bps->size(); index++) { if (bpm->same((*bps)[index])) { bp = (*bps)[index]; break; } } if (bp) { found = true; if (bp->m_state == BreakPointInfo::Once) { bp->m_state = BreakPointInfo::Disabled; toggled = true; } if (m_interrupt == BreakPointReached || m_interrupt == HardBreakPoint) { client.info("Breakpoint %d reached %s", bp->index(), m_bpi->site().c_str()); client.shortCode(m_bpi); } else { if (m_bpi->m_exceptionClass == BreakPointInfo::ErrorClassName) { client.info("Breakpoint %d reached: An error occurred %s", bp->index(), m_bpi->site().c_str()); client.shortCode(m_bpi); client.error("Error Message: %s", m_bpi->m_exceptionObject.c_str()); } else { client.info("Breakpoint %d reached: Throwing %s %s", bp->index(), m_bpi->m_exceptionClass.c_str(), m_bpi->site().c_str()); client.shortCode(m_bpi); if (client.getLogFileHandler()) { client.output(m_bpi->m_exceptionObject); } } } if (!bpm->m_output.empty()) { client.print(bpm->m_output); } } } if (toggled) { CmdBreak::SendClientBreakpointListToServer(client); } if (!found) { if (m_interrupt == HardBreakPoint) { // for HardBreakPoint, default the frame to the caller client.setFrame(1); } client.info("Break %s", m_bpi->site().c_str()); client.shortCode(m_bpi); } break; } } if (!m_errorMsg.empty()) { client.error(m_errorMsg); } // watches switch (m_interrupt) { case SessionStarted: case RequestStarted: break; default: { DebuggerClient::WatchPtrVec &watches = client.getWatches(); for (int i = 0; i < (int)watches.size(); i++) { if (i > 0) client.output("%s", ""); client.info("Watch %d: %s =", i + 1, watches[i]->second.c_str()); Variant v = CmdPrint().processWatch(client, watches[i]->first, watches[i]->second); client.output(CmdPrint::FormatResult(watches[i]->first, v)); } } } }
bool CmdInterrupt::onClient(DebuggerClient *client) { client->setCurrentLocation(m_threadId, m_bpi); client->setMatchedBreakPoints(m_matched); switch (m_interrupt) { case SessionEnded: case RequestEnded: case PSPEnded: if (m_pendingJump) { client->error("Your jump point cannot be reached. You may only jump " "to certain parallel or outer execution points."); } break; } switch (m_interrupt) { case SessionStarted: if (!m_program.empty()) { client->info("Program %s loaded. Type '[r]un' or '[c]ontinue' to go.", m_program.c_str()); m_bpi->m_file = m_program; } break; case SessionEnded: if (!m_program.empty()) { client->info("Program %s exited normally.", m_program.c_str()); } break; case RequestStarted: if (!m_program.empty()) { client->info("Web request %s started.", m_program.c_str()); } break; case RequestEnded: if (!m_program.empty()) { client->info("Web request %s ended.", m_program.c_str()); } break; case PSPEnded: if (!m_program.empty()) { client->info("Post-Send Processing for %s was ended.", m_program.c_str()); } break; case BreakPointReached: case ExceptionThrown: { bool found = false; bool toggled = false; BreakPointInfoPtrVec *bps = client->getBreakPoints(); for (unsigned int i = 0; i < m_matched.size(); i++) { BreakPointInfoPtr bpm = m_matched[i]; BreakPointInfoPtr bp; int index = 0; for (; index < (int)bps->size(); index++) { if (bpm->same((*bps)[index])) { bp = (*bps)[index]; break; } } if (bp) { found = true; if (bp->m_state == BreakPointInfo::Once) { bp->m_state = BreakPointInfo::Disabled; toggled = true; } if (m_interrupt == BreakPointReached) { client->info("Breakpoint %d reached %s", index + 1, m_bpi->site().c_str()); } else { client->info("Breakpoint %d reached: Throwing %s %s", index + 1, m_bpi->m_exceptionClass.c_str(), m_bpi->site().c_str()); client->output(m_bpi->m_exceptionObject); } if (!bpm->m_output.empty()) { client->print(bpm->m_output); } } } if (toggled) { CmdBreak().update(client); } if (!found) { client->info("Break %s", m_bpi->site().c_str()); } break; } } if (!m_errorMsg.empty()) { client->error(m_errorMsg); } // watches switch (m_interrupt) { case SessionStarted: case RequestStarted: break; default: { DebuggerClient::WatchPtrVec &watches = client->getWatches(); for (int i = 0; i < (int)watches.size(); i++) { if (i > 0) client->output(""); client->info("Watch %d: %s =", i + 1, watches[i]->second.c_str()); CmdPrint().processWatch(client, watches[i]->first, watches[i]->second); } } } return true; }