Process Listing Windows

This commit is contained in:
Friedemann Kleint
2009-03-04 16:00:43 +01:00
committed by unknown
parent 1e7d6a01e6
commit 86b6c44e4e
10 changed files with 426 additions and 197 deletions

View File

@@ -1,7 +1,8 @@
<ui version="4.0" > <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AttachExternalDialog</class> <class>AttachExternalDialog</class>
<widget class="QDialog" name="AttachExternalDialog" > <widget class="QDialog" name="AttachExternalDialog">
<property name="geometry" > <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
@@ -9,50 +10,76 @@
<height>866</height> <height>866</height>
</rect> </rect>
</property> </property>
<property name="windowTitle" > <property name="windowTitle">
<string>Start Debugger</string> <string>Start Debugger</string>
</property> </property>
<layout class="QVBoxLayout" > <layout class="QVBoxLayout">
<property name="spacing" > <property name="spacing">
<number>6</number> <number>6</number>
</property> </property>
<property name="margin" > <property name="margin">
<number>9</number> <number>9</number>
</property> </property>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout" > <layout class="QFormLayout" name="formLayout">
<item> <item row="0" column="0">
<widget class="QLabel" name="pidLabel" > <widget class="QLabel" name="pidLabel">
<property name="text" > <property name="text">
<string>Attach to Process ID:</string> <string>Attach to Process ID:</string>
</property> </property>
</widget> </widget>
</item> </item>
<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> <item>
<widget class="QLineEdit" name="pidLineEdit" /> <widget class="QLineEdit" name="filterLineEdit"/>
</item>
<item>
<widget class="QToolButton" name="filterClearToolButton">
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
</layout>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QTreeView" name="procView" > <widget class="QTreeView" name="procView">
<property name="editTriggers" > <property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set> <set>QAbstractItemView::NoEditTriggers</set>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="Line" name="line" > <widget class="Line" name="line">
<property name="orientation" > <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QDialogButtonBox" name="buttonBox" > <widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation" > <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="standardButtons" > <property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property> </property>
</widget> </widget>

View File

@@ -35,6 +35,7 @@
#include "stackhandler.h" #include "stackhandler.h"
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/winutils.h>
#include <utils/consoleprocess.h> #include <utils/consoleprocess.h>
#include <QtCore/QDebug> #include <QtCore/QDebug>
@@ -49,6 +50,31 @@
static const char *dbgEngineDllC = "dbgeng"; static const char *dbgEngineDllC = "dbgeng";
static const char *debugCreateFuncC = "DebugCreate"; 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 Debugger {
namespace Internal { namespace Internal {
@@ -179,11 +205,45 @@ void CdbDebugEngine::setToolTipExpression(const QPoint & /*pos*/, const QString
bool CdbDebugEngine::startDebugger() bool CdbDebugEngine::startDebugger()
{ {
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1); 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;
}
//if (!q->m_workingDir.isEmpty()) bool CdbDebugEngine::startAttachDebugger(unsigned long pid, QString *errorMessage)
// m_gdbProc.setWorkingDirectory(q->m_workingDir); {
//if (!q->m_environment.isEmpty()) const HRESULT hr = m_d->m_pDebugClient->AttachProcess(NULL, pid,
// m_gdbProc.setEnvironment(q->m_environment); 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;
}
bool CdbDebugEngine::startDebuggerWithExecutable(QString *errorMessage)
{
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
DEBUG_CREATE_PROCESS_OPTIONS dbgopts; DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
memset(&dbgopts, 0, sizeof(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_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); //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) { // TODO console
qWarning("CdbDebugEngine: attach to process not yet implemented!"); const QString cmd = Core::Utils::AbstractProcess::createWinCommandline(filename, m_d->m_debuggerManager->m_processArgs);
return false; if (debugCDB)
} else { qDebug() << "Starting " << cmd;
QString cmd = Core::Utils::AbstractProcess::createWinCommandline(filename, m_d->m_debuggerManager->m_processArgs);
PCWSTR env = 0; PCWSTR env = 0;
QByteArray envData; QByteArray envData;
if (!m_d->m_debuggerManager->m_environment.empty()) { if (!m_d->m_debuggerManager->m_environment.empty()) {
envData = Core::Utils::AbstractProcess::createWinEnvironment(Core::Utils::AbstractProcess::fixWinEnvironment(m_d->m_debuggerManager->m_environment)); envData = Core::Utils::AbstractProcess::createWinEnvironment(Core::Utils::AbstractProcess::fixWinEnvironment(m_d->m_debuggerManager->m_environment));
env = reinterpret_cast<PCWSTR>(envData.data()); env = reinterpret_cast<PCWSTR>(envData.data());
} }
HRESULT hr = m_d->m_pDebugClient->CreateProcess2Wide(NULL, const HRESULT hr = m_d->m_pDebugClient->CreateProcess2Wide(NULL,
const_cast<PWSTR>(cmd.utf16()), const_cast<PWSTR>(cmd.utf16()),
&dbgopts, &dbgopts,
sizeof(dbgopts), sizeof(dbgopts),
m_d->m_debuggerManager->m_workingDir.utf16(), m_d->m_debuggerManager->m_workingDir.utf16(),
env); env);
if (FAILED(hr)) { if (FAILED(hr)) {
//qWarning("CreateProcess2Wide failed"); *errorMessage = tr("CreateProcess2Wide failed for '%1': %2").arg(cmd).arg(debugEngineComError(hr));
m_d->m_debuggerManagerAccess->notifyInferiorExited(); m_d->m_debuggerManagerAccess->notifyInferiorExited();
return false; return false;
} }
} m_d->m_debuggerManagerAccess->notifyInferiorRunning();
m_d->m_debuggerManager->showStatusMessage(tr("Debugger Running"), -1);
startWatchTimer();
return true; return true;
} }

View File

@@ -99,6 +99,8 @@ protected:
void timerEvent(QTimerEvent*); void timerEvent(QTimerEvent*);
private: private:
bool startAttachDebugger(unsigned long pid, QString *errorMessage);
bool startDebuggerWithExecutable(QString *errorMessage);
void startWatchTimer(); void startWatchTimer();
void killWatchTimer(); void killWatchTimer();

View File

@@ -34,6 +34,10 @@
#include "ui_attachremotedialog.h" #include "ui_attachremotedialog.h"
#include "ui_startexternaldialog.h" #include "ui_startexternaldialog.h"
#ifdef Q_OS_WIN
# include "dbgwinutils.h"
#endif
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QFile> #include <QtCore/QFile>
@@ -41,17 +45,11 @@
#include <QtGui/QHeaderView> #include <QtGui/QHeaderView>
#include <QtGui/QFileDialog> #include <QtGui/QFileDialog>
#include <QtGui/QPushButton> #include <QtGui/QPushButton>
#include <QtGui/QProxyModel>
#ifdef Q_OS_WINDOWS #include <QtGui/QSortFilterProxyModel>
#include <windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include <stdio.h>
#endif
using namespace Debugger::Internal; using namespace Debugger::Internal;
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// //
// AttachCoreDialog // AttachCoreDialog
@@ -100,34 +98,21 @@ void AttachCoreDialog::setCoreFile(const QString &fileName)
m_ui->coreFileName->setPath(fileName); m_ui->coreFileName->setPath(fileName);
} }
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// //
// AttachExternalDialog // process model helpers
// //
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
AttachExternalDialog::AttachExternalDialog(QWidget *parent) static QStandardItemModel *createProcessModel(QObject *parent)
: QDialog(parent), m_ui(new Ui::AttachExternalDialog)
{ {
m_ui->setupUi(this); QStandardItemModel *rc = new QStandardItemModel(parent);
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); QStringList columns;
m_model = new QStandardItemModel(this); columns << AttachExternalDialog::tr("Process ID")
<< AttachExternalDialog::tr("Name")
m_ui->procView->setSortingEnabled(true); << AttachExternalDialog::tr("State");
rc->setHorizontalHeaderLabels(columns);
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); return rc;
connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(m_ui->procView, SIGNAL(activated(QModelIndex)),
this, SLOT(procSelected(QModelIndex)));
rebuildProcessList();
}
AttachExternalDialog::~AttachExternalDialog()
{
delete m_ui;
} }
static bool isProcessName(const QString &procname) static bool isProcessName(const QString &procname)
@@ -138,87 +123,122 @@ static bool isProcessName(const QString &procname)
return true; return true;
} }
struct ProcData bool operator<(const ProcData &p1, const ProcData &p2)
{ {
QString ppid; return p1.name < p2.name;
QString name;
QString state;
};
static void insertItem(QStandardItem *root, const QString &pid,
const QMap<QString, ProcData> &procs, QMap<QString, QStandardItem *> &known)
{
//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];
} }
void AttachExternalDialog::rebuildProcessList() // Determine UNIX processes by reading "/proc"
static QList<ProcData> unixProcessList()
{ {
QStringList procnames = QDir("/proc/").entryList(); QList<ProcData> rc;
if (procnames.isEmpty()) { const QStringList procnames = QDir(QLatin1String("/proc/")).entryList();
m_ui->procView->hide(); if (procnames.isEmpty())
return; return rc;
}
typedef QMap<QString, ProcData> Procs;
Procs procs;
foreach (const QString &procname, procnames) { foreach (const QString &procname, procnames) {
if (!isProcessName(procname)) if (!isProcessName(procname))
continue; continue;
QString filename = "/proc/" + procname + "/stat"; QString filename = QLatin1String("/proc/");
filename += procname;
filename += QLatin1String("/stat");
QFile file(filename); QFile file(filename);
file.open(QIODevice::ReadOnly); file.open(QIODevice::ReadOnly);
QStringList data = QString::fromLocal8Bit(file.readAll()).split(' '); const QStringList data = QString::fromLocal8Bit(file.readAll()).split(' ');
//qDebug() << filename << data;
ProcData proc; ProcData proc;
proc.name = data.at(1); 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.name = proc.name.mid(1, proc.name.size() - 2);
proc.state = data.at(2); proc.state = data.at(2);
proc.ppid = data.at(3); proc.ppid = data.at(3);
procs[procname] = proc; rc.push_back(proc);
} }
return rc;
}
m_model->clear(); static void populateProcessModel(QStandardItemModel *model)
QMap<QString, QStandardItem *> known; {
for (Procs::const_iterator it = procs.begin(); it != procs.end(); ++it) #ifdef Q_OS_WIN
insertItem(m_model->invisibleRootItem(), it.key(), procs, known); QList<ProcData> processes = winProcessList();
m_model->setHeaderData(0, Qt::Horizontal, "Process ID", Qt::DisplayRole); #else
m_model->setHeaderData(1, Qt::Horizontal, "Name", Qt::DisplayRole); QList<ProcData> processes = unixProcessList();
//model->setHeaderData(2, Qt::Horizontal, "Parent", Qt::DisplayRole); #endif
m_model->setHeaderData(2, Qt::Horizontal, "State", Qt::DisplayRole); qStableSort(processes);
m_ui->procView->setModel(m_model); 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);
}
}
///////////////////////////////////////////////////////////////////////
//
// 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->expandAll();
m_ui->procView->resizeColumnToContents(0); m_ui->procView->resizeColumnToContents(0);
m_ui->procView->resizeColumnToContents(1); m_ui->procView->resizeColumnToContents(1);
m_ui->procView->sortByColumn(1, Qt::AscendingOrder); 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); QModelIndex index = index0.sibling(index0.row(), 0);
QStandardItem *item = m_model->itemFromIndex(index); if (const QStandardItem *item = m_model->itemFromIndex(index)) {
if (!item)
return;
m_ui->pidLineEdit->setText(item->text()); m_ui->pidLineEdit->setText(item->text());
accept(); m_ui->buttonBox->button(QDialogButtonBox::Ok)->animateClick();
}
} }
int AttachExternalDialog::attachPID() const int AttachExternalDialog::attachPID() const
@@ -226,22 +246,22 @@ int AttachExternalDialog::attachPID() const
return m_ui->pidLineEdit->text().toInt(); return m_ui->pidLineEdit->text().toInt();
} }
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// //
// AttachRemoteDialog // AttachRemoteDialog
// //
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
AttachRemoteDialog::AttachRemoteDialog(QWidget *parent, const QString &pid) AttachRemoteDialog::AttachRemoteDialog(QWidget *parent, const QString &pid) :
: QDialog(parent), m_ui(new Ui::AttachRemoteDialog) QDialog(parent),
m_ui(new Ui::AttachRemoteDialog),
m_model(createProcessModel(this))
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
m_defaultPID = pid; m_defaultPID = pid;
m_model = new QStandardItemModel(this);
m_ui->procView->setModel(m_model);
m_ui->procView->setSortingEnabled(true); m_ui->procView->setSortingEnabled(true);
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
@@ -261,42 +281,7 @@ AttachRemoteDialog::~AttachRemoteDialog()
void AttachRemoteDialog::rebuildProcessList() void AttachRemoteDialog::rebuildProcessList()
{ {
QStringList procnames = QDir("/proc/").entryList(); populateProcessModel(m_model);
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);
m_ui->procView->expandAll(); m_ui->procView->expandAll();
m_ui->procView->resizeColumnToContents(0); m_ui->procView->resizeColumnToContents(0);
m_ui->procView->resizeColumnToContents(1); m_ui->procView->resizeColumnToContents(1);
@@ -317,8 +302,6 @@ int AttachRemoteDialog::attachPID() const
return m_ui->pidLineEdit->text().toInt(); return m_ui->pidLineEdit->text().toInt();
} }
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
// //
// StartExternalDialog // StartExternalDialog

View File

@@ -36,6 +36,7 @@ QT_BEGIN_NAMESPACE
class QModelIndex; class QModelIndex;
class QStandardItemModel; class QStandardItemModel;
class QSortFilterProxyModel;
namespace Ui { namespace Ui {
class AttachCoreDialog; class AttachCoreDialog;
@@ -50,6 +51,14 @@ QT_END_NAMESPACE
namespace Debugger { namespace Debugger {
namespace Internal { namespace Internal {
struct ProcData
{
QString ppid;
QString name;
QString image;
QString state;
};
class AttachCoreDialog : public QDialog class AttachCoreDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
@@ -68,7 +77,6 @@ private:
Ui::AttachCoreDialog *m_ui; Ui::AttachCoreDialog *m_ui;
}; };
class AttachExternalDialog : public QDialog class AttachExternalDialog : public QDialog
{ {
Q_OBJECT Q_OBJECT
@@ -85,6 +93,7 @@ private slots:
private: private:
Ui::AttachExternalDialog *m_ui; Ui::AttachExternalDialog *m_ui;
QSortFilterProxyModel *m_proxyModel;
QStandardItemModel *m_model; QStandardItemModel *m_model;
}; };

View File

@@ -137,7 +137,8 @@ extern IDebuggerEngine *createWinEngine(DebuggerManager *)
#endif #endif
extern IDebuggerEngine *createScriptEngine(DebuggerManager *parent); extern IDebuggerEngine *createScriptEngine(DebuggerManager *parent);
DebuggerManager::DebuggerManager() DebuggerManager::DebuggerManager() :
m_attachCoreAction(0)
{ {
init(); init();
} }
@@ -245,7 +246,6 @@ void DebuggerManager::init()
m_registerHandler = new RegisterHandler; m_registerHandler = new RegisterHandler;
registerView->setModel(m_registerHandler->model()); registerView->setModel(m_registerHandler->model());
m_watchHandler = new WatchHandler; m_watchHandler = new WatchHandler;
// Locals // Locals
@@ -295,8 +295,11 @@ void DebuggerManager::init()
m_attachExternalAction = new QAction(this); m_attachExternalAction = new QAction(this);
m_attachExternalAction->setText(tr("Attach to Running External Application...")); m_attachExternalAction->setText(tr("Attach to Running External Application..."));
#ifndef Q_OS_WIN
m_attachCoreAction = new QAction(this); m_attachCoreAction = new QAction(this);
m_attachCoreAction->setText(tr("Attach to Core...")); m_attachCoreAction->setText(tr("Attach to Core..."));
connect(m_attachCoreAction, SIGNAL(triggered()), this, SLOT(attachCore()));
#endif
m_continueAction = new QAction(this); m_continueAction = new QAction(this);
m_continueAction->setText(tr("Continue")); m_continueAction->setText(tr("Continue"));
@@ -366,8 +369,6 @@ void DebuggerManager::init()
this, SLOT(startExternalApplication())); this, SLOT(startExternalApplication()));
connect(m_attachExternalAction, SIGNAL(triggered()), connect(m_attachExternalAction, SIGNAL(triggered()),
this, SLOT(attachExternalApplication())); this, SLOT(attachExternalApplication()));
connect(m_attachCoreAction, SIGNAL(triggered()),
this, SLOT(attachCore()));
connect(m_stopAction, SIGNAL(triggered()), connect(m_stopAction, SIGNAL(triggered()),
this, SLOT(interruptDebuggingRequest())); this, SLOT(interruptDebuggingRequest()));
@@ -788,7 +789,7 @@ void DebuggerManager::attachCore()
emit debuggingFinished(); emit debuggingFinished();
} }
// Figure out the debugger type of an exexcutable // Figure out the debugger type of an executable
static bool determineDebuggerType(const QString &executable, static bool determineDebuggerType(const QString &executable,
DebuggerManager::DebuggerType *dt, DebuggerManager::DebuggerType *dt,
QString *errorMessage) QString *errorMessage)
@@ -820,6 +821,20 @@ static bool determineDebuggerType(const QString &executable,
#endif #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) bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
{ {
if (Debugger::Constants::Internal::debug) if (Debugger::Constants::Internal::debug)
@@ -828,7 +843,8 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
m_startMode = mode; m_startMode = mode;
// FIXME: Clean up // FIXME: Clean up
if (startMode() == StartExternal) { switch (startMode()) {
case StartExternal: {
StartExternalDialog dlg(mainWindow()); StartExternalDialog dlg(mainWindow());
dlg.setExecutableFile( dlg.setExecutableFile(
configValue(QLatin1String("LastExternalExecutableFile")).toString()); configValue(QLatin1String("LastExternalExecutableFile")).toString());
@@ -844,7 +860,9 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
m_processArgs = dlg.executableArguments().split(' '); m_processArgs = dlg.executableArguments().split(' ');
m_workingDir = QString(); m_workingDir = QString();
m_attachedPID = -1; m_attachedPID = -1;
} else if (startMode() == AttachExternal) { }
break;
case AttachExternal: {
AttachExternalDialog dlg(mainWindow()); AttachExternalDialog dlg(mainWindow());
if (dlg.exec() != QDialog::Accepted) if (dlg.exec() != QDialog::Accepted)
return false; return false;
@@ -857,7 +875,9 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
tr("Cannot attach to PID 0")); tr("Cannot attach to PID 0"));
return false; return false;
} }
} else if (startMode() == StartInternal) { }
break;
case StartInternal:
if (m_executable.isEmpty()) { if (m_executable.isEmpty()) {
QString startDirectory = m_executable; QString startDirectory = m_executable;
if (m_executable.isEmpty()) { if (m_executable.isEmpty()) {
@@ -881,7 +901,8 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
//m_processArgs = sd.processArgs.join(QLatin1String(" ")); //m_processArgs = sd.processArgs.join(QLatin1String(" "));
m_attachedPID = 0; m_attachedPID = 0;
} }
} else if (startMode() == AttachCore) { break;
case AttachCore: {
AttachCoreDialog dlg(mainWindow()); AttachCoreDialog dlg(mainWindow());
dlg.setExecutableFile( dlg.setExecutableFile(
configValue(QLatin1String("LastExternalExecutableFile")).toString()); configValue(QLatin1String("LastExternalExecutableFile")).toString());
@@ -899,12 +920,17 @@ bool DebuggerManager::startNewDebugger(DebuggerStartMode mode)
m_workingDir = QString(); m_workingDir = QString();
m_attachedPID = -1; m_attachedPID = -1;
} }
break;
}
emit debugModeRequested(); emit debugModeRequested();
DebuggerType type; DebuggerType type;
QString errorMessage; 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"), QMessageBox::warning(mainWindow(), tr("Warning"),
tr("Cannot debug '%1': %2").arg(m_executable, errorMessage)); tr("Cannot debug '%1': %2").arg(m_executable, errorMessage));
return false; return false;
@@ -1142,6 +1168,7 @@ void DebuggerManager::setStatus(int status)
m_startExternalAction->setEnabled(!started && !starting); m_startExternalAction->setEnabled(!started && !starting);
m_attachExternalAction->setEnabled(!started && !starting); m_attachExternalAction->setEnabled(!started && !starting);
if (m_attachCoreAction)
m_attachCoreAction->setEnabled(!started && !starting); m_attachCoreAction->setEnabled(!started && !starting);
m_watchAction->setEnabled(ready); m_watchAction->setEnabled(ready);
m_breakAction->setEnabled(true); m_breakAction->setEnabled(true);

View File

@@ -443,15 +443,15 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *error_mes
Constants::STARTEXTERNAL, globalcontext); Constants::STARTEXTERNAL, globalcontext);
mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE); mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
#ifndef Q_OS_WIN
cmd = am->registerAction(m_manager->m_attachExternalAction, cmd = am->registerAction(m_manager->m_attachExternalAction,
Constants::ATTACHEXTERNAL, globalcontext); Constants::ATTACHEXTERNAL, globalcontext);
mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE); mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
if (m_manager->m_attachCoreAction) {
cmd = am->registerAction(m_manager->m_attachCoreAction, cmd = am->registerAction(m_manager->m_attachCoreAction,
Constants::ATTACHCORE, globalcontext); Constants::ATTACHCORE, globalcontext);
mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE); mdebug->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
#endif }
cmd = am->registerAction(m_manager->m_continueAction, cmd = am->registerAction(m_manager->m_continueAction,
ProjectExplorer::Constants::DEBUG, QList<int>() << m_gdbRunningContext); ProjectExplorer::Constants::DEBUG, QList<int>() << m_gdbRunningContext);

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -1,3 +1,5 @@
INCLUDEPATH+=$$PWD INCLUDEPATH+=$$PWD
SOURCES += $$PWD/peutils.cpp SOURCES += $$PWD/peutils.cpp \
HEADERS += $$PWD/peutils.h $$PWD/dbgwinutils.cpp
HEADERS += $$PWD/peutils.h \
$$PWD/dbgwinutils.h