debuggerrunner.cpp 26.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) 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 &);
hjk's avatar
hjk committed
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
hjk's avatar
hjk committed
98 99


100 101 102 103
namespace Cdb {
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *errorMessage);
bool isCdbEngineEnabled(); // Check the configuration page
}
104 105 106

static QString toolChainName(int toolChainType)
{
107
    return ToolChain::toolChainName(ProjectExplorer::ToolChainType(toolChainType));
108 109
}

110

con's avatar
con committed
111 112
////////////////////////////////////////////////////////////////////////
//
113
// DebuggerRunControlFactory
con's avatar
con committed
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));
}

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

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

136
QString DebuggerRunControlFactory::displayName() const
con's avatar
con committed
137
{
Oswald Buddenhagen's avatar
Oswald Buddenhagen committed
138
    return tr("Debug");
con's avatar
con committed
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 165 166 167 168 169 170
// 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();
}

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

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

189
    if (debuggerCore()->isActiveDebugLanguage(QmlLanguage)) {
190
        sp.qmlServerAddress = QLatin1String("127.0.0.1");
191
        sp.qmlServerPort = runConfiguration->qmlDebugServerPort();
192

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

198 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
{
218
    QTC_ASSERT(mode == Constants::DEBUGMODE, return 0);
219
    DebuggerStartParameters sp = localStartParameters(runConfiguration);
220
    return create(sp, runConfiguration);
221 222
}

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

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


244 245
////////////////////////////////////////////////////////////////////////
//
hjk's avatar
hjk committed
246
// DebuggerRunControlPrivate
247 248 249
//
////////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
250 251 252 253 254
class DebuggerRunControlPrivate
{
public:
    DebuggerRunControlPrivate(DebuggerRunControl *parent,
        RunConfiguration *runConfiguration, unsigned enabledEngines);
255
    unsigned enabledEngines() const;
256

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

    void initGdbEngine(GdbEngine *engine);
    GdbEngine *gdbEngine() const;
    AbstractGdbAdapter *gdbAdapter() const;

public:
    DebuggerRunControl *q;
268 269 270
    DebuggerEngine *m_engine;
    const QWeakPointer<RunConfiguration> m_myRunConfiguration;
    bool m_running;
271
    const unsigned m_cmdLineEnabledEngines;
272 273 274 275
    QString m_errorMessage;
    QString m_settingsIdHint;
};

hjk's avatar
hjk committed
276
unsigned DebuggerRunControlPrivate::enabledEngines() const
277 278 279
{
    unsigned rc = m_cmdLineEnabledEngines;
#ifdef CDB_ENABLED
hjk's avatar
hjk committed
280
    if (!isCdbEngineEnabled() && !Cdb::isCdbEngineEnabled())
281 282 283 284 285
        rc &= ~CdbEngineType;
#endif
    return rc;
}

hjk's avatar
hjk committed
286 287 288 289
DebuggerRunControlPrivate::DebuggerRunControlPrivate(DebuggerRunControl *parent,
        RunConfiguration *runConfiguration, unsigned enabledEngines)
    : q(parent)
    , m_engine(0)
290
    , m_myRunConfiguration(runConfiguration)
291
    , m_running(false)
292
    , m_cmdLineEnabledEngines(enabledEngines)
293 294
{
}
295

296 297
// Figure out the debugger type of an executable. Analyze executable
// unless the toolchain provides a hint.
hjk's avatar
hjk committed
298 299
DebuggerEngineType DebuggerRunControlPrivate::engineForExecutable
    (unsigned enabledEngineTypes, const QString &executable)
300
{
301
    /*if (executable.endsWith(_("qmlviewer"))) {
302
        if (enabledEngineTypes & QmlEngineType)
303
            return QmlEngineType;
304
        d->m_errorMessage = msgEngineNotAvailable("Qml Engine");
305
    }*/
306

307
    if (executable.endsWith(_(".js"))) {
308
        if (enabledEngineTypes & ScriptEngineType)
309
            return ScriptEngineType;
hjk's avatar
hjk committed
310
        m_errorMessage = msgEngineNotAvailable("Script Engine");
311
    }
con's avatar
con committed
312

313
    if (executable.endsWith(_(".py"))) {
314
        if (enabledEngineTypes & PdbEngineType)
315
            return PdbEngineType;
hjk's avatar
hjk committed
316
        m_errorMessage = msgEngineNotAvailable("Pdb Engine");
317
    }
con's avatar
con committed
318

319 320 321
#ifdef Q_OS_WIN
    // A remote executable?
    if (!executable.endsWith(_(".exe")))
Friedemann Kleint's avatar
Friedemann Kleint committed
322
        return GdbEngineType;
323 324 325

    // If a file has PDB files, it has been compiled by VS.
    QStringList pdbFiles;
hjk's avatar
hjk committed
326
    if (!getPDBFiles(executable, &pdbFiles, &m_errorMessage)) {
327
        qWarning("Cannot determine type of executable %s: %s",
hjk's avatar
hjk committed
328
                 qPrintable(executable), qPrintable(m_errorMessage));
Friedemann Kleint's avatar
Friedemann Kleint committed
329
        return NoEngineType;
330 331 332
    }
    if (pdbFiles.empty())
        return GdbEngineType;
333

334 335
    // We need the CDB debugger in order to be able to debug VS
    // executables
hjk's avatar
hjk committed
336
    if (checkDebugConfiguration(ProjectExplorer::ToolChain_MSVC, &m_errorMessage, 0, &m_settingsIdHint)) {
337 338
        if (enabledEngineTypes & CdbEngineType)
            return CdbEngineType;
hjk's avatar
hjk committed
339
        m_errorMessage = msgEngineNotAvailable("Cdb Engine");
340 341
        return NoEngineType;
    }
342
#else
343
    if (enabledEngineTypes & GdbEngineType)
344
        return GdbEngineType;
hjk's avatar
hjk committed
345
    m_errorMessage = msgEngineNotAvailable("Gdb Engine");
346
#endif
347

348
    return NoEngineType;
349 350
}

351
// Debugger type for mode.
hjk's avatar
hjk committed
352 353
DebuggerEngineType DebuggerRunControlPrivate::engineForMode
    (unsigned enabledEngineTypes, DebuggerStartMode startMode)
354
{
355 356
    if (startMode == AttachTcf)
        return TcfEngineType;
357

358 359
#ifdef Q_OS_WIN
    // Preferably Windows debugger for attaching locally.
360
    if (startMode != AttachToRemote && (enabledEngineTypes & CdbEngineType))
361
        return CdbEngineType;
362
    if (startMode == AttachCrashedExternal) {
hjk's avatar
hjk committed
363
        m_errorMessage = tr("There is no debugging engine available for post-mortem debugging.");
364 365
        return NoEngineType;
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
366
    return GdbEngineType;
367 368
#else
    Q_UNUSED(startMode)
369
    Q_UNUSED(enabledEngineTypes)
hjk's avatar
hjk committed
370
    //  >m_errorMessage = msgEngineNotAvailable("Gdb Engine");
371 372
    return GdbEngineType;
#endif
373 374
}

hjk's avatar
hjk committed
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
void DebuggerRunControlPrivate::initGdbEngine(GdbEngine *engine)
{
    QTC_ASSERT(engine, return)

    // Forward adapter signals.
    AbstractGdbAdapter *adapter = engine->gdbAdapter();
    RemotePlainGdbAdapter *rpga = qobject_cast<RemotePlainGdbAdapter *>(adapter);
    RemoteGdbServerAdapter *rgsa = qobject_cast<RemoteGdbServerAdapter *>(adapter);
    if (rpga)
        q->connect(rpga, SIGNAL(requestSetup()), SIGNAL(engineRequestSetup()));
    else if (rgsa)
        q->connect(rgsa, SIGNAL(requestSetup()), SIGNAL(engineRequestSetup()));
}

GdbEngine *DebuggerRunControlPrivate::gdbEngine() const
{
    QTC_ASSERT(m_engine, return 0);
    if (GdbEngine *gdbEngine = qobject_cast<GdbEngine *>(m_engine))
        return gdbEngine;
    if (QmlCppEngine *qmlEngine = qobject_cast<QmlCppEngine *>(m_engine))
        if (GdbEngine *embeddedGdbEngine = qobject_cast<GdbEngine *>(qmlEngine->cppEngine()))
            return embeddedGdbEngine;
    return 0;
}

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

////////////////////////////////////////////////////////////////////////
//
// DebuggerRunControl
//
////////////////////////////////////////////////////////////////////////

DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
        unsigned enabledEngines, const DebuggerStartParameters &sp)
    : RunControl(runConfiguration, Constants::DEBUGMODE),
      d(new DebuggerRunControlPrivate(this, runConfiguration, enabledEngines))
{
    connect(this, SIGNAL(finished()), SLOT(handleFinished()));
    createEngine(sp);
}

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();
}

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:
        case ProjectExplorer::ToolChain_GCC_MAEMO:
            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;
}

466
void DebuggerRunControl::createEngine(const DebuggerStartParameters &startParams)
467
{
468 469
    DebuggerStartParameters sp = startParams;

470 471
    // Figure out engine according to toolchain, executable, attach or default.
    DebuggerEngineType engineType = NoEngineType;
472
    DebuggerLanguages activeLangs = debuggerCore()->activeLanguages();
473
    const unsigned enabledEngineTypes = d->enabledEngines();
474
    if (sp.executable.endsWith(_(".js")))
475 476 477
        engineType = ScriptEngineType;
    else if (sp.executable.endsWith(_(".py")))
        engineType = PdbEngineType;
478
    else {
479
        engineType = engineForToolChain(sp.toolChainType);
480 481 482 483 484
        if (engineType == CdbEngineType && !(enabledEngineTypes & CdbEngineType)) {
            d->m_errorMessage = msgEngineNotAvailable("Cdb Engine");
            engineType = NoEngineType;
        }
    }
485

486
    // Fixme: 1 of 3 testing hacks.
487
    if (sp.processArgs.startsWith(__("@tcf@ ")))
488 489
        engineType = GdbEngineType;

490
    if (sp.processArgs.contains( _("@lldb@")))
hjk's avatar
hjk committed
491
        engineType = LldbEngineType;
492

493 494 495
    if (engineType == NoEngineType
            && sp.startMode != AttachToRemote
            && !sp.executable.isEmpty())
hjk's avatar
hjk committed
496
        engineType = d->engineForExecutable(enabledEngineTypes, sp.executable);
497

498
    if (engineType == NoEngineType)
hjk's avatar
hjk committed
499
        engineType = d->engineForMode(enabledEngineTypes, sp.startMode);
500

501 502
    if ((engineType != QmlEngineType && engineType != NoEngineType)
        && (activeLangs & QmlLanguage)) {
503
        if (activeLangs & CppLanguage) {
504 505 506 507 508 509 510
            sp.cppEngineType = engineType;
            engineType = QmlCppEngineType;
        } else {
            engineType = QmlEngineType;
        }
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
511
    // qDebug() << "USING ENGINE : " << engineType;
512 513 514

    switch (engineType) {
        case GdbEngineType:
515
            d->m_engine = createGdbEngine(sp);
hjk's avatar
hjk committed
516
            d->initGdbEngine(qobject_cast<GdbEngine *>(d->m_engine));
517
            break;
518
        case ScriptEngineType:
hjk's avatar
hjk committed
519
            d->m_engine = createScriptEngine(sp);
520
            break;
521
        case CdbEngineType:
522
            // Try new engine, fall back to old.
hjk's avatar
hjk committed
523 524 525 526
            if (Cdb::isCdbEngineEnabled())
                d->m_engine = Cdb::createCdbEngine(sp, &d->m_errorMessage);
            else
                d->m_engine = Internal::createCdbEngine(sp, &d->m_errorMessage);
527
            break;
528
        case PdbEngineType:
hjk's avatar
hjk committed
529
            d->m_engine = createPdbEngine(sp);
530
            break;
531
        case TcfEngineType:
hjk's avatar
hjk committed
532
            d->m_engine = createTcfEngine(sp);
533
            break;
534
        case QmlEngineType:
hjk's avatar
hjk committed
535
            d->m_engine = createQmlEngine(sp);
536
            connect(qobject_cast<QmlEngine *>(d->m_engine),
hjk's avatar
hjk committed
537
                SIGNAL(remoteStartupRequested()),
538
                SIGNAL(engineRequestSetup()));
539
            break;
540
        case QmlCppEngineType:
hjk's avatar
hjk committed
541 542 543
            d->m_engine = createQmlCppEngine(sp);
            if (GdbEngine *embeddedGdbEngine = d->gdbEngine())
                d->initGdbEngine(embeddedGdbEngine);
544
            break;
hjk's avatar
hjk committed
545 546
        case LldbEngineType:
            d->m_engine = createLldbEngine(sp);
547 548
       case NoEngineType:
       case AllEngineTypes:
549
            break;
550 551 552 553 554
    }

    if (!d->m_engine) {
        // Could not find anything suitable.
        debuggingFinished();
hjk's avatar
hjk committed
555
        // Create Message box with possibility to go to settings.
556
        const QString msg = tr("Cannot debug '%1' (tool chain: '%2'): %3")
hjk's avatar
hjk committed
557
            .arg(sp.executable, toolChainName(sp.toolChainType), d->m_errorMessage);
558
        Core::ICore::instance()->showWarningWithOptions(tr("Warning"),
hjk's avatar
hjk committed
559 560
            msg, QString(), QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY),
            d->m_settingsIdHint);
561
    }
562 563
}

564
QString DebuggerRunControl::displayName() const
565
{
566 567
    QTC_ASSERT(d->m_engine, return QString());
    return d->m_engine->startParameters().displayName;
568 569
}

570
void DebuggerRunControl::setCustomEnvironment(Utils::Environment env)
571
{
572
    d->m_engine->startParameters().environment = env;
573 574
}

575 576 577 578 579 580 581 582 583 584 585 586 587
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;

588
    if (!(debuggerCore()->activeLanguages() & CppLanguage))
589 590
        return success;

591
    switch(toolChain) {
592 593 594 595 596 597 598 599
    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
600 601 602
        if (debuggerCore()->gdbBinaryForToolChain(toolChain).isEmpty()) {
            *errorMessage = msgNoBinaryForToolChain(toolChain);
            *settingsPage = GdbOptionsPage::settingsId();
603
            *errorMessage += msgEngineNotAvailable("Gdb");
hjk's avatar
hjk committed
604 605 606 607
            success = false;
        } else {
            success = true;
        }
608
        break;
609
    case ProjectExplorer::ToolChain_MSVC:
610 611
        success = checkCdbConfiguration(toolChain, errorMessage, settingsPage);
        if (!success) {
612
            *errorMessage += msgEngineNotAvailable("Cdb");
613 614 615 616 617 618 619
            if (settingsPage)
                *settingsPage = QLatin1String("Cdb");
        }
        break;
    }
    if (!success && settingsCategory && settingsPage && !settingsPage->isEmpty())
        *settingsCategory = QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY);
hjk's avatar
hjk committed
620

621
    return success;
622 623
}

624
void DebuggerRunControl::start()
625
{
626 627
    QTC_ASSERT(d->m_engine, return);
    const DebuggerStartParameters &sp = d->m_engine->startParameters();
628

629 630 631
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
632

633 634 635 636 637 638
    if (!checkDebugConfiguration(sp.toolChainType,
            &errorMessage, &settingsCategory, &settingsPage)) {
        emit appendMessage(this, errorMessage, true);
        emit finished();
        Core::ICore::instance()->showWarningWithOptions(tr("Debugger"),
            errorMessage, QString(), settingsCategory, settingsPage);
639
        return;
640
    }
641

642
    debuggerCore()->runControlStarted(this);
643

644 645
    // We might get a synchronous startFailed() notification on Windows,
    // when launching the process fails. Emit a proper finished() sequence.
646
    emit started();
647 648 649 650 651 652 653 654
    d->m_running = true;

    engine()->startDebugger(this);

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

657 658 659 660 661 662 663
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));
}

664
void DebuggerRunControl::startFailed()
665
{
666
    emit addToOutputWindowInline(this, tr("Debugging has failed"), false);
667
    d->m_running = false;
668
    emit finished();
669
    engine()->handleStartFailed();
670 671
}

672
void DebuggerRunControl::handleFinished()
673
{
674
    emit addToOutputWindowInline(this, tr("Debugging has finished"), false);
675 676
    if (engine())
        engine()->handleFinished();
677
    debuggerCore()->runControlFinished(this);
678 679
}

680
void DebuggerRunControl::showMessage(const QString &msg, int channel)
681
{
682 683 684 685 686 687 688 689 690 691 692
    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;
    }
693 694
}

695
bool DebuggerRunControl::aboutToStop() const
696
{
697 698
    QTC_ASSERT(isRunning(), return true;)

Jarek Kobus's avatar
Jarek Kobus committed
699
    const QString question = tr("A debugging session is still in progress. "
700 701 702 703 704
            "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 =
705
            QMessageBox::question(debuggerCore()->mainWindow(),
706 707 708 709 710 711 712
                                  tr("Close Debugging Session"), question,
                                  QMessageBox::Yes|QMessageBox::No);
    return answer == QMessageBox::Yes;
}

RunControl::StopResult DebuggerRunControl::stop()
{
713 714
    QTC_ASSERT(d->m_engine, return StoppedSynchronously);
    d->m_engine->quitDebugger();
715
    return AsynchronousStop;
716 717
}

718
void DebuggerRunControl::debuggingFinished()
719
{
720
    d->m_running = false;
721
    emit finished();
722 723
}

724
bool DebuggerRunControl::isRunning() const
725
{
726
    return d->m_running;
727 728
}

Friedemann Kleint's avatar
Friedemann Kleint committed
729 730
DebuggerState DebuggerRunControl::state() const
{
731 732
    QTC_ASSERT(d->m_engine, return DebuggerNotReady);
    return d->m_engine->state();
Friedemann Kleint's avatar
Friedemann Kleint committed
733 734
}

735
DebuggerEngine *DebuggerRunControl::engine()
736
{
737 738
    QTC_ASSERT(d->m_engine, /**/);
    return d->m_engine;
739 740
}

741
void DebuggerRunControl::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
742
{
hjk's avatar
hjk committed
743
    // FIXME: Use virtual functions?
744
    if (QmlEngine *qmlEngine = qobject_cast<QmlEngine *>(d->m_engine)) {
745
        qmlEngine->handleRemoteSetupDone(qmlPort);
hjk's avatar
hjk committed
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
        return;
    }

    AbstractGdbAdapter *adapter = d->gdbAdapter();
    QTC_ASSERT(adapter, return);

    RemotePlainGdbAdapter *rpga = qobject_cast<RemotePlainGdbAdapter *>(adapter);
    if (rpga) {
        rpga->handleSetupDone(qmlPort);
        return;
    }

    RemoteGdbServerAdapter *rgsa = qobject_cast<RemoteGdbServerAdapter *>(adapter);
    if (rgsa) {
        rgsa->handleSetupDone(gdbServerPort, qmlPort);
        return;
762
    }
hjk's avatar
hjk committed
763
    QTC_ASSERT(false, /**/);
764 765
}

766
void DebuggerRunControl::handleRemoteSetupFailed(const QString &message)
767
{
hjk's avatar
hjk committed
768
    // FIXME: Use virtual functions?
769 770
    if (QmlEngine *qmlEngine = qobject_cast<QmlEngine *>(d->m_engine)) {
        qmlEngine->handleRemoteSetupFailed(message);
hjk's avatar
hjk committed
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786
        return;
    }

    AbstractGdbAdapter *adapter = d->gdbAdapter();
    QTC_ASSERT(adapter, return);

    RemotePlainGdbAdapter *rpga = qobject_cast<RemotePlainGdbAdapter *>(adapter);
    if (rpga) {
        rpga->handleSetupFailed(message);
        return;
    }

    RemoteGdbServerAdapter *rgsa = qobject_cast<RemoteGdbServerAdapter *>(adapter);
    if (rgsa) {
        rgsa->handleSetupFailed(message);
        return;
787
    }
hjk's avatar
hjk committed
788
    QTC_ASSERT(false, /**/);
789
}
790 791 792 793 794 795 796 797 798 799

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);
}
800 801 802 803 804

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

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