debuggerrunner.cpp 26.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
#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
}

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
////////////////////////////////////////////////////////////////////////
//
hjk's avatar
hjk committed
248
// DebuggerRunControlPrivate
249 250 251
//
////////////////////////////////////////////////////////////////////////

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

hjk's avatar
hjk committed
259 260 261 262 263 264 265 266 267 268 269
    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;
270 271 272
    DebuggerEngine *m_engine;
    const QWeakPointer<RunConfiguration> m_myRunConfiguration;
    bool m_running;
273
    const unsigned m_cmdLineEnabledEngines;
274 275 276 277
    QString m_errorMessage;
    QString m_settingsIdHint;
};

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

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

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

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

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

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

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

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

350
    return NoEngineType;
351 352
}

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

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

hjk's avatar
hjk committed
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
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;
}

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

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

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

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

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

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

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

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

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

    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);
564
    }
565 566
}

567
QString DebuggerRunControl::displayName() const
568
{
569 570
    QTC_ASSERT(d->m_engine, return QString());
    return d->m_engine->startParameters().displayName;
571 572
}

573
void DebuggerRunControl::setCustomEnvironment(Utils::Environment env)
574
{
575
    d->m_engine->startParameters().environment = env;
576 577
}

578 579 580 581 582 583 584 585 586 587 588 589 590
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;

591
    if (!(debuggerCore()->activeLanguages() & CppLanguage))
592 593
        return success;

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

624
    return success;
625 626
}

627
void DebuggerRunControl::start()
628
{
629 630
    QTC_ASSERT(d->m_engine, return);
    const DebuggerStartParameters &sp = d->m_engine->startParameters();
631

632 633 634
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
635

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

645
    debuggerCore()->runControlStarted(this);
646

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

    engine()->startDebugger(this);

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

660 661 662 663 664 665 666
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));
}

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

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

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

698
bool DebuggerRunControl::aboutToStop() const
699
{
700 701
    QTC_ASSERT(isRunning(), return true;)

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

RunControl::StopResult DebuggerRunControl::stop()
{
716 717
    QTC_ASSERT(d->m_engine, return StoppedSynchronously);
    d->m_engine->quitDebugger();
718
    return AsynchronousStop;
719 720
}

721
void DebuggerRunControl::debuggingFinished()
722
{
723
    d->m_running = false;
724
    emit finished();
725 726
}

727
bool DebuggerRunControl::isRunning() const
728
{
729
    return d->m_running;
730 731
}

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

738
DebuggerEngine *DebuggerRunControl::engine()
739
{
740 741
    QTC_ASSERT(d->m_engine, /**/);
    return d->m_engine;
742 743
}

744
void DebuggerRunControl::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
745
{
hjk's avatar
hjk committed
746
    // FIXME: Use virtual functions?
747
    if (QmlEngine *qmlEngine = qobject_cast<QmlEngine *>(d->m_engine)) {
748
        qmlEngine->handleRemoteSetupDone(qmlPort);
hjk's avatar
hjk committed
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
        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;
765
    }
hjk's avatar
hjk committed
766
    QTC_ASSERT(false, /**/);
767 768
}

769
void DebuggerRunControl::handleRemoteSetupFailed(const QString &message)
770
{
hjk's avatar
hjk committed
771
    // FIXME: Use virtual functions?
772 773
    if (QmlEngine *qmlEngine = qobject_cast<QmlEngine *>(d->m_engine)) {
        qmlEngine->handleRemoteSetupFailed(message);
hjk's avatar
hjk committed
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
        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;
790
    }
hjk's avatar
hjk committed
791
    QTC_ASSERT(false, /**/);
792
}
793 794 795 796 797 798 799 800 801 802

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);
}
803 804 805 806 807

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

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