debuggerrunner.cpp 23.1 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 "debuggerprofileinformation.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
488
    Target *target = runConfiguration->target();
    Profile *profile = target ? target->profile() : ProfileManager::instance()->defaultProfile();
489
    fillParameters(&sp, profile);
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)
547
{
548
    QTC_ASSERT(mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain, return 0);
549
    DebuggerStartParameters sp = localStartParameters(runConfiguration);
550
551
    if (sp.startMode == NoStartMode)
        return 0;
552
    if (mode == DebugRunModeWithBreakOnMain)
553
        sp.breakOnMain = true;
hjk's avatar
hjk committed
554
555

    return doCreate(sp, runConfiguration);
556
557
}

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

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

hjk's avatar
hjk committed
581
582
583
584
585
586
587
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
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
static DebuggerEngineType guessCppEngineType(const DebuggerStartParameters &sp, RunConfiguration *rc)
{
    if (rc) {
        if (Target *target = rc->target()) {
            Profile *profile = target->profile();
            if (ToolChain *tc = ToolChainProfileInformation::toolChain(profile)) {
                DebuggerEngineType et = guessCppEngineTypeForAbi(sp, tc->targetAbi());
                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();
        bool useCppDebugger = aspect->useCppDebugger();
        bool useQmlDebugger = aspect->useQmlDebugger();
        if (useQmlDebugger) {
            if (useCppDebugger) {
                sp.masterEngineType = QmlCppEngineType;
                sp.firstSlaveEngineType = guessCppEngineType(sp, rc);
                sp.secondSlaveEngineType = QmlCppEngineType;
            } else {
                sp.masterEngineType = QmlEngineType;
            }
        } else {
            sp.masterEngineType = guessCppEngineType(sp, rc);
        }
        return;
    }

    sp.masterEngineType = guessCppEngineType(sp, rc);
}

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"));
        }
667
668
    }

hjk's avatar
hjk committed
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
    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);
691
692
}

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

hjk's avatar
hjk committed
719
} // namespace Debugger
720
721

#include "debuggerrunner.moc"