forked from qt-creator/qt-creator
Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline
This commit is contained in:
@@ -137,7 +137,7 @@ protected:
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
QualifiedNameId *qualifiedNameIdForSymbol(Symbol *s, const LookupContext &context)
|
||||
static QualifiedNameId *qualifiedNameIdForSymbol(Symbol *s, const LookupContext &context)
|
||||
{
|
||||
Name *symbolName = s->name();
|
||||
if (! symbolName)
|
||||
@@ -433,12 +433,21 @@ void CPPEditor::updateMethodBoxIndex()
|
||||
if (file()->fileName() != symbol->fileName())
|
||||
continue;
|
||||
|
||||
else if (symbol->isGenerated())
|
||||
continue;
|
||||
|
||||
else if (symbol->isBlock())
|
||||
continue;
|
||||
|
||||
if (symbol) {
|
||||
int column = symbol->column();
|
||||
|
||||
if (column != 0)
|
||||
--column;
|
||||
|
||||
if (symbol->isGenerated())
|
||||
column = 0;
|
||||
|
||||
QTextCursor c(document()->findBlockByNumber(symbol->line() - 1));
|
||||
c.setPosition(c.position() + column);
|
||||
|
||||
@@ -650,8 +659,6 @@ void CPPEditor::jumpToDefinition()
|
||||
return; // done
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "No results for expression:" << expression;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -963,14 +970,14 @@ TextEditor::ITextEditor *CPPEditor::openCppEditorAt(const QString &fileName,
|
||||
bool CPPEditor::openEditorAt(Symbol *s)
|
||||
{
|
||||
const QString fileName = QString::fromUtf8(s->fileName(), s->fileNameLength());
|
||||
|
||||
#ifdef QTCREATOR_WITH_ADVANCED_HIGHLIGHTER
|
||||
unsigned line = s->line();
|
||||
unsigned column = s->column();
|
||||
|
||||
if (column)
|
||||
--column;
|
||||
#else
|
||||
unsigned column = 0;
|
||||
#endif
|
||||
|
||||
return openCppEditorAt(fileName, s->line(), column);
|
||||
if (s->isGenerated())
|
||||
unsigned column = 0;
|
||||
|
||||
return openCppEditorAt(fileName, line, column);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,14 +203,48 @@ 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;
|
||||
}
|
||||
|
||||
bool CdbDebugEngine::startDebuggerWithExecutable(QString *errorMessage)
|
||||
{
|
||||
m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
|
||||
|
||||
//if (!q->m_workingDir.isEmpty())
|
||||
// m_gdbProc.setWorkingDirectory(q->m_workingDir);
|
||||
//if (!q->m_environment.isEmpty())
|
||||
// m_gdbProc.setEnvironment(q->m_environment);
|
||||
|
||||
DEBUG_CREATE_PROCESS_OPTIONS dbgopts;
|
||||
memset(&dbgopts, 0, sizeof(dbgopts));
|
||||
dbgopts.CreateFlags = DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS;
|
||||
@@ -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!");
|
||||
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;
|
||||
}
|
||||
// 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());
|
||||
}
|
||||
|
||||
m_d->m_debuggerManager->showStatusMessage(tr("Debugger Running"), -1);
|
||||
startWatchTimer();
|
||||
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;
|
||||
}
|
||||
m_d->m_debuggerManagerAccess->notifyInferiorRunning();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ protected:
|
||||
void timerEvent(QTimerEvent*);
|
||||
|
||||
private:
|
||||
bool startAttachDebugger(unsigned long pid, QString *errorMessage);
|
||||
bool startDebuggerWithExecutable(QString *errorMessage);
|
||||
void startWatchTimer();
|
||||
void killWatchTimer();
|
||||
|
||||
|
||||
@@ -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)
|
||||
static QStandardItemModel *createProcessModel(QObject *parent)
|
||||
{
|
||||
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()
|
||||
{
|
||||
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
|
||||
bool operator<(const ProcData &p1, const ProcData &p2)
|
||||
{
|
||||
QString ppid;
|
||||
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];
|
||||
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);
|
||||
|
||||
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->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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
79
src/plugins/debugger/win/dbgwinutils.cpp
Normal file
79
src/plugins/debugger/win/dbgwinutils.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
44
src/plugins/debugger/win/dbgwinutils.h
Normal file
44
src/plugins/debugger/win/dbgwinutils.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -164,7 +164,8 @@ Symbol::Symbol(TranslationUnit *translationUnit, unsigned sourceLocation, Name *
|
||||
_visibility(Symbol::Public),
|
||||
_scope(0),
|
||||
_index(0),
|
||||
_next(0)
|
||||
_next(0),
|
||||
_isGenerated(false)
|
||||
{
|
||||
setSourceLocation(sourceLocation);
|
||||
setName(name);
|
||||
@@ -200,14 +201,24 @@ unsigned Symbol::sourceLocation() const
|
||||
unsigned Symbol::sourceOffset() const
|
||||
{ return _sourceOffset; }
|
||||
|
||||
bool Symbol::isGenerated() const
|
||||
{ return _isGenerated; }
|
||||
|
||||
void Symbol::setSourceLocation(unsigned sourceLocation)
|
||||
{
|
||||
_sourceLocation = sourceLocation;
|
||||
|
||||
if (_sourceLocation)
|
||||
_sourceOffset = translationUnit()->tokenAt(sourceLocation).offset;
|
||||
else
|
||||
if (! _sourceLocation) {
|
||||
_isGenerated = false;
|
||||
_sourceOffset = 0;
|
||||
} else {
|
||||
TranslationUnit *unit = translationUnit();
|
||||
|
||||
const Token &tk = unit->tokenAt(sourceLocation);
|
||||
|
||||
_isGenerated = tk.generated;
|
||||
_sourceOffset = tk.offset;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned Symbol::line() const
|
||||
|
||||
@@ -233,6 +233,8 @@ public:
|
||||
|
||||
Name *identity() const;
|
||||
|
||||
bool isGenerated() const;
|
||||
|
||||
void setScope(Scope *scope); // ### make me private
|
||||
void setSourceLocation(unsigned sourceLocation); // ### make me private
|
||||
|
||||
@@ -256,6 +258,8 @@ private:
|
||||
unsigned _index;
|
||||
Symbol *_next;
|
||||
|
||||
bool _isGenerated: 1;
|
||||
|
||||
class IdentityForName;
|
||||
class HashCode;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user