From eb05d2ac0b9563312c642bf0016744b8ede9562a Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Fri, 19 Feb 2010 11:58:54 +0100
Subject: [PATCH] CDB CoreEngine: Support break by address for testing
 purposes.

---
 src/plugins/debugger/cdb/breakpoint.cpp | 65 +++++++++++++++++++------
 src/plugins/debugger/cdb/breakpoint.h   | 12 +++--
 src/plugins/debugger/cdb/coreengine.cpp | 16 ++++++
 src/plugins/debugger/cdb/coreengine.h   |  2 +
 tests/manual/ccdb/cdbapplication.cpp    | 46 +++++++++--------
 tests/manual/ccdb/cdbapplication.h      |  4 +-
 6 files changed, 104 insertions(+), 41 deletions(-)

diff --git a/src/plugins/debugger/cdb/breakpoint.cpp b/src/plugins/debugger/cdb/breakpoint.cpp
index 5ce3edf2d66..4b3aba87e98 100644
--- a/src/plugins/debugger/cdb/breakpoint.cpp
+++ b/src/plugins/debugger/cdb/breakpoint.cpp
@@ -50,8 +50,9 @@ namespace CdbCore {
 static const char sourceFileQuoteC = '`';
 
 BreakPoint::BreakPoint() :
-    ignoreCount(0),
     lineNumber(-1),
+    address(0),
+    ignoreCount(0),
     oneShot(false),
     enabled(true)
 {
@@ -59,14 +60,18 @@ BreakPoint::BreakPoint() :
 
 int BreakPoint::compare(const BreakPoint& rhs) const
 {
-    if (ignoreCount > rhs.ignoreCount)
-        return 1;
-    if (ignoreCount < rhs.ignoreCount)
-        return -1;
     if (lineNumber > rhs.lineNumber)
         return 1;
     if (lineNumber < rhs.lineNumber)
         return -1;
+    if (address > rhs.address)
+        return 1;
+    if (address < rhs.address)
+        return -1;
+    if (ignoreCount > rhs.ignoreCount)
+        return 1;
+    if (ignoreCount < rhs.ignoreCount)
+        return -1;
     if (oneShot && !rhs.oneShot)
         return 1;
     if (!oneShot && rhs.oneShot)
@@ -98,11 +103,14 @@ void BreakPoint::clearExpressionData()
     condition.clear();
     funcName.clear();
     lineNumber = -1;
+    address = 0;
 }
 
 QDebug operator<<(QDebug dbg, const BreakPoint &bp)
 {
     QDebug nsp = dbg.nospace();
+    if (bp.address)
+        nsp << "0x" << QString::number(bp.address, 16) << ' ';
     if (!bp.fileName.isEmpty()) {
         nsp << "fileName='" << bp.fileName << ':' << bp.lineNumber << '\'';
     } else {
@@ -124,16 +132,26 @@ QString BreakPoint::expression() const
     // format the breakpoint expression (file/function and condition)
     QString rc;
     QTextStream str(&rc);
-    if (funcName.isEmpty()) {
-        const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC);
-        str << sourceFileQuote << QDir::toNativeSeparators(fileName) << QLatin1Char(':') << lineNumber << sourceFileQuote;
-    } else {
-        str << funcName;
-    }
-    if (!condition.isEmpty()) {
-        const QChar doubleQuote = QLatin1Char('"');
-        str << QLatin1Char(' ') << doubleQuote << condition << doubleQuote;
-    }
+    do {
+        if (address) {
+            str.setIntegerBase(16);
+            str << "0x" << address;
+            str.setIntegerBase(10);
+            break;
+        }
+        if (!fileName.isEmpty()) {
+            const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC);
+            str << sourceFileQuote << QDir::toNativeSeparators(fileName) << QLatin1Char(':')
+                    << lineNumber << sourceFileQuote;
+            break;
+        }
+        if (!funcName.isEmpty()) {
+            str << funcName;
+            break;
+        }
+    } while (false);
+    if (!condition.isEmpty())
+        str << " \"" << condition << '"';
     return rc;
 }
 
@@ -335,7 +353,22 @@ bool BreakPoint::parseExpression(const QString &expr)
     const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC);
     // Check for file or function
     int conditionPos = 0;
-    if (expr.startsWith(sourceFileQuote)) { // `c:\foo.cpp:523`[ "condition"]
+    if (expr.startsWith(QLatin1String("0x"))) { // Check address token
+        conditionPos = expr.indexOf(QLatin1Char(' '));
+        QString addressS;
+        if (conditionPos != -1) {
+            addressS = expr.mid(2, conditionPos - 2);
+            conditionPos++;
+        } else {
+            addressS = expr.mid(2);
+            conditionPos = expr.size();
+        }
+        addressS.remove(QLatin1Char('\'')); // 64bit separator
+        bool ok;
+        address = addressS.toULongLong(&ok, 16);
+        if (!ok)
+            return false;
+    } else if (expr.startsWith(sourceFileQuote)) { // `c:\foo.cpp:523`[ "condition"]
         // Do not fall for the drive letter colon here
         const int colonPos = expr.indexOf(QLatin1Char(':'), 3);
         if (colonPos == -1)
diff --git a/src/plugins/debugger/cdb/breakpoint.h b/src/plugins/debugger/cdb/breakpoint.h
index 61fb02accd5..1d8eb050fcc 100644
--- a/src/plugins/debugger/cdb/breakpoint.h
+++ b/src/plugins/debugger/cdb/breakpoint.h
@@ -42,7 +42,10 @@ QT_END_NAMESPACE
 namespace CdbCore {
 
 /* CDB Break point data structure with utilities to
- * apply to engine and to retrieve them from the engine and comparison. */
+ * apply to engine and to retrieve them from the engine and comparison.
+ * Can stop on 'sourcefile:line', function or address.
+ * When/How many times it triggers can be influenced by
+ * condition/ignorecount and 'oneshot'-flag. */
 
 struct BreakPoint
 {
@@ -79,10 +82,12 @@ struct BreakPoint
     static void clearNormalizeFileNameCache();
 
     QString fileName;       // short name of source file
-    QString condition;      // condition associated with breakpoint
-    unsigned long ignoreCount;    // ignore count associated with breakpoint
     int lineNumber;     // line in source file
     QString funcName;       // name of containing function
+    quint64 address;
+
+    QString condition;      // condition associated with breakpoint
+    unsigned long ignoreCount;    // ignore count associated with breakpoint
     bool oneShot;
     bool enabled;
 };
@@ -93,7 +98,6 @@ inline bool operator==(const BreakPoint& b1, const BreakPoint& b2)
     { return b1.compare(b2) == 0; }
 inline bool operator!=(const BreakPoint& b1, const BreakPoint& b2)
     { return b1.compare(b2) != 0; }
-
 }
 
 #endif // CDBCOREBREAKPOINTS_H
diff --git a/src/plugins/debugger/cdb/coreengine.cpp b/src/plugins/debugger/cdb/coreengine.cpp
index 8a652ffa4a5..48315cf561d 100644
--- a/src/plugins/debugger/cdb/coreengine.cpp
+++ b/src/plugins/debugger/cdb/coreengine.cpp
@@ -789,6 +789,22 @@ bool CoreEngine::dissassemble(ULONG64 offset,
     return true;
 }
 
+quint64 CoreEngine::getSourceLineAddress(const QString &file,
+                                         int line,
+                                         QString *errorMessage) const
+{
+    ULONG64 rc = 0;
+    const HRESULT hr = m_cif.debugSymbols->GetOffsetByLineWide(line,
+                                                               const_cast<ushort*>(file.utf16()),
+                                                               &rc);
+    if (FAILED(hr)) {
+        *errorMessage = QString::fromLatin1("Unable to determine address of %1:%2 : %3").
+                        arg(file).arg(line).arg(msgComFailed("GetOffsetByLine", hr));
+        return 0;
+    }
+    return rc;
+}
+
 bool CoreEngine::autoDetectPath(QString *outPath,
                                 QStringList *checkedDirectories /* = 0 */)
 {
diff --git a/src/plugins/debugger/cdb/coreengine.h b/src/plugins/debugger/cdb/coreengine.h
index 24968a33ebd..2614f4535c5 100644
--- a/src/plugins/debugger/cdb/coreengine.h
+++ b/src/plugins/debugger/cdb/coreengine.h
@@ -144,6 +144,8 @@ public:
     bool dissassemble(ULONG64 offset, unsigned long beforeLines, unsigned long afterLines,
                       QString *target, QString *errorMessage);
 
+    quint64 getSourceLineAddress(const QString &file, int line, QString *errorMessage) const;
+
     static bool autoDetectPath(QString *outPath,
                                QStringList *checkedDirectories = 0);
 
diff --git a/tests/manual/ccdb/cdbapplication.cpp b/tests/manual/ccdb/cdbapplication.cpp
index ff4d21fcc91..82c120cfe49 100644
--- a/tests/manual/ccdb/cdbapplication.cpp
+++ b/tests/manual/ccdb/cdbapplication.cpp
@@ -37,6 +37,7 @@
 
 #include <QtCore/QStringList>
 #include <QtCore/QTimer>
+#include <QtCore/QDebug>
 
 #include <cstdio>
 
@@ -174,20 +175,30 @@ void CdbApplication::printFrame(const QString &arg)
         printf("%s\n", qPrintable(errorMessage));
 }
 
-bool CdbApplication::queueBreakPoint(const QString &arg)
+// Return address or 0 on failure
+quint64 CdbApplication::addQueuedBreakPoint(const QString &arg, QString *errorMessage)
 {
     // Queue file:line
     const int cpos = arg.lastIndexOf(QLatin1Char(':'));
-    if (cpos == -1)
-        return false;
-    CdbCore::BreakPoint bp;
-    bp.fileName = arg.left(cpos);
+    if (cpos == -1) {
+        *errorMessage = QString::fromLatin1("Syntax error in '%1': No colon.").arg(arg);
+        return 0;
+    }
+
+    const QString fileName = arg.left(cpos);
     bool ok;
-    bp.lineNumber = arg.mid(cpos + 1).toInt(&ok);
-    if (!ok || bp.lineNumber < 1)
-        return false;
-    m_queuedBreakPoints.push_back(bp);
-    return true;
+    const int lineNumber = arg.mid(cpos + 1).toInt(&ok);
+    if (!ok || lineNumber < 1) {
+        *errorMessage = QString::fromLatin1("Syntax error in '%1': No line number.").arg(arg);
+        return 0;
+    }
+    CdbCore::BreakPoint bp;
+    bp.address = m_engine->getSourceLineAddress(fileName, lineNumber, errorMessage);
+    if (!bp.address)
+        return 0;
+    if (!bp.add(m_engine->interfaces().debugControl, errorMessage))
+        return 0;
+    return bp.address;
 }
 
 void CdbApplication::syncCommand(int command, const QString &arg)
@@ -223,11 +234,8 @@ void CdbApplication::syncCommand(int command, const QString &arg)
             std::printf("Breakpoint queue cleared\n");
             m_queuedBreakPoints.clear();
         } else {
-            if (queueBreakPoint(targs)) {
-                std::printf("Queueing breakpoint %s\n", qPrintable(targs));
-            } else {
-                std::printf("BREAKPOINT SYNTAX ERROR: %s\n", qPrintable(targs));
-            }
+            m_queuedBreakPoints.push_back(targs);
+            std::printf("Queueing breakpoint %s\n", qPrintable(targs));
         }
     }
         break;
@@ -323,12 +331,12 @@ void CdbApplication::processAttached(void *handle)
         }
     }
     // Breakpoints
-    foreach(const CdbCore::BreakPoint &bp, m_queuedBreakPoints) {
-        if (bp.add(m_engine->interfaces().debugControl, &errorMessage)) {
-            std::printf("'%s' [ok]\n", qPrintable(bp.expression()));
+    foreach(const QString &bp, m_queuedBreakPoints) {
+        if (const quint64 address = addQueuedBreakPoint(bp, &errorMessage)) {
+            std::printf("'%s' 0x%lx [ok]\n", qPrintable(bp), address);
         } else {
             std::fprintf(stderr, "%s: %s\n",
-                         qPrintable(bp.expression()),
+                         qPrintable(bp),
                          qPrintable(errorMessage));
         }
     }
diff --git a/tests/manual/ccdb/cdbapplication.h b/tests/manual/ccdb/cdbapplication.h
index 9a360d43488..432806e8f1c 100644
--- a/tests/manual/ccdb/cdbapplication.h
+++ b/tests/manual/ccdb/cdbapplication.h
@@ -67,14 +67,14 @@ private slots:
 private:
     bool parseOptions();
     void printFrame(const QString &arg);
-    bool queueBreakPoint(const QString &arg);
+    quint64 addQueuedBreakPoint(const QString &arg, QString *errorMessage);
 
     QString m_engineDll;
     QSharedPointer<CdbCore::CoreEngine> m_engine;
     QScopedPointer<CdbCore::StackTraceContext> m_stackTrace;
     CdbPromptThread *m_promptThread;
     QStringList m_queuedCommands;
-    QList<CdbCore::BreakPoint> m_queuedBreakPoints;
+    QStringList m_queuedBreakPoints;
 
     void *m_processHandle;
 };
-- 
GitLab