debuggerrunner.cpp 25.5 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
#include "debuggeractions.h"
33
#include "debuggercore.h"
34 35 36
#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"
hjk's avatar
hjk committed
41
#include "gdb/gdboptionspage.h"
42
#include "qml/qmlengine.h"
43
#include "qml/qmlcppengine.h"
44
#include "lldb/lldbenginehost.h"
45

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

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

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

con's avatar
con committed
63
#include <QtCore/QDir>
64
#include <QtGui/QMessageBox>
con's avatar
con committed
65

66
using namespace ProjectExplorer;
67 68
using namespace Debugger::Internal;

69 70 71 72 73 74 75 76
namespace Debugger {
namespace Internal {

DebuggerEngine *createGdbEngine(const DebuggerStartParameters &);
DebuggerEngine *createScriptEngine(const DebuggerStartParameters &);
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &);
DebuggerEngine *createTcfEngine(const DebuggerStartParameters &);
DebuggerEngine *createQmlEngine(const DebuggerStartParameters &);
77
DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &);
78
DebuggerEngine *createLLDBEngine(const DebuggerStartParameters &);
79

hjk's avatar
hjk committed
80
extern QString msgNoBinaryForToolChain(int tc);
81 82 83 84 85 86 87

// 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
88
#ifdef CDB_ENABLED
89
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *errorMessage);
90
bool checkCdbConfiguration(int toolChain, QString *errorMsg, QString *settingsPage);
91
bool isCdbEngineEnabled(); // Check the configuration page
hjk's avatar
hjk committed
92
#else
93
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *) { return 0; }
hjk's avatar
hjk committed
94 95
bool checkCdbConfiguration(int, QString *, QString *) { return false; }
#endif
96

hjk's avatar
hjk committed
97
} // namespace Internal
98 99 100

static QString toolChainName(int toolChainType)
{
101
    return ToolChain::toolChainName(ProjectExplorer::ToolChainType(toolChainType));
102 103
}

104

con's avatar
con committed
105 106
////////////////////////////////////////////////////////////////////////
//
107
// DebuggerRunControlFactory
con's avatar
con committed
108 109 110
//
////////////////////////////////////////////////////////////////////////

111 112 113 114 115 116
static QString msgEngineNotAvailable(const char *engine)
{
    return DebuggerPlugin::tr("The application requires the debugger engine '%1', "
        "which is disabled.").arg(QLatin1String(engine));
}

117
// A factory to create DebuggerRunControls
118
DebuggerRunControlFactory::DebuggerRunControlFactory(QObject *parent,
119
        unsigned enabledEngines)
120
    : IRunControlFactory(parent), m_enabledEngines(enabledEngines)
con's avatar
con committed
121 122
{}

123
bool DebuggerRunControlFactory::canRun(RunConfiguration *runConfiguration, const QString &mode) const
con's avatar
con committed
124
{
125
//    return mode == ProjectExplorer::Constants::DEBUGMODE;
126
    return mode == Constants::DEBUGMODE
127
            && qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
con's avatar
con committed
128 129
}

130
QString DebuggerRunControlFactory::displayName() const
con's avatar
con committed
131
{
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
132
    return tr("Debug");
con's avatar
con committed
133 134
}

135 136 137 138 139 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
// 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();
}

165
static DebuggerStartParameters localStartParameters(RunConfiguration *runConfiguration)
166
{
167
    DebuggerStartParameters sp;
168 169 170 171 172
    QTC_ASSERT(runConfiguration, return sp);
    LocalApplicationRunConfiguration *rc =
            qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
    QTC_ASSERT(rc, return sp);

173 174
    sp.startMode = StartInternal;
    sp.environment = rc->environment().toStringList();
175 176 177
    sp.workingDirectory = rc->workingDirectory();
    sp.executable = rc->executable();
    sp.processArgs = rc->commandLineArguments();
178 179 180 181
    sp.toolChainType = rc->toolChainType();
    sp.useTerminal = rc->runMode() == LocalApplicationRunConfiguration::Console;
    sp.dumperLibrary = rc->dumperLibrary();
    sp.dumperLibraryLocations = rc->dumperLibraryLocations();
182

183
    if (debuggerCore()->isActiveDebugLanguage(QmlLanguage)) {
184
        sp.qmlServerAddress = QLatin1String("127.0.0.1");
185
        sp.qmlServerPort = runConfiguration->qmlDebugServerPort();
186

187 188
        sp.projectDir = runConfiguration->target()->project()->projectDirectory();
        if (runConfiguration->target()->activeBuildConfiguration())
189 190
            sp.projectBuildDir = runConfiguration->target()
                ->activeBuildConfiguration()->buildDirectory();
191

192 193
        sp.processArgs.append(QLatin1String("-qmljsdebugger=port:")
            + QString::number(sp.qmlServerPort));
194 195
    }

196 197 198 199
    // 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;
200
    sp.displayName = rc->displayName();
201

202 203
    // Find qtInstallPath.
    QString qmakePath = DebuggingHelperLibrary::findSystemQt(rc->environment());
204 205
    if (!qmakePath.isEmpty())
        sp.qtInstallPath = findQtInstallPath(qmakePath);
206
    return sp;
207 208
}

209 210
RunControl *DebuggerRunControlFactory::create
    (RunConfiguration *runConfiguration, const QString &mode)
con's avatar
con committed
211
{
212
    QTC_ASSERT(mode == Constants::DEBUGMODE, return 0);
213
    DebuggerStartParameters sp = localStartParameters(runConfiguration);
214
    return create(sp, runConfiguration);
215 216
}

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

231 232
QWidget *DebuggerRunControlFactory::createConfigurationWidget
    (RunConfiguration *runConfiguration)
con's avatar
con committed
233 234
{
    // NBS TODO: Add GDB-specific configuration widget
235
    Q_UNUSED(runConfiguration)
con's avatar
con committed
236 237 238 239
    return 0;
}


240 241
////////////////////////////////////////////////////////////////////////
//
242
// DebuggerRunControl
243 244 245
//
////////////////////////////////////////////////////////////////////////

246 247
struct DebuggerRunnerPrivate {
    explicit DebuggerRunnerPrivate(RunConfiguration *runConfiguration,
248 249 250
                                   unsigned enabledEngines);

    unsigned enabledEngines() const;
251 252 253 254

    DebuggerEngine *m_engine;
    const QWeakPointer<RunConfiguration> m_myRunConfiguration;
    bool m_running;
255
    const unsigned m_cmdLineEnabledEngines;
256 257 258 259
    QString m_errorMessage;
    QString m_settingsIdHint;
};

260 261 262 263 264 265 266 267 268 269
unsigned DebuggerRunnerPrivate::enabledEngines() const
{
    unsigned rc = m_cmdLineEnabledEngines;
#ifdef CDB_ENABLED
    if (!Internal::isCdbEngineEnabled())
        rc &= ~CdbEngineType;
#endif
    return rc;
}

270
DebuggerRunnerPrivate::DebuggerRunnerPrivate(RunConfiguration *runConfiguration,
271
                                             unsigned enabledEngines) :
272 273
      m_engine(0)
    , m_myRunConfiguration(runConfiguration)
274
    , m_running(false)
275
    , m_cmdLineEnabledEngines(enabledEngines)
276 277
{
}
278

279
DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
280
        unsigned enabledEngines, const DebuggerStartParameters &sp)
281
    : RunControl(runConfiguration, Constants::DEBUGMODE),
282
      d(new DebuggerRunnerPrivate(runConfiguration, enabledEngines))
283
{
Friedemann Kleint's avatar
Friedemann Kleint committed
284
    connect(this, SIGNAL(finished()), this, SLOT(handleFinished()));
285 286
    DebuggerStartParameters startParams = sp;
    createEngine(startParams);
287 288
}

289 290 291
DebuggerRunControl::~DebuggerRunControl()
{
    disconnect();
292 293 294 295 296
    if (DebuggerEngine *engine = d->m_engine) {
        d->m_engine = 0;
        engine->disconnect();
        delete engine;
    }
297 298
}

299 300
const DebuggerStartParameters &DebuggerRunControl::startParameters() const
{
301 302
    QTC_ASSERT(d->m_engine, return *(new DebuggerStartParameters()));
    return d->m_engine->startParameters();
303 304
}

305 306 307
static DebuggerEngineType engineForToolChain(int toolChainType)
{
    switch (toolChainType) {
308 309 310 311 312 313 314 315 316 317
        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:
        case ProjectExplorer::ToolChain_GCC_MAEMO:
318 319
            return GdbEngineType;

320 321
        case ProjectExplorer::ToolChain_MSVC:
        case ProjectExplorer::ToolChain_WINCE:
322 323
            return CdbEngineType;

324 325 326
        case ProjectExplorer::ToolChain_OTHER:
        case ProjectExplorer::ToolChain_UNKNOWN:
        case ProjectExplorer::ToolChain_INVALID:
327 328 329 330
        default:
            break;
    }
    return NoEngineType;
331 332
}

333 334 335

// Figure out the debugger type of an executable. Analyze executable
// unless the toolchain provides a hint.
336
DebuggerEngineType DebuggerRunControl::engineForExecutable(unsigned enabledEngineTypes, const QString &executable)
337
{
338
    /*if (executable.endsWith(_("qmlviewer"))) {
339
        if (enabledEngineTypes & QmlEngineType)
340
            return QmlEngineType;
341
        d->m_errorMessage = msgEngineNotAvailable("Qml Engine");
342
    }*/
343

344
    if (executable.endsWith(_(".js"))) {
345
        if (enabledEngineTypes & ScriptEngineType)
346
            return ScriptEngineType;
347
        d->m_errorMessage = msgEngineNotAvailable("Script Engine");
348
    }
con's avatar
con committed
349

350
    if (executable.endsWith(_(".py"))) {
351
        if (enabledEngineTypes & PdbEngineType)
352
            return PdbEngineType;
353
        d->m_errorMessage = msgEngineNotAvailable("Pdb Engine");
354
    }
con's avatar
con committed
355

356 357 358
#ifdef Q_OS_WIN
    // A remote executable?
    if (!executable.endsWith(_(".exe")))
Friedemann Kleint's avatar
Friedemann Kleint committed
359
        return GdbEngineType;
360 361 362

    // If a file has PDB files, it has been compiled by VS.
    QStringList pdbFiles;
363
    if (!getPDBFiles(executable, &pdbFiles, &d->m_errorMessage)) {
364
        qWarning("Cannot determine type of executable %s: %s",
365
                 qPrintable(executable), qPrintable(d->m_errorMessage));
Friedemann Kleint's avatar
Friedemann Kleint committed
366
        return NoEngineType;
367 368 369
    }
    if (pdbFiles.empty())
        return GdbEngineType;
370

371 372
    // We need the CDB debugger in order to be able to debug VS
    // executables
373
    if (checkDebugConfiguration(ProjectExplorer::ToolChain_MSVC, &d->m_errorMessage, 0, &d->m_settingsIdHint)) {
374 375 376 377 378
        if (enabledEngineTypes & CdbEngineType)
            return CdbEngineType;
        d->m_errorMessage = msgEngineNotAvailable("Cdb Engine");
        return NoEngineType;
    }
379
#else
380
    if (enabledEngineTypes & GdbEngineType)
381
        return GdbEngineType;
382
    d->m_errorMessage = msgEngineNotAvailable("Gdb Engine");
383
#endif
384

385
    return NoEngineType;
386 387
}

388
// Debugger type for mode.
389
DebuggerEngineType DebuggerRunControl::engineForMode(unsigned enabledEngineTypes, DebuggerStartMode startMode)
390
{
391 392
    if (startMode == AttachTcf)
        return TcfEngineType;
393

394 395
#ifdef Q_OS_WIN
    // Preferably Windows debugger for attaching locally.
396
    if (startMode != AttachToRemote && (enabledEngineTypes & CdbEngineType))
397
        return CdbEngineType;
398 399 400 401
    if (startMode == AttachCrashedExternal) {
        d->m_errorMessage = tr("There is no debugging engine available for post-mortem debugging.");
        return NoEngineType;
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
402
    return GdbEngineType;
403 404
#else
    Q_UNUSED(startMode)
405
    Q_UNUSED(enabledEngineTypes)
406
    //  d->m_errorMessage = msgEngineNotAvailable("Gdb Engine");
407 408
    return GdbEngineType;
#endif
409 410
}

411
void DebuggerRunControl::createEngine(const DebuggerStartParameters &startParams)
412
{
413 414
    DebuggerStartParameters sp = startParams;

415 416
    // Figure out engine according to toolchain, executable, attach or default.
    DebuggerEngineType engineType = NoEngineType;
417
    DebuggerLanguages activeLangs = debuggerCore()->activeLanguages();
418
    const unsigned enabledEngineTypes = d->enabledEngines();
419
    if (sp.executable.endsWith(_(".js")))
420 421 422
        engineType = ScriptEngineType;
    else if (sp.executable.endsWith(_(".py")))
        engineType = PdbEngineType;
423
    else {
424
        engineType = engineForToolChain(sp.toolChainType);
425 426 427 428 429
        if (engineType == CdbEngineType && !(enabledEngineTypes & CdbEngineType)) {
            d->m_errorMessage = msgEngineNotAvailable("Cdb Engine");
            engineType = NoEngineType;
        }
    }
430

431 432 433 434
    // Fixme: 1 of 3 testing hacks.
    if (sp.processArgs.size() >= 5 && sp.processArgs.at(0) == _("@tcf@"))
        engineType = GdbEngineType;

435 436 437
    if (sp.processArgs.contains( _("@lldb@")))
        engineType = LLDBEngineType;

438 439 440
    if (engineType == NoEngineType
            && sp.startMode != AttachToRemote
            && !sp.executable.isEmpty())
441
        engineType = engineForExecutable(enabledEngineTypes, sp.executable);
442

443
    if (engineType == NoEngineType)
444
        engineType = engineForMode(enabledEngineTypes, sp.startMode);
445

446 447
    if ((engineType != QmlEngineType && engineType != NoEngineType)
        && (activeLangs & QmlLanguage)) {
448
        if (activeLangs & CppLanguage) {
449 450 451 452 453 454 455
            sp.cppEngineType = engineType;
            engineType = QmlCppEngineType;
        } else {
            engineType = QmlEngineType;
        }
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
456
    // qDebug() << "USING ENGINE : " << engineType;
457 458 459

    switch (engineType) {
        case GdbEngineType:
460 461
            d->m_engine = createGdbEngine(sp);
            initGdbEngine(qobject_cast<Internal::GdbEngine *>(d->m_engine));
462
            break;
463
        case ScriptEngineType:
464
            d->m_engine = Internal::createScriptEngine(sp);
465
            break;
466
        case CdbEngineType:
467
            d->m_engine = Internal::createCdbEngine(sp, &d->m_errorMessage);
468
            break;
469
        case PdbEngineType:
470
            d->m_engine = Internal::createPdbEngine(sp);
471
            break;
472
        case TcfEngineType:
473
            d->m_engine = Internal::createTcfEngine(sp);
474
            break;
475
        case QmlEngineType:
476
            d->m_engine = Internal::createQmlEngine(sp);
477 478 479
            connect(qobject_cast<QmlEngine *>(d->m_engine),
                SIGNAL(remoteStartupRequested()), this,
                SIGNAL(engineRequestSetup()));
480
            break;
481
        case QmlCppEngineType:
482
            d->m_engine = Internal::createQmlCppEngine(sp);
483 484
            if (Internal::GdbEngine *embeddedGdbEngine = gdbEngine())
                initGdbEngine(embeddedGdbEngine);
485
            break;
486 487
        case LLDBEngineType:
            d->m_engine = Internal::createLLDBEngine(sp);
488 489
       case NoEngineType:
       case AllEngineTypes:
490
            break;
491 492 493 494 495 496 497 498 499 500 501
    }

    if (!d->m_engine) {
        // Could not find anything suitable.
        debuggingFinished();
        // Create Message box with possibility to go to settings
        const QString msg = tr("Cannot debug '%1' (tool chain: '%2'): %3")
                .arg(sp.executable, toolChainName(sp.toolChainType), d->m_errorMessage);
        Core::ICore::instance()->showWarningWithOptions(tr("Warning"),
                                                        msg, QString(), QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY),
                                                        d->m_settingsIdHint);
502
    }
503 504
}

505 506 507 508 509 510 511 512
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,
513
                SIGNAL(engineRequestSetup()));
514 515
    } else if (RemoteGdbServerAdapter *rgsa = qobject_cast<RemoteGdbServerAdapter *>(adapter)) {
        connect(rgsa, SIGNAL(requestSetup()),
516
                this, SIGNAL(engineRequestSetup()));
517 518 519
    }
}

520
QString DebuggerRunControl::displayName() const
521
{
522 523
    QTC_ASSERT(d->m_engine, return QString());
    return d->m_engine->startParameters().displayName;
524 525
}

526
void DebuggerRunControl::setCustomEnvironment(Utils::Environment env)
527
{
528
    d->m_engine->startParameters().environment = env.toStringList();
529 530
}

531 532 533 534 535 536 537 538 539 540 541 542 543
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;

544
    if (!(debuggerCore()->activeLanguages() & CppLanguage))
545 546
        return success;

547
    switch(toolChain) {
548 549 550 551 552 553 554 555
    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:
hjk's avatar
hjk committed
556 557 558
        if (debuggerCore()->gdbBinaryForToolChain(toolChain).isEmpty()) {
            *errorMessage = msgNoBinaryForToolChain(toolChain);
            *settingsPage = GdbOptionsPage::settingsId();
559
            *errorMessage += msgEngineNotAvailable("Gdb");
hjk's avatar
hjk committed
560 561 562 563
            success = false;
        } else {
            success = true;
        }
564
        break;
565
    case ProjectExplorer::ToolChain_MSVC:
566 567
        success = checkCdbConfiguration(toolChain, errorMessage, settingsPage);
        if (!success) {
568
            *errorMessage += msgEngineNotAvailable("Cdb");
569 570 571 572 573 574 575
            if (settingsPage)
                *settingsPage = QLatin1String("Cdb");
        }
        break;
    }
    if (!success && settingsCategory && settingsPage && !settingsPage->isEmpty())
        *settingsCategory = QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY);
hjk's avatar
hjk committed
576

577
    return success;
578 579
}

580
void DebuggerRunControl::start()
581
{
582 583
    QTC_ASSERT(d->m_engine, return);
    const DebuggerStartParameters &sp = d->m_engine->startParameters();
584

585 586 587
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
588

589 590 591 592 593 594
    if (!checkDebugConfiguration(sp.toolChainType,
            &errorMessage, &settingsCategory, &settingsPage)) {
        emit appendMessage(this, errorMessage, true);
        emit finished();
        Core::ICore::instance()->showWarningWithOptions(tr("Debugger"),
            errorMessage, QString(), settingsCategory, settingsPage);
595
        return;
596
    }
597

598
    debuggerCore()->runControlStarted(this);
599

600 601
    // We might get a synchronous startFailed() notification on Windows,
    // when launching the process fails. Emit a proper finished() sequence.
602
    emit started();
603 604 605 606 607 608 609 610
    d->m_running = true;

    engine()->startDebugger(this);

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

613 614 615 616 617 618 619
QString DebuggerRunControl::idString() const
{
    return tr("Starting debugger '%1' for tool chain '%2'...")
        .arg(d->m_engine->objectName())
        .arg(toolChainName(d->m_engine->startParameters().toolChainType));
}

620
void DebuggerRunControl::startFailed()
621
{
622
    emit addToOutputWindowInline(this, tr("Debugging has failed"), false);
623
    d->m_running = false;
624
    emit finished();
625
    engine()->handleStartFailed();
626 627
}

628
void DebuggerRunControl::handleFinished()
629
{
630
    emit addToOutputWindowInline(this, tr("Debugging has finished"), false);
631 632
    if (engine())
        engine()->handleFinished();
633
    debuggerCore()->runControlFinished(this);
634 635
}

636
void DebuggerRunControl::showMessage(const QString &msg, int channel)
637
{
638 639 640 641 642 643 644 645 646 647 648
    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;
    }
649 650
}

651
bool DebuggerRunControl::aboutToStop() const
652
{
653 654
    QTC_ASSERT(isRunning(), return true;)

Jarek Kobus's avatar
Jarek Kobus committed
655
    const QString question = tr("A debugging session is still in progress. "
656 657 658 659 660
            "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 =
661
            QMessageBox::question(debuggerCore()->mainWindow(),
662 663 664 665 666 667 668
                                  tr("Close Debugging Session"), question,
                                  QMessageBox::Yes|QMessageBox::No);
    return answer == QMessageBox::Yes;
}

RunControl::StopResult DebuggerRunControl::stop()
{
669 670
    QTC_ASSERT(d->m_engine, return StoppedSynchronously);
    d->m_engine->quitDebugger();
671
    return AsynchronousStop;
672 673
}

674
void DebuggerRunControl::debuggingFinished()
675
{
676
    d->m_running = false;
677
    emit finished();
678 679
}

680
bool DebuggerRunControl::isRunning() const
681
{
682
    return d->m_running;
683 684
}

Friedemann Kleint's avatar
Friedemann Kleint committed
685 686
DebuggerState DebuggerRunControl::state() const
{
687 688
    QTC_ASSERT(d->m_engine, return DebuggerNotReady);
    return d->m_engine->state();
Friedemann Kleint's avatar
Friedemann Kleint committed
689 690
}

691
DebuggerEngine *DebuggerRunControl::engine()
692
{
693 694
    QTC_ASSERT(d->m_engine, /**/);
    return d->m_engine;
695 696
}

697 698
Internal::GdbEngine *DebuggerRunControl::gdbEngine() const
{
699 700
    QTC_ASSERT(d->m_engine, return 0);
    if (GdbEngine *gdbEngine = qobject_cast<GdbEngine *>(d->m_engine))
701
        return gdbEngine;
702
    if (QmlCppEngine * const qmlEngine = qobject_cast<QmlCppEngine *>(d->m_engine))
703
        if (Internal::GdbEngine *embeddedGdbEngine = qobject_cast<GdbEngine *>(qmlEngine->cppEngine()))
704 705 706 707 708 709 710 711 712 713 714
            return embeddedGdbEngine;
    return 0;
}

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

715
void DebuggerRunControl::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
716
{
717
    if (QmlEngine *qmlEngine = qobject_cast<QmlEngine *>(d->m_engine)) {
718
        qmlEngine->handleRemoteSetupDone(qmlPort);
719 720
    } else if (Internal::AbstractGdbAdapter *adapter = gdbAdapter()) {
        if (RemotePlainGdbAdapter *rpga = qobject_cast<RemotePlainGdbAdapter *>(adapter)) {
721
            rpga->handleSetupDone(qmlPort);
722
        } else if (RemoteGdbServerAdapter *rgsa = qobject_cast<RemoteGdbServerAdapter *>(adapter)) {
723
            rgsa->handleSetupDone(gdbServerPort, qmlPort);
724 725 726
        } else {
            QTC_ASSERT(false, /* */ );
        }
727 728 729 730 731
    } else {
        QTC_ASSERT(false, /* */ );
    }
}

732
void DebuggerRunControl::handleRemoteSetupFailed(const QString &message)
733
{
734 735 736 737 738 739 740 741 742 743
    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, /* */ );
        }
744 745 746 747
    } else {
        QTC_ASSERT(false, /* */ );
    }
}
748 749 750 751 752 753 754 755 756 757

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);
}
758 759 760 761 762

RunConfiguration *DebuggerRunControl::runConfiguration() const
{
    return d->m_myRunConfiguration.data();
}
763

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