forked from qt-creator/qt-creator
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:
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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());
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -51,6 +51,19 @@ enum ModulesModelRoles
|
|||||||
LoadAllSymbolsRole
|
LoadAllSymbolsRole
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Symbol
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class Symbol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QString address;
|
||||||
|
QString state;
|
||||||
|
QString name;
|
||||||
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
@@ -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() {}
|
||||||
|
Reference in New Issue
Block a user