2009-02-25 09:15:00 +01:00
|
|
|
/**************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
**
|
2012-01-26 18:33:46 +01:00
|
|
|
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2011-11-02 15:59:12 +01:00
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** 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.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
2011-04-13 08:42:33 +02:00
|
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** Other Usage
|
|
|
|
**
|
|
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** If you have questions regarding the use of this file, please contact
|
2011-11-02 15:59:12 +01:00
|
|
|
** Nokia at qt-info@nokia.com.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
**************************************************************************/
|
2008-12-02 15:08:31 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "debuggerrunner.h"
|
2011-01-10 10:35:41 +01:00
|
|
|
#include "debuggerruncontrolfactory.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
#include "debuggeractions.h"
|
2011-04-21 15:52:51 +02:00
|
|
|
#include "debuggerinternalconstants.h"
|
2010-11-10 11:39:01 +01:00
|
|
|
#include "debuggercore.h"
|
2010-06-16 11:08:54 +02:00
|
|
|
#include "debuggerengine.h"
|
2010-12-02 17:43:14 +01:00
|
|
|
#include "debuggermainwindow.h"
|
2010-06-16 11:08:54 +02:00
|
|
|
#include "debuggerplugin.h"
|
|
|
|
#include "debuggerstringutils.h"
|
2011-01-10 10:14:23 +01:00
|
|
|
#include "debuggerstartparameters.h"
|
2010-10-08 12:14:51 +02:00
|
|
|
#include "lldb/lldbenginehost.h"
|
2011-02-11 15:00:13 +01:00
|
|
|
#include "debuggertooltipmanager.h"
|
2011-02-21 17:01:40 +01:00
|
|
|
#include "qml/qmlengine.h"
|
2010-06-15 09:13:22 +02:00
|
|
|
|
2010-06-22 12:28:05 +02:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
# include "peutils.h"
|
2011-04-19 11:07:34 +02:00
|
|
|
# include <utils/winutils.h>
|
2010-06-22 12:28:05 +02:00
|
|
|
#endif
|
|
|
|
|
2011-02-01 18:36:00 +01:00
|
|
|
#include <projectexplorer/abi.h>
|
2009-11-09 16:25:24 +01:00
|
|
|
#include <projectexplorer/debugginghelper.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <projectexplorer/project.h>
|
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
2010-02-08 15:50:06 +01:00
|
|
|
#include <projectexplorer/target.h>
|
2009-11-25 18:50:20 +01:00
|
|
|
#include <projectexplorer/buildconfiguration.h>
|
2011-02-25 16:03:22 +01:00
|
|
|
#include <projectexplorer/toolchain.h>
|
2010-06-11 16:31:54 +02:00
|
|
|
#include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2011-04-15 12:59:44 +02:00
|
|
|
#include <utils/outputformat.h>
|
2010-09-29 10:32:41 +02:00
|
|
|
#include <utils/synchronousprocess.h>
|
2008-12-09 15:25:01 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2010-08-20 14:19:25 +02:00
|
|
|
#include <utils/fancymainwindow.h>
|
2010-12-15 13:06:39 +01:00
|
|
|
#include <utils/qtcprocess.h>
|
2009-10-08 17:23:27 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2012-02-17 19:05:11 +01:00
|
|
|
#include <coreplugin/helpmanager.h>
|
2011-03-18 10:02:07 +01:00
|
|
|
#include <utils/buildablehelperlibrary.h>
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDir>
|
2012-02-17 19:05:11 +01:00
|
|
|
#include <QCheckBox>
|
|
|
|
#include <QSpinBox>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDebug>
|
|
|
|
#include <QErrorMessage>
|
2012-02-17 19:05:11 +01:00
|
|
|
#include <QFormLayout>
|
|
|
|
#include <QLabel>
|
|
|
|
#include <QMessageBox>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2010-06-11 16:16:14 +02:00
|
|
|
using namespace ProjectExplorer;
|
2010-06-14 17:23:25 +02:00
|
|
|
using namespace Debugger::Internal;
|
|
|
|
|
2011-02-25 09:34:31 +01:00
|
|
|
enum { debug = 0 };
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
namespace Debugger {
|
2011-01-11 11:06:15 +01:00
|
|
|
namespace Internal {
|
2011-01-12 12:10:12 +01:00
|
|
|
|
2010-12-10 09:37:31 +01:00
|
|
|
bool isCdbEngineEnabled(); // Check the configuration page
|
2011-02-24 16:50:15 +01:00
|
|
|
bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check);
|
2011-02-22 18:04:55 +01:00
|
|
|
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
|
2011-01-12 12:10:12 +01:00
|
|
|
DebuggerEngine *masterEngine, QString *error);
|
2011-02-25 13:43:06 +01:00
|
|
|
|
|
|
|
bool checkGdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check);
|
2011-02-22 18:04:55 +01:00
|
|
|
DebuggerEngine *createGdbEngine(const DebuggerStartParameters &sp,
|
2011-01-12 12:10:12 +01:00
|
|
|
DebuggerEngine *masterEngine);
|
2011-02-25 13:43:06 +01:00
|
|
|
|
2011-02-22 18:04:55 +01:00
|
|
|
DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp);
|
|
|
|
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &sp);
|
2011-02-21 17:01:40 +01:00
|
|
|
QmlEngine *createQmlEngine(const DebuggerStartParameters &sp,
|
2011-01-12 12:10:12 +01:00
|
|
|
DebuggerEngine *masterEngine);
|
2011-02-24 16:50:15 +01:00
|
|
|
DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &sp,
|
|
|
|
DebuggerEngineType slaveEngineType,
|
|
|
|
QString *errorMessage);
|
2011-02-22 18:04:55 +01:00
|
|
|
DebuggerEngine *createLldbEngine(const DebuggerStartParameters &sp);
|
2010-06-16 11:08:54 +02:00
|
|
|
|
2011-02-22 18:04:55 +01:00
|
|
|
extern QString msgNoBinaryForToolChain(const Abi &abi);
|
2010-06-16 11:08:54 +02:00
|
|
|
|
2011-02-24 16:50:15 +01:00
|
|
|
static const char *engineTypeName(DebuggerEngineType et)
|
|
|
|
{
|
|
|
|
switch (et) {
|
|
|
|
case Debugger::NoEngineType:
|
|
|
|
break;
|
|
|
|
case Debugger::GdbEngineType:
|
2011-03-14 17:34:27 +01:00
|
|
|
return "Gdb engine";
|
2011-02-24 16:50:15 +01:00
|
|
|
case Debugger::ScriptEngineType:
|
|
|
|
return "Script engine";
|
|
|
|
case Debugger::CdbEngineType:
|
|
|
|
return "Cdb engine";
|
|
|
|
case Debugger::PdbEngineType:
|
2011-03-14 17:34:27 +01:00
|
|
|
return "Pdb engine";
|
2011-02-24 16:50:15 +01:00
|
|
|
case Debugger::QmlEngineType:
|
|
|
|
return "QML engine";
|
|
|
|
case Debugger::QmlCppEngineType:
|
|
|
|
return "QML C++ engine";
|
|
|
|
case Debugger::LldbEngineType:
|
|
|
|
return "LLDB engine";
|
|
|
|
case Debugger::AllEngineTypes:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return "No engine";
|
|
|
|
}
|
|
|
|
|
2011-02-25 09:34:31 +01:00
|
|
|
static inline QString engineTypeNames(const QList<DebuggerEngineType> &l)
|
|
|
|
{
|
|
|
|
QString rc;
|
|
|
|
foreach (DebuggerEngineType et, l) {
|
|
|
|
if (!rc.isEmpty())
|
2011-03-14 17:34:27 +01:00
|
|
|
rc.append(QLatin1String(", "));
|
2011-02-25 09:34:31 +01:00
|
|
|
rc += QLatin1String(engineTypeName(et));
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
static QString msgEngineNotAvailable(const char *engine)
|
|
|
|
{
|
|
|
|
return DebuggerPlugin::tr("The application requires the debugger engine '%1', "
|
2011-02-22 13:23:16 +01:00
|
|
|
"which is disabled.").arg(_(engine));
|
2010-06-16 11:08:54 +02:00
|
|
|
}
|
|
|
|
|
2011-02-24 16:50:15 +01:00
|
|
|
static inline QString msgEngineNotAvailable(DebuggerEngineType et)
|
|
|
|
{
|
|
|
|
return msgEngineNotAvailable(engineTypeName(et));
|
|
|
|
}
|
|
|
|
|
2012-02-17 19:05:11 +01:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// DebuggerRunConfigWidget
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
class DebuggerLanguageChooser : public QWidget
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit DebuggerLanguageChooser(QWidget *parent = 0);
|
|
|
|
|
|
|
|
bool cppChecked() const;
|
|
|
|
bool qmlChecked() const;
|
|
|
|
uint qmlDebugServerPort() const;
|
|
|
|
|
|
|
|
void setCppChecked(bool value);
|
|
|
|
void setQmlChecked(bool value);
|
|
|
|
void setQmlDebugServerPort(uint port);
|
|
|
|
|
|
|
|
signals:
|
|
|
|
void cppLanguageToggled(bool value);
|
|
|
|
void qmlLanguageToggled(bool value);
|
|
|
|
void qmlDebugServerPortChanged(uint port);
|
|
|
|
void openHelpUrl(const QString &url);
|
|
|
|
|
|
|
|
private slots:
|
|
|
|
void useCppDebuggerToggled(bool toggled);
|
|
|
|
void useQmlDebuggerToggled(bool toggled);
|
|
|
|
void onDebugServerPortChanged(int port);
|
|
|
|
|
|
|
|
private:
|
|
|
|
QCheckBox *m_useCppDebugger;
|
|
|
|
QCheckBox *m_useQmlDebugger;
|
|
|
|
QSpinBox *m_debugServerPort;
|
|
|
|
QLabel *m_debugServerPortLabel;
|
|
|
|
QLabel *m_qmlDebuggerInfoLabel;
|
|
|
|
};
|
|
|
|
|
|
|
|
DebuggerLanguageChooser::DebuggerLanguageChooser(QWidget *parent)
|
|
|
|
: QWidget(parent)
|
|
|
|
{
|
|
|
|
m_useCppDebugger = new QCheckBox(tr("C++"), this);
|
|
|
|
m_useQmlDebugger = new QCheckBox(tr("QML"), this);
|
|
|
|
|
|
|
|
connect(m_useCppDebugger, SIGNAL(toggled(bool)),
|
|
|
|
this, SLOT(useCppDebuggerToggled(bool)));
|
|
|
|
connect(m_useQmlDebugger, SIGNAL(toggled(bool)),
|
|
|
|
this, SLOT(useQmlDebuggerToggled(bool)));
|
|
|
|
|
|
|
|
m_debugServerPortLabel = new QLabel(tr("Debug port:"), this);
|
|
|
|
m_debugServerPort = new QSpinBox(this);
|
|
|
|
m_debugServerPort->setMinimum(1);
|
|
|
|
m_debugServerPort->setMaximum(65535);
|
|
|
|
|
|
|
|
m_debugServerPortLabel->setBuddy(m_debugServerPort);
|
|
|
|
|
|
|
|
m_qmlDebuggerInfoLabel = new QLabel(tr("<a href=\""
|
|
|
|
"qthelp://com.nokia.qtcreator/doc/creator-debugging-qml.html"
|
|
|
|
"\">What are the prerequisites?</a>"));
|
|
|
|
|
|
|
|
connect(m_qmlDebuggerInfoLabel, SIGNAL(linkActivated(QString)),
|
|
|
|
this, SIGNAL(openHelpUrl(QString)));
|
|
|
|
connect(m_useQmlDebugger, SIGNAL(toggled(bool)),
|
|
|
|
m_debugServerPort, SLOT(setEnabled(bool)));
|
|
|
|
connect(m_useQmlDebugger, SIGNAL(toggled(bool)),
|
|
|
|
m_debugServerPortLabel, SLOT(setEnabled(bool)));
|
|
|
|
connect(m_debugServerPort, SIGNAL(valueChanged(int)),
|
|
|
|
this, SLOT(onDebugServerPortChanged(int)));
|
|
|
|
|
|
|
|
QHBoxLayout *qmlLayout = new QHBoxLayout;
|
|
|
|
qmlLayout->setMargin(0);
|
|
|
|
qmlLayout->addWidget(m_useQmlDebugger);
|
|
|
|
qmlLayout->addWidget(m_debugServerPortLabel);
|
|
|
|
qmlLayout->addWidget(m_debugServerPort);
|
|
|
|
qmlLayout->addWidget(m_qmlDebuggerInfoLabel);
|
|
|
|
qmlLayout->addStretch();
|
|
|
|
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
|
|
layout->setMargin(0);
|
|
|
|
layout->addWidget(m_useCppDebugger);
|
|
|
|
layout->addLayout(qmlLayout);
|
|
|
|
|
|
|
|
setLayout(layout);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DebuggerLanguageChooser::cppChecked() const
|
|
|
|
{
|
|
|
|
return m_useCppDebugger->isChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DebuggerLanguageChooser::qmlChecked() const
|
|
|
|
{
|
|
|
|
return m_useQmlDebugger->isChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint DebuggerLanguageChooser::qmlDebugServerPort() const
|
|
|
|
{
|
|
|
|
return m_debugServerPort->value();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebuggerLanguageChooser::setCppChecked(bool value)
|
|
|
|
{
|
|
|
|
m_useCppDebugger->setChecked(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebuggerLanguageChooser::setQmlChecked(bool value)
|
|
|
|
{
|
|
|
|
m_useQmlDebugger->setChecked(value);
|
|
|
|
m_debugServerPortLabel->setEnabled(value);
|
|
|
|
m_debugServerPort->setEnabled(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebuggerLanguageChooser::setQmlDebugServerPort(uint port)
|
|
|
|
{
|
|
|
|
m_debugServerPort->setValue(port);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebuggerLanguageChooser::useCppDebuggerToggled(bool toggled)
|
|
|
|
{
|
|
|
|
emit cppLanguageToggled(toggled);
|
|
|
|
if (!toggled && !m_useQmlDebugger->isChecked())
|
|
|
|
m_useQmlDebugger->setChecked(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebuggerLanguageChooser::useQmlDebuggerToggled(bool toggled)
|
|
|
|
{
|
|
|
|
emit qmlLanguageToggled(toggled);
|
|
|
|
if (!toggled && !m_useCppDebugger->isChecked())
|
|
|
|
m_useCppDebugger->setChecked(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DebuggerLanguageChooser::onDebugServerPortChanged(int port)
|
|
|
|
{
|
|
|
|
emit qmlDebugServerPortChanged((uint)port);
|
|
|
|
}
|
|
|
|
|
|
|
|
class DebuggerRunConfigWidget : public ProjectExplorer::RunConfigWidget
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit DebuggerRunConfigWidget(RunConfiguration *runConfiguration)
|
|
|
|
{
|
|
|
|
m_settings = runConfiguration->debuggerAspect();
|
|
|
|
|
|
|
|
QLabel *debuggerLabel = new QLabel(tr("Languages:"), this);
|
|
|
|
debuggerLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
|
|
|
|
|
|
|
|
m_debuggerLanguageChooser = new DebuggerLanguageChooser(this);
|
|
|
|
m_debuggerLanguageChooser->setCppChecked(m_settings->useCppDebugger());
|
|
|
|
m_debuggerLanguageChooser->setQmlChecked(runConfiguration->useQmlDebugger());
|
|
|
|
m_debuggerLanguageChooser->setQmlDebugServerPort(m_settings->qmlDebugServerPort());
|
|
|
|
|
|
|
|
QFormLayout *layout = new QFormLayout(this);
|
|
|
|
layout->addRow(debuggerLabel, m_debuggerLanguageChooser);
|
|
|
|
setLayout(layout);
|
|
|
|
|
|
|
|
connect(m_debuggerLanguageChooser, SIGNAL(cppLanguageToggled(bool)),
|
|
|
|
this, SLOT(useCppDebuggerToggled(bool)));
|
|
|
|
connect(m_debuggerLanguageChooser, SIGNAL(qmlLanguageToggled(bool)),
|
|
|
|
this, SLOT(useQmlDebuggerToggled(bool)));
|
|
|
|
connect(m_debuggerLanguageChooser, SIGNAL(qmlDebugServerPortChanged(uint)),
|
|
|
|
this, SLOT(qmlDebugServerPortChanged(uint)));
|
|
|
|
connect(m_debuggerLanguageChooser, SIGNAL(openHelpUrl(QString)),
|
|
|
|
Core::HelpManager::instance(), SLOT(handleHelpRequest(QString)));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString displayName() const
|
|
|
|
{
|
|
|
|
return tr("Debugger Settings");
|
|
|
|
}
|
|
|
|
|
|
|
|
public slots:
|
|
|
|
void useCppDebuggerToggled(bool toggled)
|
|
|
|
{
|
|
|
|
m_settings->m_useCppDebugger = toggled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void useQmlDebuggerToggled(bool toggled)
|
|
|
|
{
|
|
|
|
m_settings->m_useQmlDebugger = toggled
|
|
|
|
? DebuggerProjectSettings::EnableQmlDebugger
|
|
|
|
: DebuggerProjectSettings::DisableQmlDebugger;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qmlDebugServerPortChanged(uint port)
|
|
|
|
{
|
|
|
|
m_settings->m_qmlDebugServerPort = port;
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
DebuggerProjectSettings *m_settings; // not owned
|
|
|
|
DebuggerLanguageChooser *m_debuggerLanguageChooser; // owned
|
|
|
|
};
|
|
|
|
|
2010-06-15 08:22:02 +02:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2010-11-26 10:10:00 +01:00
|
|
|
// DebuggerRunControlPrivate
|
2010-06-15 08:22:02 +02:00
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2010-11-26 10:10:00 +01:00
|
|
|
class DebuggerRunControlPrivate
|
|
|
|
{
|
|
|
|
public:
|
2011-02-24 16:50:15 +01:00
|
|
|
explicit DebuggerRunControlPrivate(DebuggerRunControl *parent,
|
|
|
|
RunConfiguration *runConfiguration);
|
2010-09-14 08:34:07 +02:00
|
|
|
|
2010-11-26 10:10:00 +01:00
|
|
|
DebuggerEngineType engineForExecutable(unsigned enabledEngineTypes,
|
|
|
|
const QString &executable);
|
|
|
|
DebuggerEngineType engineForMode(unsigned enabledEngineTypes,
|
|
|
|
DebuggerStartMode mode);
|
|
|
|
|
|
|
|
public:
|
|
|
|
DebuggerRunControl *q;
|
2010-09-14 08:34:07 +02:00
|
|
|
DebuggerEngine *m_engine;
|
|
|
|
const QWeakPointer<RunConfiguration> m_myRunConfiguration;
|
|
|
|
bool m_running;
|
|
|
|
};
|
|
|
|
|
2010-11-26 10:10:00 +01:00
|
|
|
DebuggerRunControlPrivate::DebuggerRunControlPrivate(DebuggerRunControl *parent,
|
2011-02-24 16:50:15 +01:00
|
|
|
RunConfiguration *runConfiguration)
|
2010-11-26 10:10:00 +01:00
|
|
|
: q(parent)
|
|
|
|
, m_engine(0)
|
2010-10-22 11:27:45 +02:00
|
|
|
, m_myRunConfiguration(runConfiguration)
|
2010-08-18 13:54:12 +02:00
|
|
|
, m_running(false)
|
2010-09-14 08:34:07 +02:00
|
|
|
{
|
|
|
|
}
|
2010-08-18 13:54:12 +02:00
|
|
|
|
2010-12-10 09:37:31 +01:00
|
|
|
} // namespace Internal
|
|
|
|
|
2010-12-03 16:18:50 +01:00
|
|
|
DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
|
2011-02-24 16:50:15 +01:00
|
|
|
const DebuggerStartParameters &sp,
|
|
|
|
const QPair<DebuggerEngineType, DebuggerEngineType> &masterSlaveEngineTypes)
|
2012-01-10 19:17:24 +01:00
|
|
|
: RunControl(runConfiguration, ProjectExplorer::DebugRunMode),
|
2011-01-07 20:10:54 +01:00
|
|
|
d(new DebuggerRunControlPrivate(this, runConfiguration))
|
2009-09-09 18:35:25 +02:00
|
|
|
{
|
2010-12-03 16:18:50 +01:00
|
|
|
connect(this, SIGNAL(finished()), SLOT(handleFinished()));
|
2011-02-24 16:50:15 +01:00
|
|
|
// Create the engine. Could arguably be moved to the factory, but
|
|
|
|
// we still have a derived S60DebugControl. Should rarely fail, though.
|
|
|
|
QString errorMessage;
|
|
|
|
d->m_engine = masterSlaveEngineTypes.first == QmlCppEngineType ?
|
|
|
|
createQmlCppEngine(sp, masterSlaveEngineTypes.second, &errorMessage) :
|
|
|
|
DebuggerRunControlFactory::createEngine(masterSlaveEngineTypes.first, sp,
|
|
|
|
0, &errorMessage);
|
2011-02-11 15:00:13 +01:00
|
|
|
if (d->m_engine) {
|
|
|
|
DebuggerToolTipManager::instance()->registerEngine(d->m_engine);
|
|
|
|
} else {
|
2010-10-05 14:30:26 +02:00
|
|
|
debuggingFinished();
|
2012-01-24 15:36:40 +01:00
|
|
|
Core::ICore::showWarningWithOptions(DebuggerRunControl::tr("Debugger"), errorMessage);
|
2010-06-14 18:19:02 +02:00
|
|
|
}
|
2010-04-19 14:21:33 +02:00
|
|
|
}
|
|
|
|
|
2010-12-03 16:18:50 +01:00
|
|
|
DebuggerRunControl::~DebuggerRunControl()
|
|
|
|
{
|
|
|
|
disconnect();
|
|
|
|
if (DebuggerEngine *engine = d->m_engine) {
|
|
|
|
d->m_engine = 0;
|
|
|
|
engine->disconnect();
|
|
|
|
delete engine;
|
|
|
|
}
|
2011-09-16 15:00:41 +02:00
|
|
|
delete d;
|
2010-12-03 16:18:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const DebuggerStartParameters &DebuggerRunControl::startParameters() const
|
|
|
|
{
|
|
|
|
QTC_ASSERT(d->m_engine, return *(new DebuggerStartParameters()));
|
|
|
|
return d->m_engine->startParameters();
|
|
|
|
}
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
QString DebuggerRunControl::displayName() const
|
2010-06-15 08:22:02 +02:00
|
|
|
{
|
2010-09-14 08:34:07 +02:00
|
|
|
QTC_ASSERT(d->m_engine, return QString());
|
|
|
|
return d->m_engine->startParameters().displayName;
|
2010-06-15 08:22:02 +02:00
|
|
|
}
|
|
|
|
|
2011-03-28 19:58:13 +02:00
|
|
|
QIcon DebuggerRunControl::icon() const
|
|
|
|
{
|
2011-12-21 14:02:52 +01:00
|
|
|
return QIcon(QLatin1String(ProjectExplorer::Constants::ICON_DEBUG_SMALL));
|
2011-03-28 19:58:13 +02:00
|
|
|
}
|
|
|
|
|
2010-09-23 10:35:23 +02:00
|
|
|
void DebuggerRunControl::setCustomEnvironment(Utils::Environment env)
|
2010-06-15 08:22:02 +02:00
|
|
|
{
|
2010-12-15 09:17:31 +01:00
|
|
|
QTC_ASSERT(d->m_engine, return);
|
2010-10-19 11:14:03 +02:00
|
|
|
d->m_engine->startParameters().environment = env;
|
2010-06-15 08:22:02 +02:00
|
|
|
}
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
void DebuggerRunControl::start()
|
2010-06-15 09:13:22 +02:00
|
|
|
{
|
2010-09-14 08:34:07 +02:00
|
|
|
QTC_ASSERT(d->m_engine, return);
|
2011-04-18 13:01:12 +02:00
|
|
|
// User canceled input dialog asking for executable when working on library project.
|
|
|
|
if (d->m_engine->startParameters().startMode == StartInternal
|
|
|
|
&& d->m_engine->startParameters().executable.isEmpty()) {
|
2011-04-15 12:59:44 +02:00
|
|
|
appendMessage(tr("No executable specified.\n"), Utils::ErrorMessageFormat);
|
2011-04-18 13:01:12 +02:00
|
|
|
emit started();
|
|
|
|
emit finished();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-08-08 15:38:05 +02:00
|
|
|
if (d->m_engine->startParameters().startMode == StartInternal) {
|
|
|
|
foreach (const BreakpointModelId &id, debuggerCore()->breakHandler()->allBreakpointIds()) {
|
|
|
|
if (d->m_engine->breakHandler()->breakpointData(id).enabled
|
|
|
|
&& !d->m_engine->acceptsBreakpoint(id)) {
|
|
|
|
|
|
|
|
QString warningMessage =
|
|
|
|
DebuggerPlugin::tr("Some breakpoints cannot be handled by the debugger "
|
|
|
|
"languages currently active, and will be ignored.");
|
|
|
|
|
|
|
|
debuggerCore()->showMessage(warningMessage, LogWarning);
|
|
|
|
|
|
|
|
QErrorMessage *msgBox = new QErrorMessage(debuggerCore()->mainWindow());
|
|
|
|
msgBox->setAttribute(Qt::WA_DeleteOnClose);
|
|
|
|
msgBox->showMessage(warningMessage);
|
|
|
|
break;
|
|
|
|
}
|
2011-04-28 14:05:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-15 09:17:31 +01:00
|
|
|
debuggerCore()->runControlStarted(d->m_engine);
|
2010-08-27 16:22:51 +02:00
|
|
|
|
2010-09-29 10:32:41 +02:00
|
|
|
// We might get a synchronous startFailed() notification on Windows,
|
|
|
|
// when launching the process fails. Emit a proper finished() sequence.
|
2010-06-16 11:08:54 +02:00
|
|
|
emit started();
|
2010-09-29 10:32:41 +02:00
|
|
|
d->m_running = true;
|
|
|
|
|
2010-12-15 09:17:31 +01:00
|
|
|
d->m_engine->startDebugger(this);
|
2010-09-29 10:32:41 +02:00
|
|
|
|
2011-01-07 11:34:25 +01:00
|
|
|
if (d->m_running)
|
2011-04-15 12:59:44 +02:00
|
|
|
appendMessage(tr("Debugging starts\n"), Utils::NormalMessageFormat);
|
2010-06-15 11:42:49 +02:00
|
|
|
}
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
void DebuggerRunControl::startFailed()
|
2010-06-15 11:42:49 +02:00
|
|
|
{
|
2011-04-15 12:59:44 +02:00
|
|
|
appendMessage(tr("Debugging has failed\n"), Utils::NormalMessageFormat);
|
2010-09-14 08:34:07 +02:00
|
|
|
d->m_running = false;
|
2010-06-16 11:08:54 +02:00
|
|
|
emit finished();
|
2010-12-15 09:17:31 +01:00
|
|
|
d->m_engine->handleStartFailed();
|
2010-06-15 11:42:49 +02:00
|
|
|
}
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
void DebuggerRunControl::handleFinished()
|
2010-06-15 11:42:49 +02:00
|
|
|
{
|
2011-04-15 12:59:44 +02:00
|
|
|
appendMessage(tr("Debugging has finished\n"), Utils::NormalMessageFormat);
|
2010-12-15 09:17:31 +01:00
|
|
|
if (d->m_engine)
|
|
|
|
d->m_engine->handleFinished();
|
|
|
|
debuggerCore()->runControlFinished(d->m_engine);
|
2010-06-15 11:42:49 +02:00
|
|
|
}
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
void DebuggerRunControl::showMessage(const QString &msg, int channel)
|
2010-06-15 11:42:49 +02:00
|
|
|
{
|
2010-06-16 11:08:54 +02:00
|
|
|
switch (channel) {
|
|
|
|
case AppOutput:
|
2011-04-15 12:59:44 +02:00
|
|
|
appendMessage(msg, Utils::StdOutFormatSameLine);
|
2010-06-16 11:08:54 +02:00
|
|
|
break;
|
|
|
|
case AppError:
|
2011-04-15 12:59:44 +02:00
|
|
|
appendMessage(msg, Utils::StdErrFormatSameLine);
|
2010-06-16 11:08:54 +02:00
|
|
|
break;
|
|
|
|
case AppStuff:
|
2011-05-11 12:08:23 +02:00
|
|
|
appendMessage(msg, Utils::DebugFormat);
|
2010-06-16 11:08:54 +02:00
|
|
|
break;
|
|
|
|
}
|
2010-06-15 11:42:49 +02:00
|
|
|
}
|
|
|
|
|
2011-01-17 13:52:14 +01:00
|
|
|
bool DebuggerRunControl::promptToStop(bool *optionalPrompt) const
|
2010-06-15 11:42:49 +02:00
|
|
|
{
|
2010-08-20 14:19:25 +02:00
|
|
|
QTC_ASSERT(isRunning(), return true;)
|
|
|
|
|
2011-01-17 13:52:14 +01:00
|
|
|
if (optionalPrompt && !*optionalPrompt)
|
|
|
|
return true;
|
|
|
|
|
2010-09-29 12:48:00 +02:00
|
|
|
const QString question = tr("A debugging session is still in progress. "
|
2010-08-20 14:19:25 +02:00
|
|
|
"Terminating the session in the current"
|
|
|
|
" state can leave the target in an inconsistent state."
|
|
|
|
" Would you still like to terminate it?");
|
2011-01-17 13:52:14 +01:00
|
|
|
return showPromptToStopDialog(tr("Close Debugging Session"), question,
|
|
|
|
QString(), QString(), optionalPrompt);
|
2010-08-20 14:19:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
RunControl::StopResult DebuggerRunControl::stop()
|
|
|
|
{
|
2010-09-14 08:34:07 +02:00
|
|
|
QTC_ASSERT(d->m_engine, return StoppedSynchronously);
|
|
|
|
d->m_engine->quitDebugger();
|
2010-08-20 14:19:25 +02:00
|
|
|
return AsynchronousStop;
|
2010-06-15 11:42:49 +02:00
|
|
|
}
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
void DebuggerRunControl::debuggingFinished()
|
2010-06-15 11:42:49 +02:00
|
|
|
{
|
2010-09-14 08:34:07 +02:00
|
|
|
d->m_running = false;
|
2010-06-16 11:08:54 +02:00
|
|
|
emit finished();
|
2010-06-15 11:42:49 +02:00
|
|
|
}
|
|
|
|
|
2010-06-16 11:08:54 +02:00
|
|
|
bool DebuggerRunControl::isRunning() const
|
2010-06-15 11:42:49 +02:00
|
|
|
{
|
2010-09-14 08:34:07 +02:00
|
|
|
return d->m_running;
|
2010-06-15 11:42:49 +02:00
|
|
|
}
|
|
|
|
|
2010-09-13 13:30:35 +02:00
|
|
|
DebuggerEngine *DebuggerRunControl::engine()
|
2010-06-15 11:42:49 +02:00
|
|
|
{
|
2011-07-29 12:00:11 +02:00
|
|
|
QTC_CHECK(d->m_engine);
|
2010-09-14 08:34:07 +02:00
|
|
|
return d->m_engine;
|
2010-06-15 11:42:49 +02:00
|
|
|
}
|
|
|
|
|
2010-09-14 08:34:07 +02:00
|
|
|
RunConfiguration *DebuggerRunControl::runConfiguration() const
|
|
|
|
{
|
|
|
|
return d->m_myRunConfiguration.data();
|
|
|
|
}
|
2010-11-10 11:39:01 +01:00
|
|
|
|
2011-02-24 16:50:15 +01:00
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2011-03-16 17:59:43 +01:00
|
|
|
// Engine detection logic: Detection functions depending on tool chain, binary,
|
2011-02-24 16:50:15 +01:00
|
|
|
// etc. Return a list of possible engines (order of prefererence) without
|
|
|
|
// consideration of configuration, etc.
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2012-02-01 09:03:05 +01:00
|
|
|
static QList<DebuggerEngineType> enginesForToolChain(const Abi &toolChain,
|
|
|
|
DebuggerLanguages languages)
|
2011-02-24 16:50:15 +01:00
|
|
|
{
|
|
|
|
QList<DebuggerEngineType> result;
|
|
|
|
switch (toolChain.binaryFormat()) {
|
|
|
|
case Abi::ElfFormat:
|
|
|
|
case Abi::MachOFormat:
|
|
|
|
result.push_back(LldbEngineType);
|
|
|
|
result.push_back(GdbEngineType);
|
2012-02-01 09:03:05 +01:00
|
|
|
if (languages & QmlLanguage)
|
|
|
|
result.push_back(QmlEngineType);
|
2011-02-24 16:50:15 +01:00
|
|
|
break;
|
|
|
|
case Abi::PEFormat:
|
|
|
|
if (toolChain.osFlavor() == Abi::WindowsMSysFlavor) {
|
|
|
|
result.push_back(GdbEngineType);
|
|
|
|
result.push_back(CdbEngineType);
|
|
|
|
} else {
|
|
|
|
result.push_back(CdbEngineType);
|
|
|
|
result.push_back(GdbEngineType);
|
|
|
|
}
|
2012-02-01 09:03:05 +01:00
|
|
|
if (languages & QmlLanguage)
|
|
|
|
result.push_back(QmlEngineType);
|
2011-02-24 16:50:15 +01:00
|
|
|
break;
|
|
|
|
case Abi::RuntimeQmlFormat:
|
|
|
|
result.push_back(QmlEngineType);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline QList<DebuggerEngineType> enginesForScriptExecutables(const QString &executable)
|
|
|
|
{
|
|
|
|
QList<DebuggerEngineType> result;
|
|
|
|
if (executable.endsWith(_(".js"))) {
|
|
|
|
result.push_back(ScriptEngineType);
|
|
|
|
} else if (executable.endsWith(_(".py"))) {
|
|
|
|
result.push_back(PdbEngineType);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QList<DebuggerEngineType> enginesForExecutable(const QString &executable)
|
|
|
|
{
|
|
|
|
QList<DebuggerEngineType> result = enginesForScriptExecutables(executable);
|
|
|
|
if (!result.isEmpty())
|
|
|
|
return result;
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
// A remote executable?
|
|
|
|
if (!executable.endsWith(_(".exe"), Qt::CaseInsensitive)) {
|
|
|
|
result.push_back(GdbEngineType);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If a file has PDB files, it has been compiled by VS.
|
|
|
|
QStringList pdbFiles;
|
|
|
|
QString errorMessage;
|
|
|
|
if (getPDBFiles(executable, &pdbFiles, &errorMessage) && !pdbFiles.isEmpty()) {
|
|
|
|
result.push_back(CdbEngineType);
|
|
|
|
result.push_back(GdbEngineType);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
// Fixme: Gdb should only be preferred if MinGW can positively be detected.
|
|
|
|
result.push_back(GdbEngineType);
|
|
|
|
result.push_back(CdbEngineType);
|
|
|
|
#else
|
|
|
|
result.push_back(LldbEngineType);
|
|
|
|
result.push_back(GdbEngineType);
|
|
|
|
#endif
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Debugger type for mode.
|
|
|
|
static QList<DebuggerEngineType> enginesForMode(DebuggerStartMode startMode,
|
2012-02-01 09:03:05 +01:00
|
|
|
DebuggerLanguages languages,
|
2011-02-24 16:50:15 +01:00
|
|
|
bool hardConstraintsOnly)
|
|
|
|
{
|
|
|
|
QList<DebuggerEngineType> result;
|
2012-02-01 09:03:05 +01:00
|
|
|
|
|
|
|
if (languages == QmlLanguage) {
|
|
|
|
QTC_ASSERT(startMode == StartInternal
|
|
|
|
|| startMode == AttachToRemoteServer,
|
|
|
|
qDebug() << "qml debugging not supported for mode"
|
|
|
|
<< startMode);
|
|
|
|
|
|
|
|
// Qml language only
|
|
|
|
result.push_back(QmlEngineType);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-02-24 16:50:15 +01:00
|
|
|
switch (startMode) {
|
2011-04-07 15:12:48 +02:00
|
|
|
case NoStartMode:
|
2011-02-24 16:50:15 +01:00
|
|
|
break;
|
2011-04-07 15:12:48 +02:00
|
|
|
case StartInternal:
|
|
|
|
case StartExternal:
|
2011-02-24 16:50:15 +01:00
|
|
|
case AttachExternal:
|
|
|
|
if (!hardConstraintsOnly) {
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
result.push_back(CdbEngineType); // Preferably Windows debugger for attaching locally.
|
|
|
|
#endif
|
|
|
|
result.push_back(GdbEngineType);
|
2012-02-01 09:03:05 +01:00
|
|
|
|
|
|
|
if (languages & QmlLanguage)
|
|
|
|
result.push_back(QmlEngineType);
|
2011-02-24 16:50:15 +01:00
|
|
|
}
|
|
|
|
break;
|
2011-04-07 15:12:48 +02:00
|
|
|
case AttachCore:
|
2011-08-05 17:42:32 +02:00
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
result.push_back(CdbEngineType);
|
|
|
|
#endif
|
|
|
|
result.push_back(GdbEngineType);
|
|
|
|
break;
|
2011-12-05 17:21:48 +01:00
|
|
|
case StartRemoteProcess:
|
2011-04-07 15:12:48 +02:00
|
|
|
case StartRemoteGdb:
|
2011-02-24 16:50:15 +01:00
|
|
|
result.push_back(GdbEngineType);
|
2012-02-01 09:03:05 +01:00
|
|
|
if (languages & QmlLanguage)
|
|
|
|
result.push_back(QmlEngineType);
|
2011-02-24 16:50:15 +01:00
|
|
|
break;
|
2011-12-05 17:21:48 +01:00
|
|
|
case AttachToRemoteProcess:
|
2011-09-16 11:04:11 +02:00
|
|
|
case AttachToRemoteServer:
|
2011-02-24 16:50:15 +01:00
|
|
|
if (!hardConstraintsOnly) {
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
result.push_back(CdbEngineType);
|
|
|
|
#endif
|
|
|
|
result.push_back(GdbEngineType);
|
2012-02-01 09:03:05 +01:00
|
|
|
|
|
|
|
if (languages & QmlLanguage)
|
|
|
|
result.push_back(QmlEngineType);
|
2011-02-24 16:50:15 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AttachCrashedExternal:
|
|
|
|
result.push_back(CdbEngineType); // Only CDB can do this
|
|
|
|
break;
|
|
|
|
case StartRemoteEngine:
|
|
|
|
// FIXME: Unclear IPC override. Someone please have a better idea.
|
|
|
|
// For now thats the only supported IPC engine.
|
|
|
|
result.push_back(LldbEngineType);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Engine detection logic: Call all detection functions in order.
|
|
|
|
|
|
|
|
static QList<DebuggerEngineType> engineTypes(const DebuggerStartParameters &sp)
|
|
|
|
{
|
|
|
|
// Script executables and certain start modes are 'hard constraints'.
|
|
|
|
QList<DebuggerEngineType> result = enginesForScriptExecutables(sp.executable);
|
|
|
|
if (!result.isEmpty())
|
|
|
|
return result;
|
|
|
|
|
2012-02-01 09:03:05 +01:00
|
|
|
result = enginesForMode(sp.startMode, sp.languages, true);
|
2011-02-24 16:50:15 +01:00
|
|
|
if (!result.isEmpty())
|
|
|
|
return result;
|
|
|
|
|
|
|
|
// 'hard constraints' done (with the exception of QML ABI checked here),
|
|
|
|
// further try to restrict available engines.
|
|
|
|
if (sp.toolChainAbi.isValid()) {
|
2012-02-01 09:03:05 +01:00
|
|
|
result = enginesForToolChain(sp.toolChainAbi, sp.languages);
|
2011-02-24 16:50:15 +01:00
|
|
|
if (!result.isEmpty())
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: 1 of 3 testing hacks.
|
2012-02-16 11:12:02 +01:00
|
|
|
if (sp.processArgs.startsWith(QLatin1String("@tcf@ "))) {
|
2011-02-24 16:50:15 +01:00
|
|
|
result.push_back(GdbEngineType);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2011-12-06 15:39:25 +01:00
|
|
|
if (sp.startMode != AttachToRemoteServer
|
|
|
|
&& sp.startMode != AttachToRemoteProcess
|
|
|
|
&& !sp.executable.isEmpty())
|
2011-02-24 16:50:15 +01:00
|
|
|
result = enginesForExecutable(sp.executable);
|
|
|
|
if (!result.isEmpty())
|
|
|
|
return result;
|
|
|
|
|
2012-02-01 09:03:05 +01:00
|
|
|
result = enginesForMode(sp.startMode, sp.languages, false);
|
2011-02-24 16:50:15 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Engine detection logic: ConfigurationCheck.
|
|
|
|
ConfigurationCheck::ConfigurationCheck() :
|
|
|
|
masterSlaveEngineTypes(NoEngineType, NoEngineType)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ConfigurationCheck::operator bool() const
|
|
|
|
{
|
2011-04-07 15:12:48 +02:00
|
|
|
return errorMessage.isEmpty()
|
|
|
|
&& errorDetails.isEmpty()
|
|
|
|
&& masterSlaveEngineTypes.first != NoEngineType;
|
2011-02-25 09:34:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
QString ConfigurationCheck::errorDetailsString() const
|
|
|
|
{
|
|
|
|
return errorDetails.join(QLatin1String("\n\n"));
|
2011-02-24 16:50:15 +01:00
|
|
|
}
|
|
|
|
|
2011-03-14 17:34:27 +01:00
|
|
|
// Convenience helper to check whether an engine is enabled and configured
|
|
|
|
// correctly.
|
|
|
|
static inline bool canUseEngine(DebuggerEngineType et,
|
|
|
|
const DebuggerStartParameters &sp,
|
|
|
|
unsigned cmdLineEnabledEngines,
|
|
|
|
ConfigurationCheck *result)
|
|
|
|
{
|
|
|
|
// Enabled?
|
|
|
|
if ((et & cmdLineEnabledEngines) == 0) {
|
|
|
|
result->errorDetails.push_back(DebuggerPlugin::tr("The debugger engine '%1' is disabled.").
|
2011-12-21 14:02:52 +01:00
|
|
|
arg(QLatin1String(engineTypeName(et))));
|
2011-03-14 17:34:27 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Configured.
|
|
|
|
switch (et) {
|
2011-04-07 15:12:48 +02:00
|
|
|
case CdbEngineType:
|
2011-03-14 17:34:27 +01:00
|
|
|
return checkCdbConfiguration(sp, result);
|
2011-04-07 15:12:48 +02:00
|
|
|
case GdbEngineType:
|
2011-03-14 17:34:27 +01:00
|
|
|
return checkGdbConfiguration(sp, result);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-02-24 16:50:15 +01:00
|
|
|
/*!
|
2011-03-28 14:58:12 +02:00
|
|
|
\fn Debugger::ConfigurationCheck Debugger::checkDebugConfiguration(const DebuggerStartParameters &sp)
|
2011-02-24 16:50:15 +01:00
|
|
|
|
|
|
|
This is the master engine detection function that returns the
|
|
|
|
engine types for a given set of start parameters and checks their
|
|
|
|
configuration.
|
|
|
|
*/
|
|
|
|
|
|
|
|
DEBUGGER_EXPORT ConfigurationCheck checkDebugConfiguration(const DebuggerStartParameters &sp)
|
|
|
|
{
|
|
|
|
ConfigurationCheck result;
|
2011-02-25 09:34:31 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug().nospace() << "checkDebugConfiguration " << sp.toolChainAbi.toString()
|
|
|
|
<< " Start mode=" << sp.startMode << " Executable=" << sp.executable
|
|
|
|
<< " Debugger command=" << sp.debuggerCommand;
|
2011-02-24 16:50:15 +01:00
|
|
|
// Get all applicable types.
|
2012-02-01 09:03:05 +01:00
|
|
|
QList<DebuggerEngineType> requiredTypes = engineTypes(sp);
|
2011-02-24 16:50:15 +01:00
|
|
|
if (requiredTypes.isEmpty()) {
|
2011-03-01 17:07:15 +01:00
|
|
|
result.errorMessage = QLatin1String("Internal error: Unable to determine debugger engine type for this configuration");
|
2011-02-24 16:50:15 +01:00
|
|
|
return result;
|
|
|
|
}
|
2011-02-25 09:34:31 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug() << " Required: " << engineTypeNames(requiredTypes);
|
2012-02-01 09:03:05 +01:00
|
|
|
// Filter out disabled types, command line + current settings.
|
2011-02-24 16:50:15 +01:00
|
|
|
unsigned cmdLineEnabledEngines = debuggerCore()->enabledEngines();
|
|
|
|
#ifdef WITH_LLDB
|
2012-01-24 15:36:40 +01:00
|
|
|
if (!Core::ICore::settings()->value(QLatin1String("LLDB/enabled")).toBool())
|
2011-02-24 16:50:15 +01:00
|
|
|
cmdLineEnabledEngines &= ~LldbEngineType;
|
|
|
|
#else
|
|
|
|
cmdLineEnabledEngines &= ~LldbEngineType;
|
|
|
|
#endif
|
2012-02-01 09:03:05 +01:00
|
|
|
|
2011-03-14 17:34:27 +01:00
|
|
|
DebuggerEngineType usableType = NoEngineType;
|
|
|
|
QList<DebuggerEngineType> unavailableTypes;
|
|
|
|
foreach (DebuggerEngineType et, requiredTypes) {
|
|
|
|
if (canUseEngine(et, sp, cmdLineEnabledEngines, &result)) {
|
|
|
|
usableType = et;
|
|
|
|
break;
|
2011-03-08 12:37:13 +01:00
|
|
|
} else {
|
2011-03-14 17:34:27 +01:00
|
|
|
unavailableTypes.push_back(et);
|
2011-03-08 12:37:13 +01:00
|
|
|
}
|
2011-02-24 16:50:15 +01:00
|
|
|
}
|
2011-03-14 17:34:27 +01:00
|
|
|
if (usableType == NoEngineType) {
|
|
|
|
if (requiredTypes.size() == 1) {
|
|
|
|
result.errorMessage = DebuggerPlugin::tr(
|
|
|
|
"The debugger engine '%1' required for debugging binaries of the type '%2'"
|
|
|
|
" is not configured correctly.").
|
|
|
|
arg(QLatin1String(engineTypeName(requiredTypes.front())), sp.toolChainAbi.toString());
|
2011-02-25 13:43:06 +01:00
|
|
|
} else {
|
2011-03-14 17:34:27 +01:00
|
|
|
result.errorMessage = DebuggerPlugin::tr(
|
|
|
|
"None of the debugger engines '%1' capable of debugging binaries of the type '%2'"
|
|
|
|
" is configured correctly.").
|
|
|
|
arg(engineTypeNames(requiredTypes), sp.toolChainAbi.toString());
|
2011-02-25 13:43:06 +01:00
|
|
|
}
|
2011-03-14 17:34:27 +01:00
|
|
|
return result;
|
2011-02-25 13:43:06 +01:00
|
|
|
}
|
2011-02-25 09:34:31 +01:00
|
|
|
if (debug)
|
2011-03-14 17:34:27 +01:00
|
|
|
qDebug() << "Configured engine: " << engineTypeName(usableType);
|
|
|
|
// Inform verbosely about MinGW-gdb/CDB fallbacks. Do not complain about LLDB, for now.
|
|
|
|
if (!result.errorDetails.isEmpty() && unavailableTypes.count(LldbEngineType) != unavailableTypes.size()) {
|
|
|
|
const QString msg = DebuggerPlugin::tr(
|
|
|
|
"The preferred debugger engine for debugging binaries of type '%1' is not available.\n"
|
|
|
|
"The debugger engine '%2' will be used as a fallback.\nDetails: %3").
|
2011-12-21 14:02:52 +01:00
|
|
|
arg(sp.toolChainAbi.toString(), QLatin1String(engineTypeName(usableType)),
|
2011-03-14 17:34:27 +01:00
|
|
|
result.errorDetails.join(QString(QLatin1Char('\n'))));
|
|
|
|
debuggerCore()->showMessage(msg, LogWarning);
|
2011-04-28 12:59:54 +02:00
|
|
|
showMessageBox(QMessageBox::Warning, DebuggerPlugin::tr("Warning"), msg);
|
2011-02-24 16:50:15 +01:00
|
|
|
}
|
|
|
|
// Anything left: Happy.
|
2011-02-25 13:43:06 +01:00
|
|
|
result.errorMessage.clear();
|
|
|
|
result.errorDetails.clear();
|
2012-02-01 09:03:05 +01:00
|
|
|
|
|
|
|
|
|
|
|
// Could we actually use a combined qml/cpp-engine?
|
|
|
|
if (usableType != QmlEngineType
|
|
|
|
&& requiredTypes.contains(QmlEngineType)) {
|
|
|
|
result.masterSlaveEngineTypes.first = QmlCppEngineType;
|
|
|
|
result.masterSlaveEngineTypes.second = usableType;
|
|
|
|
} else {
|
|
|
|
result.masterSlaveEngineTypes.first = usableType;
|
|
|
|
}
|
|
|
|
|
2011-02-25 09:34:31 +01:00
|
|
|
if (debug)
|
|
|
|
qDebug() << engineTypeName(result.masterSlaveEngineTypes.first) << engineTypeName(result.masterSlaveEngineTypes.second);
|
2011-02-24 16:50:15 +01:00
|
|
|
return result;
|
|
|
|
}
|
2010-12-15 09:17:31 +01:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// DebuggerRunControlFactory
|
|
|
|
//
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// A factory to create DebuggerRunControls
|
|
|
|
DebuggerRunControlFactory::DebuggerRunControlFactory(QObject *parent,
|
|
|
|
unsigned enabledEngines)
|
|
|
|
: IRunControlFactory(parent), m_enabledEngines(enabledEngines)
|
|
|
|
{}
|
|
|
|
|
2012-01-10 19:17:24 +01:00
|
|
|
bool DebuggerRunControlFactory::canRun(RunConfiguration *runConfiguration, RunMode mode) const
|
2010-12-15 09:17:31 +01:00
|
|
|
{
|
2012-01-10 19:17:24 +01:00
|
|
|
return (mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain)
|
2010-12-15 09:17:31 +01:00
|
|
|
&& qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString DebuggerRunControlFactory::displayName() const
|
|
|
|
{
|
2011-01-19 16:50:03 +01:00
|
|
|
return DebuggerRunControl::tr("Debug");
|
2010-12-15 09:17:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find Qt installation by running qmake
|
2011-11-25 13:19:58 +01:00
|
|
|
static inline QString findQtInstallPath(const Utils::FileName &qmakePath)
|
2010-12-15 09:17:31 +01:00
|
|
|
{
|
|
|
|
QProcess proc;
|
|
|
|
QStringList args;
|
2011-02-22 13:23:16 +01:00
|
|
|
args.append(_("-query"));
|
|
|
|
args.append(_("QT_INSTALL_HEADERS"));
|
2011-11-25 13:19:58 +01:00
|
|
|
proc.start(qmakePath.toString(), args);
|
2010-12-15 09:17:31 +01:00
|
|
|
if (!proc.waitForStarted()) {
|
2011-11-25 13:19:58 +01:00
|
|
|
qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(qmakePath.toString()),
|
2010-12-15 09:17:31 +01:00
|
|
|
qPrintable(proc.errorString()));
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
proc.closeWriteChannel();
|
|
|
|
if (!proc.waitForFinished()) {
|
|
|
|
Utils::SynchronousProcess::stopProcess(proc);
|
2011-11-25 13:19:58 +01:00
|
|
|
qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(qmakePath.toString()));
|
2010-12-15 09:17:31 +01:00
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
if (proc.exitStatus() != QProcess::NormalExit) {
|
2011-11-25 13:19:58 +01:00
|
|
|
qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(qmakePath.toString()));
|
2010-12-15 09:17:31 +01:00
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
const QByteArray ba = proc.readAllStandardOutput().trimmed();
|
|
|
|
QDir dir(QString::fromLocal8Bit(ba));
|
|
|
|
if (dir.exists() && dir.cdUp())
|
|
|
|
return dir.absolutePath();
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
static DebuggerStartParameters localStartParameters(RunConfiguration *runConfiguration)
|
|
|
|
{
|
|
|
|
DebuggerStartParameters sp;
|
|
|
|
QTC_ASSERT(runConfiguration, return sp);
|
|
|
|
LocalApplicationRunConfiguration *rc =
|
|
|
|
qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
|
|
|
|
QTC_ASSERT(rc, return sp);
|
|
|
|
|
|
|
|
sp.environment = rc->environment();
|
|
|
|
sp.workingDirectory = rc->workingDirectory();
|
2011-04-19 11:07:34 +02:00
|
|
|
|
|
|
|
#if defined(Q_OS_WIN)
|
|
|
|
// Work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch' ...)
|
|
|
|
sp.workingDirectory = Utils::normalizePathName(sp.workingDirectory);
|
|
|
|
#endif
|
|
|
|
|
2010-12-15 09:17:31 +01:00
|
|
|
sp.executable = rc->executable();
|
2011-12-20 17:03:10 +01:00
|
|
|
if (sp.executable.isEmpty())
|
|
|
|
return sp;
|
|
|
|
sp.startMode = StartInternal;
|
2010-12-15 09:17:31 +01:00
|
|
|
sp.processArgs = rc->commandLineArguments();
|
2011-02-01 18:36:00 +01:00
|
|
|
sp.toolChainAbi = rc->abi();
|
2011-10-05 12:41:27 +00:00
|
|
|
if (!sp.toolChainAbi.isValid()) {
|
2012-01-13 15:07:32 +01:00
|
|
|
QList<Abi> abis = Abi::abisOfBinary(Utils::FileName::fromString(sp.executable));
|
2011-10-05 12:41:27 +00:00
|
|
|
if (!abis.isEmpty())
|
|
|
|
sp.toolChainAbi = abis.at(0);
|
|
|
|
}
|
2010-12-15 09:17:31 +01:00
|
|
|
sp.useTerminal = rc->runMode() == LocalApplicationRunConfiguration::Console;
|
|
|
|
sp.dumperLibrary = rc->dumperLibrary();
|
|
|
|
sp.dumperLibraryLocations = rc->dumperLibraryLocations();
|
|
|
|
|
2011-02-25 16:03:22 +01:00
|
|
|
if (const ProjectExplorer::Target *target = runConfiguration->target()) {
|
2011-03-18 10:02:07 +01:00
|
|
|
if (QByteArray(target->metaObject()->className()).contains("Qt4")) {
|
2011-11-25 13:19:58 +01:00
|
|
|
const Utils::FileName qmake = Utils::BuildableHelperLibrary::findSystemQt(sp.environment);
|
2011-03-18 10:02:07 +01:00
|
|
|
if (!qmake.isEmpty())
|
|
|
|
sp.qtInstallPath = findQtInstallPath(qmake);
|
|
|
|
}
|
2011-02-25 16:03:22 +01:00
|
|
|
if (const ProjectExplorer::Project *project = target->project()) {
|
2011-04-26 09:46:05 +02:00
|
|
|
sp.projectSourceDirectory = project->projectDirectory();
|
|
|
|
if (const ProjectExplorer::BuildConfiguration *buildConfig = target->activeBuildConfiguration()) {
|
|
|
|
sp.projectBuildDirectory = buildConfig->buildDirectory();
|
|
|
|
if (const ProjectExplorer::ToolChain *tc = buildConfig->toolChain())
|
2012-01-13 16:50:08 +01:00
|
|
|
sp.debuggerCommand = tc->debuggerCommand().toString();
|
2011-04-26 09:46:05 +02:00
|
|
|
}
|
|
|
|
sp.projectSourceFiles = project->files(Project::ExcludeGeneratedFiles);
|
2011-02-25 16:03:22 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 19:05:11 +01:00
|
|
|
if (runConfiguration->debuggerAspect()->useCppDebugger())
|
2012-02-01 09:03:05 +01:00
|
|
|
sp.languages |= CppLanguage;
|
|
|
|
|
|
|
|
if (runConfiguration->useQmlDebugger()) {
|
2011-02-22 13:23:16 +01:00
|
|
|
sp.qmlServerAddress = _("127.0.0.1");
|
2012-02-17 19:05:11 +01:00
|
|
|
sp.qmlServerPort = runConfiguration->debuggerAspect()->qmlDebugServerPort();
|
2012-02-01 09:03:05 +01:00
|
|
|
sp.languages |= QmlLanguage;
|
2010-12-15 09:17:31 +01:00
|
|
|
|
2011-02-07 10:55:22 +01:00
|
|
|
// Makes sure that all bindings go through the JavaScript engine, so that
|
|
|
|
// breakpoints are actually hit!
|
2011-02-25 16:03:22 +01:00
|
|
|
const QString optimizerKey = _("QML_DISABLE_OPTIMIZER");
|
|
|
|
if (!sp.environment.hasKey(optimizerKey)) {
|
|
|
|
sp.environment.set(optimizerKey, _("1"));
|
2011-02-07 10:55:22 +01:00
|
|
|
}
|
|
|
|
|
2011-12-21 14:02:52 +01:00
|
|
|
Utils::QtcProcess::addArg(&sp.processArgs,
|
|
|
|
QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(sp.qmlServerPort));
|
2010-12-15 09:17:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: If it's not yet build this will be empty and not filled
|
|
|
|
// when rebuild as the runConfiguration is not stored and therefore
|
|
|
|
// cannot be used to retrieve the dumper location.
|
|
|
|
//qDebug() << "DUMPER: " << sp.dumperLibrary << sp.dumperLibraryLocations;
|
|
|
|
sp.displayName = rc->displayName();
|
|
|
|
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
RunControl *DebuggerRunControlFactory::create
|
2012-01-10 19:17:24 +01:00
|
|
|
(RunConfiguration *runConfiguration, RunMode mode)
|
2010-12-15 09:17:31 +01:00
|
|
|
{
|
2012-01-10 19:17:24 +01:00
|
|
|
QTC_ASSERT(mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain, return 0);
|
2010-12-15 09:17:31 +01:00
|
|
|
DebuggerStartParameters sp = localStartParameters(runConfiguration);
|
2011-12-20 17:03:10 +01:00
|
|
|
if (sp.startMode == NoStartMode)
|
|
|
|
return 0;
|
2012-01-10 19:17:24 +01:00
|
|
|
if (mode == DebugRunModeWithBreakOnMain)
|
2011-05-02 18:22:32 +02:00
|
|
|
sp.breakOnMain = true;
|
2010-12-15 09:17:31 +01:00
|
|
|
return create(sp, runConfiguration);
|
|
|
|
}
|
|
|
|
|
2011-02-28 12:23:12 +01:00
|
|
|
RunConfigWidget *DebuggerRunControlFactory::createConfigurationWidget
|
2010-12-15 09:17:31 +01:00
|
|
|
(RunConfiguration *runConfiguration)
|
|
|
|
{
|
2012-02-17 19:05:11 +01:00
|
|
|
return new DebuggerRunConfigWidget(runConfiguration);
|
2010-12-15 09:17:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DebuggerRunControl *DebuggerRunControlFactory::create
|
2011-02-24 16:50:15 +01:00
|
|
|
(const DebuggerStartParameters &sp, RunConfiguration *runConfiguration)
|
2010-12-15 09:17:31 +01:00
|
|
|
{
|
2011-02-24 16:50:15 +01:00
|
|
|
const ConfigurationCheck check = checkDebugConfiguration(sp);
|
2010-12-15 09:34:02 +01:00
|
|
|
|
2011-01-07 19:50:41 +01:00
|
|
|
if (!check) {
|
2011-01-07 18:57:54 +01:00
|
|
|
//appendMessage(errorMessage, true);
|
2012-01-24 15:36:40 +01:00
|
|
|
Core::ICore::showWarningWithOptions(DebuggerRunControl::tr("Debugger"),
|
2011-02-25 09:34:31 +01:00
|
|
|
check.errorMessage, check.errorDetailsString(), check.settingsCategory, check.settingsPage);
|
2010-12-15 09:34:02 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-02-24 16:50:15 +01:00
|
|
|
return new DebuggerRunControl(runConfiguration, sp, check.masterSlaveEngineTypes);
|
|
|
|
}
|
|
|
|
|
2011-04-07 15:12:48 +02:00
|
|
|
DebuggerEngine *DebuggerRunControlFactory::createEngine
|
|
|
|
(DebuggerEngineType et,
|
|
|
|
const DebuggerStartParameters &sp,
|
|
|
|
DebuggerEngine *masterEngine,
|
|
|
|
QString *errorMessage)
|
2011-02-24 16:50:15 +01:00
|
|
|
{
|
|
|
|
switch (et) {
|
|
|
|
case GdbEngineType:
|
|
|
|
return createGdbEngine(sp, masterEngine);
|
|
|
|
case ScriptEngineType:
|
|
|
|
return createScriptEngine(sp);
|
|
|
|
case CdbEngineType:
|
|
|
|
return createCdbEngine(sp, masterEngine, errorMessage);
|
|
|
|
case PdbEngineType:
|
|
|
|
return createPdbEngine(sp);
|
|
|
|
case QmlEngineType:
|
|
|
|
return createQmlEngine(sp, masterEngine);
|
|
|
|
case LldbEngineType:
|
|
|
|
return createLldbEngine(sp);
|
2011-04-08 16:04:53 +02:00
|
|
|
default:
|
|
|
|
break;
|
2011-02-24 16:50:15 +01:00
|
|
|
}
|
|
|
|
*errorMessage = DebuggerRunControl::tr("Unable to create a debugger engine of the type '%1'").
|
|
|
|
arg(_(engineTypeName(et)));
|
2010-12-15 09:17:31 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-11 08:55:16 +02:00
|
|
|
} // namespace Debugger
|
2012-02-17 19:05:11 +01:00
|
|
|
|
|
|
|
#include "debuggerrunner.moc"
|