diff --git a/src/plugins/debugger/attachexternaldialog.ui b/src/plugins/debugger/attachexternaldialog.ui index 63f214c51ea21b8a65849dde08b2d92617d33555..0c937fa8e808f3266e27bdf30ef33f9085439985 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 d204e158c9648a84c806c004477efd6fb4991944..ab71dc23e8196767a99b82b2fb31d9317a96bbac 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 57ad5f8da348e3b1bdc48f06e0008d197f870ca2..67528008ca2e7d7093858037a7ab67618490b33a 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 4273fe743b29e10d402cfdbf76d45336e6e86cce..46f1cdfe8e5c9127b466eb966aac09f95152bb05 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 c80c8f39de19005f3b6f1da4476cd1542fd22a3c..621b978df91112d54a97a03b44dd2ba73886e146 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 3f21b4a4a1e384cf19144ffd2f875efc08d97b86..817851a574823904260ba085f8b199273ceb6d39 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 af9ee22c5d94eeae72c26760e7b54004242c0579..b27f5ad6a67a306275b541a2e2a7ee9da4ae3581 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 0000000000000000000000000000000000000000..67028e44c7bccb19d4deea94623cc2f31ed39924 --- /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 0000000000000000000000000000000000000000..1045e822b420396458ea1d3747f6b716421c1378 --- /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 7eaa43a63007e497879432e8e2497c3c256c4556..b1edeac92995b31c7665ca1de28500e8766d450a 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