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