Commit 6ac7efba authored by Friedemann Kleint's avatar Friedemann Kleint

Debugger: Move debugger executables configuration into toolchains.

parent 373000a9
......@@ -637,7 +637,19 @@ bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessa
// Determine 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)
const QFileInfo extensionFi(CdbEngine::extensionLibraryName(m_options->is64bit));
const QString executable = debuggerCore()->debuggerForAbi(sp.toolChainAbi);
if (executable.isEmpty()) {
*errorMessage = tr("There is no CDB executable specified.");
return false;
}
const bool is64bit =
#ifdef Q_OS_WIN
Utils::winIs64BitBinary(executable);
#else
false;
#endif
const QFileInfo extensionFi(CdbEngine::extensionLibraryName(is64bit));
if (!extensionFi.isFile()) {
*errorMessage = QString::fromLatin1("Internal error: The extension %1 cannot be found.").
arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath()));
......@@ -690,7 +702,6 @@ bool CdbEngine::launchCDB(const DebuggerStartParameters &sp, QString *errorMessa
nativeArguments += sp.processArgs;
}
const QString executable = m_options->executable;
const QString msg = QString::fromLatin1("Launching %1 %2\nusing %3 of %4.").
arg(QDir::toNativeSeparators(executable),
arguments.join(QString(blank)) + blank + nativeArguments,
......@@ -1119,7 +1130,7 @@ void CdbEngine::handleJumpToLineAddressResolution(const CdbBuiltinCommandPtr &cm
QByteArray registerCmd;
ByteArrayInputStream str(registerCmd);
// PC-register depending on 64/32bit.
str << "r " << (m_options->is64bit ? "rip" : "eip") << "=0x" << answer;
str << "r " << (startParameters().toolChainAbi.wordWidth() == 64 ? "rip" : "eip") << "=0x" << answer;
postCommand(registerCmd, 0);
gotoLocation(Location(cookie.fileName, cookie.lineNumber));
}
......
......@@ -32,31 +32,20 @@
**************************************************************************/
#include "cdboptions.h"
#include "cdbengine.h"
#ifdef Q_OS_WIN
# include <utils/winutils.h>
#endif
#include <QtCore/QSettings>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QCoreApplication>
static const char settingsGroupC[] = "CDB2";
static const char enabledKeyC[] = "Enabled";
static const char pathKeyC[] = "Path";
static const char symbolPathsKeyC[] = "SymbolPaths";
static const char sourcePathsKeyC[] = "SourcePaths";
static const char breakEventKeyC[] = "BreakEvent";
static const char is64bitKeyC[] = "64bit";
static const char additionalArgumentsKeyC[] = "AdditionalArguments";
namespace Debugger {
namespace Internal {
CdbOptions::CdbOptions() :
enabled(false), is64bit(false)
CdbOptions::CdbOptions() : enabled(false)
{
}
......@@ -65,90 +54,23 @@ QString CdbOptions::settingsGroup()
return QLatin1String(settingsGroupC);
}
void CdbOptions::clearExecutable()
{
is64bit = enabled = false;
executable.clear();
}
void CdbOptions::clear()
{
clearExecutable();
enabled = false;
symbolPaths.clear();
sourcePaths.clear();
}
static inline QString msgAutoDetectFail(bool is64Bit, const QString &executable,
const QString &extLib)
{
return QCoreApplication::translate("Debugger::Cdb::CdbOptions",
"Auto-detection of the CDB debugging engine (%1bit) failed:\n"
"Debugger executable: %2\n"
"Extension library : %3 not present.\n").arg(is64Bit ? 64 : 32).
arg(QDir::toNativeSeparators(executable), QDir::toNativeSeparators(extLib));
}
static inline QString msgAutoDetect(bool is64Bit, const QString &executable,
const QString &extLib,
const QStringList &symbolPaths)
{
return QCoreApplication::translate("Debugger::Cdb::CdbOptions",
"The new CDB debugging engine (%1bit) has been set up automatically:\n"
"Debugger executable: %2\n"
"Extension library : %3\n"
"Symbol paths : %4\n").arg(is64Bit ? 64 : 32).
arg(QDir::toNativeSeparators(executable), QDir::toNativeSeparators(extLib),
symbolPaths.join(QString(QLatin1Char(';'))));
}
QStringList CdbOptions::oldEngineSymbolPaths(const QSettings *s)
{
return s->value(QLatin1String("CDB/SymbolPaths")).toStringList();
}
bool CdbOptions::autoDetect(const QSettings *s)
{
QString autoExecutable;
bool auto64Bit;
// Check installation and existence of the extension library
CdbOptions::autoDetectExecutable(&autoExecutable, &auto64Bit);
if (autoExecutable.isEmpty())
return false;
const QString extLib = CdbEngine::extensionLibraryName(auto64Bit);
if (!QFileInfo(extLib).isFile()) {
const QString failMsg = msgAutoDetectFail(auto64Bit, autoExecutable, extLib);
qWarning("%s", qPrintable(failMsg));
clearExecutable();
return false;
}
enabled = true;
is64bit = auto64Bit;
executable = autoExecutable;
// Is there a symbol path from an old install? Use that
if (symbolPaths.empty())
symbolPaths = CdbOptions::oldEngineSymbolPaths(s);
const QString msg = msgAutoDetect(is64bit, QDir::toNativeSeparators(executable),
QDir::toNativeSeparators(extLib), symbolPaths);
qWarning("%s", qPrintable(msg));
return true;
}
void CdbOptions::fromSettings(QSettings *s)
{
clear();
// Is this the first time we are called ->
// try to find automatically
const QString keyRoot = QLatin1String(settingsGroupC) + QLatin1Char('/');
const QString enabledKey = keyRoot + QLatin1String(enabledKeyC);
// First-time autodetection: Write back parameters
const bool firstTime = !s->contains(enabledKey);
if (firstTime && autoDetect(s)) {
toSettings(s);
return;
}
enabled = s->value(enabledKey, false).toBool();
is64bit = s->value(keyRoot + QLatin1String(is64bitKeyC), is64bit).toBool();
executable = s->value(keyRoot + QLatin1String(pathKeyC), executable).toString();
enabled = s->value(keyRoot + QLatin1String(enabledKeyC), QVariant(false)).toBool();
additionalArguments = s->value(keyRoot + QLatin1String(additionalArgumentsKeyC), QString()).toString();
symbolPaths = s->value(keyRoot + QLatin1String(symbolPathsKeyC), QStringList()).toStringList();
sourcePaths = s->value(keyRoot + QLatin1String(sourcePathsKeyC), QStringList()).toStringList();
......@@ -159,8 +81,6 @@ void CdbOptions::toSettings(QSettings *s) const
{
s->beginGroup(QLatin1String(settingsGroupC));
s->setValue(QLatin1String(enabledKeyC), enabled);
s->setValue(QLatin1String(pathKeyC), executable);
s->setValue(QLatin1String(is64bitKeyC), is64bit);
s->setValue(QLatin1String(symbolPathsKeyC), symbolPaths);
s->setValue(QLatin1String(sourcePathsKeyC), sourcePaths);
s->setValue(QLatin1String(breakEventKeyC), breakEvents);
......@@ -170,91 +90,13 @@ void CdbOptions::toSettings(QSettings *s) const
bool CdbOptions::equals(const CdbOptions &rhs) const
{
return enabled == rhs.enabled && is64bit == rhs.is64bit
&& executable == rhs.executable
return enabled == rhs.enabled
&& additionalArguments == rhs.additionalArguments
&& symbolPaths == rhs.symbolPaths
&& sourcePaths == rhs.sourcePaths
&& breakEvents == rhs.breakEvents;
}
// Check the CDB executable and accumulate the list of checked paths
// for reporting.
static QString checkCdbExecutable(const QString &programDir, const QString &postfix,
QStringList *checkedDirectories = 0)
{
QString executable = programDir;
executable += QLatin1String("/Debugging Tools For Windows");
executable += postfix;
if (checkedDirectories)
checkedDirectories->push_back(QDir::toNativeSeparators(executable));
executable += QLatin1String("/cdb.exe");
const QFileInfo fi(executable);
return fi.isFile() && fi.isExecutable() ? fi.absoluteFilePath() : QString();
}
bool CdbOptions::autoDetectExecutable(QString *outPath, bool *is64bitIn /* = 0 */,
QStringList *checkedDirectories /* = 0 */)
{
// Look for $ProgramFiles/"Debugging Tools For Windows <bit-idy>/cdb.exe" and its
// " (x86)", " (x64)" variations.
static const char *postFixes[] = {" (x64)", " 64-bit", " (x86)", " (x32)" };
enum { first32bitIndex = 2 };
outPath->clear();
if (checkedDirectories)
checkedDirectories->clear();
const QString programDir = QString::fromLocal8Bit(qgetenv("ProgramFiles"));
if (programDir.isEmpty())
return false;
#ifdef Q_OS_WIN
const bool systemIs64Bit = Utils::winIs64BitSystem();
#else
const bool systemIs64Bit = false;
#endif
// Plain system installation. 32/64 Bit matches the system.
*outPath = checkCdbExecutable(programDir, QString(), checkedDirectories);
if (!outPath->isEmpty()) {
if (is64bitIn)
*is64bitIn = systemIs64Bit;
return true;
}
// Try the post fixes
for (unsigned i = 0; i < sizeof(postFixes)/sizeof(const char*); i++) {
*outPath = checkCdbExecutable(programDir, QLatin1String(postFixes[i]), checkedDirectories);
if (!outPath->isEmpty()) {
if (is64bitIn)
*is64bitIn = i < first32bitIndex;
return true;
}
}
// A 32bit-compile running on a 64bit system sees the 64 bit installation
// as "$ProgramFiles (x64)/Debugging Tools..." and (untested), a 64 bit-
// compile running on a 64bit system sees the 32 bit installation as
// "$ProgramFiles (x86)/Debugging Tools..." (assuming this works at all)
#ifdef Q_OS_WIN64
*outPath = checkCdbExecutable(programDir + QLatin1String(" (x32)"), QString(), checkedDirectories);
if (!outPath->isEmpty()) {
if (is64bitIn)
*is64bitIn = false;
return true;
}
#else
// A 32bit process on 64 bit sees "ProgramFiles\Debg.. (x64)"
if (programDir.endsWith(QLatin1String(" (x86)"))) {
*outPath = checkCdbExecutable(programDir.left(programDir.size() - 6),
QLatin1String(" (x64)"), checkedDirectories);
if (!outPath->isEmpty()) {
if (is64bitIn)
*is64bitIn = true;
return true;
}
}
#endif
return false;
}
} // namespace Internal
} // namespace Debugger
......@@ -48,26 +48,19 @@ struct CdbOptions
public:
CdbOptions();
bool isValid() const { return enabled && !executable.isEmpty(); }
bool isValid() const { return enabled; }
void clearExecutable();
void clear();
void fromSettings(QSettings *s); // Writes parameters on first-time autodetect
bool autoDetect(const QSettings *s);
void toSettings(QSettings *s) const;
bool equals(const CdbOptions &rhs) const;
static bool autoDetectExecutable(QString *outPath, bool *is64bit = 0,
QStringList *checkedDirectories = 0);
static QString settingsGroup();
static QStringList oldEngineSymbolPaths(const QSettings *s);
bool enabled;
bool is64bit;
QString executable;
QString additionalArguments;
QStringList symbolPaths;
QStringList sourcePaths;
......
......@@ -36,27 +36,13 @@
#include "debuggerconstants.h"
#include "cdbengine.h"
#ifdef Q_OS_WIN
# include <utils/winutils.h>
#endif
#include <utils/synchronousprocess.h>
#include <coreplugin/icore.h>
#include <QtCore/QCoreApplication>
#include <QtCore/QUrl>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QDateTime>
#include <QtCore/QTextStream>
#include <QtCore/QTimer>
#include <QtCore/QProcess>
#include <QtGui/QMessageBox>
#include <QtGui/QLineEdit>
#include <QtGui/QDesktopServices>
static const char *dgbToolsDownloadLink32C = "http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx";
static const char *dgbToolsDownloadLink64C = "http://www.microsoft.com/whdc/devtools/debugging/install64bit.Mspx";
#include <QtGui/QCheckBox>
namespace Debugger {
namespace Internal {
......@@ -173,35 +159,11 @@ QStringList CdbBreakEventWidget::breakEvents() const
return rc;
}
static inline QString msgPathConfigNote()
{
#ifdef Q_OS_WIN
const bool is64bit = Utils::winIs64BitSystem();
#else
const bool is64bit = false;
#endif
const QString link = is64bit ? QLatin1String(dgbToolsDownloadLink64C) : QLatin1String(dgbToolsDownloadLink32C);
//: Label text for path configuration. %2 is "x-bit version".
return CdbOptionsPageWidget::tr(
"<html><body><p>Specify the path to the "
"<a href=\"%1\">Windows Console Debugger executable</a>"
" (%2) here.</p>"
"</body></html>").arg(link, (is64bit ? CdbOptionsPageWidget::tr("64-bit version")
: CdbOptionsPageWidget::tr("32-bit version")));
}
CdbOptionsPageWidget::CdbOptionsPageWidget(QWidget *parent) :
QWidget(parent), m_breakEventWidget(new CdbBreakEventWidget),
m_reportTimer(0)
QWidget(parent), m_breakEventWidget(new CdbBreakEventWidget)
{
m_ui.setupUi(this);
m_ui.noteLabel->setText(msgPathConfigNote());
m_ui.noteLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
connect(m_ui.noteLabel, SIGNAL(linkActivated(QString)), this, SLOT(downLoadLinkActivated(QString)));
m_ui.pathChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
m_ui.pathChooser->addButton(tr("Autodetect"), this, SLOT(autoDetect()));
m_ui.cdbPathGroupBox->installEventFilter(this);
QVBoxLayout *eventLayout = new QVBoxLayout;
eventLayout->addWidget(m_breakEventWidget);
m_ui.eventGroupBox->setLayout(eventLayout);
......@@ -209,32 +171,18 @@ CdbOptionsPageWidget::CdbOptionsPageWidget(QWidget *parent) :
void CdbOptionsPageWidget::setOptions(CdbOptions &o)
{
m_ui.pathChooser->setPath(o.executable);
m_ui.additionalArgumentsLineEdit->setText(o.additionalArguments);
m_ui.is64BitCheckBox->setChecked(o.is64bit);
m_ui.cdbPathGroupBox->setChecked(o.enabled);
setSymbolPaths(o.symbolPaths);
m_ui.sourcePathListEditor->setPathList(o.sourcePaths);
m_breakEventWidget->setBreakEvents(o.breakEvents);
}
bool CdbOptionsPageWidget::is64Bit() const
{
return m_ui.is64BitCheckBox->isChecked();
}
QString CdbOptionsPageWidget::path() const
{
return m_ui.pathChooser->path();
}
CdbOptions CdbOptionsPageWidget::options() const
{
CdbOptions rc;
rc.executable = path();
rc.additionalArguments = m_ui.additionalArgumentsLineEdit->text().trimmed();
rc.enabled = m_ui.cdbPathGroupBox->isChecked();
rc.is64bit = is64Bit();
rc.symbolPaths = symbolPaths();
rc.sourcePaths = m_ui.sourcePathListEditor->pathList();
rc.breakEvents = m_breakEventWidget->breakEvents();
......@@ -251,128 +199,15 @@ void CdbOptionsPageWidget::setSymbolPaths(const QStringList &s)
m_ui.symbolPathListEditor->setPathList(s);
}
void CdbOptionsPageWidget::hideReportLabel()
{
m_ui.reportLabel->clear();
m_ui.reportLabel->setVisible(false);
}
void CdbOptionsPageWidget::autoDetect()
{
QString executable;
QStringList checkedDirectories;
bool is64bit;
const bool ok = CdbOptions::autoDetectExecutable(&executable, &is64bit, &checkedDirectories);
m_ui.cdbPathGroupBox->setChecked(ok);
if (ok) {
m_ui.is64BitCheckBox->setChecked(is64bit);
m_ui.pathChooser->setPath(executable);
QString report;
// Now check for the extension library as well.
const bool allOk = checkInstallation(executable, is64Bit(), &report);
setReport(report, allOk);
// On this occasion, if no symbol paths are specified, check for an
// old CDB installation
if (symbolPaths().isEmpty())
setSymbolPaths(CdbOptions::oldEngineSymbolPaths(Core::ICore::instance()->settings()));
} else {
const QString msg = tr("\"Debugging Tools for Windows\" could not be found.");
const QString details = tr("Checked:\n%1").arg(checkedDirectories.join(QString(QLatin1Char('\n'))));
QMessageBox msbBox(QMessageBox::Information, tr("Autodetection"), msg, QMessageBox::Ok, this);
msbBox.setDetailedText(details);
msbBox.exec();
}
}
void CdbOptionsPageWidget::setReport(const QString &msg, bool success)
{
// Hide label after some interval
if (!m_reportTimer) {
m_reportTimer = new QTimer(this);
m_reportTimer->setSingleShot(true);
connect(m_reportTimer, SIGNAL(timeout()), this, SLOT(hideReportLabel()));
} else {
if (m_reportTimer->isActive())
m_reportTimer->stop();
}
m_reportTimer->setInterval(success ? 10000 : 20000);
m_reportTimer->start();
m_ui.reportLabel->setText(msg);
m_ui.reportLabel->setStyleSheet(success ? QString() : QString::fromAscii("background-color : 'red'"));
m_ui.reportLabel->setVisible(true);
}
void CdbOptionsPageWidget::downLoadLinkActivated(const QString &link)
{
QDesktopServices::openUrl(QUrl(link));
}
QString CdbOptionsPageWidget::searchKeywords() const
{
QString rc;
QTextStream(&rc) << m_ui.pathLabel->text() << ' ' << m_ui.symbolPathLabel->text()
QTextStream(&rc) << m_ui.symbolPathLabel->text()
<< ' ' << m_ui.sourcePathLabel->text();
rc.remove(QLatin1Char('&'));
return rc;
}
static QString cdbVersion(const QString &executable)
{
QProcess cdb;
cdb.start(executable, QStringList(QLatin1String("-version")));
cdb.closeWriteChannel();
if (!cdb.waitForStarted())
return QString();
if (!cdb.waitForFinished()) {
Utils::SynchronousProcess::stopProcess(cdb);
return QString();
}
return QString::fromLocal8Bit(cdb.readAllStandardOutput());
}
bool CdbOptionsPageWidget::checkInstallation(const QString &executable,
bool is64Bit, QString *message)
{
// 1) Check on executable
unsigned checkedItems = 0;
QString rc;
if (executable.isEmpty()) {
message->append(tr("No cdb executable specified.\n"));
} else {
const QString version = cdbVersion(executable);
if (version.isEmpty()) {
message->append(tr("Unable to determine version of %1.\n").
arg(executable));
} else {
message->append(tr("Version: %1").arg(version));
checkedItems++;
}
}
// 2) Check on extension library
const QFileInfo extensionFi(CdbEngine::extensionLibraryName(is64Bit));
if (extensionFi.isFile()) {
message->append(tr("Extension library: %1, built: %2.\n").
arg(QDir::toNativeSeparators(extensionFi.absoluteFilePath())).
arg(extensionFi.lastModified().toString(Qt::SystemLocaleShortDate)));
checkedItems++;
} else {
message->append("Extension library not found.\n");
}
return checkedItems == 2u;
}
bool CdbOptionsPageWidget::eventFilter(QObject *o, QEvent *e)
{
if (o != m_ui.cdbPathGroupBox || e->type() != QEvent::ToolTip)
return QWidget::eventFilter(o, e);
QString message;
checkInstallation(path(), is64Bit(), &message);
m_ui.cdbPathGroupBox->setToolTip(message);
return false;
}
// ---------- CdbOptionsPage
CdbOptionsPage *CdbOptionsPage::m_instance = 0;
......
......@@ -44,7 +44,7 @@
#include <QtCore/QSharedPointer>
QT_BEGIN_NAMESPACE
class QTimer;
class QCheckBox;
QT_END_NAMESPACE
namespace Debugger {
......@@ -81,26 +81,13 @@ public:
QString searchKeywords() const;
virtual bool eventFilter(QObject *, QEvent *);
private slots:
void autoDetect();
void downLoadLinkActivated(const QString &);
void hideReportLabel();
private:
QStringList symbolPaths() const;
void setSymbolPaths(const QStringList &s);
void setReport(const QString &, bool success);
inline bool is64Bit() const;
inline QString path() const;
static bool checkInstallation(const QString &executable, bool is64Bit,
QString *message);
Ui::CdbOptionsPageWidget m_ui;
CdbBreakEventWidget *m_breakEventWidget;
QTimer *m_reportTimer;
};
class CdbOptionsPage : public Core::IOptionsPage
......
......@@ -2,6 +2,14 @@
<ui version="4.0">
<class>Debugger::Internal::CdbOptionsPageWidget</class>
<widget class="QWidget" name="Debugger::Internal::CdbOptionsPageWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>318</width>
<height>298</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
......@@ -14,27 +22,10 @@
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0">
<widget class="QLabel" name="pathLabel">
<property name="text">
<string>&amp;Path:</string>
</property>
<property name="buddy">
<cstring>pathChooser</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Utils::PathChooser" name="pathChooser" native="true"/>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="noteLabel">
<property name="text">
<string notr="true" extracomment="Placeholder">Note: bla, blah</string>
</property>
</widget>
</item>
<item