debuggerrunner.cpp 25.2 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
con's avatar
con committed
9
** No Commercial Usage
10
**
con's avatar
con committed
11
12
13
14
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
15
**
16
** GNU Lesser General Public License Usage
17
**
18
19
20
21
22
23
** Alternatively, 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.
24
**
con's avatar
con committed
25
26
27
28
29
30
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
con's avatar
con committed
31
**
32
**************************************************************************/
hjk's avatar
hjk committed
33

con's avatar
con committed
34
#include "debuggerrunner.h"
35
#include "debuggerruncontrolfactory.h"
con's avatar
con committed
36

37
#include "debuggeractions.h"
38
#include "debuggercore.h"
39
#include "debuggerengine.h"
40
#include "debuggermainwindow.h"
41
42
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
43
#include "debuggerstartparameters.h"
44
#include "lldb/lldbenginehost.h"
45
#include "debuggertooltipmanager.h"
46
#include "qml/qmlengine.h"
47

Friedemann Kleint's avatar
Friedemann Kleint committed
48
49
50
51
#ifdef Q_OS_WIN
#  include "peutils.h"
#endif

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

62
#include <utils/synchronousprocess.h>
hjk's avatar
hjk committed
63
#include <utils/qtcassert.h>
64
#include <utils/fancymainwindow.h>
65
#include <utils/qtcprocess.h>
66
#include <coreplugin/icore.h>
hjk's avatar
hjk committed
67

con's avatar
con committed
68
#include <QtCore/QDir>
69
#include <QtCore/QDebug>
70
#include <QtGui/QMessageBox>
con's avatar
con committed
71

72
using namespace ProjectExplorer;
73
74
using namespace Debugger::Internal;

75
76
enum { debug = 0 };

77
namespace Debugger {
78
namespace Internal {
79

hjk's avatar
hjk committed
80
bool isCdbEngineEnabled(); // Check the configuration page
81
bool checkCdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check);
hjk's avatar
hjk committed
82
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &sp,
83
    DebuggerEngine *masterEngine, QString *error);
84
85

bool checkGdbConfiguration(const DebuggerStartParameters &sp, ConfigurationCheck *check);
hjk's avatar
hjk committed
86
DebuggerEngine *createGdbEngine(const DebuggerStartParameters &sp,
87
    DebuggerEngine *masterEngine);
88

hjk's avatar
hjk committed
89
90
91
DebuggerEngine *createScriptEngine(const DebuggerStartParameters &sp);
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &sp);
DebuggerEngine *createTcfEngine(const DebuggerStartParameters &sp);
92
QmlEngine *createQmlEngine(const DebuggerStartParameters &sp,
93
    DebuggerEngine *masterEngine);
94
95
96
DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &sp,
                                   DebuggerEngineType slaveEngineType,
                                   QString *errorMessage);
hjk's avatar
hjk committed
97
DebuggerEngine *createLldbEngine(const DebuggerStartParameters &sp);
98

hjk's avatar
hjk committed
99
extern QString msgNoBinaryForToolChain(const Abi &abi);
100

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
static const char *engineTypeName(DebuggerEngineType et)
{
    switch (et) {
    case Debugger::NoEngineType:
        break;
    case Debugger::GdbEngineType:
        return "Gdb";
    case Debugger::ScriptEngineType:
        return "Script engine";
    case Debugger::CdbEngineType:
        return "Cdb engine";
    case Debugger::PdbEngineType:
        return "Pdb engine";    case Debugger::TcfEngineType:
        return "Tcf 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";
}

127
128
129
130
131
132
133
134
135
136
137
static inline QString engineTypeNames(const QList<DebuggerEngineType> &l)
{
    QString rc;
    foreach (DebuggerEngineType et, l) {
        if (!rc.isEmpty())
            rc.append(QLatin1Char(','));
        rc += QLatin1String(engineTypeName(et));
    }
    return rc;
}

138
139
140
static QString msgEngineNotAvailable(const char *engine)
{
    return DebuggerPlugin::tr("The application requires the debugger engine '%1', "
141
        "which is disabled.").arg(_(engine));
142
143
}

144
145
146
147
148
static inline QString msgEngineNotAvailable(DebuggerEngineType et)
{
    return msgEngineNotAvailable(engineTypeName(et));
}

149
150
////////////////////////////////////////////////////////////////////////
//
hjk's avatar
hjk committed
151
// DebuggerRunControlPrivate
152
153
154
//
////////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
155
156
157
class DebuggerRunControlPrivate
{
public:
158
159
    explicit DebuggerRunControlPrivate(DebuggerRunControl *parent,
                                       RunConfiguration *runConfiguration);
160

hjk's avatar
hjk committed
161
162
163
164
165
166
167
    DebuggerEngineType engineForExecutable(unsigned enabledEngineTypes,
        const QString &executable);
    DebuggerEngineType engineForMode(unsigned enabledEngineTypes,
        DebuggerStartMode mode);

public:
    DebuggerRunControl *q;
168
169
170
171
172
    DebuggerEngine *m_engine;
    const QWeakPointer<RunConfiguration> m_myRunConfiguration;
    bool m_running;
};

hjk's avatar
hjk committed
173
DebuggerRunControlPrivate::DebuggerRunControlPrivate(DebuggerRunControl *parent,
174
                                                     RunConfiguration *runConfiguration)
hjk's avatar
hjk committed
175
176
    : q(parent)
    , m_engine(0)
177
    , m_myRunConfiguration(runConfiguration)
178
    , m_running(false)
179
180
{
}
181

hjk's avatar
hjk committed
182
183
} // namespace Internal

hjk's avatar
hjk committed
184
DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
185
186
                                       const DebuggerStartParameters &sp,
                                       const QPair<DebuggerEngineType, DebuggerEngineType> &masterSlaveEngineTypes)
hjk's avatar
hjk committed
187
    : RunControl(runConfiguration, Constants::DEBUGMODE),
188
      d(new DebuggerRunControlPrivate(this, runConfiguration))
189
{
hjk's avatar
hjk committed
190
    connect(this, SIGNAL(finished()), SLOT(handleFinished()));
191
192
193
194
195
196
197
    // 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);
198
199
200
    if (d->m_engine) {
        DebuggerToolTipManager::instance()->registerEngine(d->m_engine);
    } else {
201
        debuggingFinished();
202
        Core::ICore::instance()->showWarningWithOptions(DebuggerRunControl::tr("Debugger"), errorMessage);
203
    }
204
205
}

hjk's avatar
hjk committed
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
DebuggerRunControl::~DebuggerRunControl()
{
    disconnect();
    if (DebuggerEngine *engine = d->m_engine) {
        d->m_engine = 0;
        engine->disconnect();
        delete engine;
    }
}

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

222
QString DebuggerRunControl::displayName() const
223
{
224
225
    QTC_ASSERT(d->m_engine, return QString());
    return d->m_engine->startParameters().displayName;
226
227
}

228
void DebuggerRunControl::setCustomEnvironment(Utils::Environment env)
229
{
230
    QTC_ASSERT(d->m_engine, return);
231
    d->m_engine->startParameters().environment = env;
232
233
}

234
void DebuggerRunControl::start()
235
{
236
    QTC_ASSERT(d->m_engine, return);
237
    debuggerCore()->runControlStarted(d->m_engine);
238

239
240
    // We might get a synchronous startFailed() notification on Windows,
    // when launching the process fails. Emit a proper finished() sequence.
241
    emit started();
242
243
    d->m_running = true;

244
    d->m_engine->startDebugger(this);
245

246
    if (d->m_running)
247
        appendMessage(tr("Debugging starts"), NormalMessageFormat);
248
249
}

250
void DebuggerRunControl::startFailed()
251
{
252
    appendMessage(tr("Debugging has failed"), NormalMessageFormat);
253
    d->m_running = false;
254
    emit finished();
255
    d->m_engine->handleStartFailed();
256
257
}

258
void DebuggerRunControl::handleFinished()
259
{
260
    appendMessage(tr("Debugging has finished"), NormalMessageFormat);
261
262
263
    if (d->m_engine)
        d->m_engine->handleFinished();
    debuggerCore()->runControlFinished(d->m_engine);
264
265
}

266
void DebuggerRunControl::showMessage(const QString &msg, int channel)
267
{
268
269
    switch (channel) {
        case AppOutput:
270
            appendMessage(msg, StdOutFormatSameLine);
271
272
            break;
        case AppError:
273
            appendMessage(msg, StdErrFormatSameLine);
274
275
            break;
        case AppStuff:
276
            appendMessage(msg, NormalMessageFormat);
277
278
            break;
    }
279
280
}

281
bool DebuggerRunControl::promptToStop(bool *optionalPrompt) const
282
{
283
284
    QTC_ASSERT(isRunning(), return true;)

285
286
287
    if (optionalPrompt && !*optionalPrompt)
        return true;

Jarek Kobus's avatar
Jarek Kobus committed
288
    const QString question = tr("A debugging session is still in progress. "
289
290
291
            "Terminating the session in the current"
            " state can leave the target in an inconsistent state."
            " Would you still like to terminate it?");
292
293
    return showPromptToStopDialog(tr("Close Debugging Session"), question,
                                  QString(), QString(), optionalPrompt);
294
295
296
297
}

RunControl::StopResult DebuggerRunControl::stop()
{
298
299
    QTC_ASSERT(d->m_engine, return StoppedSynchronously);
    d->m_engine->quitDebugger();
300
    return AsynchronousStop;
301
302
}

303
void DebuggerRunControl::debuggingFinished()
304
{
305
    d->m_running = false;
306
    emit finished();
307
308
}

309
bool DebuggerRunControl::isRunning() const
310
{
311
    return d->m_running;
312
313
}

314
DebuggerEngine *DebuggerRunControl::engine()
315
{
316
317
    QTC_ASSERT(d->m_engine, /**/);
    return d->m_engine;
318
319
}

320
321
322
323
RunConfiguration *DebuggerRunControl::runConfiguration() const
{
    return d->m_myRunConfiguration.data();
}
324

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
////////////////////////////////////////////////////////////////////////
//
// Engine detection logic: Detection functions depending on toolchain, binary,
// etc. Return a list of possible engines (order of prefererence) without
// consideration of configuration, etc.
//
////////////////////////////////////////////////////////////////////////

static QList<DebuggerEngineType> enginesForToolChain(const Abi &toolChain)
{
    QList<DebuggerEngineType> result;
    switch (toolChain.binaryFormat()) {
    case Abi::ElfFormat:
    case Abi::MachOFormat:
        result.push_back(LldbEngineType);
        result.push_back(GdbEngineType);
        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);
        }
        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,
                                                bool hardConstraintsOnly)
{
    QList<DebuggerEngineType> result;
    switch (startMode) {
    case Debugger::NoStartMode:
        break;
    case Debugger::StartInternal:
    case Debugger::StartExternal:
    case AttachExternal:
        if (!hardConstraintsOnly) {
#ifdef Q_OS_WIN
            result.push_back(CdbEngineType); // Preferably Windows debugger for attaching locally.
#endif
            result.push_back(GdbEngineType);
        }
        break;
    case Debugger::AttachCore:
    case Debugger::StartRemoteGdb:
        result.push_back(GdbEngineType);
        break;
    case Debugger::AttachToRemote:
        if (!hardConstraintsOnly) {
#ifdef Q_OS_WIN
            result.push_back(CdbEngineType);
#endif
            result.push_back(GdbEngineType);
        }
        break;
    case AttachTcf:
        result.push_back(TcfEngineType);
        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;

    result = enginesForMode(sp.startMode, true);
    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()) {
        result = enginesForToolChain(sp.toolChainAbi);
        if (!result.isEmpty())
            return result;
    }

    // FIXME: 1 of 3 testing hacks.
    if (sp.processArgs.startsWith(__("@tcf@ "))) {
        result.push_back(GdbEngineType);
        return result;
    }

    if (sp.startMode != AttachToRemote && !sp.executable.isEmpty())
        result = enginesForExecutable(sp.executable);
    if (!result.isEmpty())
        return result;

    result = enginesForMode(sp.startMode, false);
    return result;
}

// Engine detection logic: ConfigurationCheck.
ConfigurationCheck::ConfigurationCheck() :
    masterSlaveEngineTypes(NoEngineType, NoEngineType)
{
}

ConfigurationCheck::operator bool() const
{
490
491
492
493
494
495
    return errorMessage.isEmpty() &&  errorDetails.isEmpty() && masterSlaveEngineTypes.first != NoEngineType;
}

QString ConfigurationCheck::errorDetailsString() const
{
    return errorDetails.join(QLatin1String("\n\n"));
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
}

/*!
    \fn ConfigurationCheck checkDebugConfiguration(unsigned cmdLineEnabledEngines,
                                                   const DebuggerStartParameters &sp)

    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;
    const unsigned activeLangs = debuggerCore()->activeLanguages();
    const bool qmlLanguage = activeLangs & QmlLanguage;
    const bool cppLanguage = activeLangs & CppLanguage;
513
514
515
516
    if (debug)
        qDebug().nospace() << "checkDebugConfiguration " << sp.toolChainAbi.toString()
                           << " Start mode=" << sp.startMode << " Executable=" << sp.executable
                           << " Debugger command=" << sp.debuggerCommand;
517
518
519
520
521
522
523
524
    // Get all applicable types.
    QList<DebuggerEngineType> requiredTypes;
    if (qmlLanguage && !cppLanguage) {
        requiredTypes.push_back(QmlEngineType);
    } else {
        requiredTypes = engineTypes(sp);
    }
    if (requiredTypes.isEmpty()) {
Friedemann Kleint's avatar
Friedemann Kleint committed
525
        result.errorMessage = QLatin1String("Internal error: Unable to determine debugger engine type for this configuration");
526
527
        return result;
    }
528
529
    if (debug)
        qDebug() << " Required: " << engineTypeNames(requiredTypes);
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
    // Filter out disables types, command line + current settings.
    unsigned cmdLineEnabledEngines = debuggerCore()->enabledEngines();
#ifdef CDB_ENABLED
     if (!isCdbEngineEnabled() && !Cdb::isCdbEngineEnabled())
         cmdLineEnabledEngines &= ~CdbEngineType;
#endif
#ifdef WITH_LLDB
    if (!Core::ICore::instance()->settings()->value(QLatin1String("LLDB/enabled")).toBool())
        cmdLineEnabledEngines &= ~LldbEngineType;
#else
     cmdLineEnabledEngines &= ~LldbEngineType;
#endif
    QList<DebuggerEngineType> usableTypes;
    foreach (DebuggerEngineType et, requiredTypes)
        if (et & cmdLineEnabledEngines)
            usableTypes.push_back(et);
    if (usableTypes.isEmpty()) {
        result.errorMessage = DebuggerPlugin::tr("This configuration requires the debugger engine %1, which is disabled.").
                arg(QLatin1String(engineTypeName(usableTypes.front())));
        return result;
    }
551
552
    if (debug)
        qDebug() << " Usable engines: " << engineTypeNames(usableTypes);
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
    // Configuration check: Strip off non-configured engines, find first one to use.
    while (!usableTypes.isEmpty()) {
        bool configurationOk = true;
        switch (usableTypes.front()) {
        case Debugger::CdbEngineType:
            configurationOk = checkCdbConfiguration(sp, &result);
            break;
        case Debugger::GdbEngineType:
            configurationOk = checkGdbConfiguration(sp, &result);
            break;
        default:
            break;
        }
        if (configurationOk) {
            break;
        } else {
            usableTypes.pop_front();
        }
    }
572
573
    if (debug)
        qDebug() << "Configured engines: " << engineTypeNames(usableTypes);
574
    if (usableTypes.isEmpty()) {
575
        result.errorMessage = DebuggerPlugin::tr("The debugger engine required for this configuration is not correctly configured.");
576
577
578
        return result;
    }
    // Anything left: Happy.
579
580
    result.errorMessage.clear();
    result.errorDetails.clear();
581
582
583
584
585
586
    if (qmlLanguage && cppLanguage) {
        result.masterSlaveEngineTypes.first = QmlCppEngineType;
        result.masterSlaveEngineTypes.second = usableTypes.front();
    } else {
        result.masterSlaveEngineTypes.first = usableTypes.front();
    }
587
588
    if (debug)
        qDebug() << engineTypeName(result.masterSlaveEngineTypes.first) << engineTypeName(result.masterSlaveEngineTypes.second);
589
590
    return result;
}
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612

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

// A factory to create DebuggerRunControls
DebuggerRunControlFactory::DebuggerRunControlFactory(QObject *parent,
        unsigned enabledEngines)
    : IRunControlFactory(parent), m_enabledEngines(enabledEngines)
{}

bool DebuggerRunControlFactory::canRun(RunConfiguration *runConfiguration, const QString &mode) const
{
//    return mode == ProjectExplorer::Constants::DEBUGMODE;
    return mode == Constants::DEBUGMODE
            && qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
}

QString DebuggerRunControlFactory::displayName() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
613
    return DebuggerRunControl::tr("Debug");
614
615
616
617
618
619
620
}

// Find Qt installation by running qmake
static inline QString findQtInstallPath(const QString &qmakePath)
{
    QProcess proc;
    QStringList args;
621
622
    args.append(_("-query"));
    args.append(_("QT_INSTALL_HEADERS"));
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
    proc.start(qmakePath, args);
    if (!proc.waitForStarted()) {
        qWarning("%s: Cannot start '%s': %s", Q_FUNC_INFO, qPrintable(qmakePath),
           qPrintable(proc.errorString()));
        return QString();
    }
    proc.closeWriteChannel();
    if (!proc.waitForFinished()) {
        Utils::SynchronousProcess::stopProcess(proc);
        qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(qmakePath));
        return QString();
    }
    if (proc.exitStatus() != QProcess::NormalExit) {
        qWarning("%s: '%s' crashed.", Q_FUNC_INFO, qPrintable(qmakePath));
        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.startMode = StartInternal;
    sp.environment = rc->environment();
    sp.workingDirectory = rc->workingDirectory();
    sp.executable = rc->executable();
    sp.processArgs = rc->commandLineArguments();
659
    sp.toolChainAbi = rc->abi();
660
661
662
663
    sp.useTerminal = rc->runMode() == LocalApplicationRunConfiguration::Console;
    sp.dumperLibrary = rc->dumperLibrary();
    sp.dumperLibraryLocations = rc->dumperLibraryLocations();

664
665
666
667
668
669
670
671
672
673
674
    if (const ProjectExplorer::Target *target = runConfiguration->target()) {
        if (const ProjectExplorer::Project *project = target->project()) {
              sp.projectDir = project->projectDirectory();
              if (const ProjectExplorer::BuildConfiguration *buildConfig = target->activeBuildConfiguration()) {
                  sp.projectBuildDir = buildConfig->buildDirectory();
                  if (const ProjectExplorer::ToolChain *tc = buildConfig->toolChain())
                    sp.debuggerCommand = tc->debuggerCommand();
              }
        }
    }

675
    if (debuggerCore()->isActiveDebugLanguage(QmlLanguage)) {
676
        sp.qmlServerAddress = _("127.0.0.1");
677
678
        sp.qmlServerPort = runConfiguration->qmlDebugServerPort();

679
680
        // Makes sure that all bindings go through the JavaScript engine, so that
        // breakpoints are actually hit!
681
682
683
        const QString optimizerKey = _("QML_DISABLE_OPTIMIZER");
        if (!sp.environment.hasKey(optimizerKey)) {
            sp.environment.set(optimizerKey, _("1"));
684
685
        }

686
        Utils::QtcProcess::addArg(&sp.processArgs, _("-qmljsdebugger=port:")
687
                                  + QString::number(sp.qmlServerPort));
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
    }

    // 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, const QString &mode)
{
    QTC_ASSERT(mode == Constants::DEBUGMODE, return 0);
    DebuggerStartParameters sp = localStartParameters(runConfiguration);
    return create(sp, runConfiguration);
}

707
RunConfigWidget *DebuggerRunControlFactory::createConfigurationWidget
708
709
710
711
712
713
714
715
    (RunConfiguration *runConfiguration)
{
    // NBS TODO: Add GDB-specific configuration widget
    Q_UNUSED(runConfiguration)
    return 0;
}

DebuggerRunControl *DebuggerRunControlFactory::create
716
    (const DebuggerStartParameters &sp, RunConfiguration *runConfiguration)
717
{
718
    const ConfigurationCheck check = checkDebugConfiguration(sp);
719

720
    if (!check) {
721
        //appendMessage(errorMessage, true);
Friedemann Kleint's avatar
Friedemann Kleint committed
722
        Core::ICore::instance()->showWarningWithOptions(DebuggerRunControl::tr("Debugger"),
723
            check.errorMessage, check.errorDetailsString(), check.settingsCategory, check.settingsPage);
724
725
726
        return 0;
    }

727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
    return new DebuggerRunControl(runConfiguration, sp, check.masterSlaveEngineTypes);
}

DebuggerEngine *
    DebuggerRunControlFactory::createEngine(DebuggerEngineType et,
                                            const DebuggerStartParameters &sp,
                                            DebuggerEngine *masterEngine,
                                            QString *errorMessage)
{
    switch (et) {
    case GdbEngineType:
        return createGdbEngine(sp, masterEngine);
    case ScriptEngineType:
        return createScriptEngine(sp);
    case CdbEngineType:
        return createCdbEngine(sp, masterEngine, errorMessage);
        break;
    case PdbEngineType:
        return createPdbEngine(sp);
        break;
    case TcfEngineType:
        return createTcfEngine(sp);
        break;
    case QmlEngineType:
        return createQmlEngine(sp, masterEngine);
        break;
    case LldbEngineType:
        return createLldbEngine(sp);
    default:
        break;
    }
    *errorMessage = DebuggerRunControl::tr("Unable to create a debugger engine of the type '%1'").
                    arg(_(engineTypeName(et)));
760
761
762
    return 0;
}

763

hjk's avatar
hjk committed
764
} // namespace Debugger