From 4c2f5d1eafc15a108def26eea40bda0eaf011586 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Wed, 15 Apr 2009 12:01:58 +0200
Subject: [PATCH] Make the "Show symbols" option of the module window work on
 Windows.

Introduce API to debug engines and debugger manager to do this.
Reviewed-by: hjk <qtc-commiter@nokia.com>
---
 src/plugins/debugger/cdb/cdbmodules.cpp  | 32 ++++++++++++--
 src/plugins/debugger/cdb/cdbmodules.h    |  5 +++
 src/plugins/debugger/debuggermanager.cpp |  8 +++-
 src/plugins/debugger/debuggermanager.h   |  4 +-
 src/plugins/debugger/gdbengine.cpp       | 34 +++++++++++++++
 src/plugins/debugger/gdbengine.h         |  1 +
 src/plugins/debugger/idebuggerengine.h   |  4 ++
 src/plugins/debugger/moduleshandler.h    | 13 ++++++
 src/plugins/debugger/moduleswindow.cpp   | 53 +++++++++++++-----------
 src/plugins/debugger/moduleswindow.h     |  5 ++-
 src/plugins/debugger/scriptengine.cpp    |  5 +++
 src/plugins/debugger/scriptengine.h      |  1 +
 12 files changed, 134 insertions(+), 31 deletions(-)

diff --git a/src/plugins/debugger/cdb/cdbmodules.cpp b/src/plugins/debugger/cdb/cdbmodules.cpp
index 70e8bd7d523..8dd52a01353 100644
--- a/src/plugins/debugger/cdb/cdbmodules.cpp
+++ b/src/plugins/debugger/cdb/cdbmodules.cpp
@@ -31,6 +31,8 @@
 #include "moduleshandler.h"
 #include "cdbdebugengine_p.h"
 
+#include <QtCore/QFileInfo>
+
 namespace Debugger {
 namespace Internal {
 
@@ -82,11 +84,13 @@ bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern,
                    QStringList *matches, QString *errorMessage)
 {
     matches->clear();    
-    ULONG64 handle;
-    // E_NOINTERFACE means "no match"
+    ULONG64 handle = 0;
+    // E_NOINTERFACE means "no match". Apparently, it does not always
+    // set handle.
     HRESULT hr = syms->StartSymbolMatchWide(pattern.utf16(), &handle);
     if (hr == E_NOINTERFACE) {
-        syms->EndSymbolMatch(handle);
+        if (handle)
+            syms->EndSymbolMatch(handle);
         return true;
     }
     if (FAILED(hr)) {
@@ -133,5 +137,27 @@ ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol,
     return ResolveSymbolOk;
 }
 
+// List symbols of a module
+bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName,
+                      QList<Symbol> *symbols, QString *errorMessage)
+{
+    // Search all symbols and retrieve addresses
+    symbols->clear();
+    QStringList matches;
+    const QString pattern = QFileInfo(moduleName).baseName() + QLatin1String("!*");
+    if (!searchSymbols(syms, pattern, &matches, errorMessage))
+        return false;
+    const QString hexPrefix = QLatin1String("0x");
+    foreach (const QString &name, matches) {
+        Symbol symbol;
+        symbol.name = name;
+        ULONG64 offset = 0;
+        if (SUCCEEDED(syms->GetOffsetByNameWide(name.utf16(), &offset)))
+            symbol.address = hexPrefix + QString::number(offset, 16);
+        symbols->push_back(symbol);
+    }
+    return true;
+}
+
 }
 }
diff --git a/src/plugins/debugger/cdb/cdbmodules.h b/src/plugins/debugger/cdb/cdbmodules.h
index a7be7a94321..d3058bc906f 100644
--- a/src/plugins/debugger/cdb/cdbmodules.h
+++ b/src/plugins/debugger/cdb/cdbmodules.h
@@ -40,6 +40,7 @@ namespace Debugger {
 namespace Internal {
 
 class Module;
+class Symbol;
 
 bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage);
 // Search symbols matching a pattern
@@ -54,6 +55,10 @@ enum ResolveSymbolResult { ResolveSymbolOk, ResolveSymbolAmbiguous,
 
 ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol, QString *errorMessage);
 
+// List symbols of a module
+bool getModuleSymbols(IDebugSymbols3 *syms, const QString &moduleName,
+                      QList<Symbol> *symbols, QString *errorMessage);
+
 }
 }
 
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 9597c128c9b..5f8f07aed0e 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -175,7 +175,7 @@ void DebuggerManager::init()
     m_statusLabel = new QLabel;
     m_breakWindow = new BreakWindow;
     m_disassemblerWindow = new DisassemblerWindow;
-    m_modulesWindow = new ModulesWindow;
+    m_modulesWindow = new ModulesWindow(this);
     m_outputWindow = new DebuggerOutputWindow;
     m_registerWindow = new RegisterWindow;
     m_stackWindow = new StackWindow;
@@ -998,6 +998,12 @@ void DebuggerManager::loadSymbols(const QString &module)
     m_engine->loadSymbols(module);
 }
 
+QList<Symbol> DebuggerManager::moduleSymbols(const QString &moduleName)
+{
+    QTC_ASSERT(m_engine, return QList<Symbol>());
+    return m_engine->moduleSymbols(moduleName);
+}
+
 void DebuggerManager::stepExec()
 {
     QTC_ASSERT(m_engine, return);
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 72c1467c52e..b9709a68fa5 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -65,7 +65,7 @@ class WatchHandler;
 class SourceFilesWindow;
 class WatchData;
 class BreakpointData;
-
+class Symbol;
 
 // Note: the Debugger process itself is referred to as 'Debugger',
 // whereas the debugged process is referred to as 'Inferior' or 'Debuggee'.
@@ -309,6 +309,8 @@ public:
     int status() const { return m_status; }
     DebuggerStartMode startMode() const { return m_startMode; }
 
+    QList<Symbol> moduleSymbols(const QString &moduleName);
+
 signals:
     void debuggingFinished();
     void inferiorPidChanged(qint64 pid);
diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp
index af3bde01f31..0279c15181f 100644
--- a/src/plugins/debugger/gdbengine.cpp
+++ b/src/plugins/debugger/gdbengine.cpp
@@ -2389,6 +2389,40 @@ void GdbEngine::loadAllSymbols()
     reloadModules();
 }
 
+QList<Symbol> GdbEngine::moduleSymbols(const QString &moduleName)
+{
+    QList<Symbol> rc;
+    bool success = false;
+    QString errorMessage;
+    do {
+        const QString nmBinary = QLatin1String("nm");
+        QProcess proc;
+        proc.start(nmBinary, QStringList() << QLatin1String("-D") << moduleName);
+        if (!proc.waitForFinished()) {
+            errorMessage = tr("Unable to run '%1': %2").arg(nmBinary, proc.errorString());
+            break;
+        }
+        const QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput());
+        const QRegExp re(QLatin1String("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)"));
+        Q_ASSERT(re.isValid());
+        foreach (const QString &line, contents.split(QLatin1Char('\n'))) {
+            if (re.indexIn(line) != -1) {
+                Symbol symbol;
+                symbol.address = re.cap(1);
+                symbol.state = re.cap(2);
+                symbol.name = re.cap(3);
+                rc.push_back(symbol);
+            } else {
+                qWarning("moduleSymbols: unhandled: %s", qPrintable(line));
+            }
+        }
+        success = true;
+    } while (false);
+    if (!success)
+        qWarning("moduleSymbols: %s\n", qPrintable(errorMessage));
+    return rc;
+}
+
 void GdbEngine::reloadModules()
 {
     sendCommand("info shared", ModulesList, QVariant());
diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h
index aebb5da6373..b5f5868dcf5 100644
--- a/src/plugins/debugger/gdbengine.h
+++ b/src/plugins/debugger/gdbengine.h
@@ -129,6 +129,7 @@ private:
 
     void loadSymbols(const QString &moduleName);
     void loadAllSymbols();
+    virtual QList<Symbol> moduleSymbols(const QString &moduleName);
 
     Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
     Q_SLOT void setUseDebuggingHelpers(const QVariant &on);
diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h
index 2bb44f8e47b..0d3863a34e7 100644
--- a/src/plugins/debugger/idebuggerengine.h
+++ b/src/plugins/debugger/idebuggerengine.h
@@ -31,6 +31,7 @@
 #define DEBUGGER_IDEBUGGERENGINE_H
 
 #include <QtCore/QObject>
+#include <QtCore/QList>
 
 QT_BEGIN_NAMESPACE
 class QPoint;
@@ -40,6 +41,8 @@ QT_END_NAMESPACE
 namespace Debugger {
 namespace Internal {
 
+class Symbol;
+
 class IDebuggerEngine : public QObject
 {
 public:
@@ -79,6 +82,7 @@ public:
     virtual void reloadModules() = 0;
     virtual void loadSymbols(const QString &moduleName) = 0;
     virtual void loadAllSymbols() = 0;
+    virtual QList<Symbol> moduleSymbols(const QString &moduleName) = 0;
 
     virtual void reloadRegisters() = 0;
 
diff --git a/src/plugins/debugger/moduleshandler.h b/src/plugins/debugger/moduleshandler.h
index 4c555c83929..a6d77e4a28e 100644
--- a/src/plugins/debugger/moduleshandler.h
+++ b/src/plugins/debugger/moduleshandler.h
@@ -51,6 +51,19 @@ enum ModulesModelRoles
     LoadAllSymbolsRole
 };
 
+//////////////////////////////////////////////////////////////////
+//
+// Symbol
+//
+//////////////////////////////////////////////////////////////////
+
+class Symbol
+{
+public:
+    QString address;
+    QString state;
+    QString name;
+};
 
 //////////////////////////////////////////////////////////////////
 //
diff --git a/src/plugins/debugger/moduleswindow.cpp b/src/plugins/debugger/moduleswindow.cpp
index 8d87709eadc..6435e8b65a6 100644
--- a/src/plugins/debugger/moduleswindow.cpp
+++ b/src/plugins/debugger/moduleswindow.cpp
@@ -29,6 +29,7 @@
 
 #include "moduleswindow.h"
 #include "moduleshandler.h" // for model roles
+#include "debuggermanager.h"
 
 #include <QtCore/QDebug>
 #include <QtCore/QProcess>
@@ -40,7 +41,7 @@
 #include <QtGui/QResizeEvent>
 #include <QtGui/QToolButton>
 #include <QtGui/QTreeWidget>
-
+#include <QtGui/QApplication>
 
 ///////////////////////////////////////////////////////////////////////////
 //
@@ -48,10 +49,14 @@
 //
 ///////////////////////////////////////////////////////////////////////////
 
-using Debugger::Internal::ModulesWindow;
+namespace Debugger {
+namespace Internal {
 
-ModulesWindow::ModulesWindow(QWidget *parent)
-    : QTreeView(parent), m_alwaysResizeColumnsToContents(false)
+ModulesWindow::ModulesWindow(DebuggerManager *debuggerManager,
+                             QWidget *parent)  :
+    QTreeView(parent),
+    m_alwaysResizeColumnsToContents(false),
+    m_debuggerManager(debuggerManager)
 {
     setWindowTitle(tr("Modules"));
     setSortingEnabled(true);
@@ -88,9 +93,12 @@ void ModulesWindow::resizeEvent(QResizeEvent *event)
 
 void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
 {
+    QString name;
     QModelIndex index = indexAt(ev->pos());
-    index = index.sibling(index.row(), 0);
-    QString name = model()->data(index).toString();
+    if (index.isValid())
+        index = index.sibling(index.row(), 0);
+    if (index.isValid())
+        name = model()->data(index).toString();
 
     QMenu menu;
     QAction *act0 = new QAction(tr("Update module list"), &menu);
@@ -116,9 +124,6 @@ void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
     act5->setDisabled(name.isEmpty());
     act6->setDisabled(name.isEmpty());
     act7->setDisabled(name.isEmpty());
-    #ifndef Q_OS_LINUX
-    act7->setDisabled(true);
-    #endif
 
     menu.addAction(act0);
     menu.addAction(act4);
@@ -178,28 +183,26 @@ void ModulesWindow::showSymbols(const QString &name)
 {
     if (name.isEmpty())
         return;
-    QProcess proc;
-    proc.start("nm", QStringList() << "-D" << name);
-    proc.waitForFinished();
+    QApplication::setOverrideCursor(Qt::WaitCursor);
+    const QList<Symbol> symbols = m_debuggerManager->moduleSymbols(name);
+    QApplication::restoreOverrideCursor();
+    if (symbols.empty())
+        return;
     QTreeWidget *w = new QTreeWidget;
     w->setColumnCount(3);
     w->setRootIsDecorated(false);
     w->setAlternatingRowColors(true);
-    //w->header()->hide();
     w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol"));
     w->setWindowTitle(tr("Symbols in \"%1\"").arg(name));
-    QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput());
-    QRegExp re("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)");
-    foreach (QString line, contents.split('\n')) {
-        if (re.indexIn(line) != -1) {
-            QTreeWidgetItem *it = new QTreeWidgetItem;
-            it->setData(0, Qt::DisplayRole, re.cap(1));
-            it->setData(1, Qt::DisplayRole, re.cap(2));
-            it->setData(2, Qt::DisplayRole, re.cap(3));
-            w->addTopLevelItem(it);
-        } else {
-            qDebug() << "UNHANDLED LINE" << line;
-        }
+    foreach (const Symbol &s, symbols) {
+        QTreeWidgetItem *it = new QTreeWidgetItem;
+        it->setData(0, Qt::DisplayRole, s.address);
+        it->setData(1, Qt::DisplayRole, s.state);
+        it->setData(2, Qt::DisplayRole, s.name);
+        w->addTopLevelItem(it);
     }
     emit newDockRequested(w);
 }
+
+}
+}
diff --git a/src/plugins/debugger/moduleswindow.h b/src/plugins/debugger/moduleswindow.h
index 36377fb58ee..fc2b1af2acf 100644
--- a/src/plugins/debugger/moduleswindow.h
+++ b/src/plugins/debugger/moduleswindow.h
@@ -35,12 +35,14 @@
 namespace Debugger {
 namespace Internal {
 
+class DebuggerManager;
+
 class ModulesWindow : public QTreeView
 {
     Q_OBJECT
 
 public:
-    explicit ModulesWindow(QWidget *parent = 0);
+    explicit ModulesWindow(DebuggerManager *debuggerManager, QWidget *parent = 0);
 
 signals:
     void reloadModulesRequested();
@@ -62,6 +64,7 @@ private:
     void setModel(QAbstractItemModel *model);
 
     bool m_alwaysResizeColumnsToContents;
+    DebuggerManager *m_debuggerManager;
 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/scriptengine.cpp b/src/plugins/debugger/scriptengine.cpp
index 3ee8b7f8697..4ab74e2154a 100644
--- a/src/plugins/debugger/scriptengine.cpp
+++ b/src/plugins/debugger/scriptengine.cpp
@@ -38,6 +38,7 @@
 #include "registerhandler.h"
 #include "stackhandler.h"
 #include "watchhandler.h"
+#include "moduleshandler.h"
 
 #include <utils/qtcassert.h>
 
@@ -405,6 +406,10 @@ void ScriptEngine::reloadModules()
 {
 }
 
+QList<Symbol> ScriptEngine::moduleSymbols(const QString & /*moduleName*/)
+{
+    return QList<Symbol>();
+}
 
 
 //////////////////////////////////////////////////////////////////////
diff --git a/src/plugins/debugger/scriptengine.h b/src/plugins/debugger/scriptengine.h
index 5e009327da7..ee5612d09d8 100644
--- a/src/plugins/debugger/scriptengine.h
+++ b/src/plugins/debugger/scriptengine.h
@@ -102,6 +102,7 @@ private:
 
     void loadSymbols(const QString &moduleName);
     void loadAllSymbols();
+    virtual QList<Symbol> moduleSymbols(const QString &moduleName);
     void reloadDisassembler();
     void reloadModules();
     void reloadRegisters() {}
-- 
GitLab