diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp index 6da7af596a3fd883ca7281c0911b03d9b47fcbe0..d752a4d533ad040b2929d43ea4cef10c51fb87b4 100644 --- a/src/plugins/debugger/debuggerdialogs.cpp +++ b/src/plugins/debugger/debuggerdialogs.cpp @@ -68,9 +68,13 @@ class ProcessListFilterModel : public QSortFilterProxyModel public: explicit ProcessListFilterModel(QObject *parent); QString processIdAt(const QModelIndex &index) const; + QString executableForPid(const QString& pid) const; + void populate(QList<ProcData> processes, const QString &excludePid = QString()); private: + enum { processImageRole = Qt::UserRole }; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const; QStandardItemModel *m_model; @@ -111,6 +115,17 @@ QString ProcessListFilterModel::processIdAt(const QModelIndex &index) const 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) { qStableSort(processes); @@ -122,10 +137,12 @@ void ProcessListFilterModel::populate(QList<ProcData> processes, const QString & foreach(const ProcData &proc, processes) { QList<QStandardItem *> row; row.append(new QStandardItem(proc.ppid)); + row.front()->setData(QVariant(proc.image), processImageRole); row.append(new QStandardItem(proc.name)); if (!proc.image.isEmpty()) row.back()->setToolTip(proc.image); row.append(new QStandardItem(proc.state)); + if (proc.ppid == excludePid) foreach(QStandardItem *i, row) i->setEnabled(false); @@ -372,9 +389,20 @@ void AttachExternalDialog::procClicked(const QModelIndex &proxyIndex) m_ui->pidLineEdit->setText(processId); } +QString AttachExternalDialog::attachPIDText() const +{ + return m_ui->pidLineEdit->text().trimmed(); +} + 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) diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h index e714e005a00d98a257936443face099fad7f32a4..7b9fedca8da17ee22106d6fb0625631d7891a5ae 100644 --- a/src/plugins/debugger/debuggerdialogs.h +++ b/src/plugins/debugger/debuggerdialogs.h @@ -89,6 +89,7 @@ public: ~AttachExternalDialog(); qint64 attachPID() const; + QString executable() const; private slots: void rebuildProcessList(); @@ -99,8 +100,9 @@ private slots: private: inline QPushButton *okButton() const; - const QString m_selfPid; + inline QString attachPIDText() const; + const QString m_selfPid; Ui::AttachExternalDialog *m_ui; ProcessListFilterModel *m_model; }; diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp index 361060a0580e1c1e6b94c119e978a47dc674b3c5..9c0e217e14ee02c6d06c36cb353957aa3c237e8c 100644 --- a/src/plugins/debugger/debuggermanager.cpp +++ b/src/plugins/debugger/debuggermanager.cpp @@ -964,10 +964,9 @@ static IDebuggerEngine *debuggerEngineForToolChain(int toolChainType) // Figure out the debugger type of an executable. Analyze executable // unless the toolchain provides a hint. -static IDebuggerEngine *determineDebuggerEngine(const QString &executable, - int toolChainType, - QString *errorMessage, - QString *settingsIdHint) +static IDebuggerEngine *debuggerEngineForExecutable(const QString &executable, + QString *errorMessage, + QString *settingsIdHint) { if (executable.endsWith(_(".js"))) { if (!scriptEngine) { @@ -977,19 +976,6 @@ static IDebuggerEngine *determineDebuggerEngine(const QString &executable, 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 Q_UNUSED(settingsIdHint) if (!gdbEngine) { @@ -1004,8 +990,11 @@ static IDebuggerEngine *determineDebuggerEngine(const QString &executable, return gdbEngine; // If a file has PDB files, it has been compiled by VS. 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; + } if (pdbFiles.empty()) return gdbEngine; @@ -1018,12 +1007,8 @@ static IDebuggerEngine *determineDebuggerEngine(const QString &executable, } // Figure out the debugger type of a PID -static IDebuggerEngine *determineDebuggerEngine(int /* pid */, - int toolChainType, - QString *errorMessage) +static IDebuggerEngine *debuggerEngineForAttach(QString *errorMessage) { - if (IDebuggerEngine *tce = debuggerEngineForToolChain(toolChainType)) - return tce; #ifdef Q_OS_WIN // Preferably Windows debugger if (winEngine) @@ -1059,17 +1044,18 @@ void DebuggerManager::startNewDebugger(const DebuggerStartParametersPtr &sp) QString errorMessage; QString settingsIdHint; - switch (d->m_startParameters->startMode) { - case AttachExternal: - case AttachCrashedExternal: - d->m_engine = determineDebuggerEngine(d->m_startParameters->attachPID, - d->m_startParameters->toolChainType, &errorMessage); - break; - default: - d->m_engine = determineDebuggerEngine(d->m_startParameters->executable, - d->m_startParameters->toolChainType, &errorMessage, &settingsIdHint); - break; - } + + // Figure out engine: toolchain, executable or attach + const DebuggerStartMode startMode = d->m_startParameters->startMode; + d->m_engine = debuggerEngineForToolChain(d->m_startParameters->toolChainType); + + if (d->m_engine == 0 && startMode != StartRemote + && !d->m_startParameters->executable.isEmpty()) + d->m_engine = debuggerEngineForExecutable(d->m_startParameters->executable, &errorMessage, &settingsIdHint); + + if (d->m_engine == 0 + && (startMode == AttachExternal || startMode == AttachCrashedExternal)) + d->m_engine = debuggerEngineForAttach(&errorMessage); if (!d->m_engine) { emit debuggingFinished(); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index c6b47f4d7ffe1566ce57e911b8431d6a5bd28782..43b5a5fc94230c67d4fb5ddaa763f9eacccfeaa9 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -999,7 +999,7 @@ void DebuggerPlugin::attachCmdLine() m_manager->showStatusMessage(tr("Attaching to PID %1.").arg(m_attachRemoteParameters.attachPid)); const QString crashParameter = m_attachRemoteParameters.winCrashEvent ? QString::number(m_attachRemoteParameters.winCrashEvent) : QString(); - attachExternalApplication(m_attachRemoteParameters.attachPid, crashParameter); + attachExternalApplication(m_attachRemoteParameters.attachPid, QString(), crashParameter); return; } if (!m_attachRemoteParameters.attachCore.isEmpty()) { @@ -1282,10 +1282,12 @@ void DebuggerPlugin::attachExternalApplication() { AttachExternalDialog dlg(m_uiSwitcher->mainWindow()); 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) { QMessageBox::warning(m_uiSwitcher->mainWindow(), tr("Warning"), @@ -1294,6 +1296,7 @@ void DebuggerPlugin::attachExternalApplication(qint64 pid, const QString &crashP } const DebuggerStartParametersPtr sp(new DebuggerStartParameters); sp->attachPID = pid; + sp->executable = binary; sp->crashParameter = crashParameter; sp->startMode = crashParameter.isEmpty() ? AttachExternal : AttachCrashedExternal; if (RunControl *runControl = m_debuggerRunControlFactory->create(sp)) diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h index 348dff8a793107ea9542f915b31772f8c69b2208..8ecf7e492c362886282b9f305137ac8731e1931b 100644 --- a/src/plugins/debugger/debuggerplugin.h +++ b/src/plugins/debugger/debuggerplugin.h @@ -125,7 +125,9 @@ private slots: private: void readSettings(); 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); friend class Debugger::DebuggerManager; diff --git a/src/plugins/debugger/shared/dbgwinutils.cpp b/src/plugins/debugger/shared/dbgwinutils.cpp index 102958d9c1c6d480a0cca8061d09e15e2c316b20..104e1f1b4fab38c564a42505bcdadd3c56594572 100644 --- a/src/plugins/debugger/shared/dbgwinutils.cpp +++ b/src/plugins/debugger/shared/dbgwinutils.cpp @@ -29,16 +29,44 @@ #include "winutils.h" #include "debuggerdialogs.h" + +#include <QtCore/QDebug> + #include <windows.h> #include <tlhelp32.h> -#ifdef USE_PSAPI -# include <psapi.h> +#include <psapi.h> + +#ifdef __GNUC__ +# include <QtCore/QLibrary> #endif namespace Debugger { 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) { QString rc; @@ -46,12 +74,17 @@ static inline QString imageName(DWORD processId) if (handle == INVALID_HANDLE_VALUE) return rc; 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); +#endif CloseHandle(handle); return rc; } -#endif QList<ProcData> winProcessList() { @@ -67,9 +100,7 @@ QList<ProcData> winProcessList() ProcData procData; procData.ppid = QString::number(pe.th32ProcessID); procData.name = QString::fromUtf16(reinterpret_cast<ushort*>(pe.szExeFile)); -#ifdef USE_PSAPI procData.image = imageName(pe.th32ProcessID); -#endif rc.push_back(procData); } CloseHandle(snapshot);