From 0f1b7183593c96ea89ca23ad4f7bb3b0463d674b Mon Sep 17 00:00:00 2001 From: hjk <qtc-committer@nokia.com> Date: Fri, 26 Mar 2010 10:29:19 +0100 Subject: [PATCH] debugger: move breakpoint marker to the line where the breakpoint will be actually hit --- src/plugins/debugger/breakhandler.cpp | 85 ++++++++++++-------- src/plugins/debugger/breakhandler.h | 22 +++-- src/plugins/debugger/gdb/gdbengine.cpp | 75 ++++++++++++----- src/plugins/debugger/gdb/gdbengine.h | 1 + src/plugins/debugger/script/scriptengine.cpp | 14 ++-- 5 files changed, 127 insertions(+), 70 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index e051804c1ae..7b9046fa929 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -124,9 +124,9 @@ public: return; //if (m_data->markerLineNumber == lineNumber) // return; - if (m_data->markerLineNumber != lineNumber) { - m_data->markerLineNumber = lineNumber; - // FIXME: should we tell gdb about the change? + if (m_data->markerLineNumber() != lineNumber) { + m_data->setMarkerLineNumber(lineNumber); + // FIXME: Should we tell gdb about the change? // Ignore it for now, as we would require re-compilation // and debugger re-start anyway. if (0 && !m_data->bpLineNumber.isEmpty()) { @@ -135,8 +135,14 @@ public: } } } - m_data->lineNumber = QByteArray::number(lineNumber); - m_data->handler()->updateMarkers(); + // Ignore updates to the "real" line number while the debugger is + // running, as this can be triggered by moving the breakpoint to + // the next line that generated code. + // FIXME: Do we need yet another data member? + if (m_data->bpNumber.trimmed().isEmpty()) { + m_data->lineNumber = QByteArray::number(lineNumber); + m_data->handler()->updateMarkers(); + } } private: @@ -163,7 +169,7 @@ BreakpointData::BreakpointData(BreakHandler *handler) enabled = true; pending = true; marker = 0; - markerLineNumber = 0; + m_markerLineNumber = 0; bpMultiple = false; //#if defined(Q_OS_MAC) // // full names do not work on Mac/MI @@ -189,26 +195,36 @@ void BreakpointData::removeMarker() void BreakpointData::updateMarker() { - if (marker && (markerFileName != marker->fileName() - || markerLineNumber != marker->lineNumber())) + if (marker && (m_markerFileName != marker->fileName() + || m_markerLineNumber != marker->lineNumber())) removeMarker(); - if (!marker && !markerFileName.isEmpty() && markerLineNumber > 0) - marker = new BreakpointMarker(this, markerFileName, markerLineNumber); + if (!marker && !m_markerFileName.isEmpty() && m_markerLineNumber > 0) + marker = new BreakpointMarker(this, m_markerFileName, m_markerLineNumber); if (marker) marker->setPending(pending, enabled); } +void BreakpointData::setMarkerFileName(const QString &fileName) +{ + m_markerFileName = fileName; +} + +void BreakpointData::setMarkerLineNumber(int lineNumber) +{ + m_markerLineNumber = lineNumber; +} + QString BreakpointData::toToolTip() const { QString rc; QTextStream str(&rc); str << "<html><body><table>" << "<tr><td>" << BreakHandler::tr("Marker File:") - << "</td><td>" << markerFileName << "</td></tr>" + << "</td><td>" << m_markerFileName << "</td></tr>" << "<tr><td>" << BreakHandler::tr("Marker Line:") - << "</td><td>" << markerLineNumber << "</td></tr>" + << "</td><td>" << m_markerLineNumber << "</td></tr>" << "<tr><td>" << BreakHandler::tr("Breakpoint Number:") << "</td><td>" << bpNumber << "</td></tr>" << "<tr><td>" << BreakHandler::tr("Breakpoint Address:") @@ -226,8 +242,7 @@ QString BreakpointData::toToolTip() const << "<tr><td>" << BreakHandler::tr("Line Number:") << "</td><td>" << lineNumber << "</td><td>" << bpLineNumber << "</td></tr>" << "<tr><td>" << BreakHandler::tr("Corrected Line Number:") - << "</td><td>" << lineNumber - << "</td><td>" << bpCorrectedLineNumber << "</td></tr>" + << "</td><td>-</td><td>" << bpCorrectedLineNumber << "</td></tr>" << "<tr><td>" << BreakHandler::tr("Condition:") << "</td><td>" << condition << "</td><td>" << bpCondition << "</td></tr>" << "<tr><td>" << BreakHandler::tr("Ignore Count:") @@ -240,8 +255,8 @@ QString BreakpointData::toString() const { QString rc; QTextStream str(&rc); - str << BreakHandler::tr("Marker File:") << markerFileName << ' ' - << BreakHandler::tr("Marker Line:") << markerLineNumber << ' ' + str << BreakHandler::tr("Marker File:") << m_markerFileName << ' ' + << BreakHandler::tr("Marker Line:") << m_markerLineNumber << ' ' << BreakHandler::tr("Breakpoint Number:") << bpNumber << ' ' << BreakHandler::tr("Breakpoint Address:") << bpAddress << '\n' << BreakHandler::tr("File Name:") @@ -268,7 +283,8 @@ bool BreakpointData::isLocatedAt(const QString &fileName_, int lineNumber_) cons return true; return false; */ - return lineNumber_ == markerLineNumber && fileNameMatch(fileName_, markerFileName); + return lineNumber_ == m_markerLineNumber + && fileNameMatch(fileName_, m_markerFileName); } bool BreakpointData::conditionsMatch() const @@ -343,7 +359,7 @@ void BreakHandler::clear() m_inserted.clear(); } -int BreakHandler::findBreakpoint(const BreakpointData &needle) +int BreakHandler::findBreakpoint(const BreakpointData &needle) const { // Search a breakpoint we might refer to. for (int index = 0; index != size(); ++index) { @@ -360,7 +376,7 @@ int BreakHandler::findBreakpoint(const BreakpointData &needle) return -1; } -int BreakHandler::findBreakpoint(const QString &fileName, int lineNumber) +int BreakHandler::findBreakpoint(const QString &fileName, int lineNumber) const { for (int index = 0; index != size(); ++index) if (at(index)->isLocatedAt(fileName, lineNumber)) @@ -368,15 +384,15 @@ int BreakHandler::findBreakpoint(const QString &fileName, int lineNumber) return -1; } -int BreakHandler::findBreakpoint(int bpNumber) +BreakpointData *BreakHandler::findBreakpoint(int bpNumber) const { if (!size()) - return -1; + return 0; QString numStr = QString::number(bpNumber); for (int index = 0; index != size(); ++index) if (at(index)->bpNumber == numStr) - return index; - return -1; + return at(index); + return 0; } void BreakHandler::saveBreakpoints() @@ -433,8 +449,8 @@ void BreakHandler::loadBreakpoints() v = map.value(QLatin1String("usefullpath")); if (v.isValid()) data->useFullPath = bool(v.toInt()); - data->markerFileName = data->fileName; - data->markerLineNumber = data->lineNumber.toInt(); + data->setMarkerFileName(data->fileName); + data->setMarkerLineNumber(data->lineNumber.toInt()); append(data); } } @@ -450,14 +466,15 @@ void BreakHandler::resetBreakpoints() data->bpFuncName.clear(); data->bpFileName.clear(); data->bpLineNumber.clear(); + data->bpCorrectedLineNumber.clear(); data->bpCondition.clear(); data->bpIgnoreCount.clear(); data->bpAddress.clear(); // Keep marker data if it was primary. - if (data->markerFileName != data->fileName) - data->markerFileName.clear(); - if (data->markerLineNumber != data->lineNumber.toInt()) - data->markerLineNumber = 0; + if (data->markerFileName() != data->fileName) + data->setMarkerFileName(QString()); + if (data->markerLineNumber() != data->lineNumber.toInt()) + data->setMarkerLineNumber(0); } m_enabled.clear(); m_disabled.clear(); @@ -696,8 +713,8 @@ void BreakHandler::setBreakpoint(const QString &fileName, int lineNumber) data->fileName = fileName; data->lineNumber = QByteArray::number(lineNumber); data->pending = true; - data->markerFileName = fileName; - data->markerLineNumber = lineNumber; + data->setMarkerFileName(fileName); + data->setMarkerLineNumber(lineNumber); append(data); emit layoutChanged(); saveBreakpoints(); @@ -738,10 +755,10 @@ void BreakHandler::loadSessionData() void BreakHandler::activateBreakpoint(int index) { const BreakpointData *data = at(index); - if (!data->markerFileName.isEmpty()) { + if (!data->markerFileName().isEmpty()) { StackFrame frame; - frame.file = data->markerFileName; - frame.line = data->markerLineNumber; + frame.file = data->markerFileName(); + frame.line = data->markerLineNumber(); m_manager->gotoLocation(frame, false); } } diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index 63ac4efbb52..c9d476657bb 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -88,16 +88,24 @@ public: QByteArray bpCondition; // Condition acknowledged by the debugger engine. QByteArray bpIgnoreCount;// Ignore count acknowledged by the debugger engine. QString bpFileName; // File name acknowledged by the debugger engine. + QString bpFullName; // Full file name acknowledged by the debugger engine. QByteArray bpLineNumber; // Line number acknowledged by the debugger engine. QByteArray bpCorrectedLineNumber; // Acknowledged by the debugger engine. QString bpFuncName; // Function name acknowledged by the debugger engine. QByteArray bpAddress; // Address acknowledged by the debugger engine. - bool bpMultiple; // Happens in constructors/gdb. - bool bpEnabled; // Enable/disable command sent. + bool bpMultiple; // Happens in constructors/gdb. + bool bpEnabled; // Enable/disable command sent. + void setMarkerFileName(const QString &fileName); + QString markerFileName() const { return m_markerFileName; } + + void setMarkerLineNumber(int lineNumber); + int markerLineNumber() const { return m_markerLineNumber; } + +private: // Taken from either user input or gdb responses. - QString markerFileName; // Used to locate the marker. - int markerLineNumber; + QString m_markerFileName; // Used to locate the marker. + int m_markerLineNumber; // Our red blob in the editor. BreakpointMarker *marker; @@ -132,9 +140,9 @@ public: void removeAt(int index); // This also deletes the marker. void clear(); // This also deletes all the marker. int indexOf(BreakpointData *data) { return m_bp.indexOf(data); } - int findBreakpoint(const QString &fileName, int lineNumber); - int findBreakpoint(const BreakpointData &data); // Returns index. - int findBreakpoint(int bpNumber); // Returns index. + int findBreakpoint(const QString &fileName, int lineNumber) const; + int findBreakpoint(const BreakpointData &data) const; // Returns index. + BreakpointData *findBreakpoint(int bpNumber) const; void updateMarkers(); QList<BreakpointData *> insertedBreakpoints() const; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 2321d8b2c5e..562f497e54f 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -2038,8 +2038,8 @@ void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt fullName = child.data(); } else if (child.hasName("line")) { data->bpLineNumber = child.data(); - if (child.data().toInt()) - data->markerLineNumber = child.data().toInt(); + if (child.data().toInt() && data->bpCorrectedLineNumber.isEmpty()) + data->setMarkerLineNumber(child.data().toInt()); } else if (child.hasName("cond")) { data->bpCondition = child.data(); // gdb 6.3 likes to "rewrite" conditions. Just accept that fact. @@ -2067,8 +2067,10 @@ void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt QString name; if (!fullName.isEmpty()) { name = cleanupFullName(QFile::decodeName(fullName)); - if (data->markerFileName.isEmpty()) - data->markerFileName = name; + if (data->markerFileName().isEmpty()) { + qDebug() << "222" << name; + data->setMarkerFileName(name); + } } else { name = QFile::decodeName(file); // Use fullName() once we have a mapping which is more complete than @@ -2221,7 +2223,7 @@ void GdbEngine::handleBreakDisable(const GdbResponse &response) void GdbEngine::handleBreakIgnore(const GdbResponse &response) { - int index = response.cookie.toInt(); + int bpNumber = response.cookie.toInt(); // gdb 6.8: // ignore 2 0: // ~"Will stop next time breakpoint 2 is reached.\n" @@ -2233,9 +2235,9 @@ void GdbEngine::handleBreakIgnore(const GdbResponse &response) // // gdb 6.3 does not produce any console output BreakHandler *handler = manager()->breakHandler(); - if (response.resultClass == GdbResultDone && index < handler->size()) { + BreakpointData *data = handler->findBreakpoint(bpNumber); + if (response.resultClass == GdbResultDone && data) { QString msg = _(response.data.findChild("consolestreamoutput").data()); - BreakpointData *data = handler->at(index); //if (msg.contains(__("Will stop next time breakpoint"))) { // data->bpIgnoreCount = _("0"); //} else if (msg.contains(__("Will ignore next"))) { @@ -2249,21 +2251,20 @@ void GdbEngine::handleBreakIgnore(const GdbResponse &response) void GdbEngine::handleBreakCondition(const GdbResponse &response) { - int index = response.cookie.toInt(); + int bpNumber = response.cookie.toInt(); BreakHandler *handler = manager()->breakHandler(); + BreakpointData *data = handler->findBreakpoint(bpNumber); if (response.resultClass == GdbResultDone) { // We just assume it was successful. Otherwise we had to parse // the output stream data. - BreakpointData *data = handler->at(index); - //qDebug() << "HANDLE BREAK CONDITION" << index << data->condition; + //qDebug() << "HANDLE BREAK CONDITION" << bpNumber << data->condition; data->bpCondition = data->condition; } else { QByteArray msg = response.data.findChild("msg").data(); // happens on Mac if (1 || msg.startsWith("Error parsing breakpoint condition. " " Will try again when we hit the breakpoint.")) { - BreakpointData *data = handler->at(index); - //qDebug() << "ERROR BREAK CONDITION" << index << data->condition; + //qDebug() << "ERROR BREAK CONDITION" << bpNumber << data->condition; data->bpCondition = data->condition; } } @@ -2316,8 +2317,11 @@ void GdbEngine::extractDataFromInfoBreak(const QString &output, BreakpointData * // the marker in more cases. if (data->fileName.endsWith(full)) full = data->fileName; - data->markerLineNumber = data->bpLineNumber.toInt(); - data->markerFileName = full; + data->setMarkerLineNumber(data->bpLineNumber.toInt()); + if (data->markerFileName().isEmpty()) { + qDebug() << "111"; + data->setMarkerFileName(full); + } data->bpFileName = full; } else { qDebug() << "COULD NOT MATCH " << re.pattern() << " AND " << output; @@ -2327,16 +2331,35 @@ void GdbEngine::extractDataFromInfoBreak(const QString &output, BreakpointData * void GdbEngine::handleBreakInfo(const GdbResponse &response) { - int bpNumber = response.cookie.toInt(); - BreakHandler *handler = manager()->breakHandler(); if (response.resultClass == GdbResultDone) { // Old-style output for multiple breakpoints, presumably in a // constructor. - int found = handler->findBreakpoint(bpNumber); - if (found != -1) { + const int bpNumber = response.cookie.toInt(); + const BreakHandler *handler = manager()->breakHandler(); + BreakpointData *data = handler->findBreakpoint(bpNumber); + if (data) { QString str = QString::fromLocal8Bit( response.data.findChild("consolestreamoutput").data()); - extractDataFromInfoBreak(str, handler->at(found)); + extractDataFromInfoBreak(str, data); + } + } +} + +void GdbEngine::handleInfoLine(const GdbResponse &response) +{ + if (response.resultClass == GdbResultDone) { + // Old-style output: "Line 1102 of \"simple/app.cpp\" starts + // at address 0x80526aa <_Z10...+131> and ends at 0x80526b5 + // <_Z10testQStackv+142>.\n" + const int bpNumber = response.cookie.toInt(); + const BreakHandler *handler = manager()->breakHandler(); + BreakpointData *data = handler->findBreakpoint(bpNumber); + QByteArray ba = response.data.findChild("consolestreamoutput").data(); + const int pos = ba.indexOf(' ', 5); + if (ba.startsWith("Line ") && pos != -1) { + const QByteArray line = ba.mid(5, pos - 5); + data->bpCorrectedLineNumber = line; + data->setMarkerLineNumber(line.toInt()); } } } @@ -2412,7 +2435,7 @@ void GdbEngine::attemptBreakpointSynchronization() foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) { QByteArray bpNumber = data->bpNumber; debugMessage(_("DELETING BP " + bpNumber + " IN " - + data->markerFileName.toLocal8Bit())); + + data->markerFileName().toLocal8Bit())); if (!bpNumber.trimmed().isEmpty()) postCommand("-break-delete " + bpNumber, NeedsStop | RebuildBreakpointModel); @@ -2435,14 +2458,14 @@ void GdbEngine::attemptBreakpointSynchronization() // Update conditions if needed. postCommand("condition " + data->bpNumber + ' ' + data->condition, NeedsStop | RebuildBreakpointModel, - CB(handleBreakCondition), index); + CB(handleBreakCondition), data->bpNumber.toInt()); } else // Because gdb won't do both changes at a time anyway. if (data->ignoreCount != data->bpIgnoreCount) { // Update ignorecount if needed. postCommand("ignore " + data->bpNumber + ' ' + data->ignoreCount, NeedsStop | RebuildBreakpointModel, - CB(handleBreakIgnore), index); + CB(handleBreakIgnore), data->bpNumber.toInt()); continue; } if (!data->enabled && data->bpEnabled) { @@ -2452,6 +2475,14 @@ void GdbEngine::attemptBreakpointSynchronization() data->bpEnabled = false; continue; } + if (!data->bpAddress.isEmpty() + && data->bpCorrectedLineNumber.isEmpty()) { + // Prevent endless loop. + data->bpCorrectedLineNumber = " "; + postCommand("info line *" + data->bpAddress, + NeedsStop | RebuildBreakpointModel, + CB(handleInfoLine), data->bpNumber.toInt()); + } } } diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index 8cc9d3af4f7..f0216a5e8f3 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -342,6 +342,7 @@ private: ////////// View & Data Stuff ////////// void handleBreakInsert2(const GdbResponse &response); void handleBreakCondition(const GdbResponse &response); void handleBreakInfo(const GdbResponse &response); + void handleInfoLine(const GdbResponse &response); void extractDataFromInfoBreak(const QString &output, BreakpointData *data); void breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt); QByteArray breakpointLocation(int index); diff --git a/src/plugins/debugger/script/scriptengine.cpp b/src/plugins/debugger/script/scriptengine.cpp index 0eabcda3992..d4588f6520f 100644 --- a/src/plugins/debugger/script/scriptengine.cpp +++ b/src/plugins/debugger/script/scriptengine.cpp @@ -425,9 +425,9 @@ void ScriptEngine::attemptBreakpointSynchronization() data->bpNumber = QByteArray::number(index + 1); updateNeeded = true; } - if (!data->fileName.isEmpty() && data->markerFileName.isEmpty()) { - data->markerFileName = data->fileName; - data->markerLineNumber = data->lineNumber.toInt(); + if (!data->fileName.isEmpty() && data->markerFileName().isEmpty()) { + data->setMarkerFileName(data->fileName); + data->setMarkerLineNumber(data->lineNumber.toInt()); updateNeeded = true; } } @@ -597,8 +597,8 @@ bool ScriptEngine::checkForBreakCondition(bool byFunction) if (byFunction && functionName.isEmpty()) return false; BreakpointData *data = byFunction ? - findBreakPointByFunction(manager()->breakHandler(), functionName) : - findBreakPointByFileName(manager()->breakHandler(), lineNumber, fileName); + findBreakPointByFunction(manager()->breakHandler(), functionName) : + findBreakPointByFileName(manager()->breakHandler(), lineNumber, fileName); if (!data) return false; @@ -607,8 +607,8 @@ bool ScriptEngine::checkForBreakCondition(bool byFunction) data->bpLineNumber = QByteArray::number(lineNumber); data->bpFileName = fileName; data->bpFuncName = functionName; - data->markerLineNumber = lineNumber; - data->markerFileName = fileName; + data->setMarkerLineNumber(lineNumber); + data->setMarkerFileName(fileName); data->pending = false; data->updateMarker(); } -- GitLab