forked from qt-creator/qt-creator
Remove the RunConfiguration parameter from guessCppEngineType() and use the DebuggerStartParameter::toolChainAbi only. Use fillParameter() to set the debugger command and toolchain in order to prevent mismatches. Add logic trying to figure out the profile to fillParameters() in case the profile passed in is 0 for the command line cases. Use CDB matcher for post mortem and Remote CDB, fix it to prefer 64bit CDB on 64bit OS. Change-Id: Icedc3883fe15660303060498ab609957e6d01cd1 Reviewed-by: hjk <qthjk@ovi.com>
718 lines
23 KiB
C++
718 lines
23 KiB
C++
/**************************************************************************
|
|
**
|
|
** This file is part of Qt Creator
|
|
**
|
|
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
|
**
|
|
** Contact: http://www.qt-project.org/
|
|
**
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
**
|
|
** 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.
|
|
**
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** 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.
|
|
**
|
|
**
|
|
**************************************************************************/
|
|
|
|
#include "debuggerrunner.h"
|
|
#include "debuggerruncontrolfactory.h"
|
|
|
|
#include "debuggeractions.h"
|
|
#include "debuggerinternalconstants.h"
|
|
#include "debuggercore.h"
|
|
#include "debuggerengine.h"
|
|
#include "debuggermainwindow.h"
|
|
#include "debuggerplugin.h"
|
|
#include "debuggerstringutils.h"
|
|
#include "debuggerstartparameters.h"
|
|
#include "debuggerprofileinformation.h"
|
|
#include "lldb/lldbenginehost.h"
|
|
#include "debuggertooltipmanager.h"
|
|
|
|
#ifdef Q_OS_WIN
|
|
# include "peutils.h"
|
|
# include <utils/winutils.h>
|
|
#endif
|
|
|
|
#include <projectexplorer/abi.h>
|
|
#include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*
|
|
#include <projectexplorer/buildconfiguration.h>
|
|
#include <projectexplorer/project.h>
|
|
#include <projectexplorer/projectexplorer.h>
|
|
#include <projectexplorer/target.h>
|
|
#include <projectexplorer/toolchain.h>
|
|
|
|
#include <utils/outputformat.h>
|
|
#include <utils/synchronousprocess.h>
|
|
#include <utils/qtcassert.h>
|
|
#include <utils/fancymainwindow.h>
|
|
#include <utils/qtcprocess.h>
|
|
#include <coreplugin/icore.h>
|
|
#include <coreplugin/helpmanager.h>
|
|
|
|
#include <QDir>
|
|
#include <QCheckBox>
|
|
#include <QSpinBox>
|
|
#include <QDebug>
|
|
#include <QErrorMessage>
|
|
#include <QFormLayout>
|
|
#include <QLabel>
|
|
|
|
using namespace Debugger::Internal;
|
|
using namespace ProjectExplorer;
|
|
using namespace Utils;
|
|
|
|
enum { debug = 0 };
|
|
|
|
namespace Debugger {
|
|
namespace Internal {
|
|
|
|
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp, QString *error);
|
|
DebuggerEngine *createGdbEngine(const DebuggerStartParameters &sp);
|
|
DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp);
|
|
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &sp);
|
|
DebuggerEngine *createQmlEngine(const DebuggerStartParameters &sp);
|
|
DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &sp, QString *error);
|
|
DebuggerEngine *createLldbEngine(const DebuggerStartParameters &sp);
|
|
|
|
static const char *engineTypeName(DebuggerEngineType et)
|
|
{
|
|
switch (et) {
|
|
case Debugger::NoEngineType:
|
|
break;
|
|
case Debugger::GdbEngineType:
|
|
return "Gdb engine";
|
|
case Debugger::ScriptEngineType:
|
|
return "Script engine";
|
|
case Debugger::CdbEngineType:
|
|
return "Cdb engine";
|
|
case Debugger::PdbEngineType:
|
|
return "Pdb engine";
|
|
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";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DebuggerRunConfigWidget
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
class DebuggerRunConfigWidget : public RunConfigWidget
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
explicit DebuggerRunConfigWidget(RunConfiguration *runConfiguration);
|
|
QString displayName() const { return tr("Debugger Settings"); }
|
|
|
|
private slots:
|
|
void useCppDebuggerToggled(bool on);
|
|
void useQmlDebuggerToggled(bool on);
|
|
void qmlDebugServerPortChanged(int port);
|
|
void useMultiProcessToggled(bool on);
|
|
|
|
public:
|
|
DebuggerRunConfigurationAspect *m_aspect; // not owned
|
|
|
|
QCheckBox *m_useCppDebugger;
|
|
QCheckBox *m_useQmlDebugger;
|
|
QSpinBox *m_debugServerPort;
|
|
QLabel *m_debugServerPortLabel;
|
|
QLabel *m_qmlDebuggerInfoLabel;
|
|
QCheckBox *m_useMultiProcess;
|
|
};
|
|
|
|
DebuggerRunConfigWidget::DebuggerRunConfigWidget(RunConfiguration *runConfiguration)
|
|
{
|
|
m_aspect = runConfiguration->debuggerAspect();
|
|
|
|
m_useCppDebugger = new QCheckBox(tr("Enable C++"), this);
|
|
m_useQmlDebugger = new QCheckBox(tr("Enable QML"), this);
|
|
|
|
m_debugServerPort = new QSpinBox(this);
|
|
m_debugServerPort->setMinimum(1);
|
|
m_debugServerPort->setMaximum(65535);
|
|
|
|
m_debugServerPortLabel = new QLabel(tr("Debug port:"), this);
|
|
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>"));
|
|
|
|
m_useCppDebugger->setChecked(m_aspect->useCppDebugger());
|
|
m_useQmlDebugger->setChecked(m_aspect->useQmlDebugger());
|
|
|
|
m_debugServerPort->setValue(m_aspect->qmlDebugServerPort());
|
|
|
|
static const QByteArray env = qgetenv("QTC_DEBUGGER_MULTIPROCESS");
|
|
m_useMultiProcess =
|
|
new QCheckBox(tr("Enable Debugging of Subprocesses"), this);
|
|
m_useMultiProcess->setChecked(m_aspect->useMultiProcess());
|
|
m_useMultiProcess->setVisible(env.toInt());
|
|
|
|
connect(m_qmlDebuggerInfoLabel, SIGNAL(linkActivated(QString)),
|
|
Core::HelpManager::instance(), SLOT(handleHelpRequest(QString)));
|
|
connect(m_useQmlDebugger, SIGNAL(toggled(bool)),
|
|
SLOT(useQmlDebuggerToggled(bool)));
|
|
connect(m_useCppDebugger, SIGNAL(toggled(bool)),
|
|
SLOT(useCppDebuggerToggled(bool)));
|
|
connect(m_debugServerPort, SIGNAL(valueChanged(int)),
|
|
SLOT(qmlDebugServerPortChanged(int)));
|
|
connect(m_useMultiProcess, SIGNAL(toggled(bool)),
|
|
SLOT(useMultiProcessToggled(bool)));
|
|
|
|
if (m_aspect->isDisplaySuppressed())
|
|
hide();
|
|
|
|
if (m_aspect->areQmlDebuggingOptionsSuppressed()) {
|
|
m_debugServerPortLabel->hide();
|
|
m_debugServerPort->hide();
|
|
m_useQmlDebugger->hide();
|
|
}
|
|
|
|
if (m_aspect->areCppDebuggingOptionsSuppressed())
|
|
m_useCppDebugger->hide();
|
|
|
|
if (m_aspect->isQmlDebuggingSpinboxSuppressed()) {
|
|
m_debugServerPort->hide();
|
|
m_debugServerPortLabel->hide();
|
|
}
|
|
|
|
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);
|
|
layout->addWidget(m_useMultiProcess);
|
|
setLayout(layout);
|
|
}
|
|
|
|
void DebuggerRunConfigWidget::qmlDebugServerPortChanged(int port)
|
|
{
|
|
m_aspect->m_qmlDebugServerPort = port;
|
|
}
|
|
|
|
void DebuggerRunConfigWidget::useCppDebuggerToggled(bool on)
|
|
{
|
|
m_aspect->m_useCppDebugger = on;
|
|
if (!on && !m_useQmlDebugger->isChecked())
|
|
m_useQmlDebugger->setChecked(true);
|
|
}
|
|
|
|
void DebuggerRunConfigWidget::useQmlDebuggerToggled(bool on)
|
|
{
|
|
m_debugServerPort->setEnabled(on);
|
|
m_debugServerPortLabel->setEnabled(on);
|
|
|
|
m_aspect->m_useQmlDebugger = on
|
|
? DebuggerRunConfigurationAspect::EnableQmlDebugger
|
|
: DebuggerRunConfigurationAspect::DisableQmlDebugger;
|
|
if (!on && !m_useCppDebugger->isChecked())
|
|
m_useCppDebugger->setChecked(true);
|
|
}
|
|
|
|
void DebuggerRunConfigWidget::useMultiProcessToggled(bool on)
|
|
{
|
|
m_aspect->m_useMultiProcess = on;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DebuggerRunControlPrivate
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
class DebuggerRunControlPrivate
|
|
{
|
|
public:
|
|
explicit DebuggerRunControlPrivate(DebuggerRunControl *parent,
|
|
RunConfiguration *runConfiguration);
|
|
|
|
DebuggerEngineType engineForExecutable(unsigned enabledEngineTypes,
|
|
const QString &executable);
|
|
DebuggerEngineType engineForMode(unsigned enabledEngineTypes,
|
|
DebuggerStartMode mode);
|
|
|
|
public:
|
|
DebuggerRunControl *q;
|
|
DebuggerEngine *m_engine;
|
|
const QWeakPointer<RunConfiguration> m_myRunConfiguration;
|
|
bool m_running;
|
|
};
|
|
|
|
DebuggerRunControlPrivate::DebuggerRunControlPrivate(DebuggerRunControl *parent,
|
|
RunConfiguration *runConfiguration)
|
|
: q(parent)
|
|
, m_engine(0)
|
|
, m_myRunConfiguration(runConfiguration)
|
|
, m_running(false)
|
|
{
|
|
}
|
|
|
|
} // namespace Internal
|
|
|
|
DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
|
|
const DebuggerStartParameters &sp)
|
|
: RunControl(runConfiguration, DebugRunMode),
|
|
d(new DebuggerRunControlPrivate(this, runConfiguration))
|
|
{
|
|
connect(this, SIGNAL(finished()), SLOT(handleFinished()));
|
|
// 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 = DebuggerRunControlFactory::createEngine(sp.masterEngineType, sp, &errorMessage);
|
|
|
|
if (d->m_engine) {
|
|
DebuggerToolTipManager::instance()->registerEngine(d->m_engine);
|
|
} else {
|
|
debuggingFinished();
|
|
Core::ICore::showWarningWithOptions(DebuggerRunControl::tr("Debugger"), errorMessage);
|
|
}
|
|
}
|
|
|
|
DebuggerRunControl::~DebuggerRunControl()
|
|
{
|
|
disconnect();
|
|
if (DebuggerEngine *engine = d->m_engine) {
|
|
d->m_engine = 0;
|
|
engine->disconnect();
|
|
delete engine;
|
|
}
|
|
delete d;
|
|
}
|
|
|
|
const DebuggerStartParameters &DebuggerRunControl::startParameters() const
|
|
{
|
|
QTC_ASSERT(d->m_engine, return *(new DebuggerStartParameters()));
|
|
return d->m_engine->startParameters();
|
|
}
|
|
|
|
QString DebuggerRunControl::displayName() const
|
|
{
|
|
QTC_ASSERT(d->m_engine, return QString());
|
|
return d->m_engine->startParameters().displayName;
|
|
}
|
|
|
|
QIcon DebuggerRunControl::icon() const
|
|
{
|
|
return QIcon(QLatin1String(ProjectExplorer::Constants::ICON_DEBUG_SMALL));
|
|
}
|
|
|
|
void DebuggerRunControl::setCustomEnvironment(Environment env)
|
|
{
|
|
QTC_ASSERT(d->m_engine, return);
|
|
d->m_engine->startParameters().environment = env;
|
|
}
|
|
|
|
void DebuggerRunControl::start()
|
|
{
|
|
QTC_ASSERT(d->m_engine, return);
|
|
// 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()) {
|
|
appendMessage(tr("No executable specified.\n"), ErrorMessageFormat);
|
|
emit started();
|
|
emit finished();
|
|
return;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
debuggerCore()->runControlStarted(d->m_engine);
|
|
|
|
// We might get a synchronous startFailed() notification on Windows,
|
|
// when launching the process fails. Emit a proper finished() sequence.
|
|
emit started();
|
|
d->m_running = true;
|
|
|
|
d->m_engine->startDebugger(this);
|
|
|
|
if (d->m_running)
|
|
appendMessage(tr("Debugging starts\n"), NormalMessageFormat);
|
|
}
|
|
|
|
void DebuggerRunControl::startFailed()
|
|
{
|
|
appendMessage(tr("Debugging has failed\n"), NormalMessageFormat);
|
|
d->m_running = false;
|
|
emit finished();
|
|
d->m_engine->handleStartFailed();
|
|
}
|
|
|
|
void DebuggerRunControl::handleFinished()
|
|
{
|
|
appendMessage(tr("Debugging has finished\n"), NormalMessageFormat);
|
|
if (d->m_engine)
|
|
d->m_engine->handleFinished();
|
|
debuggerCore()->runControlFinished(d->m_engine);
|
|
}
|
|
|
|
void DebuggerRunControl::showMessage(const QString &msg, int channel)
|
|
{
|
|
switch (channel) {
|
|
case AppOutput:
|
|
appendMessage(msg, StdOutFormatSameLine);
|
|
break;
|
|
case AppError:
|
|
appendMessage(msg, StdErrFormatSameLine);
|
|
break;
|
|
case AppStuff:
|
|
appendMessage(msg, DebugFormat);
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool DebuggerRunControl::promptToStop(bool *optionalPrompt) const
|
|
{
|
|
QTC_ASSERT(isRunning(), return true);
|
|
|
|
if (optionalPrompt && !*optionalPrompt)
|
|
return true;
|
|
|
|
const QString question = tr("A debugging session is still in progress. "
|
|
"Terminating the session in the current"
|
|
" state can leave the target in an inconsistent state."
|
|
" Would you still like to terminate it?");
|
|
return showPromptToStopDialog(tr("Close Debugging Session"), question,
|
|
QString(), QString(), optionalPrompt);
|
|
}
|
|
|
|
RunControl::StopResult DebuggerRunControl::stop()
|
|
{
|
|
QTC_ASSERT(d->m_engine, return StoppedSynchronously);
|
|
d->m_engine->quitDebugger();
|
|
return AsynchronousStop;
|
|
}
|
|
|
|
void DebuggerRunControl::debuggingFinished()
|
|
{
|
|
d->m_running = false;
|
|
emit finished();
|
|
}
|
|
|
|
bool DebuggerRunControl::isRunning() const
|
|
{
|
|
return d->m_running;
|
|
}
|
|
|
|
DebuggerEngine *DebuggerRunControl::engine()
|
|
{
|
|
QTC_CHECK(d->m_engine);
|
|
return d->m_engine;
|
|
}
|
|
|
|
RunConfiguration *DebuggerRunControl::runConfiguration() const
|
|
{
|
|
return d->m_myRunConfiguration.data();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// DebuggerRunControlFactory
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
DebuggerRunControlFactory::DebuggerRunControlFactory(QObject *parent)
|
|
: IRunControlFactory(parent)
|
|
{}
|
|
|
|
bool DebuggerRunControlFactory::canRun(RunConfiguration *runConfiguration, RunMode mode) const
|
|
{
|
|
return (mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain)
|
|
&& qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
|
|
}
|
|
|
|
QString DebuggerRunControlFactory::displayName() const
|
|
{
|
|
return DebuggerPlugin::tr("Debug");
|
|
}
|
|
|
|
static DebuggerStartParameters localStartParameters(RunConfiguration *runConfiguration)
|
|
{
|
|
DebuggerStartParameters sp;
|
|
QTC_ASSERT(runConfiguration, return sp);
|
|
LocalApplicationRunConfiguration *rc =
|
|
qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
|
|
QTC_ASSERT(rc, return sp);
|
|
|
|
Target *target = runConfiguration->target();
|
|
Profile *profile = target ? target->profile() : ProfileManager::instance()->defaultProfile();
|
|
fillParameters(&sp, profile);
|
|
sp.environment = rc->environment();
|
|
sp.workingDirectory = rc->workingDirectory();
|
|
|
|
#if defined(Q_OS_WIN)
|
|
// Work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch' ...)
|
|
sp.workingDirectory = normalizePathName(sp.workingDirectory);
|
|
#endif
|
|
|
|
sp.executable = rc->executable();
|
|
if (sp.executable.isEmpty())
|
|
return sp;
|
|
sp.startMode = StartInternal;
|
|
sp.processArgs = rc->commandLineArguments();
|
|
sp.useTerminal = rc->runMode() == LocalApplicationRunConfiguration::Console;
|
|
sp.dumperLibrary = rc->dumperLibrary();
|
|
sp.dumperLibraryLocations = rc->dumperLibraryLocations();
|
|
|
|
if (target) {
|
|
if (const Project *project = target->project()) {
|
|
sp.projectSourceDirectory = project->projectDirectory();
|
|
if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration())
|
|
sp.projectBuildDirectory = buildConfig->buildDirectory();
|
|
sp.projectSourceFiles = project->files(Project::ExcludeGeneratedFiles);
|
|
}
|
|
}
|
|
|
|
DebuggerRunConfigurationAspect *aspect = runConfiguration->debuggerAspect();
|
|
sp.multiProcess = aspect->useMultiProcess();
|
|
|
|
if (aspect->useCppDebugger())
|
|
sp.languages |= CppLanguage;
|
|
|
|
if (aspect->useQmlDebugger()) {
|
|
sp.qmlServerAddress = _("127.0.0.1");
|
|
sp.qmlServerPort = aspect->qmlDebugServerPort();
|
|
sp.languages |= QmlLanguage;
|
|
|
|
// Makes sure that all bindings go through the JavaScript engine, so that
|
|
// breakpoints are actually hit!
|
|
const QString optimizerKey = _("QML_DISABLE_OPTIMIZER");
|
|
if (!sp.environment.hasKey(optimizerKey))
|
|
sp.environment.set(optimizerKey, _("1"));
|
|
|
|
QtcProcess::addArg(&sp.processArgs, QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(sp.qmlServerPort));
|
|
}
|
|
|
|
// 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
|
|
(RunConfiguration *runConfiguration, RunMode mode)
|
|
{
|
|
QTC_ASSERT(mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain, return 0);
|
|
DebuggerStartParameters sp = localStartParameters(runConfiguration);
|
|
if (sp.startMode == NoStartMode)
|
|
return 0;
|
|
if (mode == DebugRunModeWithBreakOnMain)
|
|
sp.breakOnMain = true;
|
|
|
|
return doCreate(sp, runConfiguration);
|
|
}
|
|
|
|
static DebuggerEngineType guessUnixCppEngineType(const DebuggerStartParameters &sp)
|
|
{
|
|
if (sp.debuggerCommand.contains(QLatin1String("lldb")))
|
|
return LldbEngineType;
|
|
return GdbEngineType;
|
|
}
|
|
|
|
static DebuggerEngineType guessCppEngineTypeForAbi(const DebuggerStartParameters &sp, const Abi &abi)
|
|
{
|
|
switch (abi.binaryFormat()) {
|
|
case Abi::ElfFormat:
|
|
case Abi::MachOFormat:
|
|
return guessUnixCppEngineType(sp) ;
|
|
case Abi::PEFormat:
|
|
if (abi.osFlavor() == Abi::WindowsMSysFlavor)
|
|
return guessUnixCppEngineType(sp);
|
|
return CdbEngineType;
|
|
default:
|
|
break;
|
|
}
|
|
return NoEngineType;
|
|
}
|
|
|
|
static DebuggerEngineType guessCppEngineType(const DebuggerStartParameters &sp)
|
|
{
|
|
if (sp.toolChainAbi.isValid()) {
|
|
const DebuggerEngineType et = guessCppEngineTypeForAbi(sp, sp.toolChainAbi);
|
|
if (et != NoEngineType)
|
|
return et;
|
|
}
|
|
|
|
#ifdef Q_OS_WIN
|
|
// If a file has PDB files, it has been compiled by VS.
|
|
if (sp.executable.endsWith(_(".exe"), Qt::CaseInsensitive)) {
|
|
QStringList pdbFiles;
|
|
QString errorMessage;
|
|
if (getPDBFiles(sp.executable, &pdbFiles, &errorMessage) && !pdbFiles.isEmpty())
|
|
return CdbEngineType;
|
|
}
|
|
#endif
|
|
|
|
QList<Abi> abis = Abi::abisOfBinary(FileName::fromString(sp.executable));
|
|
foreach (const Abi &abi, abis) {
|
|
DebuggerEngineType et = guessCppEngineTypeForAbi(sp, abi);
|
|
if (et != NoEngineType)
|
|
return et;
|
|
}
|
|
|
|
return guessUnixCppEngineType(sp);
|
|
}
|
|
|
|
static void fixupEngineTypes(DebuggerStartParameters &sp, RunConfiguration *rc)
|
|
{
|
|
if (sp.masterEngineType != NoEngineType)
|
|
return;
|
|
|
|
if (sp.executable.endsWith(_(".js"))) {
|
|
sp.masterEngineType = ScriptEngineType;
|
|
return;
|
|
}
|
|
|
|
if (sp.executable.endsWith(_(".py"))) {
|
|
sp.masterEngineType = PdbEngineType;
|
|
return;
|
|
}
|
|
|
|
if (rc) {
|
|
DebuggerRunConfigurationAspect *aspect = rc->debuggerAspect();
|
|
if (const Target *target = rc->target())
|
|
fillParameters(&sp, target->profile());
|
|
const bool useCppDebugger = aspect->useCppDebugger();
|
|
const bool useQmlDebugger = aspect->useQmlDebugger();
|
|
if (useQmlDebugger) {
|
|
if (useCppDebugger) {
|
|
sp.masterEngineType = QmlCppEngineType;
|
|
sp.firstSlaveEngineType = guessCppEngineType(sp);
|
|
sp.secondSlaveEngineType = QmlCppEngineType;
|
|
} else {
|
|
sp.masterEngineType = QmlEngineType;
|
|
}
|
|
} else {
|
|
sp.masterEngineType = guessCppEngineType(sp);
|
|
}
|
|
return;
|
|
}
|
|
sp.masterEngineType = guessCppEngineType(sp);
|
|
}
|
|
|
|
DebuggerRunControl *DebuggerRunControlFactory::doCreate
|
|
(const DebuggerStartParameters &sp0, RunConfiguration *rc)
|
|
{
|
|
DebuggerStartParameters sp = sp0;
|
|
if (!debuggerCore()->boolSetting(AutoEnrichParameters)) {
|
|
const QString sysroot = sp.sysRoot;
|
|
if (sp.debugInfoLocation.isEmpty()) {
|
|
sp.debugInfoLocation = sysroot + QLatin1String("/usr/lib/debug");
|
|
}
|
|
if (sp.debugSourceLocation.isEmpty()) {
|
|
QString base = sysroot + QLatin1String("/usr/src/debug/");
|
|
sp.debugSourceLocation.append(base + QLatin1String("qt5base/src/corelib"));
|
|
sp.debugSourceLocation.append(base + QLatin1String("qt5base/src/gui"));
|
|
sp.debugSourceLocation.append(base + QLatin1String("qt5base/src/network"));
|
|
sp.debugSourceLocation.append(base + QLatin1String("qt5base/src/v8"));
|
|
sp.debugSourceLocation.append(base + QLatin1String("qt5declarative/src/qml"));
|
|
}
|
|
}
|
|
|
|
fixupEngineTypes(sp, rc);
|
|
if (!sp.masterEngineType)
|
|
return 0;
|
|
|
|
return new DebuggerRunControl(rc, sp);
|
|
}
|
|
|
|
DebuggerRunControl *DebuggerRunControlFactory::createAndScheduleRun
|
|
(const DebuggerStartParameters &sp, RunConfiguration *runConfiguration)
|
|
{
|
|
DebuggerRunControl *rc = doCreate(sp, runConfiguration);
|
|
if (!rc)
|
|
return 0;
|
|
debuggerCore()->showMessage(sp.startMessage, 0);
|
|
ProjectExplorerPlugin::instance()->startRunControl(rc, DebugRunMode);
|
|
return rc;
|
|
}
|
|
|
|
RunConfigWidget *DebuggerRunControlFactory::createConfigurationWidget
|
|
(RunConfiguration *runConfiguration)
|
|
{
|
|
return new DebuggerRunConfigWidget(runConfiguration);
|
|
}
|
|
|
|
DebuggerEngine *DebuggerRunControlFactory::createEngine(DebuggerEngineType et,
|
|
const DebuggerStartParameters &sp, QString *errorMessage)
|
|
{
|
|
switch (et) {
|
|
case GdbEngineType:
|
|
return createGdbEngine(sp);
|
|
case ScriptEngineType:
|
|
return createScriptEngine(sp);
|
|
case CdbEngineType:
|
|
return createCdbEngine(sp, errorMessage);
|
|
case PdbEngineType:
|
|
return createPdbEngine(sp);
|
|
case QmlEngineType:
|
|
return createQmlEngine(sp);
|
|
case LldbEngineType:
|
|
return createLldbEngine(sp);
|
|
case QmlCppEngineType:
|
|
return createQmlCppEngine(sp, errorMessage);
|
|
default:
|
|
break;
|
|
}
|
|
*errorMessage = DebuggerPlugin::tr("Unable to create a debugger engine of the type '%1'").
|
|
arg(_(engineTypeName(et)));
|
|
return 0;
|
|
}
|
|
|
|
} // namespace Debugger
|
|
|
|
#include "debuggerrunner.moc"
|