forked from qt-creator/qt-creator
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:
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user