debuggerrunner.cpp 23.2 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2 3 4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
Eike Ziller's avatar
Eike Ziller committed
7
** Contact: http://www.qt-project.org/
con's avatar
con committed
8
**
9
**
10
** GNU Lesser General Public License Usage
11
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** 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.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** 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.
**
con's avatar
con committed
28
**
29
**************************************************************************/
hjk's avatar
hjk committed
30

con's avatar
con committed
31
#include "debuggerrunner.h"
32
#include "debuggerruncontrolfactory.h"
con's avatar
con committed
33

34
#include "debuggeractions.h"
35
#include "debuggerinternalconstants.h"
36
#include "debuggercore.h"
37
#include "debuggerengine.h"
38
#include "debuggermainwindow.h"
39 40
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
41
#include "debuggerstartparameters.h"
Tobias Hunger's avatar
Tobias Hunger committed
42
#include "debuggerkitinformation.h"
43
#include "lldb/lldbenginehost.h"
44
#include "debuggertooltipmanager.h"
45

Friedemann Kleint's avatar
Friedemann Kleint committed
46 47
#ifdef Q_OS_WIN
#  include "peutils.h"
48
#  include <utils/winutils.h>
Friedemann Kleint's avatar
Friedemann Kleint committed
49 50
#endif

51
#include <projectexplorer/abi.h>
hjk's avatar
hjk committed
52 53
#include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*
#include <projectexplorer/buildconfiguration.h>
con's avatar
con committed
54
#include <projectexplorer/project.h>
hjk's avatar
hjk committed
55
#include <projectexplorer/projectexplorer.h>
Tobias Hunger's avatar
Tobias Hunger committed
56
#include <projectexplorer/target.h>
57
#include <projectexplorer/toolchain.h>
con's avatar
con committed
58

con's avatar
con committed
59
#include <utils/outputformat.h>
60
#include <utils/synchronousprocess.h>
hjk's avatar
hjk committed
61
#include <utils/qtcassert.h>
62
#include <utils/fancymainwindow.h>
63
#include <utils/qtcprocess.h>
64
#include <coreplugin/icore.h>
65
#include <coreplugin/helpmanager.h>
hjk's avatar
hjk committed
66

67
#include <QDir>
68 69
#include <QCheckBox>
#include <QSpinBox>
70 71
#include <QDebug>
#include <QErrorMessage>
72 73
#include <QFormLayout>
#include <QLabel>
con's avatar
con committed
74

75
using namespace Debugger::Internal;
hjk's avatar
hjk committed
76 77
using namespace ProjectExplorer;
using namespace Utils;
78

79 80
enum { debug = 0 };

81
namespace Debugger {
82
namespace Internal {
83

84 85
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp, QString *error);
DebuggerEngine *createGdbEngine(const DebuggerStartParameters &sp);
hjk's avatar
hjk committed
86 87
DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp);
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &sp);
88 89
DebuggerEngine *createQmlEngine(const DebuggerStartParameters &sp);
DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &sp, QString *error);
hjk's avatar
hjk committed
90
DebuggerEngine *createLldbEngine(const DebuggerStartParameters &sp);
91

92 93 94 95 96 97
static const char *engineTypeName(DebuggerEngineType et)
{
    switch (et) {
    case Debugger::NoEngineType:
        break;
    case Debugger::GdbEngineType:
98
        return "Gdb engine";
99 100 101 102 103
    case Debugger::ScriptEngineType:
        return "Script engine";
    case Debugger::CdbEngineType:
        return "Cdb engine";
    case Debugger::PdbEngineType:
104
        return "Pdb engine";
105 106 107 108 109 110 111 112 113 114 115 116
    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";
}

117 118 119 120 121 122
////////////////////////////////////////////////////////////////////////
//
// DebuggerRunConfigWidget
//
////////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
123
class DebuggerRunConfigWidget : public RunConfigWidget
124 125 126 127
{
    Q_OBJECT

public:
128 129
    explicit DebuggerRunConfigWidget(RunConfiguration *runConfiguration);
    QString displayName() const { return tr("Debugger Settings"); }
130 131

private slots:
132 133
    void useCppDebuggerToggled(bool on);
    void useQmlDebuggerToggled(bool on);
134
    void qmlDebugServerPortChanged(int port);
135
    void useMultiProcessToggled(bool on);
136 137

public:
138
    DebuggerRunConfigurationAspect *m_aspect; // not owned
139 140 141 142 143 144

    QCheckBox *m_useCppDebugger;
    QCheckBox *m_useQmlDebugger;
    QSpinBox *m_debugServerPort;
    QLabel *m_debugServerPortLabel;
    QLabel *m_qmlDebuggerInfoLabel;
145
    QCheckBox *m_useMultiProcess;
146 147
};

148
DebuggerRunConfigWidget::DebuggerRunConfigWidget(RunConfiguration *runConfiguration)
149
{
150
    m_aspect = runConfiguration->debuggerAspect();
151

152 153
    m_useCppDebugger = new QCheckBox(tr("Enable C++"), this);
    m_useQmlDebugger = new QCheckBox(tr("Enable QML"), this);
154 155 156 157 158

    m_debugServerPort = new QSpinBox(this);
    m_debugServerPort->setMinimum(1);
    m_debugServerPort->setMaximum(65535);

159
    m_debugServerPortLabel = new QLabel(tr("Debug port:"), this);
160 161 162 163 164 165
    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>"));

166 167 168
    m_useCppDebugger->setChecked(m_aspect->useCppDebugger());
    m_useQmlDebugger->setChecked(m_aspect->useQmlDebugger());

169
    m_debugServerPort->setValue(m_aspect->qmlDebugServerPort());
170

171 172 173 174 175 176
    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());

177
    connect(m_qmlDebuggerInfoLabel, SIGNAL(linkActivated(QString)),
178
            Core::HelpManager::instance(), SLOT(handleHelpRequest(QString)));
179
    connect(m_useQmlDebugger, SIGNAL(toggled(bool)),
180 181 182
            SLOT(useQmlDebuggerToggled(bool)));
    connect(m_useCppDebugger, SIGNAL(toggled(bool)),
            SLOT(useCppDebuggerToggled(bool)));
183
    connect(m_debugServerPort, SIGNAL(valueChanged(int)),
184
            SLOT(qmlDebugServerPortChanged(int)));
185 186
    connect(m_useMultiProcess, SIGNAL(toggled(bool)),
            SLOT(useMultiProcessToggled(bool)));
187

188 189 190
    if (m_aspect->isDisplaySuppressed())
        hide();

191
    if (m_aspect->areQmlDebuggingOptionsSuppressed()) {
192 193 194 195
        m_debugServerPortLabel->hide();
        m_debugServerPort->hide();
        m_useQmlDebugger->hide();
    }
196

197 198 199
    if (m_aspect->areCppDebuggingOptionsSuppressed())
        m_useCppDebugger->hide();

200 201 202 203 204
    if (m_aspect->isQmlDebuggingSpinboxSuppressed()) {
        m_debugServerPort->hide();
        m_debugServerPortLabel->hide();
    }

205 206 207 208 209 210 211 212 213 214 215 216
    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);
217
    layout->addWidget(m_useMultiProcess);
218 219 220
    setLayout(layout);
}

221
void DebuggerRunConfigWidget::qmlDebugServerPortChanged(int port)
222
{
223
    m_aspect->m_qmlDebugServerPort = port;
224 225
}

226
void DebuggerRunConfigWidget::useCppDebuggerToggled(bool on)
227
{
228 229
    m_aspect->m_useCppDebugger = on;
    if (!on && !m_useQmlDebugger->isChecked())
230 231 232
        m_useQmlDebugger->setChecked(true);
}

233
void DebuggerRunConfigWidget::useQmlDebuggerToggled(bool on)
234
{
235 236
    m_debugServerPort->setEnabled(on);
    m_debugServerPortLabel->setEnabled(on);
237

238
    m_aspect->m_useQmlDebugger = on
239 240
            ? DebuggerRunConfigurationAspect::EnableQmlDebugger
            : DebuggerRunConfigurationAspect::DisableQmlDebugger;
241
    if (!on && !m_useCppDebugger->isChecked())
242 243 244
        m_useCppDebugger->setChecked(true);
}

245 246 247 248 249
void DebuggerRunConfigWidget::useMultiProcessToggled(bool on)
{
    m_aspect->m_useMultiProcess = on;
}

250 251
////////////////////////////////////////////////////////////////////////
//
hjk's avatar
hjk committed
252
// DebuggerRunControlPrivate
253 254 255
//
////////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
256 257 258
class DebuggerRunControlPrivate
{
public:
259 260
    explicit DebuggerRunControlPrivate(DebuggerRunControl *parent,
                                       RunConfiguration *runConfiguration);
261

hjk's avatar
hjk committed
262 263 264 265 266 267 268
    DebuggerEngineType engineForExecutable(unsigned enabledEngineTypes,
        const QString &executable);
    DebuggerEngineType engineForMode(unsigned enabledEngineTypes,
        DebuggerStartMode mode);

public:
    DebuggerRunControl *q;
269 270 271 272 273
    DebuggerEngine *m_engine;
    const QWeakPointer<RunConfiguration> m_myRunConfiguration;
    bool m_running;
};

hjk's avatar
hjk committed
274
DebuggerRunControlPrivate::DebuggerRunControlPrivate(DebuggerRunControl *parent,
275
                                                     RunConfiguration *runConfiguration)
hjk's avatar
hjk committed
276 277
    : q(parent)
    , m_engine(0)
278
    , m_myRunConfiguration(runConfiguration)
279
    , m_running(false)
280 281
{
}
282

hjk's avatar
hjk committed
283 284
} // namespace Internal

hjk's avatar
hjk committed
285
DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
hjk's avatar
hjk committed
286
                                       const DebuggerStartParameters &sp)
hjk's avatar
hjk committed
287
    : RunControl(runConfiguration, DebugRunMode),
288
      d(new DebuggerRunControlPrivate(this, runConfiguration))
289
{
hjk's avatar
hjk committed
290
    connect(this, SIGNAL(finished()), SLOT(handleFinished()));
291 292 293
    // Create the engine. Could arguably be moved to the factory, but
    // we still have a derived S60DebugControl. Should rarely fail, though.
    QString errorMessage;
294
    d->m_engine = DebuggerRunControlFactory::createEngine(sp.masterEngineType, sp, &errorMessage);
hjk's avatar
hjk committed
295

296 297 298
    if (d->m_engine) {
        DebuggerToolTipManager::instance()->registerEngine(d->m_engine);
    } else {
299
        debuggingFinished();
hjk's avatar
hjk committed
300
        Core::ICore::showWarningWithOptions(DebuggerRunControl::tr("Debugger"), errorMessage);
301
    }
302 303
}

hjk's avatar
hjk committed
304 305 306 307 308 309 310 311
DebuggerRunControl::~DebuggerRunControl()
{
    disconnect();
    if (DebuggerEngine *engine = d->m_engine) {
        d->m_engine = 0;
        engine->disconnect();
        delete engine;
    }
hjk's avatar
hjk committed
312
    delete d;
hjk's avatar
hjk committed
313 314 315 316 317 318 319 320
}

const DebuggerStartParameters &DebuggerRunControl::startParameters() const
{
    QTC_ASSERT(d->m_engine, return *(new DebuggerStartParameters()));
    return d->m_engine->startParameters();
}

321
QString DebuggerRunControl::displayName() const
322
{
323 324
    QTC_ASSERT(d->m_engine, return QString());
    return d->m_engine->startParameters().displayName;
325 326
}

327 328
QIcon DebuggerRunControl::icon() const
{
329
    return QIcon(QLatin1String(ProjectExplorer::Constants::ICON_DEBUG_SMALL));
330 331
}

hjk's avatar
hjk committed
332
void DebuggerRunControl::setCustomEnvironment(Environment env)
333
{
334
    QTC_ASSERT(d->m_engine, return);
335
    d->m_engine->startParameters().environment = env;
336 337
}

338
void DebuggerRunControl::start()
339
{
340
    QTC_ASSERT(d->m_engine, return);
341 342 343
    // 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()) {
hjk's avatar
hjk committed
344
        appendMessage(tr("No executable specified.\n"), ErrorMessageFormat);
345 346 347 348 349
        emit started();
        emit finished();
        return;
    }

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
    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;
            }
366 367 368
        }
    }

369
    debuggerCore()->runControlStarted(d->m_engine);
370

371 372
    // We might get a synchronous startFailed() notification on Windows,
    // when launching the process fails. Emit a proper finished() sequence.
373
    emit started();
374 375
    d->m_running = true;

376
    d->m_engine->startDebugger(this);
377

378
    if (d->m_running)
hjk's avatar
hjk committed
379
        appendMessage(tr("Debugging starts\n"), NormalMessageFormat);
380 381
}

382
void DebuggerRunControl::startFailed()
383
{
hjk's avatar
hjk committed
384
    appendMessage(tr("Debugging has failed\n"), NormalMessageFormat);
385
    d->m_running = false;
386
    emit finished();
387
    d->m_engine->handleStartFailed();
388 389
}

390
void DebuggerRunControl::handleFinished()
391
{
hjk's avatar
hjk committed
392
    appendMessage(tr("Debugging has finished\n"), NormalMessageFormat);
393 394 395
    if (d->m_engine)
        d->m_engine->handleFinished();
    debuggerCore()->runControlFinished(d->m_engine);
396 397
}

398
void DebuggerRunControl::showMessage(const QString &msg, int channel)
399
{
400 401
    switch (channel) {
        case AppOutput:
hjk's avatar
hjk committed
402
            appendMessage(msg, StdOutFormatSameLine);
403 404
            break;
        case AppError:
hjk's avatar
hjk committed
405
            appendMessage(msg, StdErrFormatSameLine);
406 407
            break;
        case AppStuff:
hjk's avatar
hjk committed
408
            appendMessage(msg, DebugFormat);
409 410
            break;
    }
411 412
}

413
bool DebuggerRunControl::promptToStop(bool *optionalPrompt) const
414
{
415
    QTC_ASSERT(isRunning(), return true);
416

417 418 419
    if (optionalPrompt && !*optionalPrompt)
        return true;

Jarek Kobus's avatar
Jarek Kobus committed
420
    const QString question = tr("A debugging session is still in progress. "
421 422 423
            "Terminating the session in the current"
            " state can leave the target in an inconsistent state."
            " Would you still like to terminate it?");
424 425
    return showPromptToStopDialog(tr("Close Debugging Session"), question,
                                  QString(), QString(), optionalPrompt);
426 427 428 429
}

RunControl::StopResult DebuggerRunControl::stop()
{
430 431
    QTC_ASSERT(d->m_engine, return StoppedSynchronously);
    d->m_engine->quitDebugger();
432
    return AsynchronousStop;
433 434
}

435
void DebuggerRunControl::debuggingFinished()
436
{
437
    d->m_running = false;
438
    emit finished();
439 440
}

441
bool DebuggerRunControl::isRunning() const
442
{
443
    return d->m_running;
444 445
}

446
DebuggerEngine *DebuggerRunControl::engine()
447
{
448
    QTC_CHECK(d->m_engine);
449
    return d->m_engine;
450 451
}

452 453 454 455
RunConfiguration *DebuggerRunControl::runConfiguration() const
{
    return d->m_myRunConfiguration.data();
}
456

457 458 459 460 461 462 463

////////////////////////////////////////////////////////////////////////
//
// DebuggerRunControlFactory
//
////////////////////////////////////////////////////////////////////////

464 465
DebuggerRunControlFactory::DebuggerRunControlFactory(QObject *parent)
    : IRunControlFactory(parent)
466 467
{}

468
bool DebuggerRunControlFactory::canRun(RunConfiguration *runConfiguration, RunMode mode) const
469
{
470
    return (mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain)
471 472 473 474 475
            && qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
}

QString DebuggerRunControlFactory::displayName() const
{
hjk's avatar
hjk committed
476
    return DebuggerPlugin::tr("Debug");
477 478 479 480 481 482 483 484 485 486
}

static DebuggerStartParameters localStartParameters(RunConfiguration *runConfiguration)
{
    DebuggerStartParameters sp;
    QTC_ASSERT(runConfiguration, return sp);
    LocalApplicationRunConfiguration *rc =
            qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
    QTC_ASSERT(rc, return sp);

hjk's avatar
hjk committed
487
    Target *target = runConfiguration->target();
Tobias Hunger's avatar
Tobias Hunger committed
488 489
    Kit *kit = target ? target->kit() : KitManager::instance()->defaultKit();
    fillParameters(&sp, kit);
490 491
    sp.environment = rc->environment();
    sp.workingDirectory = rc->workingDirectory();
492 493 494

#if defined(Q_OS_WIN)
    // Work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch' ...)
hjk's avatar
hjk committed
495
    sp.workingDirectory = normalizePathName(sp.workingDirectory);
496 497
#endif

498
    sp.executable = rc->executable();
499 500 501
    if (sp.executable.isEmpty())
        return sp;
    sp.startMode = StartInternal;
502 503 504 505 506
    sp.processArgs = rc->commandLineArguments();
    sp.useTerminal = rc->runMode() == LocalApplicationRunConfiguration::Console;
    sp.dumperLibrary = rc->dumperLibrary();
    sp.dumperLibraryLocations = rc->dumperLibraryLocations();

hjk's avatar
hjk committed
507 508
    if (target) {
        if (const Project *project = target->project()) {
509
            sp.projectSourceDirectory = project->projectDirectory();
hjk's avatar
hjk committed
510
            if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration())
511 512
                sp.projectBuildDirectory = buildConfig->buildDirectory();
            sp.projectSourceFiles = project->files(Project::ExcludeGeneratedFiles);
513 514 515
        }
    }

516 517 518 519
    DebuggerRunConfigurationAspect *aspect = runConfiguration->debuggerAspect();
    sp.multiProcess = aspect->useMultiProcess();

    if (aspect->useCppDebugger())
520 521
        sp.languages |= CppLanguage;

522
    if (aspect->useQmlDebugger()) {
523
        sp.qmlServerAddress = _("127.0.0.1");
524
        sp.qmlServerPort = aspect->qmlDebugServerPort();
525
        sp.languages |= QmlLanguage;
526

527 528
        // Makes sure that all bindings go through the JavaScript engine, so that
        // breakpoints are actually hit!
529
        const QString optimizerKey = _("QML_DISABLE_OPTIMIZER");
hjk's avatar
hjk committed
530
        if (!sp.environment.hasKey(optimizerKey))
531
            sp.environment.set(optimizerKey, _("1"));
532

hjk's avatar
hjk committed
533
        QtcProcess::addArg(&sp.processArgs, QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(sp.qmlServerPort));
534 535 536 537 538 539 540 541 542 543 544 545
    }

    // 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
546
    (RunConfiguration *runConfiguration, RunMode mode, QString *errorMessage)
547
{
548
    Q_UNUSED(errorMessage)
549
    QTC_ASSERT(mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain, return 0);
550
    DebuggerStartParameters sp = localStartParameters(runConfiguration);
551 552
    if (sp.startMode == NoStartMode)
        return 0;
553
    if (mode == DebugRunModeWithBreakOnMain)
554
        sp.breakOnMain = true;
hjk's avatar
hjk committed
555

556
    return doCreate(sp, runConfiguration, errorMessage);
557 558
}

hjk's avatar
hjk committed
559
static DebuggerEngineType guessUnixCppEngineType(const DebuggerStartParameters &sp)
560
{
hjk's avatar
hjk committed
561 562 563
    if (sp.debuggerCommand.contains(QLatin1String("lldb")))
        return LldbEngineType;
    return GdbEngineType;
564 565
}

hjk's avatar
hjk committed
566
static DebuggerEngineType guessCppEngineTypeForAbi(const DebuggerStartParameters &sp, const Abi &abi)
567
{
hjk's avatar
hjk committed
568 569 570 571 572 573 574 575 576 577 578 579 580
    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;
}
581

582
static DebuggerEngineType guessCppEngineType(const DebuggerStartParameters &sp)
hjk's avatar
hjk committed
583
{
584 585 586 587
    if (sp.toolChainAbi.isValid()) {
        const  DebuggerEngineType et = guessCppEngineTypeForAbi(sp, sp.toolChainAbi);
        if (et != NoEngineType)
            return et;
hjk's avatar
hjk committed
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
    }

    #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();
627
        if (const Target *target = rc->target())
Tobias Hunger's avatar
Tobias Hunger committed
628
            fillParameters(&sp, target->kit());
629 630
        const bool useCppDebugger = aspect->useCppDebugger();
        const bool useQmlDebugger = aspect->useQmlDebugger();
hjk's avatar
hjk committed
631 632 633
        if (useQmlDebugger) {
            if (useCppDebugger) {
                sp.masterEngineType = QmlCppEngineType;
634
                sp.firstSlaveEngineType = guessCppEngineType(sp);
hjk's avatar
hjk committed
635 636 637 638 639
                sp.secondSlaveEngineType = QmlCppEngineType;
            } else {
                sp.masterEngineType = QmlEngineType;
            }
        } else {
640
            sp.masterEngineType = guessCppEngineType(sp);
hjk's avatar
hjk committed
641 642 643
        }
        return;
    }
644
    sp.masterEngineType = guessCppEngineType(sp);
hjk's avatar
hjk committed
645 646 647
}

DebuggerRunControl *DebuggerRunControlFactory::doCreate
648
    (const DebuggerStartParameters &sp0, RunConfiguration *rc, QString *errorMessage)
hjk's avatar
hjk committed
649
{
650
    Q_UNUSED(errorMessage);
hjk's avatar
hjk committed
651 652 653 654 655 656 657 658 659 660 661 662 663 664
    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"));
        }
665 666
    }

hjk's avatar
hjk committed
667
    fixupEngineTypes(sp, rc);
668
    if (!sp.masterEngineType) {
hjk's avatar
hjk committed
669
        return 0;
670
    }
hjk's avatar
hjk committed
671 672 673 674 675 676 677

    return new DebuggerRunControl(rc, sp);
}

DebuggerRunControl *DebuggerRunControlFactory::createAndScheduleRun
    (const DebuggerStartParameters &sp, RunConfiguration *runConfiguration)
{
678 679 680 681
    QString errorMessage;
    DebuggerRunControl *rc = doCreate(sp, runConfiguration, &errorMessage);
    if (!rc) {
        ProjectExplorer::ProjectExplorerPlugin::showRunErrorMessage(errorMessage);
hjk's avatar
hjk committed
682
        return 0;
683
    }
hjk's avatar
hjk committed
684 685 686 687 688 689 690 691 692
    debuggerCore()->showMessage(sp.startMessage, 0);
    ProjectExplorerPlugin::instance()->startRunControl(rc, DebugRunMode);
    return rc;
}

RunConfigWidget *DebuggerRunControlFactory::createConfigurationWidget
    (RunConfiguration *runConfiguration)
{
    return new DebuggerRunConfigWidget(runConfiguration);
693 694
}

695 696
DebuggerEngine *DebuggerRunControlFactory::createEngine(DebuggerEngineType et,
    const DebuggerStartParameters &sp, QString *errorMessage)
697 698 699
{
    switch (et) {
    case GdbEngineType:
700
        return createGdbEngine(sp);
701 702 703
    case ScriptEngineType:
        return createScriptEngine(sp);
    case CdbEngineType:
704
        return createCdbEngine(sp, errorMessage);
705 706 707
    case PdbEngineType:
        return createPdbEngine(sp);
    case QmlEngineType:
708
        return createQmlEngine(sp);
709 710
    case LldbEngineType:
        return createLldbEngine(sp);
hjk's avatar
hjk committed
711 712
    case QmlCppEngineType:
        return createQmlCppEngine(sp, errorMessage);
713 714
    default:
        break;
715
    }
hjk's avatar
hjk committed
716
    *errorMessage = DebuggerPlugin::tr("Unable to create a debugger engine of the type '%1'").
717
                    arg(_(engineTypeName(et)));
718 719 720
    return 0;
}

hjk's avatar
hjk committed
721
} // namespace Debugger
722 723

#include "debuggerrunner.moc"