From 2a9233a03a5fa71e302a9268b156bb098038749d Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Mon, 5 Oct 2009 17:20:38 +0200
Subject: [PATCH] CDB: Provide thread frame information

---
 src/plugins/debugger/cdb/cdbdebugengine.cpp   |  32 +-----
 .../debugger/cdb/cdbstacktracecontext.cpp     | 100 ++++++++++++++++++
 .../debugger/cdb/cdbstacktracecontext.h       |   9 ++
 3 files changed, 113 insertions(+), 28 deletions(-)

diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index c6e4ca512c4..11f37d15f19 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -1701,36 +1701,12 @@ ULONG CdbDebugEnginePrivate::updateThreadList()
     if (debugCDB)
         qDebug() << Q_FUNC_INFO << m_hDebuggeeProcess;
 
-    ThreadsHandler* th = manager()->threadsHandler();
     QList<ThreadData> threads;
-    bool success = false;
+    ULONG currentThreadId;
     QString errorMessage;
-    ULONG currentThreadId = 0;
-    do {
-        ULONG threadCount;
-        HRESULT hr= m_cif.debugSystemObjects->GetNumberThreads(&threadCount);
-        if (FAILED(hr)) {
-            errorMessage= msgComFailed("GetNumberThreads", hr);
-            break;
-        }
-        // Get ids and index of current
-        if (threadCount) {
-            m_cif.debugSystemObjects->GetCurrentThreadId(&currentThreadId);
-            QVector<ULONG> threadIds(threadCount);
-            hr = m_cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds.begin()), 0);
-            if (FAILED(hr)) {
-                errorMessage= msgComFailed("GetThreadIdsByIndex", hr);
-                break;
-            }
-            for (ULONG i = 0; i < threadCount; i++)
-                threads.push_back(ThreadData(threadIds.at(i)));
-        }
-
-        th->setThreads(threads);
-        success = true;
-    } while (false);
-    if (!success)
-        m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
+    if (!CdbStackTraceContext::getThreads(m_cif, true, &threads, &currentThreadId, &errorMessage))
+        m_engine->warning(errorMessage);
+    manager()->threadsHandler()->setThreads(threads);
     return currentThreadId;
 }
 
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
index 40cd9776bcb..3e5f1c65fcb 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
@@ -219,5 +219,105 @@ void CdbStackTraceContext::format(QTextStream &str) const
     }
 }
 
+// Thread state helper
+
+static inline QString msgGetThreadStateFailed(unsigned long threadId, const QString &why)
+{
+    return QString::fromLatin1("Unable to determine the state of thread %1: %2").arg(threadId).arg(why);
+}
+
+static inline bool getStoppedThreadState(const CdbComInterfaces &cif,
+                                         ThreadData *t,
+                                         QString *errorMessage)
+{
+    ULONG currentThread;
+    HRESULT hr = cif.debugSystemObjects->GetCurrentThreadId(&currentThread);
+    if (FAILED(hr)) {
+        *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("GetCurrentThreadId", hr));
+        return false;
+    }
+    if (currentThread != t->id) {
+        hr = cif.debugSystemObjects->SetCurrentThreadId(t->id);
+        if (FAILED(hr)) {
+            *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("SetCurrentThreadId", hr));
+            return false;
+        }
+    }
+    ULONG frameCount;
+    DEBUG_STACK_FRAME topFrame[1];
+    hr = cif.debugControl->GetStackTrace(0, 0, 0, topFrame, 1, &frameCount);
+    if (FAILED(hr)) {
+        *errorMessage = msgGetThreadStateFailed(t->id, msgComFailed("GetStackTrace", hr));
+        return false;
+    }
+
+    t->address = topFrame[0].InstructionOffset;
+    WCHAR wszBuf[MAX_PATH];
+
+    cif.debugSymbols->GetNameByOffsetWide(topFrame[0].InstructionOffset, wszBuf, MAX_PATH, 0, 0);
+    t->function = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
+    ULONG ulLine;
+    hr = cif.debugSymbols->GetLineByOffsetWide(topFrame[0].InstructionOffset, &ulLine, wszBuf, MAX_PATH, 0, 0);
+    if (SUCCEEDED(hr)) {
+        t->line = ulLine;
+        // Just display base name
+        t->file = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
+        if (!t->file.isEmpty()) {
+            const int slashPos = t->file.lastIndexOf(QLatin1Char('\\'));
+            if (slashPos != -1)
+                t->file.remove(0, slashPos + 1);
+        }
+    }
+    return true;
+}
+
+static inline QString msgGetThreadsFailed(const QString &why)
+{
+    return QString::fromLatin1("Unable to determine the thread information: %1").arg(why);
+}
+
+bool CdbStackTraceContext::getThreads(const CdbComInterfaces &cif,
+                                      bool isStopped,
+                                      QList<ThreadData> *threads,
+                                      ULONG *currentThreadId,
+                                      QString *errorMessage)
+{
+    threads->clear();
+    ULONG threadCount;
+    *currentThreadId = 0;
+    HRESULT hr= cif.debugSystemObjects->GetNumberThreads(&threadCount);
+    if (FAILED(hr)) {
+        *errorMessage= msgGetThreadsFailed(msgComFailed("GetNumberThreads", hr));
+        return false;
+    }
+    // Get ids and index of current
+    if (!threadCount)
+        return true;
+    hr = cif.debugSystemObjects->GetCurrentThreadId(currentThreadId);
+    if (FAILED(hr)) {
+        *errorMessage= msgGetThreadsFailed(msgComFailed("GetCurrentThreadId", hr));
+        return false;
+    }
+
+    QVector<ULONG> threadIds(threadCount);
+    hr = cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds.begin()), 0);
+    if (FAILED(hr)) {
+        *errorMessage= msgGetThreadsFailed(msgComFailed("GetThreadIdsByIndex", hr));
+        return false;
+    }
+    for (ULONG i = 0; i < threadCount; i++) {
+        ThreadData threadData(threadIds.at(i));
+        if (isStopped) {
+            if (!getStoppedThreadState(cif, &threadData, errorMessage)) {
+                qWarning("%s\n", qPrintable(*errorMessage));
+                errorMessage->clear();
+            }
+        }
+        threads->push_back(threadData);
+    }
+    return true;
+}
+
+
 } // namespace Internal
 } // namespace Debugger
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h
index d0d05bea1e8..ff8c62d5b19 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.h
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h
@@ -49,6 +49,7 @@ struct CdbComInterfaces;
 class CdbSymbolGroupContext;
 class CdbStackFrameContext;
 class CdbDumperHelper;
+struct ThreadData;
 
 /* Context representing a break point stack consisting of several frames.
  * Maintains an on-demand constructed list of CdbStackFrameContext
@@ -81,6 +82,14 @@ public:
     void format(QTextStream &str) const;
     QString toString() const;
 
+    // Retrieve information about threads. When stopped, add
+    // current stack frame.
+    static bool getThreads(const CdbComInterfaces &cif,
+                           bool isStopped,
+                           QList<ThreadData> *threads,
+                           ULONG *currentThreadId,
+                           QString *errorMessage);
+
 private:
     bool init(unsigned long frameCount, QString *errorMessage);
     CIDebugSymbolGroup *createSymbolGroup(int index, QString *errorMessage);
-- 
GitLab