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>
This commit is contained in:
Friedemann Kleint
2009-04-15 12:01:58 +02:00
parent d11242feba
commit 4c2f5d1eaf
12 changed files with 134 additions and 31 deletions

View File

@@ -31,6 +31,8 @@
#include "moduleshandler.h" #include "moduleshandler.h"
#include "cdbdebugengine_p.h" #include "cdbdebugengine_p.h"
#include <QtCore/QFileInfo>
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
@@ -82,10 +84,12 @@ bool searchSymbols(IDebugSymbols3 *syms, const QString &pattern,
QStringList *matches, QString *errorMessage) QStringList *matches, QString *errorMessage)
{ {
matches->clear(); matches->clear();
ULONG64 handle; ULONG64 handle = 0;
// E_NOINTERFACE means "no match" // E_NOINTERFACE means "no match". Apparently, it does not always
// set handle.
HRESULT hr = syms->StartSymbolMatchWide(pattern.utf16(), &handle); HRESULT hr = syms->StartSymbolMatchWide(pattern.utf16(), &handle);
if (hr == E_NOINTERFACE) { if (hr == E_NOINTERFACE) {
if (handle)
syms->EndSymbolMatch(handle); syms->EndSymbolMatch(handle);
return true; return true;
} }
@@ -133,5 +137,27 @@ ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol,
return ResolveSymbolOk; 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;
}
} }
} }

View File

@@ -40,6 +40,7 @@ namespace Debugger {
namespace Internal { namespace Internal {
class Module; class Module;
class Symbol;
bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage); bool getModuleList(IDebugSymbols3 *syms, QList<Module> *modules, QString *errorMessage);
// Search symbols matching a pattern // Search symbols matching a pattern
@@ -54,6 +55,10 @@ enum ResolveSymbolResult { ResolveSymbolOk, ResolveSymbolAmbiguous,
ResolveSymbolResult resolveSymbol(IDebugSymbols3 *syms, QString *symbol, QString *errorMessage); 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);
} }
} }

View File

@@ -175,7 +175,7 @@ void DebuggerManager::init()
m_statusLabel = new QLabel; m_statusLabel = new QLabel;
m_breakWindow = new BreakWindow; m_breakWindow = new BreakWindow;
m_disassemblerWindow = new DisassemblerWindow; m_disassemblerWindow = new DisassemblerWindow;
m_modulesWindow = new ModulesWindow; m_modulesWindow = new ModulesWindow(this);
m_outputWindow = new DebuggerOutputWindow; m_outputWindow = new DebuggerOutputWindow;
m_registerWindow = new RegisterWindow; m_registerWindow = new RegisterWindow;
m_stackWindow = new StackWindow; m_stackWindow = new StackWindow;
@@ -998,6 +998,12 @@ void DebuggerManager::loadSymbols(const QString &module)
m_engine->loadSymbols(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() void DebuggerManager::stepExec()
{ {
QTC_ASSERT(m_engine, return); QTC_ASSERT(m_engine, return);

View File

@@ -65,7 +65,7 @@ class WatchHandler;
class SourceFilesWindow; class SourceFilesWindow;
class WatchData; class WatchData;
class BreakpointData; class BreakpointData;
class Symbol;
// Note: the Debugger process itself is referred to as 'Debugger', // Note: the Debugger process itself is referred to as 'Debugger',
// whereas the debugged process is referred to as 'Inferior' or 'Debuggee'. // whereas the debugged process is referred to as 'Inferior' or 'Debuggee'.
@@ -309,6 +309,8 @@ public:
int status() const { return m_status; } int status() const { return m_status; }
DebuggerStartMode startMode() const { return m_startMode; } DebuggerStartMode startMode() const { return m_startMode; }
QList<Symbol> moduleSymbols(const QString &moduleName);
signals: signals:
void debuggingFinished(); void debuggingFinished();
void inferiorPidChanged(qint64 pid); void inferiorPidChanged(qint64 pid);

View File

@@ -2389,6 +2389,40 @@ void GdbEngine::loadAllSymbols()
reloadModules(); 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() void GdbEngine::reloadModules()
{ {
sendCommand("info shared", ModulesList, QVariant()); sendCommand("info shared", ModulesList, QVariant());

View File

@@ -129,6 +129,7 @@ private:
void loadSymbols(const QString &moduleName); void loadSymbols(const QString &moduleName);
void loadAllSymbols(); void loadAllSymbols();
virtual QList<Symbol> moduleSymbols(const QString &moduleName);
Q_SLOT void setDebugDebuggingHelpers(const QVariant &on); Q_SLOT void setDebugDebuggingHelpers(const QVariant &on);
Q_SLOT void setUseDebuggingHelpers(const QVariant &on); Q_SLOT void setUseDebuggingHelpers(const QVariant &on);

View File

@@ -31,6 +31,7 @@
#define DEBUGGER_IDEBUGGERENGINE_H #define DEBUGGER_IDEBUGGERENGINE_H
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QList>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QPoint; class QPoint;
@@ -40,6 +41,8 @@ QT_END_NAMESPACE
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class Symbol;
class IDebuggerEngine : public QObject class IDebuggerEngine : public QObject
{ {
public: public:
@@ -79,6 +82,7 @@ public:
virtual void reloadModules() = 0; virtual void reloadModules() = 0;
virtual void loadSymbols(const QString &moduleName) = 0; virtual void loadSymbols(const QString &moduleName) = 0;
virtual void loadAllSymbols() = 0; virtual void loadAllSymbols() = 0;
virtual QList<Symbol> moduleSymbols(const QString &moduleName) = 0;
virtual void reloadRegisters() = 0; virtual void reloadRegisters() = 0;

View File

@@ -51,6 +51,19 @@ enum ModulesModelRoles
LoadAllSymbolsRole LoadAllSymbolsRole
}; };
//////////////////////////////////////////////////////////////////
//
// Symbol
//
//////////////////////////////////////////////////////////////////
class Symbol
{
public:
QString address;
QString state;
QString name;
};
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// //

View File

@@ -29,6 +29,7 @@
#include "moduleswindow.h" #include "moduleswindow.h"
#include "moduleshandler.h" // for model roles #include "moduleshandler.h" // for model roles
#include "debuggermanager.h"
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QProcess> #include <QtCore/QProcess>
@@ -40,7 +41,7 @@
#include <QtGui/QResizeEvent> #include <QtGui/QResizeEvent>
#include <QtGui/QToolButton> #include <QtGui/QToolButton>
#include <QtGui/QTreeWidget> #include <QtGui/QTreeWidget>
#include <QtGui/QApplication>
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// //
@@ -48,10 +49,14 @@
// //
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
using Debugger::Internal::ModulesWindow; namespace Debugger {
namespace Internal {
ModulesWindow::ModulesWindow(QWidget *parent) ModulesWindow::ModulesWindow(DebuggerManager *debuggerManager,
: QTreeView(parent), m_alwaysResizeColumnsToContents(false) QWidget *parent) :
QTreeView(parent),
m_alwaysResizeColumnsToContents(false),
m_debuggerManager(debuggerManager)
{ {
setWindowTitle(tr("Modules")); setWindowTitle(tr("Modules"));
setSortingEnabled(true); setSortingEnabled(true);
@@ -88,9 +93,12 @@ void ModulesWindow::resizeEvent(QResizeEvent *event)
void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev) void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
{ {
QString name;
QModelIndex index = indexAt(ev->pos()); QModelIndex index = indexAt(ev->pos());
if (index.isValid())
index = index.sibling(index.row(), 0); index = index.sibling(index.row(), 0);
QString name = model()->data(index).toString(); if (index.isValid())
name = model()->data(index).toString();
QMenu menu; QMenu menu;
QAction *act0 = new QAction(tr("Update module list"), &menu); QAction *act0 = new QAction(tr("Update module list"), &menu);
@@ -116,9 +124,6 @@ void ModulesWindow::contextMenuEvent(QContextMenuEvent *ev)
act5->setDisabled(name.isEmpty()); act5->setDisabled(name.isEmpty());
act6->setDisabled(name.isEmpty()); act6->setDisabled(name.isEmpty());
act7->setDisabled(name.isEmpty()); act7->setDisabled(name.isEmpty());
#ifndef Q_OS_LINUX
act7->setDisabled(true);
#endif
menu.addAction(act0); menu.addAction(act0);
menu.addAction(act4); menu.addAction(act4);
@@ -178,28 +183,26 @@ void ModulesWindow::showSymbols(const QString &name)
{ {
if (name.isEmpty()) if (name.isEmpty())
return; return;
QProcess proc; QApplication::setOverrideCursor(Qt::WaitCursor);
proc.start("nm", QStringList() << "-D" << name); const QList<Symbol> symbols = m_debuggerManager->moduleSymbols(name);
proc.waitForFinished(); QApplication::restoreOverrideCursor();
if (symbols.empty())
return;
QTreeWidget *w = new QTreeWidget; QTreeWidget *w = new QTreeWidget;
w->setColumnCount(3); w->setColumnCount(3);
w->setRootIsDecorated(false); w->setRootIsDecorated(false);
w->setAlternatingRowColors(true); w->setAlternatingRowColors(true);
//w->header()->hide();
w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol")); w->setHeaderLabels(QStringList() << tr("Address") << tr("Code") << tr("Symbol"));
w->setWindowTitle(tr("Symbols in \"%1\"").arg(name)); w->setWindowTitle(tr("Symbols in \"%1\"").arg(name));
QString contents = QString::fromLocal8Bit(proc.readAllStandardOutput()); foreach (const Symbol &s, symbols) {
QRegExp re("([0-9a-f]+)?\\s+([^\\s]+)\\s+([^\\s]+)");
foreach (QString line, contents.split('\n')) {
if (re.indexIn(line) != -1) {
QTreeWidgetItem *it = new QTreeWidgetItem; QTreeWidgetItem *it = new QTreeWidgetItem;
it->setData(0, Qt::DisplayRole, re.cap(1)); it->setData(0, Qt::DisplayRole, s.address);
it->setData(1, Qt::DisplayRole, re.cap(2)); it->setData(1, Qt::DisplayRole, s.state);
it->setData(2, Qt::DisplayRole, re.cap(3)); it->setData(2, Qt::DisplayRole, s.name);
w->addTopLevelItem(it); w->addTopLevelItem(it);
} else {
qDebug() << "UNHANDLED LINE" << line;
}
} }
emit newDockRequested(w); emit newDockRequested(w);
} }
}
}

View File

@@ -35,12 +35,14 @@
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
class DebuggerManager;
class ModulesWindow : public QTreeView class ModulesWindow : public QTreeView
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit ModulesWindow(QWidget *parent = 0); explicit ModulesWindow(DebuggerManager *debuggerManager, QWidget *parent = 0);
signals: signals:
void reloadModulesRequested(); void reloadModulesRequested();
@@ -62,6 +64,7 @@ private:
void setModel(QAbstractItemModel *model); void setModel(QAbstractItemModel *model);
bool m_alwaysResizeColumnsToContents; bool m_alwaysResizeColumnsToContents;
DebuggerManager *m_debuggerManager;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -38,6 +38,7 @@
#include "registerhandler.h" #include "registerhandler.h"
#include "stackhandler.h" #include "stackhandler.h"
#include "watchhandler.h" #include "watchhandler.h"
#include "moduleshandler.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -405,6 +406,10 @@ void ScriptEngine::reloadModules()
{ {
} }
QList<Symbol> ScriptEngine::moduleSymbols(const QString & /*moduleName*/)
{
return QList<Symbol>();
}
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@@ -102,6 +102,7 @@ private:
void loadSymbols(const QString &moduleName); void loadSymbols(const QString &moduleName);
void loadAllSymbols(); void loadAllSymbols();
virtual QList<Symbol> moduleSymbols(const QString &moduleName);
void reloadDisassembler(); void reloadDisassembler();
void reloadModules(); void reloadModules();
void reloadRegisters() {} void reloadRegisters() {}