debuggerrunner.cpp 24.3 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) 2010 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
**
9
** Commercial Usage
10
**
11 12 13 14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
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
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30 31
#include "debuggerrunner.h"

32 33 34 35 36
#include "debuggeractions.h"
#include "debuggerconstants.h"
#include "debuggerengine.h"
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
37
#include "debuggeruiswitcher.h"
38 39 40
#include "gdb/gdbengine.h"
#include "gdb/remotegdbserveradapter.h"
#include "gdb/remoteplaingdbadapter.h"
41
#include "qml/qmlengine.h"
42
#include "qml/qmlcppengine.h"
43

Friedemann Kleint's avatar
Friedemann Kleint committed
44 45 46 47
#ifdef Q_OS_WIN
#  include "peutils.h"
#endif

hjk's avatar
hjk committed
48
#include <projectexplorer/debugginghelper.h>
con's avatar
con committed
49
#include <projectexplorer/project.h>
50
#include <projectexplorer/projectexplorer.h>
con's avatar
con committed
51
#include <projectexplorer/projectexplorerconstants.h>
Tobias Hunger's avatar
Tobias Hunger committed
52
#include <projectexplorer/target.h>
53
#include <projectexplorer/buildconfiguration.h>
54
#include <projectexplorer/applicationrunconfiguration.h> // For LocalApplication*
con's avatar
con committed
55

56
#include <utils/environment.h>
57
#include <utils/synchronousprocess.h>
hjk's avatar
hjk committed
58
#include <utils/qtcassert.h>
59
#include <utils/fancymainwindow.h>
60
#include <coreplugin/icore.h>
hjk's avatar
hjk committed
61

con's avatar
con committed
62 63 64
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
65
#include <QtCore/QTimer>
Friedemann Kleint's avatar
Friedemann Kleint committed
66
#include <QtCore/QStringList>
hjk's avatar
hjk committed
67

68
#include <QtGui/QAbstractItemView>
69
#include <QtGui/QTextDocument>
70
#include <QtGui/QTreeWidget>
71
#include <QtGui/QMessageBox>
con's avatar
con committed
72

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

76 77 78 79 80 81 82 83
namespace Debugger {
namespace Internal {

DebuggerEngine *createGdbEngine(const DebuggerStartParameters &);
DebuggerEngine *createScriptEngine(const DebuggerStartParameters &);
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &);
DebuggerEngine *createTcfEngine(const DebuggerStartParameters &);
DebuggerEngine *createQmlEngine(const DebuggerStartParameters &);
84
DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &);
85

hjk's avatar
hjk committed
86
bool checkGdbConfiguration(int toolChain, QString *errorMsg, QString *settingsPage);
87 88 89 90 91 92 93

// FIXME: Outdated?
// The createCdbEngine function takes a list of options pages it can add to.
// This allows for having a "enabled" toggle on the page independently
// of the engine. That's good for not enabling the related ActiveX control
// unnecessarily.

hjk's avatar
hjk committed
94 95
#ifdef CDB_ENABLED
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &);
96
bool checkCdbConfiguration(int toolChain, QString *errorMsg, QString *settingsPage);
hjk's avatar
hjk committed
97 98 99 100
#else
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &) { return 0; }
bool checkCdbConfiguration(int, QString *, QString *) { return false; }
#endif
101

hjk's avatar
hjk committed
102
} // namespace Internal
103 104 105 106 107 108

static QString toolChainName(int toolChainType)
{
    return ToolChain::toolChainName(ToolChain::ToolChainType(toolChainType));
}

109

con's avatar
con committed
110 111
////////////////////////////////////////////////////////////////////////
//
112
// DebuggerRunControlFactory
con's avatar
con committed
113 114 115
//
////////////////////////////////////////////////////////////////////////

116 117 118 119 120 121 122
static QString msgEngineNotAvailable(const char *engine)
{
    return DebuggerPlugin::tr("The application requires the debugger engine '%1', "
        "which is disabled.").arg(QLatin1String(engine));
}

static DebuggerPlugin *plugin() { return DebuggerPlugin::instance(); }
123

124
// A factory to create DebuggerRunControls
125 126 127
DebuggerRunControlFactory::DebuggerRunControlFactory(QObject *parent,
        DebuggerEngineType enabledEngines)
    : IRunControlFactory(parent), m_enabledEngines(enabledEngines)
con's avatar
con committed
128 129
{}

130
bool DebuggerRunControlFactory::canRun(RunConfiguration *runConfiguration, const QString &mode) const
con's avatar
con committed
131
{
132
//    return mode == ProjectExplorer::Constants::DEBUGMODE;
133
    return mode == ProjectExplorer::Constants::DEBUGMODE
134
            && qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
con's avatar
con committed
135 136
}

137
QString DebuggerRunControlFactory::displayName() const
con's avatar
con committed
138
{
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
139
    return tr("Debug");
con's avatar
con committed
140 141
}

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
// Find Qt installation by running qmake
static inline QString findQtInstallPath(const QString &qmakePath)
{
    QProcess proc;
    QStringList args;
    args.append(QLatin1String("-query"));
    args.append(QLatin1String("QT_INSTALL_HEADERS"));
    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();
}

172
static DebuggerStartParameters localStartParameters(RunConfiguration *runConfiguration)
173
{
174
    DebuggerStartParameters sp;
175 176 177 178 179
    QTC_ASSERT(runConfiguration, return sp);
    LocalApplicationRunConfiguration *rc =
            qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
    QTC_ASSERT(rc, return sp);

180 181
    sp.startMode = StartInternal;
    sp.environment = rc->environment().toStringList();
182 183 184
    sp.workingDirectory = rc->workingDirectory();
    sp.executable = rc->executable();
    sp.processArgs = rc->commandLineArguments();
185 186 187 188
    sp.toolChainType = rc->toolChainType();
    sp.useTerminal = rc->runMode() == LocalApplicationRunConfiguration::Console;
    sp.dumperLibrary = rc->dumperLibrary();
    sp.dumperLibraryLocations = rc->dumperLibraryLocations();
189

190 191
    DebuggerLanguages activeLangs = DebuggerUISwitcher::instance()->activeDebugLanguages();
    if (activeLangs & QmlLanguage) {
192
        sp.qmlServerAddress = QLatin1String("127.0.0.1");
193
        sp.qmlServerPort = runConfiguration->qmlDebugServerPort();
194

195 196 197 198
        sp.projectDir = runConfiguration->target()->project()->projectDirectory();
        if (runConfiguration->target()->activeBuildConfiguration())
            sp.projectBuildDir = runConfiguration->target()->activeBuildConfiguration()->buildDirectory();

199
        sp.processArgs.append(QLatin1String("-qmljsdebugger=port:") + QString::number(sp.qmlServerPort));
200 201
    }

202 203 204 205
    // 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;
206
    sp.displayName = rc->displayName();
207

208 209
    // Find qtInstallPath.
    QString qmakePath = DebuggingHelperLibrary::findSystemQt(rc->environment());
210 211
    if (!qmakePath.isEmpty())
        sp.qtInstallPath = findQtInstallPath(qmakePath);
212
    return sp;
213 214
}

215 216
RunControl *DebuggerRunControlFactory::create
    (RunConfiguration *runConfiguration, const QString &mode)
con's avatar
con committed
217
{
hjk's avatar
hjk committed
218
    QTC_ASSERT(mode == ProjectExplorer::Constants::DEBUGMODE, return 0);
219
    DebuggerStartParameters sp = localStartParameters(runConfiguration);
220
    return create(sp, runConfiguration);
221 222
}

223 224
DebuggerRunControl *DebuggerRunControlFactory::create(
    const DebuggerStartParameters &sp,
225
    RunConfiguration *runConfiguration)
226
{
227 228
    DebuggerRunControl *runControl =
        new DebuggerRunControl(runConfiguration, m_enabledEngines, sp);
229 230 231 232 233 234
    if (!runControl->engine()) {
        qDebug() << "FAILED TO CREATE ENGINE";
        delete runControl;
        return 0;
    }
    return runControl;
con's avatar
con committed
235 236
}

237 238
QWidget *DebuggerRunControlFactory::createConfigurationWidget
    (RunConfiguration *runConfiguration)
con's avatar
con committed
239 240
{
    // NBS TODO: Add GDB-specific configuration widget
241
    Q_UNUSED(runConfiguration)
con's avatar
con committed
242 243 244 245
    return 0;
}


246 247
////////////////////////////////////////////////////////////////////////
//
248
// DebuggerRunControl
249 250 251
//
////////////////////////////////////////////////////////////////////////

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
struct DebuggerRunnerPrivate {
    explicit DebuggerRunnerPrivate(RunConfiguration *runConfiguration,
                                   DebuggerEngineType enabledEngines);

    DebuggerEngine *m_engine;
    const QWeakPointer<RunConfiguration> m_myRunConfiguration;
    bool m_running;
    const DebuggerEngineType m_enabledEngines;
    QString m_errorMessage;
    QString m_settingsIdHint;
};

DebuggerRunnerPrivate::DebuggerRunnerPrivate(RunConfiguration *runConfiguration,
                                             DebuggerEngineType enabledEngines) :
      m_myRunConfiguration(runConfiguration)
267
    , m_running(false)
268
    , m_enabledEngines(enabledEngines)
269 270
{
}
271

272 273 274 275
DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
        DebuggerEngineType enabledEngines, const DebuggerStartParameters &sp)
    : RunControl(runConfiguration, ProjectExplorer::Constants::DEBUGMODE),
      d(new DebuggerRunnerPrivate(runConfiguration, enabledEngines))
276
{
Friedemann Kleint's avatar
Friedemann Kleint committed
277
    connect(this, SIGNAL(finished()), this, SLOT(handleFinished()));
278 279
    DebuggerStartParameters startParams = sp;
    createEngine(startParams);
280 281
}

282 283 284
DebuggerRunControl::~DebuggerRunControl()
{
    disconnect();
285 286
    DebuggerEngine *engine = d->m_engine;
    d->m_engine = 0;
287 288 289 290
    engine->disconnect();
    delete engine;
}

291 292
const DebuggerStartParameters &DebuggerRunControl::startParameters() const
{
293 294
    QTC_ASSERT(d->m_engine, return *(new DebuggerStartParameters()));
    return d->m_engine->startParameters();
295 296
}

297 298 299 300 301 302 303 304 305 306 307 308
static DebuggerEngineType engineForToolChain(int toolChainType)
{
    switch (toolChainType) {
        case ProjectExplorer::ToolChain::LINUX_ICC:
        case ProjectExplorer::ToolChain::MinGW:
        case ProjectExplorer::ToolChain::GCC:
        case ProjectExplorer::ToolChain::WINSCW: // S60
        case ProjectExplorer::ToolChain::GCCE:
        case ProjectExplorer::ToolChain::RVCT_ARMV5:
        case ProjectExplorer::ToolChain::RVCT_ARMV6:
        case ProjectExplorer::ToolChain::RVCT_ARMV5_GNUPOC:
        case ProjectExplorer::ToolChain::GCCE_GNUPOC:
309
        case ProjectExplorer::ToolChain::GCC_MAEMO:
310 311 312 313 314 315 316 317 318 319 320 321 322
            return GdbEngineType;

        case ProjectExplorer::ToolChain::MSVC:
        case ProjectExplorer::ToolChain::WINCE:
            return CdbEngineType;

        case ProjectExplorer::ToolChain::OTHER:
        case ProjectExplorer::ToolChain::UNKNOWN:
        case ProjectExplorer::ToolChain::INVALID:
        default:
            break;
    }
    return NoEngineType;
323 324
}

325 326 327 328

// Figure out the debugger type of an executable. Analyze executable
// unless the toolchain provides a hint.
DebuggerEngineType DebuggerRunControl::engineForExecutable(const QString &executable)
329
{
330
    /*if (executable.endsWith(_("qmlviewer"))) {
331
        if (d->m_enabledEngines & QmlEngineType)
332
            return QmlEngineType;
333
        d->m_errorMessage = msgEngineNotAvailable("Qml Engine");
334
    }*/
335

336
    if (executable.endsWith(_(".js"))) {
337
        if (d->m_enabledEngines & ScriptEngineType)
338
            return ScriptEngineType;
339
        d->m_errorMessage = msgEngineNotAvailable("Script Engine");
340
    }
con's avatar
con committed
341

342
    if (executable.endsWith(_(".py"))) {
343
        if (d->m_enabledEngines & PdbEngineType)
344
            return PdbEngineType;
345
        d->m_errorMessage = msgEngineNotAvailable("Pdb Engine");
346
    }
con's avatar
con committed
347

348 349 350
#ifdef Q_OS_WIN
    // A remote executable?
    if (!executable.endsWith(_(".exe")))
Friedemann Kleint's avatar
Friedemann Kleint committed
351
        return GdbEngineType;
352 353 354

    // If a file has PDB files, it has been compiled by VS.
    QStringList pdbFiles;
355
    if (!getPDBFiles(executable, &pdbFiles, &d->m_errorMessage)) {
356
        qWarning("Cannot determine type of executable %s: %s",
357
                 qPrintable(executable), qPrintable(d->m_errorMessage));
Friedemann Kleint's avatar
Friedemann Kleint committed
358
        return NoEngineType;
359 360 361
    }
    if (pdbFiles.empty())
        return GdbEngineType;
362

363 364
    // We need the CDB debugger in order to be able to debug VS
    // executables
365
    if (checkDebugConfiguration(ToolChain::MSVC, &d->m_errorMessage, 0, &d->m_settingsIdHint))
366 367
        return CdbEngineType;
#else
368
    if (d->m_enabledEngines & GdbEngineType)
369
        return GdbEngineType;
370
    d->m_errorMessage = msgEngineNotAvailable("Gdb Engine");
371
#endif
372

373
    return NoEngineType;
374 375
}

376 377
// Debugger type for mode.
DebuggerEngineType DebuggerRunControl::engineForMode(DebuggerStartMode startMode)
378
{
379 380
    if (startMode == AttachTcf)
        return TcfEngineType;
381

382 383
#ifdef Q_OS_WIN
    // Preferably Windows debugger for attaching locally.
Friedemann Kleint's avatar
Friedemann Kleint committed
384
    if (startMode != AttachToRemote)
385
        return CdbEngineType;
Friedemann Kleint's avatar
Friedemann Kleint committed
386
    return GdbEngineType;
387
    d->m_errorMessage = msgEngineNotAvailable("Gdb Engine");
388 389 390
    return NoEngineType;
#else
    Q_UNUSED(startMode)
391
    //  d->m_errorMessage = msgEngineNotAvailable("Gdb Engine");
392 393
    return GdbEngineType;
#endif
394 395
}

396
void DebuggerRunControl::createEngine(const DebuggerStartParameters &startParams)
397
{
398 399
    DebuggerStartParameters sp = startParams;

400 401
    // Figure out engine according to toolchain, executable, attach or default.
    DebuggerEngineType engineType = NoEngineType;
402
    DebuggerLanguages activeLangs = DebuggerPlugin::instance()->activeLanguages();
403
    if (sp.executable.endsWith(_(".js")))
404 405 406 407 408 409
        engineType = ScriptEngineType;
    else if (sp.executable.endsWith(_(".py")))
        engineType = PdbEngineType;
    else
        engineType = engineForToolChain(sp.toolChainType);

410 411 412 413
    // Fixme: 1 of 3 testing hacks.
    if (sp.processArgs.size() >= 5 && sp.processArgs.at(0) == _("@tcf@"))
        engineType = GdbEngineType;

414 415 416 417 418 419 420 421
    if (engineType == NoEngineType
            && sp.startMode != AttachToRemote
            && !sp.executable.isEmpty())
        engineType = engineForExecutable(sp.executable);

    if (!engineType)
        engineType = engineForMode(sp.startMode);

422
    if (engineType != QmlEngineType && (activeLangs & QmlLanguage)) {
423
        if (activeLangs & CppLanguage) {
424 425 426 427 428 429 430
            sp.cppEngineType = engineType;
            engineType = QmlCppEngineType;
        } else {
            engineType = QmlEngineType;
        }
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
431
    // qDebug() << "USING ENGINE : " << engineType;
432 433 434

    switch (engineType) {
        case GdbEngineType:
435 436
            d->m_engine = createGdbEngine(sp);
            initGdbEngine(qobject_cast<Internal::GdbEngine *>(d->m_engine));
437
            break;
438
        case ScriptEngineType:
439
            d->m_engine = Internal::createScriptEngine(sp);
440
            break;
441
        case CdbEngineType:
442
            d->m_engine = Internal::createCdbEngine(sp);
443
            break;
444
        case PdbEngineType:
445
            d->m_engine = Internal::createPdbEngine(sp);
446
            break;
447
        case TcfEngineType:
448
            d->m_engine = Internal::createTcfEngine(sp);
449
            break;
450
        case QmlEngineType:
451
            d->m_engine = Internal::createQmlEngine(sp);
452 453 454
            connect(qobject_cast<QmlEngine *>(d->m_engine),
                SIGNAL(remoteStartupRequested()), this,
                SIGNAL(engineRequestSetup()));
455
            break;
456
        case QmlCppEngineType:
457
            d->m_engine = Internal::createQmlCppEngine(sp);
458 459
            if (Internal::GdbEngine *embeddedGdbEngine = gdbEngine())
                initGdbEngine(embeddedGdbEngine);
460
            break;
461 462
        default: {
            // Could not find anything suitable.
463
            debuggingFinished();
464 465
            // Create Message box with possibility to go to settings
            const QString msg = tr("Cannot debug '%1' (tool chain: '%2'): %3")
466
                .arg(sp.executable, toolChainName(sp.toolChainType), d->m_errorMessage);
467 468
            Core::ICore::instance()->showWarningWithOptions(tr("Warning"),
                msg, QString(), QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY),
469
                d->m_settingsIdHint);
470
            break;
471
        }
472
    }
473 474
}

475 476 477 478 479 480 481 482
void DebuggerRunControl::initGdbEngine(Internal::GdbEngine *engine)
{
    QTC_ASSERT(engine, return)

    // Forward adapter signals.
    Internal::AbstractGdbAdapter *adapter = engine->gdbAdapter();
    if (RemotePlainGdbAdapter *rpga = qobject_cast<RemotePlainGdbAdapter *>(adapter)) {
        connect(rpga, SIGNAL(requestSetup()), this,
483
                SIGNAL(engineRequestSetup()));
484 485
    } else if (RemoteGdbServerAdapter *rgsa = qobject_cast<RemoteGdbServerAdapter *>(adapter)) {
        connect(rgsa, SIGNAL(requestSetup()),
486
                this, SIGNAL(engineRequestSetup()));
487 488 489
    }
}

490
QString DebuggerRunControl::displayName() const
491
{
492 493
    QTC_ASSERT(d->m_engine, return QString());
    return d->m_engine->startParameters().displayName;
494 495
}

496
void DebuggerRunControl::setCustomEnvironment(Utils::Environment env)
497
{
498
    d->m_engine->startParameters().environment = env.toStringList();
499 500
}

501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
bool DebuggerRunControl::checkDebugConfiguration(int toolChain,
                                              QString *errorMessage,
                                              QString *settingsCategory /* = 0 */,
                                              QString *settingsPage /* = 0 */)
{
    errorMessage->clear();
    if (settingsCategory)
        settingsCategory->clear();
    if (settingsPage)
        settingsPage->clear();

    bool success = true;

    switch(toolChain) {
    case ProjectExplorer::ToolChain::GCC:
    case ProjectExplorer::ToolChain::LINUX_ICC:
    case ProjectExplorer::ToolChain::MinGW:
    case ProjectExplorer::ToolChain::WINCE: // S60
    case ProjectExplorer::ToolChain::WINSCW:
    case ProjectExplorer::ToolChain::GCCE:
    case ProjectExplorer::ToolChain::RVCT_ARMV5:
    case ProjectExplorer::ToolChain::RVCT_ARMV6:
        success = checkGdbConfiguration(toolChain, errorMessage, settingsPage);
        if (!success)
525
            *errorMessage += msgEngineNotAvailable("Gdb");
526 527 528 529
        break;
    case ProjectExplorer::ToolChain::MSVC:
        success = checkCdbConfiguration(toolChain, errorMessage, settingsPage);
        if (!success) {
530
            *errorMessage += msgEngineNotAvailable("Cdb");
531 532 533 534 535 536 537
            if (settingsPage)
                *settingsPage = QLatin1String("Cdb");
        }
        break;
    }
    if (!success && settingsCategory && settingsPage && !settingsPage->isEmpty())
        *settingsCategory = QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY);
hjk's avatar
hjk committed
538

539
    return success;
540 541
}

542
void DebuggerRunControl::start()
543
{
544 545
    QTC_ASSERT(d->m_engine, return);
    const DebuggerStartParameters &sp = d->m_engine->startParameters();
546

547 548 549
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
550

551 552 553 554 555 556
    if (!checkDebugConfiguration(sp.toolChainType,
            &errorMessage, &settingsCategory, &settingsPage)) {
        emit appendMessage(this, errorMessage, true);
        emit finished();
        Core::ICore::instance()->showWarningWithOptions(tr("Debugger"),
            errorMessage, QString(), settingsCategory, settingsPage);
557
        return;
558
    }
559

560
    plugin()->activateDebugMode();
561
    DebuggerUISwitcher::instance()->aboutToStartDebugger();
Friedemann Kleint's avatar
Friedemann Kleint committed
562 563

    const QString message = tr("Starting debugger '%1' for tool chain '%2'...").
564
                  arg(d->m_engine->objectName(), toolChainName(sp.toolChainType));
Friedemann Kleint's avatar
Friedemann Kleint committed
565
    plugin()->showMessage(message, StatusBar);
566
    plugin()->showMessage(DebuggerSettings::instance()->dump(), LogDebug);
Friedemann Kleint's avatar
Friedemann Kleint committed
567
    plugin()->runControlStarted(this);
568

569 570
    // We might get a synchronous startFailed() notification on Windows,
    // when launching the process fails. Emit a proper finished() sequence.
571
    emit started();
572 573 574 575 576 577 578 579
    d->m_running = true;

    engine()->startDebugger(this);

    if (d->m_running) {
        emit addToOutputWindowInline(this, tr("Debugging starts"), false);
        emit addToOutputWindowInline(this, "\n", false);
    }
580 581
}

582
void DebuggerRunControl::startFailed()
583
{
584
    emit addToOutputWindowInline(this, tr("Debugging has failed"), false);
585
    d->m_running = false;
586
    emit finished();
587
    engine()->handleStartFailed();
588 589
}

590
void DebuggerRunControl::handleFinished()
591
{
592
    emit addToOutputWindowInline(this, tr("Debugging has finished"), false);
593
    engine()->handleFinished();
594
    plugin()->runControlFinished(this);
595 596
}

597
void DebuggerRunControl::showMessage(const QString &msg, int channel)
598
{
599 600 601 602 603 604 605 606 607 608 609
    switch (channel) {
        case AppOutput:
            emit addToOutputWindowInline(this, msg, false);
            break;
        case AppError:
            emit addToOutputWindowInline(this, msg, true);
            break;
        case AppStuff:
            emit appendMessage(this, msg, true);
            break;
    }
610 611
}

612
bool DebuggerRunControl::aboutToStop() const
613
{
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
    QTC_ASSERT(isRunning(), return true;)

    const QString question = tr("A debugging session are 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?");

    const QMessageBox::StandardButton answer =
            QMessageBox::question(DebuggerUISwitcher::instance()->mainWindow(),
                                  tr("Close Debugging Session"), question,
                                  QMessageBox::Yes|QMessageBox::No);
    return answer == QMessageBox::Yes;
}

RunControl::StopResult DebuggerRunControl::stop()
{
630 631
    QTC_ASSERT(d->m_engine, return StoppedSynchronously);
    d->m_engine->quitDebugger();
632
    return AsynchronousStop;
633 634
}

635
void DebuggerRunControl::debuggingFinished()
636
{
637
    d->m_running = false;
638
    emit finished();
639 640
}

641
bool DebuggerRunControl::isRunning() const
642
{
643
    return d->m_running;
644 645
}

Friedemann Kleint's avatar
Friedemann Kleint committed
646 647
DebuggerState DebuggerRunControl::state() const
{
648 649
    QTC_ASSERT(d->m_engine, return DebuggerNotReady);
    return d->m_engine->state();
Friedemann Kleint's avatar
Friedemann Kleint committed
650 651
}

652
DebuggerEngine *DebuggerRunControl::engine()
653
{
654 655
    QTC_ASSERT(d->m_engine, /**/);
    return d->m_engine;
656 657
}

658 659
Internal::GdbEngine *DebuggerRunControl::gdbEngine() const
{
660 661
    QTC_ASSERT(d->m_engine, return 0);
    if (GdbEngine *gdbEngine = qobject_cast<GdbEngine *>(d->m_engine))
662
        return gdbEngine;
663
    if (QmlCppEngine * const qmlEngine = qobject_cast<QmlCppEngine *>(d->m_engine))
664
        if (Internal::GdbEngine *embeddedGdbEngine = qobject_cast<GdbEngine *>(qmlEngine->cppEngine()))
665 666 667 668 669 670 671 672 673 674 675
            return embeddedGdbEngine;
    return 0;
}

Internal::AbstractGdbAdapter *DebuggerRunControl::gdbAdapter() const
{
    GdbEngine *engine = gdbEngine();
    QTC_ASSERT(engine, return 0)
    return engine->gdbAdapter();
}

676
void DebuggerRunControl::handleRemoteSetupDone()
677
{
678 679 680 681 682 683 684 685 686 687
    if (QmlEngine *qmlEngine = qobject_cast<QmlEngine *>(d->m_engine)) {
        qmlEngine->handleRemoteSetupDone();
    } else if (Internal::AbstractGdbAdapter *adapter = gdbAdapter()) {
        if (RemotePlainGdbAdapter *rpga = qobject_cast<RemotePlainGdbAdapter *>(adapter)) {
            rpga->handleSetupDone();
        } else if (RemoteGdbServerAdapter *rgsa = qobject_cast<RemoteGdbServerAdapter *>(adapter)) {
            rgsa->handleSetupDone();
        } else {
            QTC_ASSERT(false, /* */ );
        }
688 689 690 691 692
    } else {
        QTC_ASSERT(false, /* */ );
    }
}

693
void DebuggerRunControl::handleRemoteSetupFailed(const QString &message)
694
{
695 696 697 698 699 700 701 702 703 704
    if (QmlEngine *qmlEngine = qobject_cast<QmlEngine *>(d->m_engine)) {
        qmlEngine->handleRemoteSetupFailed(message);
    } else if (Internal::AbstractGdbAdapter *adapter = gdbAdapter()) {
        if (RemotePlainGdbAdapter *rpga = qobject_cast<RemotePlainGdbAdapter *>(adapter)) {
            rpga->handleSetupFailed(message);
        } else if (RemoteGdbServerAdapter *rgsa = qobject_cast<RemoteGdbServerAdapter *>(adapter)) {
            rgsa->handleSetupFailed(message);
        } else {
            QTC_ASSERT(false, /* */ );
        }
705 706 707 708
    } else {
        QTC_ASSERT(false, /* */ );
    }
}
709 710 711 712 713 714 715 716 717 718

void DebuggerRunControl::emitAddToOutputWindow(const QString &line, bool onStdErr)
{
    emit addToOutputWindow(this, line, onStdErr);
}

void DebuggerRunControl::emitAppendMessage(const QString &m, bool isError)
{
    emit appendMessage(this, m, isError);
}
719 720 721 722 723

RunConfiguration *DebuggerRunControl::runConfiguration() const
{
    return d->m_myRunConfiguration.data();
}
hjk's avatar
hjk committed
724
} // namespace Debugger