Commit 4c2f5d1e authored by Friedemann Kleint's avatar Friedemann Kleint

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: default avatarhjk <qtc-commiter@nokia.com>
parent d11242fe
......@@ -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;
}
}
}
......@@ -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);
}
}
......
......@@ -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);
......
......@@ -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);
......
......@@ -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());
......
......@@ -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);
......
......@@ -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;
......
......@@ -51,6 +51,19 @@ enum ModulesModelRoles
LoadAllSymbolsRole
};
//////////////////////////////////////////////////////////////////
//
// Symbol
//
//////////////////////////////////////////////////////////////////
class Symbol
{
public:
QString address;
QString state;
QString name;
};
//////////////////////////////////////////////////////////////////
//
......
......@@ -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);
}
}
}
......@@ -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
......
......@@ -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>();
}
//////////////////////////////////////////////////////////////////////
......
......@@ -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() {}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment