summaryrefslogtreecommitdiff
path: root/src/plugins/debugger
diff options
context:
space:
mode:
authorFriedemann Kleint <qtc-committer@nokia.com>2009-03-04 16:00:43 +0100
committerunknown <Thomas@.(none)>2009-03-04 16:00:43 +0100
commit86b6c44e4e35c8a4754b28b5dbbe1bbd49d4e167 (patch)
treea1a360449ca7368240dcfc17ee74af449aecb9ad /src/plugins/debugger
parent1e7d6a01e6fca4cb47b64d85887d482ff3119ae1 (diff)
downloadqt-creator-86b6c44e4e35c8a4754b28b5dbbe1bbd49d4e167.tar.gz
Process Listing Windows
Diffstat (limited to 'src/plugins/debugger')
-rw-r--r--src/plugins/debugger/attachexternaldialog.ui67
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine.cpp114
-rw-r--r--src/plugins/debugger/cdb/cdbdebugengine.h2
-rw-r--r--src/plugins/debugger/debuggerdialogs.cpp239
-rw-r--r--src/plugins/debugger/debuggerdialogs.h11
-rw-r--r--src/plugins/debugger/debuggermanager.cpp49
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp10
-rw-r--r--src/plugins/debugger/win/dbgwinutils.cpp79
-rw-r--r--src/plugins/debugger/win/dbgwinutils.h44
-rw-r--r--src/plugins/debugger/win/win.pri6
10 files changed, 425 insertions, 196 deletions
diff --git a/src/plugins/debugger/attachexternaldialog.ui b/src/plugins/debugger/attachexternaldialog.ui
index 63f214c51e..0c937fa8e8 100644
--- a/src/plugins/debugger/attachexternaldialog.ui
+++ b/src/plugins/debugger/attachexternaldialog.ui
@@ -1,7 +1,8 @@
-<ui version="4.0" >
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
<class>AttachExternalDialog</class>
- <widget class="QDialog" name="AttachExternalDialog" >
- <property name="geometry" >
+ <widget class="QDialog" name="AttachExternalDialog">
+ <property name="geometry">
<rect>
<x>0</x>
<y>0</y>
@@ -9,50 +10,76 @@
<height>866</height>
</rect>
</property>
- <property name="windowTitle" >
+ <property name="windowTitle">
<string>Start Debugger</string>
</property>
- <layout class="QVBoxLayout" >
- <property name="spacing" >
+ <layout class="QVBoxLayout">
+ <property name="spacing">
<number>6</number>
</property>
- <property name="margin" >
+ <property name="margin">
<number>9</number>
</property>
<item>
- <layout class="QHBoxLayout" name="horizontalLayout" >
- <item>
- <widget class="QLabel" name="pidLabel" >
- <property name="text" >
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="pidLabel">
+ <property name="text">
<string>Attach to Process ID:</string>
</property>
</widget>
</item>
- <item>
- <widget class="QLineEdit" name="pidLineEdit" />
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="pidLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="filterLabel">
+ <property name="text">
+ <string>Filter:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QWidget" name="filterWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLineEdit" name="filterLineEdit"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="filterClearToolButton">
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
</item>
</layout>
</item>
<item>
- <widget class="QTreeView" name="procView" >
- <property name="editTriggers" >
+ <widget class="QTreeView" name="procView">
+ <property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
</widget>
</item>
<item>
- <widget class="Line" name="line" >
- <property name="orientation" >
+ <widget class="Line" name="line">
+ <property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
- <widget class="QDialogButtonBox" name="buttonBox" >
- <property name="orientation" >
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
- <property name="standardButtons" >
+ <property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index d204e158c9..ab71dc23e8 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -35,6 +35,7 @@
#include "stackhandler.h"
#include <utils/qtcassert.h>
+#include <utils/winutils.h>
#include <utils/consoleprocess.h>
#include <QtCore/QDebug>
@@ -49,6 +50,31 @@
static const char *dbgEngineDllC = "dbgeng";
static const char *debugCreateFuncC = "DebugCreate";
+static QString debugEngineComError(HRESULT hr)
+{
+ if (!FAILED(hr))
+ return QLatin1String("S_OK");
+ switch (hr) {
+ case E_FAIL:
+ break;
+ case E_INVALIDARG:
+ return QLatin1String("E_INVALIDARG");
+ case E_NOINTERFACE:
+ return QLatin1String("E_NOINTERFACE");
+ case E_OUTOFMEMORY:
+ return QLatin1String("E_OUTOFMEMORY");
+ case E_UNEXPECTED:
+ return QLatin1String("E_UNEXPECTED");
+ case E_NOTIMPL:
+ return QLatin1String("E_NOTIMPL");
+ }
+ if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
+ return QLatin1String("ERROR_ACCESS_DENIED");;
+ if (hr == HRESULT_FROM_NT(STATUS_CONTROL_C_EXIT))
+ return QLatin1String("STATUS_CONTROL_C_EXIT");
+ return Core::Utils::winErrorMessage(HRESULT_CODE(hr));
+}
+
namespace Debugger {
namespace Internal {
@@ -177,13 +203,47 @@ void CdbDebugEngine::setToolTipExpression(const QPoint & /*pos*/, const QString
}
bool CdbDebugEngine::startDebugger()
-{
+{
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
+ QString errorMessage;
+ bool rc = false;
+ switch (m_d->m_debuggerManager->startMode()) {
+ case AttachExternal:
+ rc = startAttachDebugger(m_d->m_debuggerManager->m_attachedPID, &errorMessage);
+ break;
+ case StartInternal:
+ case StartExternal:
+ rc = startDebuggerWithExecutable(&errorMessage);
+ break;
+ case AttachCore:
+ errorMessage = tr("CdbDebugEngine: Attach to core not supported!");
+ break;
+ }
+ if (rc) {
+ m_d->m_debuggerManager->showStatusMessage(tr("Debugger Running"), -1);
+ startWatchTimer();
+ } else {
+ qWarning("%s\n", qPrintable(errorMessage));
+ }
+ return rc;
+}
+
+bool CdbDebugEngine::startAttachDebugger(unsigned long pid, QString *errorMessage)
+{
+ const HRESULT hr = m_d->m_pDebugClient->AttachProcess(NULL, pid,
+ DEBUG_ATTACH_NONINVASIVE |DEBUG_ATTACH_NONINVASIVE_NO_SUSPEND);
+ if (debugCDB)
+ qDebug() << "Attaching to " << pid << " returns " << hr;
+ if (FAILED(hr)) {
+ *errorMessage = tr("AttachProcess failed for pid %1: %2").arg(pid).arg(debugEngineComError(hr));
+ return false;
+ }
+ return true;
+}
- //if (!q->m_workingDir.isEmpty())
- // m_gdbProc.setWorkingDirectory(q->m_workingDir);
- //if (!q->m_environment.isEmpty())
- // m_gdbProc.setEnvironment(q->m_environment);
+bool CdbDebugEngine::startDebuggerWithExecutable(QString *errorMessage)
+{
+ m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
memset(&dbgopts, 0, sizeof(dbgopts));
@@ -199,32 +259,28 @@ bool CdbDebugEngine::startDebugger()
m_d->m_pDebugSymbols->SetSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS);
//m_pDebugSymbols->AddSymbolOptions(SYMOPT_CASE_INSENSITIVE | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST | SYMOPT_AUTO_PUBLICS | SYMOPT_NO_IMAGE_SEARCH);
- if (m_d->m_debuggerManager->startMode() == AttachExternal) {
- qWarning("CdbDebugEngine: attach to process not yet implemented!");
+ // TODO console
+ const QString cmd = Core::Utils::AbstractProcess::createWinCommandline(filename, m_d->m_debuggerManager->m_processArgs);
+ if (debugCDB)
+ qDebug() << "Starting " << cmd;
+ PCWSTR env = 0;
+ QByteArray envData;
+ if (!m_d->m_debuggerManager->m_environment.empty()) {
+ envData = Core::Utils::AbstractProcess::createWinEnvironment(Core::Utils::AbstractProcess::fixWinEnvironment(m_d->m_debuggerManager->m_environment));
+ env = reinterpret_cast<PCWSTR>(envData.data());
+ }
+ const HRESULT hr = m_d->m_pDebugClient->CreateProcess2Wide(NULL,
+ const_cast<PWSTR>(cmd.utf16()),
+ &dbgopts,
+ sizeof(dbgopts),
+ m_d->m_debuggerManager->m_workingDir.utf16(),
+ env);
+ if (FAILED(hr)) {
+ *errorMessage = tr("CreateProcess2Wide failed for '%1': %2").arg(cmd).arg(debugEngineComError(hr));
+ m_d->m_debuggerManagerAccess->notifyInferiorExited();
return false;
- } else {
- QString cmd = Core::Utils::AbstractProcess::createWinCommandline(filename, m_d->m_debuggerManager->m_processArgs);
- PCWSTR env = 0;
- QByteArray envData;
- if (!m_d->m_debuggerManager->m_environment.empty()) {
- envData = Core::Utils::AbstractProcess::createWinEnvironment(Core::Utils::AbstractProcess::fixWinEnvironment(m_d->m_debuggerManager->m_environment));
- env = reinterpret_cast<PCWSTR>(envData.data());
- }
- HRESULT hr = m_d->m_pDebugClient->CreateProcess2Wide(NULL,
- const_cast<PWSTR>(cmd.utf16()),
- &dbgopts,
- sizeof(dbgopts),
- m_d->m_debuggerManager->m_workingDir.utf16(),
- env);
- if (FAILED(hr)) {
- //qWarning("CreateProcess2Wide failed");
- m_d->m_debuggerManagerAccess->notifyInferiorExited();
- return false;
- }
}
-
- m_d->m_debuggerManager->showStatusMessage(tr("Debugger Running"), -1);
- startWatchTimer();
+ m_d->m_debuggerManagerAccess->notifyInferiorRunning();
return true;
}
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.h b/src/plugins/debugger/cdb/cdbdebugengine.h
index 57ad5f8da3..67528008ca 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine.h
@@ -99,6 +99,8 @@ protected:
void timerEvent(QTimerEvent*);
private:
+ bool startAttachDebugger(unsigned long pid, QString *errorMessage);
+ bool startDebuggerWithExecutable(QString *errorMessage);
void startWatchTimer();
void killWatchTimer();
diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp
index 4273fe743b..46f1cdfe8e 100644
--- a/src/plugins/debugger/debuggerdialogs.cpp
+++ b/src/plugins/debugger/debuggerdialogs.cpp
@@ -34,6 +34,10 @@
#include "ui_attachremotedialog.h"
#include "ui_startexternaldialog.h"
+#ifdef Q_OS_WIN
+# include "dbgwinutils.h"
+#endif
+
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFile>
@@ -41,17 +45,11 @@
#include <QtGui/QHeaderView>
#include <QtGui/QFileDialog>
#include <QtGui/QPushButton>
-
-#ifdef Q_OS_WINDOWS
-#include <windows.h>
-#include <tlhelp32.h>
-#include <tchar.h>
-#include <stdio.h>
-#endif
+#include <QtGui/QProxyModel>
+#include <QtGui/QSortFilterProxyModel>
using namespace Debugger::Internal;
-
///////////////////////////////////////////////////////////////////////
//
// AttachCoreDialog
@@ -100,34 +98,21 @@ void AttachCoreDialog::setCoreFile(const QString &fileName)
m_ui->coreFileName->setPath(fileName);
}
-
///////////////////////////////////////////////////////////////////////
//
-// AttachExternalDialog
+// process model helpers
//
///////////////////////////////////////////////////////////////////////
-AttachExternalDialog::AttachExternalDialog(QWidget *parent)
- : QDialog(parent), m_ui(new Ui::AttachExternalDialog)
-{
- m_ui->setupUi(this);
- m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
- m_model = new QStandardItemModel(this);
-
- m_ui->procView->setSortingEnabled(true);
-
- connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
- connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
-
- connect(m_ui->procView, SIGNAL(activated(QModelIndex)),
- this, SLOT(procSelected(QModelIndex)));
-
- rebuildProcessList();
-}
-
-AttachExternalDialog::~AttachExternalDialog()
+static QStandardItemModel *createProcessModel(QObject *parent)
{
- delete m_ui;
+ QStandardItemModel *rc = new QStandardItemModel(parent);
+ QStringList columns;
+ columns << AttachExternalDialog::tr("Process ID")
+ << AttachExternalDialog::tr("Name")
+ << AttachExternalDialog::tr("State");
+ rc->setHorizontalHeaderLabels(columns);
+ return rc;
}
static bool isProcessName(const QString &procname)
@@ -138,87 +123,122 @@ static bool isProcessName(const QString &procname)
return true;
}
-struct ProcData
-{
- QString ppid;
- QString name;
- QString state;
-};
-
-static void insertItem(QStandardItem *root, const QString &pid,
- const QMap<QString, ProcData> &procs, QMap<QString, QStandardItem *> &known)
+bool operator<(const ProcData &p1, const ProcData &p2)
{
- //qDebug() << "HANDLING " << pid;
- QStandardItem *parent = 0;
- const ProcData &proc = procs[pid];
- if (1 || pid == "0") { // FIXME: a real tree is not-so-nice to search
- parent = root;
- } else {
- if (!known.contains(proc.ppid))
- insertItem(root, proc.ppid, procs, known);
- parent = known[proc.ppid];
- }
- QList<QStandardItem *> row;
- row.append(new QStandardItem(pid));
- row.append(new QStandardItem(proc.name));
- //row.append(new QStandardItem(proc.ppid));
- row.append(new QStandardItem(proc.state));
- parent->appendRow(row);
- known[pid] = row[0];
+ return p1.name < p2.name;
}
-void AttachExternalDialog::rebuildProcessList()
+// Determine UNIX processes by reading "/proc"
+static QList<ProcData> unixProcessList()
{
- QStringList procnames = QDir("/proc/").entryList();
- if (procnames.isEmpty()) {
- m_ui->procView->hide();
- return;
- }
-
- typedef QMap<QString, ProcData> Procs;
- Procs procs;
+ QList<ProcData> rc;
+ const QStringList procnames = QDir(QLatin1String("/proc/")).entryList();
+ if (procnames.isEmpty())
+ return rc;
foreach (const QString &procname, procnames) {
if (!isProcessName(procname))
continue;
- QString filename = "/proc/" + procname + "/stat";
+ QString filename = QLatin1String("/proc/");
+ filename += procname;
+ filename += QLatin1String("/stat");
QFile file(filename);
file.open(QIODevice::ReadOnly);
- QStringList data = QString::fromLocal8Bit(file.readAll()).split(' ');
- //qDebug() << filename << data;
+ const QStringList data = QString::fromLocal8Bit(file.readAll()).split(' ');
ProcData proc;
proc.name = data.at(1);
- if (proc.name.startsWith('(') && proc.name.endsWith(')'))
+ if (proc.name.startsWith(QLatin1Char('(')) && proc.name.endsWith(QLatin1Char(')')))
proc.name = proc.name.mid(1, proc.name.size() - 2);
proc.state = data.at(2);
proc.ppid = data.at(3);
- procs[procname] = proc;
+ rc.push_back(proc);
}
+ return rc;
+}
- m_model->clear();
- QMap<QString, QStandardItem *> known;
- for (Procs::const_iterator it = procs.begin(); it != procs.end(); ++it)
- insertItem(m_model->invisibleRootItem(), it.key(), procs, known);
- m_model->setHeaderData(0, Qt::Horizontal, "Process ID", Qt::DisplayRole);
- m_model->setHeaderData(1, Qt::Horizontal, "Name", Qt::DisplayRole);
- //model->setHeaderData(2, Qt::Horizontal, "Parent", Qt::DisplayRole);
- m_model->setHeaderData(2, Qt::Horizontal, "State", Qt::DisplayRole);
+static void populateProcessModel(QStandardItemModel *model)
+{
+#ifdef Q_OS_WIN
+ QList<ProcData> processes = winProcessList();
+#else
+ QList<ProcData> processes = unixProcessList();
+#endif
+ qStableSort(processes);
+
+ if (const int rowCount = model->rowCount())
+ model->removeRows(0, rowCount);
+
+ QStandardItem *root = model->invisibleRootItem();
+ foreach(const ProcData &proc, processes) {
+ QList<QStandardItem *> row;
+ row.append(new QStandardItem(proc.ppid));
+ row.append(new QStandardItem(proc.name));
+ if (!proc.image.isEmpty())
+ row.back()->setToolTip(proc.image);
+ row.append(new QStandardItem(proc.state));
+ root->appendRow(row);
+ }
+}
- m_ui->procView->setModel(m_model);
+///////////////////////////////////////////////////////////////////////
+//
+// AttachExternalDialog
+//
+///////////////////////////////////////////////////////////////////////
+
+AttachExternalDialog::AttachExternalDialog(QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Ui::AttachExternalDialog),
+ m_model(createProcessModel(this)),
+ m_proxyModel(new QSortFilterProxyModel(this))
+{
+ m_ui->setupUi(this);
+ m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+
+ m_proxyModel->setSourceModel(m_model);
+ m_proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_proxyModel->setFilterKeyColumn(1);
+ m_ui->procView->setModel(m_proxyModel);
+ m_ui->procView->setSortingEnabled(true);
+
+ connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ QPushButton *refreshButton = new QPushButton(tr("Refresh"));
+ connect(refreshButton, SIGNAL(clicked()), this, SLOT(rebuildProcessList()));
+ m_ui->buttonBox->addButton(refreshButton, QDialogButtonBox::ActionRole);
+
+ connect(m_ui->procView, SIGNAL(activated(QModelIndex)),
+ this, SLOT(procSelected(QModelIndex)));
+ connect(m_ui->filterClearToolButton, SIGNAL(clicked()),
+ m_ui->filterLineEdit, SLOT(clear()));
+ connect(m_ui->filterLineEdit, SIGNAL(textChanged(QString)),
+ m_proxyModel, SLOT(setFilterFixedString(QString)));
+
+ rebuildProcessList();
+}
+
+AttachExternalDialog::~AttachExternalDialog()
+{
+ delete m_ui;
+}
+
+void AttachExternalDialog::rebuildProcessList()
+{
+ populateProcessModel(m_model);
m_ui->procView->expandAll();
m_ui->procView->resizeColumnToContents(0);
m_ui->procView->resizeColumnToContents(1);
m_ui->procView->sortByColumn(1, Qt::AscendingOrder);
}
-void AttachExternalDialog::procSelected(const QModelIndex &index0)
+void AttachExternalDialog::procSelected(const QModelIndex &proxyIndex)
{
+ const QModelIndex index0 = m_proxyModel->mapToSource(proxyIndex);
QModelIndex index = index0.sibling(index0.row(), 0);
- QStandardItem *item = m_model->itemFromIndex(index);
- if (!item)
- return;
- m_ui->pidLineEdit->setText(item->text());
- accept();
+ if (const QStandardItem *item = m_model->itemFromIndex(index)) {
+ m_ui->pidLineEdit->setText(item->text());
+ m_ui->buttonBox->button(QDialogButtonBox::Ok)->animateClick();
+ }
}
int AttachExternalDialog::attachPID() const
@@ -226,22 +246,22 @@ int AttachExternalDialog::attachPID() const
return m_ui->pidLineEdit->text().toInt();
}
-
-
///////////////////////////////////////////////////////////////////////
//
// AttachRemoteDialog
//
///////////////////////////////////////////////////////////////////////
-AttachRemoteDialog::AttachRemoteDialog(QWidget *parent, const QString &pid)
- : QDialog(parent), m_ui(new Ui::AttachRemoteDialog)
+AttachRemoteDialog::AttachRemoteDialog(QWidget *parent, const QString &pid) :
+ QDialog(parent),
+ m_ui(new Ui::AttachRemoteDialog),
+ m_model(createProcessModel(this))
{
m_ui->setupUi(this);
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
m_defaultPID = pid;
- m_model = new QStandardItemModel(this);
+ m_ui->procView->setModel(m_model);
m_ui->procView->setSortingEnabled(true);
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
@@ -261,42 +281,7 @@ AttachRemoteDialog::~AttachRemoteDialog()
void AttachRemoteDialog::rebuildProcessList()
{
- QStringList procnames = QDir("/proc/").entryList();
- if (procnames.isEmpty()) {
- m_ui->procView->hide();
- return;
- }
-
- typedef QMap<QString, ProcData> Procs;
- Procs procs;
-
- foreach (const QString &procname, procnames) {
- if (!isProcessName(procname))
- continue;
- QString filename = "/proc/" + procname + "/stat";
- QFile file(filename);
- file.open(QIODevice::ReadOnly);
- QStringList data = QString::fromLocal8Bit(file.readAll()).split(' ');
- //qDebug() << filename << data;
- ProcData proc;
- proc.name = data.at(1);
- if (proc.name.startsWith('(') && proc.name.endsWith(')'))
- proc.name = proc.name.mid(1, proc.name.size() - 2);
- proc.state = data.at(2);
- proc.ppid = data.at(3);
- procs[procname] = proc;
- }
-
- m_model->clear();
- QMap<QString, QStandardItem *> known;
- for (Procs::const_iterator it = procs.begin(); it != procs.end(); ++it)
- insertItem(m_model->invisibleRootItem(), it.key(), procs, known);
- m_model->setHeaderData(0, Qt::Horizontal, "Process ID", Qt::DisplayRole);
- m_model->setHeaderData(1, Qt::Horizontal, "Name", Qt::DisplayRole);
- //model->setHeaderData(2, Qt::Horizontal, "Parent", Qt::DisplayRole);
- m_model->setHeaderData(2, Qt::Horizontal, "State", Qt::DisplayRole);
-
- m_ui->procView->setModel(m_model);
+ populateProcessModel(m_model);
m_ui->procView->expandAll();
m_ui->procView->resizeColumnToContents(0);
m_ui->procView->resizeColumnToContents(1);
@@ -317,8 +302,6 @@ int AttachRemoteDialog::attachPID() const
return m_ui->pidLineEdit->text().toInt();
}
-
-
///////////////////////////////////////////////////////////////////////
//
// StartExternalDialog
diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h
index c80c8f39de..621b978df9 100644
--- a/src/plugins/debugger/debuggerdialogs.h
+++ b/src/plugins/debugger/debuggerdialogs.h
@@ -36,6 +36,7 @@ QT_BEGIN_NAMESPACE
class QModelIndex;
class QStandardItemModel;
+class QSortFilterProxyModel;
namespace Ui {
class AttachCoreDialog;
@@ -50,6 +51,14 @@ QT_END_NAMESPACE
namespace Debugger {
namespace Internal {
+struct ProcData
+{
+ QString ppid;
+ QString name;
+ QString image;
+ QString state;
+};
+
class AttachCoreDialog : public QDialog
{
Q_OBJECT
@@ -68,7 +77,6 @@ private:
Ui::AttachCoreDialog *m_ui;
};
-
class AttachExternalDialog : public QDialog
{
Q_OBJECT
@@ -85,6 +93,7 @@ private slots:
private:
Ui::AttachExternalDialog *m_ui;
+ QSortFilterProxyModel *m_proxyModel;
QStandardItemModel *m_model;
};
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index 3f21b4a4a1..817851a574 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -137,7 +137,8 @@ extern IDebuggerEngine *createWinEngine(DebuggerManager *)
#endif
extern IDebuggerEngine *createScriptEngine(DebuggerManager *parent);
-DebuggerManager::DebuggerManager()
+DebuggerManager::DebuggerManager() :
+ m_attachCoreAction(0)
{
init();
}
@@ -245,7 +246,6 @@ void DebuggerManager::init()
m_registerHandler = new RegisterHandler;
registerView->setModel(m_registerHandler->model());
-
m_watchHandler = new WatchHandler;
// Locals
@@ -295,8 +295,11 @@ void DebuggerManager::init()
m_attachExternalAction = new QAction(this);
m_attachExternalAction->setText(tr("Attach to Running External Application..."));
+#ifndef Q_OS_WIN
m_attachCoreAction = new QAction(this);
m_attachCoreAction->setText(tr("Attach to Core..."));
+ connect(m_attachCoreAction, SIGNAL(triggered()), this, SLOT(attachCore()));
+#endif
m_continueAction = new QAction(this);
m_continueAction->setText(tr("Continue"));
@@ -366,8 +369,6 @@ void DebuggerManager::init()
this, SLOT(startExternalApplication()));
connect(m_attachExternalAction, SIGNAL(triggered()),
this, SLOT(attachExternalApplication()));
- connect(m_attachCoreAction, SIGNAL(triggered()),
- this, SLOT(attachCore()));
connect(m_stopAction, SIGNAL(triggered()),
this, SLOT(interruptDebuggingRequest()));
@@ -788,7 +789,7 @@ void DebuggerManager::attachCore()
emit debuggingFinished();
}
-// Figure out the debugger type of an exexcutable
+// Figure out the debugger type of an executable
static bool determineDebuggerType(const QString &executable,
DebuggerManager::DebuggerType *dt,
QString *errorMessage)
@@ -820,6 +821,20 @@ static bool determineDebuggerType(const QString &executable,
#endif
}
+// Figure out the debugger type of a PID
+static bool determineDebuggerType(int /* pid */,
+ DebuggerManager::DebuggerType *dt,
+ QString * /*errorMessage*/)
+{
+#ifdef Q_OS_WIN
+ // Preferably Windows debugger
+ *dt = winEngine ? DebuggerManager::WinDebugger : DebuggerManager::GdbDebugger;
+#else
+ *dt = DebuggerManager::GdbDebugger;
+#endif
+ return true;
+}
+
bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
{
if (Debugger::Constants::Internal::debug)
@@ -828,7 +843,8 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
m_startMode = mode;
// FIXME: Clean up
- if (startMode() == StartExternal) {
+ switch (startMode()) {
+ case StartExternal: {
StartExternalDialog dlg(mainWindow());
dlg.setExecutableFile(
configValue(QLatin1String("LastExternalExecutableFile")).toString());
@@ -844,7 +860,9 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
m_processArgs = dlg.executableArguments().split(' ');
m_workingDir = QString();
m_attachedPID = -1;
- } else if (startMode() == AttachExternal) {
+ }
+ break;
+ case AttachExternal: {
AttachExternalDialog dlg(mainWindow());
if (dlg.exec() != QDialog::Accepted)
return false;
@@ -857,7 +875,9 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
tr("Cannot attach to PID 0"));
return false;
}
- } else if (startMode() == StartInternal) {
+ }
+ break;
+ case StartInternal:
if (m_executable.isEmpty()) {
QString startDirectory = m_executable;
if (m_executable.isEmpty()) {
@@ -881,7 +901,8 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
//m_processArgs = sd.processArgs.join(QLatin1String(" "));
m_attachedPID = 0;
}
- } else if (startMode() == AttachCore) {
+ break;
+ case AttachCore: {
AttachCoreDialog dlg(mainWindow());
dlg.setExecutableFile(
configValue(QLatin1String("LastExternalExecutableFile")).toString());
@@ -899,12 +920,17 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
m_workingDir = QString();
m_attachedPID = -1;
}
+ break;
+ }
emit debugModeRequested();
DebuggerType type;
QString errorMessage;
- if (!determineDebuggerType(m_executable, &type, &errorMessage)) {
+ const bool hasDebugger = startMode() == AttachExternal ?
+ determineDebuggerType(m_attachedPID, &type, &errorMessage) :
+ determineDebuggerType(m_executable, &type, &errorMessage);
+ if (!hasDebugger) {
QMessageBox::warning(mainWindow(), tr("Warning"),
tr("Cannot debug '%1': %2").arg(m_executable, errorMessage));
return false;
@@ -1142,7 +1168,8 @@ void DebuggerManager::setStatus(int status)
m_startExternalAction->setEnabled(!started && !starting);
m_attachExternalAction->setEnabled(!started && !starting);
- m_attachCoreAction->setEnabled(!started && !starting);
+ if (m_attachCoreAction)
+ m_attachCoreAction->setEnabled(!started && !starting);
m_watchAction->setEnabled(ready);
m_breakAction->setEnabled(true);
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index af9ee22c5d..b27f5ad6a6 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -443,15 +443,15 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *error_mes
Constants::STARTEXTERNAL, globalcontext);
mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
-#ifndef Q_OS_WIN
cmd = am->registerAction(m_manager->m_attachExternalAction,
Constants::ATTACHEXTERNAL, globalcontext);
mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
- cmd = am->registerAction(m_manager->m_attachCoreAction,
- Constants::ATTACHCORE, globalcontext);
- mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
-#endif
+ if (m_manager->m_attachCoreAction) {
+ cmd = am->registerAction(m_manager->m_attachCoreAction,
+ Constants::ATTACHCORE, globalcontext);
+ mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
+ }
cmd = am->registerAction(m_manager->m_continueAction,
ProjectExplorer::Constants::DEBUG, QList<int>() << m_gdbRunningContext);
diff --git a/src/plugins/debugger/win/dbgwinutils.cpp b/src/plugins/debugger/win/dbgwinutils.cpp
new file mode 100644
index 0000000000..67028e44c7
--- /dev/null
+++ b/src/plugins/debugger/win/dbgwinutils.cpp
@@ -0,0 +1,79 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "winutils.h"
+#include "debuggerdialogs.h"
+#include <windows.h>
+#include <tlhelp32.h>
+#ifdef USE_PSAPI
+# include <psapi.h>
+#endif
+namespace Debugger {
+namespace Internal {
+
+#ifdef USE_PSAPI
+static inline QString imageName(DWORD processId)
+{
+ QString rc;
+ HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION , FALSE, processId);
+ if (handle == INVALID_HANDLE_VALUE)
+ return rc;
+ WCHAR buffer[MAX_PATH];
+ if (GetProcessImageFileName(handle, buffer, MAX_PATH))
+ rc = QString::fromUtf16(buffer);
+ CloseHandle(handle);
+ return rc;
+}
+#endif
+
+QList<ProcData> winProcessList()
+{
+ QList<ProcData> rc;
+
+ PROCESSENTRY32 pe;
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (snapshot == INVALID_HANDLE_VALUE)
+ return rc;
+
+ for (bool hasNext = Process32First(snapshot, &pe); hasNext; hasNext = Process32Next(snapshot, &pe)) {
+ ProcData procData;
+ procData.ppid = QString::number(pe.th32ProcessID);
+ procData.name = QString::fromUtf16(pe.szExeFile);
+#ifdef USE_PSAPI
+ procData.image = imageName(pe.th32ProcessID);
+#endif
+ rc.push_back(procData);
+ }
+ CloseHandle(snapshot);
+ return rc;
+}
+
+}
+}
diff --git a/src/plugins/debugger/win/dbgwinutils.h b/src/plugins/debugger/win/dbgwinutils.h
new file mode 100644
index 0000000000..1045e822b4
--- /dev/null
+++ b/src/plugins/debugger/win/dbgwinutils.h
@@ -0,0 +1,44 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef _DBG_WINDUTILS_H
+#define _DBG_WINDUTILS_H
+
+#include <QtCore/QList>
+
+namespace Debugger {
+namespace Internal {
+
+struct ProcData; // debuggerdialogs, used by the process listing dialogs
+
+QList<ProcData> winProcessList();
+
+}
+}
+#endif
diff --git a/src/plugins/debugger/win/win.pri b/src/plugins/debugger/win/win.pri
index 7eaa43a630..b1edeac929 100644
--- a/src/plugins/debugger/win/win.pri
+++ b/src/plugins/debugger/win/win.pri
@@ -1,3 +1,5 @@
INCLUDEPATH+=$$PWD
-SOURCES += $$PWD/peutils.cpp
-HEADERS += $$PWD/peutils.h
+SOURCES += $$PWD/peutils.cpp \
+ $$PWD/dbgwinutils.cpp
+HEADERS += $$PWD/peutils.h \
+ $$PWD/dbgwinutils.h