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