Debugger: Improve engine detection.

Try to detect engine by looking at toolchain, executable,
attach mode. Find out path to executable in attach to running
dialog.

Reviewed-by: hjk
This commit is contained in:
Friedemann Kleint
2010-03-17 10:57:19 +01:00
parent 3e750afc73
commit 0146926f19
6 changed files with 99 additions and 47 deletions

View File

@@ -68,9 +68,13 @@ class ProcessListFilterModel : public QSortFilterProxyModel
public: public:
explicit ProcessListFilterModel(QObject *parent); explicit ProcessListFilterModel(QObject *parent);
QString processIdAt(const QModelIndex &index) const; QString processIdAt(const QModelIndex &index) const;
QString executableForPid(const QString& pid) const;
void populate(QList<ProcData> processes, const QString &excludePid = QString()); void populate(QList<ProcData> processes, const QString &excludePid = QString());
private: private:
enum { processImageRole = Qt::UserRole };
bool lessThan(const QModelIndex &left, const QModelIndex &right) const; bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
QStandardItemModel *m_model; QStandardItemModel *m_model;
@@ -111,6 +115,17 @@ QString ProcessListFilterModel::processIdAt(const QModelIndex &index) const
return QString(); return QString();
} }
QString ProcessListFilterModel::executableForPid(const QString &pid) const
{
const int rowCount = m_model->rowCount();
for (int r = 0; r < rowCount; r++) {
const QStandardItem *item = m_model->item(r, 0);
if (item->text() == pid)
return item->data(processImageRole).toString();
}
return QString();
}
void ProcessListFilterModel::populate(QList<ProcData> processes, const QString &excludePid) void ProcessListFilterModel::populate(QList<ProcData> processes, const QString &excludePid)
{ {
qStableSort(processes); qStableSort(processes);
@@ -122,10 +137,12 @@ void ProcessListFilterModel::populate(QList<ProcData> processes, const QString &
foreach(const ProcData &proc, processes) { foreach(const ProcData &proc, processes) {
QList<QStandardItem *> row; QList<QStandardItem *> row;
row.append(new QStandardItem(proc.ppid)); row.append(new QStandardItem(proc.ppid));
row.front()->setData(QVariant(proc.image), processImageRole);
row.append(new QStandardItem(proc.name)); row.append(new QStandardItem(proc.name));
if (!proc.image.isEmpty()) if (!proc.image.isEmpty())
row.back()->setToolTip(proc.image); row.back()->setToolTip(proc.image);
row.append(new QStandardItem(proc.state)); row.append(new QStandardItem(proc.state));
if (proc.ppid == excludePid) if (proc.ppid == excludePid)
foreach(QStandardItem *i, row) foreach(QStandardItem *i, row)
i->setEnabled(false); i->setEnabled(false);
@@ -372,9 +389,20 @@ void AttachExternalDialog::procClicked(const QModelIndex &proxyIndex)
m_ui->pidLineEdit->setText(processId); m_ui->pidLineEdit->setText(processId);
} }
QString AttachExternalDialog::attachPIDText() const
{
return m_ui->pidLineEdit->text().trimmed();
}
qint64 AttachExternalDialog::attachPID() const qint64 AttachExternalDialog::attachPID() const
{ {
return m_ui->pidLineEdit->text().toLongLong(); return attachPIDText().toLongLong();
}
QString AttachExternalDialog::executable() const
{
// Search pid in model in case the user typed in the PID.
return m_model->executableForPid(attachPIDText());
} }
void AttachExternalDialog::pidChanged(const QString &pid) void AttachExternalDialog::pidChanged(const QString &pid)

View File

@@ -89,6 +89,7 @@ public:
~AttachExternalDialog(); ~AttachExternalDialog();
qint64 attachPID() const; qint64 attachPID() const;
QString executable() const;
private slots: private slots:
void rebuildProcessList(); void rebuildProcessList();
@@ -99,8 +100,9 @@ private slots:
private: private:
inline QPushButton *okButton() const; inline QPushButton *okButton() const;
const QString m_selfPid; inline QString attachPIDText() const;
const QString m_selfPid;
Ui::AttachExternalDialog *m_ui; Ui::AttachExternalDialog *m_ui;
ProcessListFilterModel *m_model; ProcessListFilterModel *m_model;
}; };

View File

@@ -964,8 +964,7 @@ static IDebuggerEngine *debuggerEngineForToolChain(int toolChainType)
// Figure out the debugger type of an executable. Analyze executable // Figure out the debugger type of an executable. Analyze executable
// unless the toolchain provides a hint. // unless the toolchain provides a hint.
static IDebuggerEngine *determineDebuggerEngine(const QString &executable, static IDebuggerEngine *debuggerEngineForExecutable(const QString &executable,
int toolChainType,
QString *errorMessage, QString *errorMessage,
QString *settingsIdHint) QString *settingsIdHint)
{ {
@@ -977,19 +976,6 @@ static IDebuggerEngine *determineDebuggerEngine(const QString &executable,
return scriptEngine; return scriptEngine;
} }
/*
if (executable.endsWith(_(".sym"))) {
if (!gdbEngine) {
*errorMessage = msgEngineNotAvailable("Gdb Engine");
return 0;
}
return gdbEngine;
}
*/
if (IDebuggerEngine *tce = debuggerEngineForToolChain(toolChainType))
return tce;
#ifndef Q_OS_WIN #ifndef Q_OS_WIN
Q_UNUSED(settingsIdHint) Q_UNUSED(settingsIdHint)
if (!gdbEngine) { if (!gdbEngine) {
@@ -1004,8 +990,11 @@ static IDebuggerEngine *determineDebuggerEngine(const QString &executable,
return gdbEngine; return gdbEngine;
// If a file has PDB files, it has been compiled by VS. // If a file has PDB files, it has been compiled by VS.
QStringList pdbFiles; QStringList pdbFiles;
if (!getPDBFiles(executable, &pdbFiles, errorMessage)) if (!getPDBFiles(executable, &pdbFiles, errorMessage)) {
qWarning("Cannot determine type of executable %s: %s",
qPrintable(executable), qPrintable(*errorMessage));
return 0; return 0;
}
if (pdbFiles.empty()) if (pdbFiles.empty())
return gdbEngine; return gdbEngine;
@@ -1018,12 +1007,8 @@ static IDebuggerEngine *determineDebuggerEngine(const QString &executable,
} }
// Figure out the debugger type of a PID // Figure out the debugger type of a PID
static IDebuggerEngine *determineDebuggerEngine(int /* pid */, static IDebuggerEngine *debuggerEngineForAttach(QString *errorMessage)
int toolChainType,
QString *errorMessage)
{ {
if (IDebuggerEngine *tce = debuggerEngineForToolChain(toolChainType))
return tce;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
// Preferably Windows debugger // Preferably Windows debugger
if (winEngine) if (winEngine)
@@ -1059,17 +1044,18 @@ void DebuggerManager::startNewDebugger(const DebuggerStartParametersPtr &sp)
QString errorMessage; QString errorMessage;
QString settingsIdHint; QString settingsIdHint;
switch (d->m_startParameters->startMode) {
case AttachExternal: // Figure out engine: toolchain, executable or attach
case AttachCrashedExternal: const DebuggerStartMode startMode = d->m_startParameters->startMode;
d->m_engine = determineDebuggerEngine(d->m_startParameters->attachPID, d->m_engine = debuggerEngineForToolChain(d->m_startParameters->toolChainType);
d->m_startParameters->toolChainType, &errorMessage);
break; if (d->m_engine == 0 && startMode != StartRemote
default: && !d->m_startParameters->executable.isEmpty())
d->m_engine = determineDebuggerEngine(d->m_startParameters->executable, d->m_engine = debuggerEngineForExecutable(d->m_startParameters->executable, &errorMessage, &settingsIdHint);
d->m_startParameters->toolChainType, &errorMessage, &settingsIdHint);
break; if (d->m_engine == 0
} && (startMode == AttachExternal || startMode == AttachCrashedExternal))
d->m_engine = debuggerEngineForAttach(&errorMessage);
if (!d->m_engine) { if (!d->m_engine) {
emit debuggingFinished(); emit debuggingFinished();

View File

@@ -999,7 +999,7 @@ void DebuggerPlugin::attachCmdLine()
m_manager->showStatusMessage(tr("Attaching to PID %1.").arg(m_attachRemoteParameters.attachPid)); m_manager->showStatusMessage(tr("Attaching to PID %1.").arg(m_attachRemoteParameters.attachPid));
const QString crashParameter = const QString crashParameter =
m_attachRemoteParameters.winCrashEvent ? QString::number(m_attachRemoteParameters.winCrashEvent) : QString(); m_attachRemoteParameters.winCrashEvent ? QString::number(m_attachRemoteParameters.winCrashEvent) : QString();
attachExternalApplication(m_attachRemoteParameters.attachPid, crashParameter); attachExternalApplication(m_attachRemoteParameters.attachPid, QString(), crashParameter);
return; return;
} }
if (!m_attachRemoteParameters.attachCore.isEmpty()) { if (!m_attachRemoteParameters.attachCore.isEmpty()) {
@@ -1282,10 +1282,12 @@ void DebuggerPlugin::attachExternalApplication()
{ {
AttachExternalDialog dlg(m_uiSwitcher->mainWindow()); AttachExternalDialog dlg(m_uiSwitcher->mainWindow());
if (dlg.exec() == QDialog::Accepted) if (dlg.exec() == QDialog::Accepted)
attachExternalApplication(dlg.attachPID()); attachExternalApplication(dlg.attachPID(), dlg.executable(), QString());
} }
void DebuggerPlugin::attachExternalApplication(qint64 pid, const QString &crashParameter) void DebuggerPlugin::attachExternalApplication(qint64 pid,
const QString &binary,
const QString &crashParameter)
{ {
if (pid == 0) { if (pid == 0) {
QMessageBox::warning(m_uiSwitcher->mainWindow(), tr("Warning"), QMessageBox::warning(m_uiSwitcher->mainWindow(), tr("Warning"),
@@ -1294,6 +1296,7 @@ void DebuggerPlugin::attachExternalApplication(qint64 pid, const QString &crashP
} }
const DebuggerStartParametersPtr sp(new DebuggerStartParameters); const DebuggerStartParametersPtr sp(new DebuggerStartParameters);
sp->attachPID = pid; sp->attachPID = pid;
sp->executable = binary;
sp->crashParameter = crashParameter; sp->crashParameter = crashParameter;
sp->startMode = crashParameter.isEmpty() ? AttachExternal : AttachCrashedExternal; sp->startMode = crashParameter.isEmpty() ? AttachExternal : AttachCrashedExternal;
if (RunControl *runControl = m_debuggerRunControlFactory->create(sp)) if (RunControl *runControl = m_debuggerRunControlFactory->create(sp))

View File

@@ -125,7 +125,9 @@ private slots:
private: private:
void readSettings(); void readSettings();
void writeSettings() const; void writeSettings() const;
void attachExternalApplication(qint64 pid, const QString &crashParameter = QString()); void attachExternalApplication(qint64 pid,
const QString &binary,
const QString &crashParameter);
void attachCore(const QString &core, const QString &exeFileName); void attachCore(const QString &core, const QString &exeFileName);
friend class Debugger::DebuggerManager; friend class Debugger::DebuggerManager;

View File

@@ -29,16 +29,44 @@
#include "winutils.h" #include "winutils.h"
#include "debuggerdialogs.h" #include "debuggerdialogs.h"
#include <QtCore/QDebug>
#include <windows.h> #include <windows.h>
#include <tlhelp32.h> #include <tlhelp32.h>
#ifdef USE_PSAPI #include <psapi.h>
# include <psapi.h>
#ifdef __GNUC__
# include <QtCore/QLibrary>
#endif #endif
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
#ifdef USE_PSAPI #ifdef __GNUC__
// Resolve QueryFullProcessImageNameW out of kernel32.dll due
// to incomplete MinGW import libs.
static inline BOOL minGW_QueryFullProcessImageName(HANDLE h,
DWORD flags,
LPWSTR buffer,
DWORD *size)
{
// Resolve required symbols from the kernel32.dll
typedef BOOL (WINAPI *QueryFullProcessImageNameWProtoType)
(HANDLE, DWORD, LPWSTR, PDWORD);
static QueryFullProcessImageNameWProtoType queryFullProcessImageNameW = 0;
if (!queryFullProcessImageNameW) {
QLibrary kernel32Lib(QLatin1String("kernel32.dll"), 0);
if (kernel32Lib.isLoaded() || kernel32Lib.load())
queryFullProcessImageNameW = (QueryFullProcessImageNameWProtoType)kernel32Lib.resolve("QueryFullProcessImageNameW");
}
if (!queryFullProcessImageNameW)
return FALSE;
// Read out process
return (*queryFullProcessImageNameW)(h, flags, buffer, size);
}
#endif
static inline QString imageName(DWORD processId) static inline QString imageName(DWORD processId)
{ {
QString rc; QString rc;
@@ -46,12 +74,17 @@ static inline QString imageName(DWORD processId)
if (handle == INVALID_HANDLE_VALUE) if (handle == INVALID_HANDLE_VALUE)
return rc; return rc;
WCHAR buffer[MAX_PATH]; WCHAR buffer[MAX_PATH];
if (GetProcessImageFileName(handle, buffer, MAX_PATH)) DWORD bufSize = MAX_PATH;
#ifdef __GNUC__
if (minGW_QueryFullProcessImageName(handle, 0, buffer, &bufSize))
rc = QString::fromUtf16(reinterpret_cast<const ushort*>(buffer));
#else
if (QueryFullProcessImageNameW(handle, 0, buffer, &bufSize))
rc = QString::fromUtf16(buffer); rc = QString::fromUtf16(buffer);
#endif
CloseHandle(handle); CloseHandle(handle);
return rc; return rc;
} }
#endif
QList<ProcData> winProcessList() QList<ProcData> winProcessList()
{ {
@@ -67,9 +100,7 @@ QList<ProcData> winProcessList()
ProcData procData; ProcData procData;
procData.ppid = QString::number(pe.th32ProcessID); procData.ppid = QString::number(pe.th32ProcessID);
procData.name = QString::fromUtf16(reinterpret_cast<ushort*>(pe.szExeFile)); procData.name = QString::fromUtf16(reinterpret_cast<ushort*>(pe.szExeFile));
#ifdef USE_PSAPI
procData.image = imageName(pe.th32ProcessID); procData.image = imageName(pe.th32ProcessID);
#endif
rc.push_back(procData); rc.push_back(procData);
} }
CloseHandle(snapshot); CloseHandle(snapshot);