Commit 91ead6c8 authored by Friedemann Kleint's avatar Friedemann Kleint
Browse files

Debugger[CDB]: Refactor breakpoint handling.

Add a command to list breakpoints enabling id access.
Implemented breakpoint handling similar to gdb using breakpoint
ids (no longer delete and re-set all breakpoints on a change).
Save the module that is reported back in the session so that
it can be re-used for the next start. Keep a per-debugger-session
cache of fileName->Module for adding breakpoints to accelerate
setting breakpoints in the same file.
Polish the breakpoint tooltip.
parent d5a33d28
......@@ -107,16 +107,14 @@ STDMETHODIMP EventCallback::Breakpoint(THIS_ __in PDEBUG_BREAKPOINT b)
typedef ExtensionContext::StopReasonMap StopReasonMap;
typedef ExtensionContext::StopReasonMap::value_type StopReasonMapValue;
ULONG id = 0;
ULONG uId = 0;
ULONG64 address = 0;
b->GetId(&id);
b->GetOffset(&address);
StopReasonMap stopReason;
stopReason.insert(StopReasonMapValue(std::string("breakpointId"), toString(id)));
if (address)
if (SUCCEEDED(b->GetId(&uId)))
stopReason.insert(StopReasonMapValue(std::string("breakpointId"), toString(uId)));
if (SUCCEEDED(b->GetOffset(&address)))
stopReason.insert(StopReasonMapValue(std::string("breakpointAddress"), toString(address)));
ExtensionContext::instance().setStopReason(stopReason, "breakpoint");
ExtensionContext::instance().setStopReason(stopReason, ExtensionContext::breakPointStopReasonC);
return m_wrapped ? m_wrapped->Breakpoint(b) : S_OK;
}
......@@ -172,7 +170,7 @@ STDMETHODIMP EventCallback::Exception(
std::ostringstream str;
formatGdbmiHash(str, parameters);
ExtensionContext::instance().setStopReason(parameters, ExtensionContext::breakPointStopReasonC);
ExtensionContext::instance().setStopReason(parameters, "exception");
ExtensionContext::instance().report('E', 0, 0, "exception", "%s", str.str().c_str());
return m_wrapped ? m_wrapped->Exception(Ex, FirstChance) : S_OK;
}
......
......@@ -198,17 +198,6 @@ void ExtensionContext::notifyIdleCommand(CIDebugClient *client)
} else {
str << ",stack=" << stackInfo;
}
// Report breakpoints
const StopReasonMap::const_iterator rit = stopReasons.find(stopReasonKeyC);
if (rit != stopReasons.end() && rit->second == breakPointStopReasonC) {
const std::string breakpoints = gdbmiBreakpoints(exc.control(), exc.symbols(),
false, false, &errorMessage);
if (breakpoints.empty()) {
str << ",breakpointserror=" << gdbmiStringFormat(errorMessage);
} else {
str << ",breakpoints=" << breakpoints;
}
}
str << '}';
reportLong('E', 0, "session_idle", str.str());
}
......
......@@ -679,11 +679,14 @@ static inline void formatGdbmiFlag(std::ostream &str, const char *name, bool v)
static bool gdbmiFormatBreakpoint(std::ostream &str,
IDebugBreakpoint *bp,
CIDebugSymbols *symbols /* = 0 */,
bool verbose, std::string *errorMessage)
unsigned verbose, std::string *errorMessage)
{
enum { BufSize = 512 };
ULONG64 offset = 0;
ULONG flags = 0;
ULONG id = 0;
if (SUCCEEDED(bp->GetId(&id)))
str << ",id=\"" << id << '"';
HRESULT hr = bp->GetFlags(&flags);
if (FAILED(hr)) {
*errorMessage = msgDebugEngineComFailed("GetFlags", hr);
......@@ -691,8 +694,8 @@ static bool gdbmiFormatBreakpoint(std::ostream &str,
}
const bool deferred = (flags & DEBUG_BREAKPOINT_DEFERRED) != 0;
formatGdbmiFlag(str, ",deferred", deferred);
formatGdbmiFlag(str, ",enabled", (flags & DEBUG_BREAKPOINT_ENABLED) != 0);
if (verbose) {
formatGdbmiFlag(str, ",enabled", (flags & DEBUG_BREAKPOINT_ENABLED) != 0);
formatGdbmiFlag(str, ",oneshot", (flags & DEBUG_BREAKPOINT_ONE_SHOT) != 0);
str << ",flags=\"" << flags << '"';
ULONG threadId = 0;
......@@ -713,16 +716,18 @@ static bool gdbmiFormatBreakpoint(std::ostream &str,
}
}
// Expression
char buf[BufSize];
if (SUCCEEDED(bp->GetOffsetExpression(buf, BUFSIZ, 0)))
str << ",expression=\"" << gdbmiStringFormat(buf) << '"';
if (verbose > 1) {
char buf[BufSize];
if (SUCCEEDED(bp->GetOffsetExpression(buf, BUFSIZ, 0)))
str << ",expression=\"" << gdbmiStringFormat(buf) << '"';
}
return true;
}
// Format breakpoints as GDBMI
std::string gdbmiBreakpoints(CIDebugControl *ctrl,
CIDebugSymbols *symbols /* = 0 */,
bool humanReadable, bool verbose, std::string *errorMessage)
bool humanReadable, unsigned verbose, std::string *errorMessage)
{
ULONG breakPointCount = 0;
HRESULT hr = ctrl->GetNumberBreakpoints(&breakPointCount);
......@@ -735,7 +740,7 @@ std::string gdbmiBreakpoints(CIDebugControl *ctrl,
if (humanReadable)
str << '\n';
for (ULONG i = 0; i < breakPointCount; i++) {
str << "{id=\"" << i << '"';
str << "{number=\"" << i << '"';
IDebugBreakpoint *bp = 0;
hr = ctrl->GetBreakpointByIndex(i, &bp);
if (FAILED(hr) || !bp) {
......
......@@ -117,7 +117,7 @@ std::string gdbmiModules(CIDebugSymbols *syms, bool humanReadable, std::string *
std::string gdbmiBreakpoints(CIDebugControl *ctrl,
CIDebugSymbols *symbols /* = 0 */,
bool humanReadable,
bool verbose,
unsigned verbose,
std::string *errorMessage);
/* Helpers for registers */
......
......@@ -263,7 +263,7 @@ extern "C" HRESULT CALLBACK pid(CIDebugClient *client, PCSTR args)
int token;
commandTokens<StringList>(args, &token);
dprintf("Qt Creator CDB extension version 0.1 %d bit built %s.\n", sizeof(void *) > 4 ? 64 : 32, __DATE__);
if (const ULONG pid = currentProcessId(client)) {
ExtensionContext::instance().report('R', token, 0, "pid", "%u", pid);
} else {
......@@ -992,7 +992,7 @@ extern "C" HRESULT CALLBACK breakpoints(CIDebugClient *client, PCSTR argsIn)
int token;
std::string errorMessage;
bool humanReadable = false;
bool verbose = false;
unsigned verbose = 0;
StringList tokens = commandTokens<StringList>(argsIn, &token);
while (!tokens.empty() && tokens.front().size() == 2 && tokens.front().at(0) == '-') {
switch (tokens.front().at(1)) {
......@@ -1000,7 +1000,7 @@ extern "C" HRESULT CALLBACK breakpoints(CIDebugClient *client, PCSTR argsIn)
humanReadable = true;
break;
case 'v':
verbose = true;
verbose++;
break;
}
tokens.pop_front();
......
......@@ -980,12 +980,22 @@ bool BreakHandler::needsChange(BreakpointId id) const
return it->needsChange();
}
void BreakHandler::setResponse(BreakpointId id, const BreakpointResponse &data)
void BreakHandler::setResponse(BreakpointId id, const BreakpointResponse &response, bool takeOver)
{
Iterator it = m_storage.find(id);
QTC_ASSERT(it != m_storage.end(), return);
it->response = data;
it->destroyMarker();
BreakpointItem &item = it.value();
item.response = response;
item.destroyMarker();
// Take over corrected values from response
if (takeOver) {
if (item.data.type == BreakpointByFileAndLine
&& response.correctedLineNumber > 0)
item.data.lineNumber = response.correctedLineNumber;
if ((item.data.type == BreakpointByFileAndLine || item.data.type == BreakpointByFunction)
&& !response.module.isEmpty())
item.data.module = response.module;
}
updateMarker(id);
}
......@@ -1149,19 +1159,25 @@ QString BreakHandler::BreakpointItem::toToolTip() const
str << "<html><body><table>"
//<< "<tr><td>" << tr("Id:") << "</td><td>" << m_id << "</td></tr>"
<< "<tr><td>" << tr("State:")
<< "</td><td>" << state << " (" << stateToString(state) << ")</td></tr>"
<< "<tr><td>" << tr("Engine:")
<< "</td><td>" << (engine ? engine->objectName() : "0") << "</td></tr>"
<< "<tr><td>" << tr("Breakpoint Number:")
<< "</td><td>" << response.number << "</td></tr>"
<< "<tr><td>" << tr("Breakpoint Type:")
<< "</td><td>" << t << "</td></tr>"
<< "<tr><td>" << tr("Extra Information:")
<< "</td><td>" << response.extra << "</td></tr>"
<< "<tr><td>" << tr("Pending:")
<< "</td><td>" << (response.pending ? "True" : "False") << "</td></tr>"
<< "<tr><td>" << tr("Marker File:")
<< "</td><td>" << markerFileName() << "</td></tr>"
<< "</td><td>" << (data.enabled ? tr("Enabled") : tr("Disabled"));
if (response.pending)
str << tr(", pending");
str << ", " << state << " (" << stateToString(state) << ")</td></tr>";
if (engine) {
str << "<tr><td>" << tr("Engine:")
<< "</td><td>" << engine->objectName() << "</td></tr>";
}
if (!response.pending) {
str << "<tr><td>" << tr("Breakpoint Number:")
<< "</td><td>" << response.number << "</td></tr>";
}
str << "<tr><td>" << tr("Breakpoint Type:")
<< "</td><td>" << t << "</td></tr>";
if (!response.extra.isEmpty()) {
str << "<tr><td>" << tr("Extra Information:")
<< "</td><td>" << response.extra << "</td></tr>"; }
str << "<tr><td>" << tr("Marker File:")
<< "</td><td>" << QDir::toNativeSeparators(markerFileName()) << "</td></tr>"
<< "<tr><td>" << tr("Marker Line:")
<< "</td><td>" << markerLineNumber() << "</td></tr>"
<< "</table><br><hr><table>"
......@@ -1199,28 +1215,32 @@ QString BreakHandler::BreakpointItem::toToolTip() const
formatAddress(str, data.address);
str << "</td><td>";
formatAddress(str, response.address);
//str << "</td></tr>"
// << "<tr><td>" << tr("Corrected Line Number:")
// << "</td><td>-</td><td>";
//if (response.bpCorrectedLineNumber > 0)
// str << response.bpCorrectedLineNumber;
//else
// str << '-';
str << "</td></tr>"
<< "<tr><td>" << tr("Condition:")
<< "</td><td>" << data.condition
<< "</td><td>" << response.condition << "</td></tr>"
<< "<tr><td>" << tr("Ignore Count:") << "</td><td>";
if (data.ignoreCount)
str << data.ignoreCount;
str << "</td><td>";
if (response.ignoreCount)
str << response.ignoreCount;
str << "</td></tr>"
<< "<tr><td>" << tr("Thread Specification:")
<< "</td><td>" << data.threadSpec
<< "</td><td>" << response.threadSpec << "</td></tr>"
<< "</table></body></html>";
if (!data.condition.isEmpty() || !response.condition.isEmpty()) {
str << "</td></tr>"
<< "<tr><td>" << tr("Condition:")
<< "</td><td>" << data.condition
<< "</td><td>" << response.condition << "</td></tr>";
}
if (data.ignoreCount || response.ignoreCount) {
str << "<tr><td>" << tr("Ignore Count:") << "</td><td>";
if (data.ignoreCount)
str << data.ignoreCount;
str << "</td><td>";
if (response.ignoreCount)
str << response.ignoreCount;
}
if (data.threadSpec >= 0 || response.threadSpec >= 0) {
str << "</td></tr>"
<< "<tr><td>" << tr("Thread Specification:")
<< "</td><td>";
if (data.threadSpec >= 0)
str << data.threadSpec;
str << "</td><td>";
if (response.threadSpec >= 0)
str << response.threadSpec;
str << "</td></tr>";
}
str << "</table></body></html>";
return rc;
}
......
......@@ -136,7 +136,7 @@ public:
DebuggerEngine *engine(BreakpointId id) const;
void setEngine(BreakpointId id, DebuggerEngine *engine);
const BreakpointResponse &response(BreakpointId id) const;
void setResponse(BreakpointId id, const BreakpointResponse &data);
void setResponse(BreakpointId id, const BreakpointResponse &data, bool takeOver = true);
bool needsChange(BreakpointId id) const;
// State transitions.
......
......@@ -117,6 +117,12 @@ BreakpointDialog::BreakpointDialog(QWidget *parent)
connect(m_ui.comboBoxType, SIGNAL(activated(int)), SLOT(typeChanged(int)));
m_ui.lineEditIgnoreCount->setValidator(
new QIntValidator(0, 2147483647, m_ui.lineEditIgnoreCount));
const QString moduleToolTip =
tr("Specifying the module (base name of the library or executable)\n"
"for function or file type breakpoints can significantly speed up\n"
"debugger start-up times (CDB, LLDB).");
m_ui.labelModule->setToolTip(moduleToolTip);
m_ui.lineEditModule->setToolTip(moduleToolTip);
}
void BreakpointDialog::setType(BreakpointType type)
......
......@@ -380,7 +380,6 @@ CdbEngine::CdbEngine(const DebuggerStartParameters &sp,
m_accessible(false),
m_specialStopMode(NoSpecialStop),
m_nextCommandToken(0),
m_nextBreakpointNumber(1),
m_currentBuiltinCommandIndex(-1),
m_extensionCommandPrefixBA("!"QT_CREATOR_CDB_EXT"."),
m_operateByInstructionPending(true),
......@@ -1022,7 +1021,7 @@ void CdbEngine::executeRunToLine(const QString &fileName, int lineNumber)
BreakpointParameters bp(BreakpointByFileAndLine);
bp.fileName = fileName;
bp.lineNumber = lineNumber;
postCommand(cdbAddBreakpointCommand(bp, true), 0);
postCommand(cdbAddBreakpointCommand(bp, BreakpointId(-1), true), 0);
continueInferior();
}
......@@ -1032,7 +1031,7 @@ void CdbEngine::executeRunToFunction(const QString &functionName)
BreakpointParameters bp(BreakpointByFunction);
bp.functionName = functionName;
postCommand(cdbAddBreakpointCommand(bp, true), 0);
postCommand(cdbAddBreakpointCommand(bp, BreakpointId(-1), true), 0);
continueInferior();
}
......@@ -1607,8 +1606,15 @@ unsigned CdbEngine::examineStopReason(const GdbMi &stopReason,
}
const int threadId = stopReason.findChild("threadId").data().toInt();
if (reason == "breakpoint") {
const int number = stopReason.findChild("breakpointId").data().toInt();
const BreakpointId id = breakHandler()->findBreakpointByNumber(number);
// Note: Internal breakpoints (run to line) are reported with id=0.
BreakpointId id = 0;
int number = 0;
const GdbMi breakpointIdG = stopReason.findChild("breakpointId");
if (breakpointIdG.isValid()) {
id = breakpointIdG.data().toULongLong();
if (id)
number = breakHandler()->response(id).number;
}
if (id && breakHandler()->type(id) == Watchpoint) {
*message = msgWatchpointTriggered(id, number, breakHandler()->address(id), QString::number(threadId));
} else {
......@@ -1750,6 +1756,8 @@ void CdbEngine::handleSessionIdle(const QByteArray &messageBA)
showMessage(QString::fromAscii(stopReason.findChild("threaderror").data()), LogError);
}
// Fire off remaining commands asynchronously
if (!m_pendingBreakpointMap.isEmpty())
postCommandSequence(CommandListBreakPoints);
if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_REGISTER)))
postCommandSequence(CommandListRegisters);
if (debuggerCore()->isDockVisible(QLatin1String(Constants::DOCKWIDGET_MODULES)))
......@@ -2069,33 +2077,6 @@ static QByteArray multiBreakpointCommand(const char *cmdC, const Breakpoints &bp
}
#endif
// Figure out what kind of changes are required to synchronize
enum BreakPointSyncType {
BreakpointsUnchanged, BreakpointsAdded, BreakpointsRemovedChanged
};
static inline BreakPointSyncType breakPointSyncType(const BreakHandler *handler,
const BreakpointIds ids)
{
bool added = false;
foreach (BreakpointId id, ids) {
const BreakpointState state = handler->state(id);
if (debugBreakpoints > 1)
qDebug(" Checking on breakpoint %llu, state %d\n", id, state);
switch (state) {
case BreakpointInsertRequested:
added = true;
break;
case BreakpointChangeRequested:
case BreakpointRemoveRequested:
return BreakpointsRemovedChanged;
default:
break;
}
}
return added ? BreakpointsAdded : BreakpointsUnchanged;
}
bool CdbEngine::stateAcceptsBreakpointChanges() const
{
switch (state()) {
......@@ -2124,13 +2105,33 @@ void CdbEngine::attemptBreakpointSynchronization()
if (acceptsBreakpoint(id))
handler->setEngine(id, this);
// Find out if there is a need to synchronize again
// Quick check: is there a need to change something? - Populate module cache
bool changed = false;
const BreakpointIds ids = handler->engineBreakpointIds(this);
const BreakPointSyncType syncType = breakPointSyncType(handler, ids);
foreach (BreakpointId id, ids) {
switch (handler->state(id)) {
case BreakpointInsertRequested:
case BreakpointRemoveRequested:
case BreakpointChangeRequested:
changed = true;
break;
case BreakpointInserted: {
// Collect the new modules matching the files.
// In the future, that information should be obtained from the build system.
const BreakpointParameters &data = handler->breakpointData(id);
if (data.type == BreakpointByFileAndLine && !data.module.isEmpty())
m_fileNameModuleHash.insert(data.fileName, data.module);
}
break;
default:
break;
}
}
if (debugBreakpoints)
qDebug("attemptBreakpointSynchronizationI %dms accessible=%d, %s %d breakpoints, syncType=%d",
elapsedLogTime(), m_accessible, stateName(state()), ids.size(), syncType);
if (syncType == BreakpointsUnchanged)
qDebug("attemptBreakpointSynchronizationI %dms accessible=%d, %s %d breakpoints, changed=%d",
elapsedLogTime(), m_accessible, stateName(state()), ids.size(), changed);
if (!changed)
return;
if (!m_accessible) {
......@@ -2139,55 +2140,64 @@ void CdbEngine::attemptBreakpointSynchronization()
doInterruptInferior(SpecialStopSynchronizeBreakpoints);
return;
}
// If there are changes/removals, delete all breakpoints and re-insert
// all enabled breakpoints. This is the simplest
// way to apply changes since CDB ids shift when removing breakpoints and there is no
// easy way to re-match them.
if (syncType == BreakpointsRemovedChanged) { // Need to clear out all?
postCommand("bc *", 0);
m_nextBreakpointNumber = 0;
}
// Add/Change breakpoints and store pending ones in map, since
// Breakhandler::setResponse() on pending breakpoints clears the pending flag.
// handleBreakPoints will the complete that information and set it on the break handler.
bool addedChanged = false;
foreach (BreakpointId id, ids) {
BreakpointParameters parameters = handler->breakpointData(id);
BreakpointResponse response;
const BreakpointParameters &p = handler->breakpointData(id);
response.fromParameters(p);
response.fromParameters(parameters);
// If we encountered that file and have a module for it: Add it.
if (parameters.type == BreakpointByFileAndLine && parameters.module.isEmpty()) {
const QHash<QString, QString>::const_iterator it = m_fileNameModuleHash.constFind(parameters.fileName);
if (it != m_fileNameModuleHash.constEnd())
parameters.module = it.value();
}
switch (handler->state(id)) {
case BreakpointInsertRequested:
response.number = m_nextBreakpointNumber++;
postCommand(cdbAddBreakpointCommand(p, false, response.number), 0);
postCommand(cdbAddBreakpointCommand(parameters, id, false), 0);
if (!parameters.enabled)
postCommand("bd " + QByteArray::number(id), 0);
handler->notifyBreakpointInsertProceeding(id);
handler->notifyBreakpointInsertOk(id);
handler->setResponse(id, response);
m_pendingBreakpointMap.insert(id, response);
addedChanged = true;
if (debugBreakpoints)
qDebug("Adding %llu %s\n", id, qPrintable(response.toString()));
break;
case BreakpointChangeRequested:
// Skip disabled breakpoints, else add.
handler->notifyBreakpointChangeProceeding(id);
if (p.enabled) {
response.number = m_nextBreakpointNumber++;
postCommand(cdbAddBreakpointCommand(p, false, response.number), 0);
handler->notifyBreakpointChangeOk(id);
if (parameters.enabled != handler->response(id).enabled) {
// Change enabled/disabled breakpoints without triggering update.
postCommand((parameters.enabled ? "be " : "bd ") + QByteArray::number(id), 0);
response.pending = false;
response.enabled = parameters.enabled;
handler->setResponse(id, response);
} else {
// Delete and re-add, triggering update
addedChanged = true;
postCommand("bc " + QByteArray::number(id), 0);
postCommand(cdbAddBreakpointCommand(parameters, id, false), 0);
m_pendingBreakpointMap.insert(id, response);
}
handler->notifyBreakpointChangeOk(id);
if (debugBreakpoints)
qDebug("Changing %llu %s\n", id, qPrintable(response.toString()));
break;
case BreakpointRemoveRequested:
postCommand("bc " + QByteArray::number(id), 0);
handler->notifyBreakpointRemoveProceeding(id);
handler->notifyBreakpointRemoveOk(id);
break;
case BreakpointInserted:
// Existing breakpoints were deleted due to change/removal, re-set
if (syncType == BreakpointsRemovedChanged) {
response.number = m_nextBreakpointNumber++;;
postCommand(cdbAddBreakpointCommand(p, false, response.number), 0);
handler->setResponse(id, response);
}
m_pendingBreakpointMap.remove(id);
break;
default:
break;
}
}
// List breakpoints and send responses
if (addedChanged)
postCommandSequence(CommandListBreakPoints);
}
QString CdbEngine::normalizeFileName(const QString &f)
......@@ -2308,6 +2318,11 @@ void CdbEngine::postCommandSequence(unsigned mask)
postExtensionCommand("modules", QByteArray(), 0, &CdbEngine::handleModules, mask & ~CommandListModules);
return;
}
if (mask & CommandListBreakPoints) {
postExtensionCommand("breakpoints", QByteArray("-v"), 0,
&CdbEngine::handleBreakPoints, mask & ~CommandListBreakPoints);
return;
}
}
void CdbEngine::handleWidgetAt(const CdbExtensionCommandPtr &reply)
......@@ -2342,6 +2357,81 @@ void CdbEngine::handleWidgetAt(const CdbExtensionCommandPtr &reply)
m_watchPointX = m_watchPointY = 0;
}
static inline void formatCdbBreakPointResponse(BreakpointId id, const BreakpointResponse &r,
QTextStream &str)
{
str << "Obtained breakpoint " << id << " (#" << r.number << ')';
if (r.pending) {
str << ", pending";
} else {
str.setIntegerBase(16);
str << ", at 0x" << r.address;
str.setIntegerBase(10);
}
if (!r.enabled)
str << ", disabled";
if (!r.module.isEmpty())
str << ", module: '" << r.module << '\'';
str << '\n';
}
void CdbEngine::handleBreakPoints(const CdbExtensionCommandPtr &reply)
{
if (debugBreakpoints)
qDebug("CdbEngine::handleBreakPoints: sucess=%d: %s", reply->success, reply->reply.constData());
if (!reply->success) {
showMessage(QString::fromAscii(reply->errorMessage), LogError);
return;
}
GdbMi value;
value.fromString(reply->reply);
if (value.type() != GdbMi::List) {
showMessage(QString::fromAscii("Unabled to parse breakpoints reply"), LogError);
return;
}
handleBreakPoints(value);
}
void CdbEngine::handleBreakPoints(const GdbMi &value)
{
// Report all obtained parameters back. Note that not all parameters are reported
// back, so, match by id and complete
if (debugBreakpoints)
qDebug("\nCdbEngine::handleBreakPoints with %d", value.childCount());
QString message;
QTextStream str(&message);
BreakHandler *handler = breakHandler();
foreach (const GdbMi &breakPointG, value.children()) {
BreakpointResponse reportedResponse;
const BreakpointId id = parseBreakPoint(breakPointG, &reportedResponse);
if (debugBreakpoints)
qDebug(" Parsed %llu: pending=%d %s\n", id, reportedResponse.pending,
qPrintable(reportedResponse.toString()));
if (!reportedResponse.pending) {
const PendingBreakPointMap::iterator it = m_pendingBreakpointMap.find(id);
if (it != m_pendingBreakpointMap.end()) {
// Complete the response and set on handler.
BreakpointResponse &currentResponse = it.value();
currentResponse.number = reportedResponse.number;
currentResponse.address = reportedResponse.address;
currentResponse.module = reportedResponse.module;
currentResponse.pending = reportedResponse.pending;
currentResponse.enabled = reportedResponse.enabled;
formatCdbBreakPointResponse(id, currentResponse, str);