Commit 75f4b9cf authored by Friedemann Kleint's avatar Friedemann Kleint

Debugger: Add toolchain combos to start dialogs, refactor detection.

Add combo box listing toolchains with debuggers to start external,
attach and core.
Another attempt at streamlining engine detection:
Split in detection functions that first collect a list of
available engines by preference, then remove disabled and
wrongly configured engines and use the remaining best.
matching. checkconfiguration is now the central place where
engine detection and config check takes place.

Rubber-stamped-by: hjk
parent 93b3c8bb
......@@ -2,14 +2,6 @@
<ui version="4.0">
<class>AttachCoreDialog</class>
<widget class="QDialog" name="AttachCoreDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>567</width>
<height>126</height>
</rect>
</property>
<property name="windowTitle">
<string>Start Debugger</string>
</property>
......@@ -21,32 +13,54 @@
<number>9</number>
</property>
<item>
<layout class="QGridLayout">
<property name="margin">
<number>0</number>
<layout class="QFormLayout" name="formLayout">
<property name="horizontalSpacing">
<number>6</number>
</property>
<property name="spacing">
<property name="verticalSpacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="execLabel">
<property name="text">
<string>Executable:</string>
<string>&amp;Executable:</string>
</property>
<property name="buddy">
<cstring>execFileName</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Utils::PathChooser" name="execFileName"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="coreLabel">
<property name="text">
<string>Core file:</string>
<string>&amp;Core file:</string>
</property>
<property name="buddy">
<cstring>coreFileName</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Utils::PathChooser" name="execFileName" native="true"/>
</item>
<item row="1" column="1">
<widget class="Utils::PathChooser" name="coreFileName" native="true"/>
<widget class="Utils::PathChooser" name="coreFileName"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="toolchainLabel">
<property name="text">
<string>&amp;Toolchain:</string>
</property>
<property name="buddy">
<cstring>toolchainComboBox</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Debugger::Internal::DebuggerToolChainComboBox" name="toolchainComboBox"/>
</item>
</layout>
</item>
......@@ -57,8 +71,8 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>407</width>
<height>16</height>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
......@@ -89,6 +103,11 @@
<header location="global">utils/pathchooser.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>DebuggerToolChainComboBox</class>
<extends>QComboBox</extends>
<header>debuggertoolchaincombobox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
......
......@@ -28,16 +28,32 @@
<item row="0" column="0">
<widget class="QLabel" name="pidLabel">
<property name="text">
<string>Attach to process ID:</string>
<string>Attach to &amp;process ID:</string>
</property>
<property name="buddy">
<cstring>pidLineEdit</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="pidLineEdit"/>
</item>
<item row="1" column="0" colspan="2">
<item row="2" column="0" colspan="2">
<widget class="Utils::FilterLineEdit" name="filterWidget"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="toolchainLabel">
<property name="text">
<string>&amp;Toolchain:</string>
</property>
<property name="buddy">
<cstring>toolchainComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Debugger::Internal::DebuggerToolChainComboBox" name="toolchainComboBox"/>
</item>
</layout>
</item>
<item>
......@@ -77,6 +93,11 @@
<extends>Utils::FancyLineEdit</extends>
<header location="global">utils/filterlineedit.h</header>
</customwidget>
<customwidget>
<class>Debugger::Internal::DebuggerToolChainComboBox</class>
<extends>QComboBox</extends>
<header>debuggertoolchaincombobox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
......
......@@ -59,6 +59,7 @@
#include <coreplugin/icore.h>
#include <texteditor/itexteditor.h>
#include <projectexplorer/toolchain.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <utils/synchronousprocess.h>
#include <utils/winutils.h>
......@@ -299,24 +300,14 @@ static inline bool validMode(DebuggerStartMode sm)
return true;
}
static inline QString msgCdbDisabled(const Abi &abi)
{
return CdbEngine::tr("The CDB debug engine required for %1 is currently disabled.").
arg(abi.toString());
}
// Accessed by RunControlFactory
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
DebuggerEngine *masterEngine, QString *errorMessage)
{
#ifdef Q_OS_WIN
CdbOptionsPage *op = CdbOptionsPage::instance();
if (!op || !op->options()->isValid()) {
*errorMessage = msgCdbDisabled(sp.toolChainAbi);
return 0;
}
if (!validMode(sp.startMode)) {
*errorMessage = CdbEngine::tr("The CDB debug engine does not support start mode %1.").arg(sp.startMode);
if (!op || !op->options()->isValid() || !validMode(sp.startMode)) {
*errorMessage = QLatin1String("Internal error: Invalid start parameters passed for thre CDB engine.");
return 0;
}
return new CdbEngine(sp, masterEngine, op->options());
......@@ -337,21 +328,45 @@ bool isCdbEngineEnabled()
#endif
}
ConfigurationCheck checkCdbConfiguration(const Abi &abi)
static inline QString msgNoCdbBinaryForToolChain(const ProjectExplorer::Abi &tc)
{
ConfigurationCheck check;
if (abi.binaryFormat() == Abi::PEFormat
&& abi.osFlavor() != Abi::WindowsMSysFlavor) {
if (!isCdbEngineEnabled()) {
check.errorMessage = msgCdbDisabled(abi);
check.settingsPage = CdbOptionsPage::settingsId();
}
} else {
check.errorMessage = CdbEngine::tr("The CDB debug engine does not support the %1 ABI.").
arg(abi.toString());
check.settingsPage = CdbOptionsPage::settingsId();
return CdbEngine::tr("There is no CDB binary available for binaries in format '%1'").arg(tc.toString());
}
bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check)
{
#ifdef Q_OS_WIN
if (!isCdbEngineEnabled()) {
check->errorMessage = CdbEngine::tr("The CDB debug engine required for %1 is currently disabled.").
arg(sp.toolChainAbi.toString());
check->settingsCategory = QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY);
check->settingsPage = CdbOptionsPage::settingsId();
return false;
}
return check;
if (debuggerCore()->debuggerForAbi(sp.toolChainAbi, CdbEngineType).isEmpty()) {
check->errorMessage = msgNoCdbBinaryForToolChain(sp.toolChainAbi);
check->settingsCategory = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
check->settingsPage = QLatin1String(ProjectExplorer::Constants::TOOLCHAIN_SETTINGS_CATEGORY);
return false;
}
if (!validMode(sp.startMode)) {
check->errorMessage = CdbEngine::tr("The CDB engine does not support start mode %1.").arg(sp.startMode);
return false;
}
if (sp.toolChainAbi.binaryFormat() != Abi::PEFormat || sp.toolChainAbi.os() != Abi::WindowsOS) {
check->errorMessage = CdbEngine::tr("The CDB debug engine does not support the %1 ABI.").
arg(sp.toolChainAbi.toString());
return false;
}
return true;
#else
Q_UNUSED(sp);
check->errorMessage = QString::fromLatin1("Unsupported debug mode");
return false;
#endif
}
void addCdbOptionPages(QList<Core::IOptionsPage *> *opts)
......@@ -637,12 +652,7 @@ bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessa
// Determine binary (force MSVC), extension lib name and path to use
// The extension is passed as relative name with the path variable set
//(does not work with absolute path names)
Abi abi = sp.toolChainAbi;
if (abi.osFlavor() == Abi::UnknownFlavor
|| abi.osFlavor() == Abi::WindowsMSysFlavor)
abi = Abi(abi.architecture(), abi.os(), Abi::WindowsMsvcFlavor,
abi.binaryFormat(), abi.wordWidth());
const QString executable = debuggerCore()->debuggerForAbi(abi);
const QString executable = debuggerCore()->debuggerForAbi(sp.toolChainAbi, CdbEngineType);
if (executable.isEmpty()) {
*errorMessage = tr("There is no CDB executable specified.");
return false;
......
......@@ -62,7 +62,8 @@ HEADERS += breakhandler.h \
threadshandler.h \
watchdelegatewidgets.h \
debuggerruncontrolfactory.h \
debuggertooltipmanager.h
debuggertooltipmanager.h \
debuggertoolchaincombobox.h
SOURCES += breakhandler.cpp \
breakpoint.cpp \
......@@ -104,7 +105,8 @@ SOURCES += breakhandler.cpp \
watchwindow.cpp \
stackframe.cpp \
watchdelegatewidgets.cpp \
debuggertooltipmanager.cpp
debuggertooltipmanager.cpp \
debuggertoolchaincombobox.cpp
FORMS += attachexternaldialog.ui \
attachcoredialog.ui \
......
......@@ -98,12 +98,13 @@ public:
virtual void runControlFinished(DebuggerEngine *engine) = 0;
virtual void displayDebugger(DebuggerEngine *engine, bool updateEngine) = 0;
virtual DebuggerLanguages activeLanguages() const = 0;
virtual unsigned enabledEngines() const = 0;
virtual void synchronizeBreakpoints() = 0;
virtual bool initialize(const QStringList &arguments, QString *errorMessage) = 0;
virtual QWidget *mainWindow() const = 0;
virtual bool isDockVisible(const QString &objectName) const = 0;
virtual QString debuggerForAbi(const ProjectExplorer::Abi &abi) const = 0;
virtual QString debuggerForAbi(const ProjectExplorer::Abi &abi, DebuggerEngineType et = NoEngineType) const = 0;
virtual void showModuleSymbols(const QString &moduleName,
const QVector<Symbol> &symbols) = 0;
virtual void openMemoryEditor() = 0;
......
......@@ -48,6 +48,7 @@
#endif
#include <coreplugin/icore.h>
#include <projectexplorer/abi.h>
#include <utils/synchronousprocess.h>
#include <utils/historycompleter.h>
#include <utils/qtcassert.h>
......@@ -180,7 +181,9 @@ void ProcessListFilterModel::populate
AttachCoreDialog::AttachCoreDialog(QWidget *parent)
: QDialog(parent), m_ui(new Ui::AttachCoreDialog)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_ui->setupUi(this);
m_ui->toolchainComboBox->init(false);
m_ui->execFileName->setExpectedKind(PathChooser::File);
m_ui->execFileName->setPromptDialogTitle(tr("Select Executable"));
......@@ -192,6 +195,9 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent)
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(m_ui->coreFileName, SIGNAL(changed(QString)), this, SLOT(changed()));
connect(m_ui->execFileName, SIGNAL(changed(QString)), this, SLOT(changed()));
changed();
}
AttachCoreDialog::~AttachCoreDialog()
......@@ -207,6 +213,7 @@ QString AttachCoreDialog::executableFile() const
void AttachCoreDialog::setExecutableFile(const QString &fileName)
{
m_ui->execFileName->setPath(fileName);
changed();
}
QString AttachCoreDialog::coreFile() const
......@@ -217,8 +224,29 @@ QString AttachCoreDialog::coreFile() const
void AttachCoreDialog::setCoreFile(const QString &fileName)
{
m_ui->coreFileName->setPath(fileName);
changed();
}
ProjectExplorer::Abi AttachCoreDialog::abi() const
{
return m_ui->toolchainComboBox->abi();
}
void AttachCoreDialog::setAbi(const ProjectExplorer::Abi &abi)
{
m_ui->toolchainComboBox->setAbi(abi);
}
bool AttachCoreDialog::isValid() const
{
return m_ui->toolchainComboBox->currentIndex() >= 0 &&
!coreFile().isEmpty();
}
void AttachCoreDialog::changed()
{
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isValid());
}
///////////////////////////////////////////////////////////////////////
//
......@@ -333,7 +361,9 @@ AttachExternalDialog::AttachExternalDialog(QWidget *parent)
m_ui(new Ui::AttachExternalDialog),
m_model(new ProcessListFilterModel(this))
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_ui->setupUi(this);
m_ui->toolchainComboBox->init(true);
okButton()->setDefault(true);
okButton()->setEnabled(false);
......@@ -429,9 +459,20 @@ QString AttachExternalDialog::executable() const
return m_model->executableForPid(attachPIDText());
}
ProjectExplorer::Abi AttachExternalDialog::abi() const
{
return m_ui->toolchainComboBox->abi();
}
void AttachExternalDialog::setAbi(const ProjectExplorer::Abi &abi)
{
m_ui->toolchainComboBox->setAbi(abi);
}
void AttachExternalDialog::pidChanged(const QString &pid)
{
bool enabled = !pid.isEmpty() && pid != QLatin1String("0") && pid != m_selfPid;
const bool enabled = !pid.isEmpty() && pid != QLatin1String("0") && pid != m_selfPid
&& m_ui->toolchainComboBox->currentIndex() >= 0;
okButton()->setEnabled(enabled);
}
......@@ -460,14 +501,15 @@ AttachTcfDialog::AttachTcfDialog(QWidget *parent)
: QDialog(parent),
m_ui(new Ui::AttachTcfDialog)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_ui->setupUi(this);
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
m_ui->serverStartScript->setExpectedKind(PathChooser::File);
m_ui->serverStartScript->setPromptDialogTitle(tr("Select Executable"));
connect(m_ui->useServerStartScriptCheckBox, SIGNAL(toggled(bool)),
connect(m_ui->useServerStartScriptCheckBox, SIGNAL(toggled(bool)),
this, SLOT(updateState()));
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
......@@ -548,27 +590,25 @@ void AttachTcfDialog::updateState()
StartExternalDialog::StartExternalDialog(QWidget *parent)
: QDialog(parent), m_ui(new Ui::StartExternalDialog)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_ui->setupUi(this);
m_ui->toolChainComboBox->init(true);
m_ui->execFile->setExpectedKind(PathChooser::File);
m_ui->execFile->setPromptDialogTitle(tr("Select Executable"));
m_ui->execFile->lineEdit()->setCompleter(
new HistoryCompleter(m_ui->execFile->lineEdit()));
connect(m_ui->execFile, SIGNAL(changed(QString)), this, SLOT(changed()));
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
m_ui->workingDirectory->setExpectedKind(PathChooser::ExistingDirectory);
m_ui->workingDirectory->setPromptDialogTitle(tr("Select Working Directory"));
m_ui->workingDirectory->lineEdit()->setCompleter(
new HistoryCompleter(m_ui->workingDirectory->lineEdit()));
//execLabel->setHidden(false);
//execEdit->setHidden(false);
//browseButton->setHidden(false);
m_ui->execLabel->setText(tr("Executable:"));
m_ui->argsLabel->setText(tr("Arguments:"));
m_ui->argsEdit->setCompleter(new HistoryCompleter(m_ui->argsEdit));
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
changed();
}
StartExternalDialog::~StartExternalDialog()
......@@ -579,6 +619,7 @@ StartExternalDialog::~StartExternalDialog()
void StartExternalDialog::setExecutableFile(const QString &str)
{
m_ui->execFile->setPath(str);
changed();
}
QString StartExternalDialog::executableFile() const
......@@ -611,6 +652,27 @@ bool StartExternalDialog::breakAtMain() const
return m_ui->checkBoxBreakAtMain->isChecked();
}
ProjectExplorer::Abi StartExternalDialog::abi() const
{
return m_ui->toolChainComboBox->abi();
}
void StartExternalDialog::setAbi(const ProjectExplorer::Abi &abi)
{
m_ui->toolChainComboBox->setAbi(abi);
}
bool StartExternalDialog::isValid() const
{
return m_ui->toolChainComboBox->currentIndex() >= 0
&& !executableFile().isEmpty();
}
void StartExternalDialog::changed()
{
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isValid());
}
///////////////////////////////////////////////////////////////////////
//
// StartRemoteDialog
......@@ -621,6 +683,7 @@ StartRemoteDialog::StartRemoteDialog(QWidget *parent)
: QDialog(parent),
m_ui(new Ui::StartRemoteDialog)
{
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_ui->setupUi(this);
m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
m_ui->debuggerPathChooser->setExpectedKind(PathChooser::File);
......@@ -912,13 +975,14 @@ StartRemoteEngineDialog::StartRemoteEngineDialog(QWidget *parent) :
QDialog(parent) ,
m_ui(new Ui::StartRemoteEngineDialog)
{
m_ui->setupUi(this);
m_ui->host->setCompleter(new HistoryCompleter(m_ui->host));
m_ui->username->setCompleter(new HistoryCompleter(m_ui->username));
m_ui->enginepath->setCompleter(new HistoryCompleter(m_ui->enginepath));
m_ui->inferiorpath->setCompleter(new HistoryCompleter(m_ui->inferiorpath));
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_ui->setupUi(this);
m_ui->host->setCompleter(new HistoryCompleter(m_ui->host));
m_ui->username->setCompleter(new HistoryCompleter(m_ui->username));
m_ui->enginepath->setCompleter(new HistoryCompleter(m_ui->enginepath));
m_ui->inferiorpath->setCompleter(new HistoryCompleter(m_ui->inferiorpath));
connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
StartRemoteEngineDialog::~StartRemoteEngineDialog()
......@@ -950,6 +1014,5 @@ QString StartRemoteEngineDialog::enginePath() const
return m_ui->enginepath->text();
}
} // namespace Internal
} // namespace Debugger
......@@ -54,6 +54,9 @@ class StartRemoteEngineDialog;
QT_END_NAMESPACE
namespace ProjectExplorer {
class Abi;
}
namespace Debugger {
namespace Internal {
......@@ -82,7 +85,15 @@ public:
QString executableFile() const;
QString coreFile() const;
ProjectExplorer::Abi abi() const;
void setAbi(const ProjectExplorer::Abi &);
private slots:
void changed();
private:
bool isValid() const;
Ui::AttachCoreDialog *m_ui;
};
......@@ -97,6 +108,9 @@ public:
qint64 attachPID() const;
QString executable() const;
ProjectExplorer::Abi abi() const;
void setAbi(const ProjectExplorer::Abi &);
virtual void accept();
private slots:
......@@ -159,8 +173,16 @@ public:
QString workingDirectory() const;
void setWorkingDirectory(const QString &str);
ProjectExplorer::Abi abi() const;
void setAbi(const ProjectExplorer::Abi &);
bool breakAtMain() const;
bool isValid() const;
private slots:
void changed();
private:
Ui::StartExternalDialog *m_ui;
};
......
......@@ -94,6 +94,7 @@
#include <projectexplorer/toolchainmanager.h>
#include <projectexplorer/session.h>
#include <projectexplorer/target.h>
#include <projectexplorer/abi.h>
#include <qt4projectmanager/qt4projectmanagerconstants.h>
......@@ -695,10 +696,11 @@ public slots:
void startRemoteApplication();
void startRemoteEngine();
void attachExternalApplication();
void attachExternalApplication(qint64 pid, const QString &binary);
void attachExternalApplication(qint64 pid, const QString &binary,
const ProjectExplorer::Abi &abi = ProjectExplorer::Abi());
void runScheduled();
void attachCore();
void attachCore(const QString &core, const QString &exeFileName);
void attachCore(const QString &core, const QString &exeFileName, const ProjectExplorer::Abi &abi = ProjectExplorer::Abi());
void attachRemote(const QString &spec);
void attachRemoteTcf();
......@@ -720,7 +722,8 @@ public slots:
void runControlStarted(DebuggerEngine *engine);
void runControlFinished(DebuggerEngine *engine);
DebuggerLanguages activeLanguages() const;
QString debuggerForAbi(const Abi &abi) const;
unsigned enabledEngines() const { return m_cmdLineEnabledEngines; }
QString debuggerForAbi(const Abi &abi, DebuggerEngineType et = NoEngineType) const;
void remoteCommand(const QStringList &options, const QStringList &);
bool isReverseDebugging() const;
......@@ -1339,6 +1342,10 @@ void DebuggerPluginPrivate::startExternalApplication()
configValue(_("LastExternalExecutableArguments")).toString());
dlg.setWorkingDirectory(
configValue(_("LastExternalWorkingDirectory")).toString());
const QString abiString = configValue(_("LastExternalAbi")).toString();
if (!abiString.isEmpty())
dlg.setAbi(ProjectExplorer::Abi(abiString));
if (dlg.exec() != QDialog::Accepted)
return;
......@@ -1348,9 +1355,12 @@ void DebuggerPluginPrivate::startExternalApplication()
dlg.executableArguments());
setConfigValue(_("LastExternalWorkingDirectory"),
dlg.workingDirectory());
setConfigValue(_("LastExternalAbi"),
dlg.abi().toString());
sp.executable = dlg.executableFile();
sp.startMode = StartExternal;
sp.toolChainAbi = abiOfBinary(sp.executable);
sp.toolChainAbi = dlg.abi();
sp.workingDirectory = dlg.workingDirectory();
if (!dlg.executableArguments().isEmpty())
sp.processArgs = dlg.executableArguments();
......@@ -1375,12 +1385,20 @@ void DebuggerPluginPrivate::startExternalApplication()
void DebuggerPluginPrivate::attachExternalApplication()
{
AttachExternalDialog dlg(mainWindow());
if (dlg.exec() == QDialog::Accepted)
attachExternalApplication(dlg.attachPID(), dlg.executable());
const QString abiString = configValue(_("LastAttachExternalAbi")).toString();
if (!abiString.isEmpty())
dlg.setAbi(ProjectExplorer::Abi(abiString));