debuggerrunner.cpp 22.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
#include "debuggerengine.h"
35
#include "debuggermainwindow.h"
36 37
#include "debuggerplugin.h"
#include "debuggerstringutils.h"
hjk's avatar
hjk committed
38
#include "gdb/gdboptionspage.h"
39
#include "lldb/lldbenginehost.h"
40

Friedemann Kleint's avatar
Friedemann Kleint committed
41 42 43 44
#ifdef Q_OS_WIN
#  include "peutils.h"
#endif

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

53
#include <utils/synchronousprocess.h>
hjk's avatar
hjk committed
54
#include <utils/qtcassert.h>
55
#include <utils/fancymainwindow.h>
56
#include <coreplugin/icore.h>
hjk's avatar
hjk committed
57

con's avatar
con committed
58
#include <QtCore/QDir>
59
#include <QtGui/QMessageBox>
con's avatar
con committed
60

61
using namespace ProjectExplorer;
62 63
using namespace Debugger::Internal;

64
namespace Debugger {
hjk's avatar
hjk committed
65 66 67 68 69 70

namespace Cdb {
DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *error);
bool isCdbEngineEnabled(); // Check the configuration page
}

71 72 73 74 75 76 77
namespace Internal {

DebuggerEngine *createGdbEngine(const DebuggerStartParameters &);
DebuggerEngine *createScriptEngine(const DebuggerStartParameters &);
DebuggerEngine *createPdbEngine(const DebuggerStartParameters &);
DebuggerEngine *createTcfEngine(const DebuggerStartParameters &);
DebuggerEngine *createQmlEngine(const DebuggerStartParameters &);
78
DebuggerEngine *createQmlCppEngine(const DebuggerStartParameters &);
hjk's avatar
hjk committed
79
DebuggerEngine *createLldbEngine(const DebuggerStartParameters &);
80

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

// 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
89
#ifdef CDB_ENABLED
hjk's avatar
hjk committed
90 91

DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *error);
92
bool checkCdbConfiguration(int toolChain, QString *errorMsg, QString *settingsPage);
93
bool isCdbEngineEnabled(); // Check the configuration page
hjk's avatar
hjk committed
94

hjk's avatar
hjk committed
95
#else
hjk's avatar
hjk committed
96 97 98 99 100 101 102 103 104 105 106

DebuggerEngine *createCdbEngine(const DebuggerStartParameters &, QString *)
{
    return 0;
}

bool checkCdbConfiguration(int, QString *, QString *)
{
    return false;
}

hjk's avatar
hjk committed
107
#endif
108 109 110 111 112 113 114

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

115 116
////////////////////////////////////////////////////////////////////////
//
hjk's avatar
hjk committed
117
// DebuggerRunControlPrivate
118 119 120
//
////////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
121 122 123 124 125
class DebuggerRunControlPrivate
{
public:
    DebuggerRunControlPrivate(DebuggerRunControl *parent,
        RunConfiguration *runConfiguration, unsigned enabledEngines);
126
    unsigned enabledEngines() const;
127

hjk's avatar
hjk committed
128 129 130 131 132 133 134
    DebuggerEngineType engineForExecutable(unsigned enabledEngineTypes,
        const QString &executable);
    DebuggerEngineType engineForMode(unsigned enabledEngineTypes,
        DebuggerStartMode mode);

public:
    DebuggerRunControl *q;
135 136 137
    DebuggerEngine *m_engine;
    const QWeakPointer<RunConfiguration> m_myRunConfiguration;
    bool m_running;
138
    const unsigned m_cmdLineEnabledEngines;
139 140 141 142
    QString m_errorMessage;
    QString m_settingsIdHint;
};

hjk's avatar
hjk committed
143
unsigned DebuggerRunControlPrivate::enabledEngines() const
144 145 146
{
    unsigned rc = m_cmdLineEnabledEngines;
#ifdef CDB_ENABLED
hjk's avatar
hjk committed
147
    if (!isCdbEngineEnabled() && !Cdb::isCdbEngineEnabled())
148 149 150 151 152
        rc &= ~CdbEngineType;
#endif
    return rc;
}

hjk's avatar
hjk committed
153 154 155 156
DebuggerRunControlPrivate::DebuggerRunControlPrivate(DebuggerRunControl *parent,
        RunConfiguration *runConfiguration, unsigned enabledEngines)
    : q(parent)
    , m_engine(0)
157
    , m_myRunConfiguration(runConfiguration)
158
    , m_running(false)
159
    , m_cmdLineEnabledEngines(enabledEngines)
160 161
{
}
162

163 164
// Figure out the debugger type of an executable. Analyze executable
// unless the toolchain provides a hint.
hjk's avatar
hjk committed
165 166
DebuggerEngineType DebuggerRunControlPrivate::engineForExecutable
    (unsigned enabledEngineTypes, const QString &executable)
167
{
168
    if (executable.endsWith(_(".js"))) {
169
        if (enabledEngineTypes & ScriptEngineType)
170
            return ScriptEngineType;
hjk's avatar
hjk committed
171
        m_errorMessage = msgEngineNotAvailable("Script Engine");
172
    }
con's avatar
con committed
173

174
    if (executable.endsWith(_(".py"))) {
175
        if (enabledEngineTypes & PdbEngineType)
176
            return PdbEngineType;
hjk's avatar
hjk committed
177
        m_errorMessage = msgEngineNotAvailable("Pdb Engine");
178
    }
con's avatar
con committed
179

180 181 182
#ifdef Q_OS_WIN
    // A remote executable?
    if (!executable.endsWith(_(".exe")))
Friedemann Kleint's avatar
Friedemann Kleint committed
183
        return GdbEngineType;
184 185 186

    // If a file has PDB files, it has been compiled by VS.
    QStringList pdbFiles;
hjk's avatar
hjk committed
187
    if (!getPDBFiles(executable, &pdbFiles, &m_errorMessage)) {
188
        qWarning("Cannot determine type of executable %s: %s",
hjk's avatar
hjk committed
189
                 qPrintable(executable), qPrintable(m_errorMessage));
Friedemann Kleint's avatar
Friedemann Kleint committed
190
        return NoEngineType;
191 192 193
    }
    if (pdbFiles.empty())
        return GdbEngineType;
194

195
    // We need the CDB debugger in order to be able to debug VS
hjk's avatar
hjk committed
196
    // executables.
197
   if (DebuggerRunControl::checkDebugConfiguration(ProjectExplorer::ToolChain_MSVC,
hjk's avatar
hjk committed
198
            &m_errorMessage, 0, &m_settingsIdHint)) {
199 200
        if (enabledEngineTypes & CdbEngineType)
            return CdbEngineType;
hjk's avatar
hjk committed
201
        m_errorMessage = msgEngineNotAvailable("Cdb Engine");
202 203
        return NoEngineType;
    }
204
#else
205
    if (enabledEngineTypes & GdbEngineType)
206
        return GdbEngineType;
hjk's avatar
hjk committed
207
    m_errorMessage = msgEngineNotAvailable("Gdb Engine");
208
#endif
209

210
    return NoEngineType;
211 212
}

213
// Debugger type for mode.
hjk's avatar
hjk committed
214 215
DebuggerEngineType DebuggerRunControlPrivate::engineForMode
    (unsigned enabledEngineTypes, DebuggerStartMode startMode)
216
{
217 218
    if (startMode == AttachTcf)
        return TcfEngineType;
219

220 221
#ifdef Q_OS_WIN
    // Preferably Windows debugger for attaching locally.
222
    if (startMode != AttachToRemote && (enabledEngineTypes & CdbEngineType))
223
        return CdbEngineType;
224
    if (startMode == AttachCrashedExternal) {
225
        m_errorMessage = DebuggerRunControl::tr("There is no debugging engine available for post-mortem debugging.");
226 227
        return NoEngineType;
    }
Friedemann Kleint's avatar
Friedemann Kleint committed
228
    return GdbEngineType;
229 230
#else
    Q_UNUSED(startMode)
231
    Q_UNUSED(enabledEngineTypes)
hjk's avatar
hjk committed
232
    //  >m_errorMessage = msgEngineNotAvailable("Gdb Engine");
233 234
    return GdbEngineType;
#endif
235 236
}

hjk's avatar
hjk committed
237 238 239
} // namespace Internal


hjk's avatar
hjk committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253
////////////////////////////////////////////////////////////////////////
//
// DebuggerRunControl
//
////////////////////////////////////////////////////////////////////////

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:
254 255
        case ProjectExplorer::ToolChain_RVCT2_ARMV5:
        case ProjectExplorer::ToolChain_RVCT2_ARMV6:
hjk's avatar
hjk committed
256 257 258
        case ProjectExplorer::ToolChain_RVCT_ARMV5_GNUPOC:
        case ProjectExplorer::ToolChain_GCCE_GNUPOC:
        case ProjectExplorer::ToolChain_GCC_MAEMO:
259 260 261 262 263
#ifdef WITH_LLDB
            // lldb override
            if (Core::ICore::instance()->settings()->value("LLDB/enabled").toBool())
                return LldbEngineType;
#endif
hjk's avatar
hjk committed
264 265
            return GdbEngineType;

266

hjk's avatar
hjk committed
267 268 269 270 271 272 273 274 275 276 277 278 279
        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;
}

hjk's avatar
hjk committed
280 281 282 283
DebuggerRunControl::DebuggerRunControl(RunConfiguration *runConfiguration,
        unsigned enabledEngines, const DebuggerStartParameters &startParams)
    : RunControl(runConfiguration, Constants::DEBUGMODE),
      d(new DebuggerRunControlPrivate(this, runConfiguration, enabledEngines))
284
{
hjk's avatar
hjk committed
285
    connect(this, SIGNAL(finished()), SLOT(handleFinished()));
286

287 288
    // Figure out engine according to toolchain, executable, attach or default.
    DebuggerEngineType engineType = NoEngineType;
289
    DebuggerLanguages activeLangs = debuggerCore()->activeLanguages();
hjk's avatar
hjk committed
290
    DebuggerStartParameters sp = startParams;
291
    const unsigned enabledEngineTypes = d->enabledEngines();
292
    if (sp.executable.endsWith(_(".js")))
293 294 295
        engineType = ScriptEngineType;
    else if (sp.executable.endsWith(_(".py")))
        engineType = PdbEngineType;
296
    else {
297
        engineType = engineForToolChain(sp.toolChainType);
298 299 300 301 302
        if (engineType == CdbEngineType && !(enabledEngineTypes & CdbEngineType)) {
            d->m_errorMessage = msgEngineNotAvailable("Cdb Engine");
            engineType = NoEngineType;
        }
    }
303

304 305 306
    // Fixme: unclean ipc override. Someone please have a better idea
    if (sp.startMode == StartRemoteEngine)
        // for now thats the only supported ipc engine
307 308
        engineType = LldbEngineType;

309
    // Fixme: 1 of 3 testing hacks.
310
    if (sp.processArgs.startsWith(__("@tcf@ ")))
311 312
        engineType = GdbEngineType;

313 314 315
    if (engineType == NoEngineType
            && sp.startMode != AttachToRemote
            && !sp.executable.isEmpty())
hjk's avatar
hjk committed
316
        engineType = d->engineForExecutable(enabledEngineTypes, sp.executable);
317

318
    if (engineType == NoEngineType)
hjk's avatar
hjk committed
319
        engineType = d->engineForMode(enabledEngineTypes, sp.startMode);
320

321 322
    if ((engineType != QmlEngineType && engineType != NoEngineType)
        && (activeLangs & QmlLanguage)) {
323
        if (activeLangs & CppLanguage) {
324 325 326 327 328 329 330
            sp.cppEngineType = engineType;
            engineType = QmlCppEngineType;
        } else {
            engineType = QmlEngineType;
        }
    }

Friedemann Kleint's avatar
Friedemann Kleint committed
331
    // qDebug() << "USING ENGINE : " << engineType;
332 333 334

    switch (engineType) {
        case GdbEngineType:
335
            d->m_engine = createGdbEngine(sp);
336
            break;
337
        case ScriptEngineType:
hjk's avatar
hjk committed
338
            d->m_engine = createScriptEngine(sp);
339
            break;
340
        case CdbEngineType:
341
            // Try new engine, fall back to old.
hjk's avatar
hjk committed
342 343 344 345
            if (Cdb::isCdbEngineEnabled())
                d->m_engine = Cdb::createCdbEngine(sp, &d->m_errorMessage);
            else
                d->m_engine = Internal::createCdbEngine(sp, &d->m_errorMessage);
346
            break;
347
        case PdbEngineType:
hjk's avatar
hjk committed
348
            d->m_engine = createPdbEngine(sp);
349
            break;
350
        case TcfEngineType:
hjk's avatar
hjk committed
351
            d->m_engine = createTcfEngine(sp);
352
            break;
353
        case QmlEngineType:
hjk's avatar
hjk committed
354
            d->m_engine = createQmlEngine(sp);
355
            break;
356
        case QmlCppEngineType:
hjk's avatar
hjk committed
357
            d->m_engine = createQmlCppEngine(sp);
358
            break;
hjk's avatar
hjk committed
359 360
        case LldbEngineType:
            d->m_engine = createLldbEngine(sp);
361 362
        case NoEngineType:
        case AllEngineTypes:
363
            break;
364 365 366 367 368
    }

    if (!d->m_engine) {
        // Could not find anything suitable.
        debuggingFinished();
hjk's avatar
hjk committed
369
        // Create Message box with possibility to go to settings.
370
        const QString msg = tr("Cannot debug '%1' (tool chain: '%2'): %3")
hjk's avatar
hjk committed
371
            .arg(sp.executable, sp.toolChainName(), d->m_errorMessage);
372
        Core::ICore::instance()->showWarningWithOptions(tr("Warning"),
hjk's avatar
hjk committed
373 374
            msg, QString(), QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY),
            d->m_settingsIdHint);
375
    }
376 377
}

hjk's avatar
hjk committed
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
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();
}

394
QString DebuggerRunControl::displayName() const
395
{
396 397
    QTC_ASSERT(d->m_engine, return QString());
    return d->m_engine->startParameters().displayName;
398 399
}

400
void DebuggerRunControl::setCustomEnvironment(Utils::Environment env)
401
{
402
    QTC_ASSERT(d->m_engine, return);
403
    d->m_engine->startParameters().environment = env;
404 405
}

406 407 408 409 410 411 412 413 414 415 416 417 418
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;

419
    if (!(debuggerCore()->activeLanguages() & CppLanguage))
420 421
        return success;

422
    switch(toolChain) {
423 424 425 426 427 428
    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:
429 430
    case ProjectExplorer::ToolChain_RVCT2_ARMV5:
    case ProjectExplorer::ToolChain_RVCT2_ARMV6:
hjk's avatar
hjk committed
431 432 433
        if (debuggerCore()->gdbBinaryForToolChain(toolChain).isEmpty()) {
            *errorMessage = msgNoBinaryForToolChain(toolChain);
            *settingsPage = GdbOptionsPage::settingsId();
434
            *errorMessage += msgEngineNotAvailable("Gdb");
hjk's avatar
hjk committed
435 436 437 438
            success = false;
        } else {
            success = true;
        }
439
        break;
440
    case ProjectExplorer::ToolChain_MSVC:
441 442
        success = checkCdbConfiguration(toolChain, errorMessage, settingsPage);
        if (!success) {
443
            *errorMessage += msgEngineNotAvailable("Cdb");
444 445 446 447 448 449 450
            if (settingsPage)
                *settingsPage = QLatin1String("Cdb");
        }
        break;
    }
    if (!success && settingsCategory && settingsPage && !settingsPage->isEmpty())
        *settingsCategory = QLatin1String(Constants::DEBUGGER_SETTINGS_CATEGORY);
hjk's avatar
hjk committed
451

452
    return success;
453 454
}

455
void DebuggerRunControl::start()
456
{
457 458
    QTC_ASSERT(d->m_engine, return);
    const DebuggerStartParameters &sp = d->m_engine->startParameters();
459

460 461 462
    QString errorMessage;
    QString settingsCategory;
    QString settingsPage;
463

464 465 466 467 468 469
    if (!checkDebugConfiguration(sp.toolChainType,
            &errorMessage, &settingsCategory, &settingsPage)) {
        emit appendMessage(this, errorMessage, true);
        emit finished();
        Core::ICore::instance()->showWarningWithOptions(tr("Debugger"),
            errorMessage, QString(), settingsCategory, settingsPage);
470
        return;
471
    }
472

473
    debuggerCore()->runControlStarted(d->m_engine);
474

475 476
    // We might get a synchronous startFailed() notification on Windows,
    // when launching the process fails. Emit a proper finished() sequence.
477
    emit started();
478 479
    d->m_running = true;

480
    d->m_engine->startDebugger(this);
481 482 483 484 485

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

488
void DebuggerRunControl::startFailed()
489
{
490
    emit addToOutputWindowInline(this, tr("Debugging has failed"), false);
491
    d->m_running = false;
492
    emit finished();
493
    d->m_engine->handleStartFailed();
494 495
}

496
void DebuggerRunControl::handleFinished()
497
{
498
    emit addToOutputWindowInline(this, tr("Debugging has finished"), false);
499 500 501
    if (d->m_engine)
        d->m_engine->handleFinished();
    debuggerCore()->runControlFinished(d->m_engine);
502 503
}

504
void DebuggerRunControl::showMessage(const QString &msg, int channel)
505
{
506 507 508 509 510 511 512 513 514 515 516
    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;
    }
517 518
}

519
bool DebuggerRunControl::aboutToStop() const
520
{
521 522
    QTC_ASSERT(isRunning(), return true;)

Jarek Kobus's avatar
Jarek Kobus committed
523
    const QString question = tr("A debugging session is still in progress. "
524 525 526 527 528
            "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 =
529
            QMessageBox::question(debuggerCore()->mainWindow(),
530 531 532 533 534 535 536
                                  tr("Close Debugging Session"), question,
                                  QMessageBox::Yes|QMessageBox::No);
    return answer == QMessageBox::Yes;
}

RunControl::StopResult DebuggerRunControl::stop()
{
537 538
    QTC_ASSERT(d->m_engine, return StoppedSynchronously);
    d->m_engine->quitDebugger();
539
    return AsynchronousStop;
540 541
}

542
void DebuggerRunControl::debuggingFinished()
543
{
544
    d->m_running = false;
545
    emit finished();
546 547
}

548
bool DebuggerRunControl::isRunning() const
549
{
550
    return d->m_running;
551 552
}

553
DebuggerEngine *DebuggerRunControl::engine()
554
{
555 556
    QTC_ASSERT(d->m_engine, /**/);
    return d->m_engine;
557 558
}

559 560 561 562
RunConfiguration *DebuggerRunControl::runConfiguration() const
{
    return d->m_myRunConfiguration.data();
}
563

564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689

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

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

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

QString DebuggerRunControlFactory::displayName() const
{
    return tr("Debug");
}

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

static DebuggerStartParameters localStartParameters(RunConfiguration *runConfiguration)
{
    DebuggerStartParameters sp;
    QTC_ASSERT(runConfiguration, return sp);
    LocalApplicationRunConfiguration *rc =
            qobject_cast<LocalApplicationRunConfiguration *>(runConfiguration);
    QTC_ASSERT(rc, return sp);

    sp.startMode = StartInternal;
    sp.environment = rc->environment();
    sp.workingDirectory = rc->workingDirectory();
    sp.executable = rc->executable();
    sp.processArgs = rc->commandLineArguments();
    sp.toolChainType = rc->toolChainType();
    sp.useTerminal = rc->runMode() == LocalApplicationRunConfiguration::Console;
    sp.dumperLibrary = rc->dumperLibrary();
    sp.dumperLibraryLocations = rc->dumperLibraryLocations();

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

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

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

    // FIXME: If it's not yet build this will be empty and not filled
    // when rebuild as the runConfiguration is not stored and therefore
    // cannot be used to retrieve the dumper location.
    //qDebug() << "DUMPER: " << sp.dumperLibrary << sp.dumperLibraryLocations;
    sp.displayName = rc->displayName();

    // Find qtInstallPath.
    QString qmakePath = DebuggingHelperLibrary::findSystemQt(rc->environment());
    if (!qmakePath.isEmpty())
        sp.qtInstallPath = findQtInstallPath(qmakePath);
    return sp;
}

RunControl *DebuggerRunControlFactory::create
    (RunConfiguration *runConfiguration, const QString &mode)
{
    QTC_ASSERT(mode == Constants::DEBUGMODE, return 0);
    DebuggerStartParameters sp = localStartParameters(runConfiguration);
    return create(sp, runConfiguration);
}

QWidget *DebuggerRunControlFactory::createConfigurationWidget
    (RunConfiguration *runConfiguration)
{
    // NBS TODO: Add GDB-specific configuration widget
    Q_UNUSED(runConfiguration)
    return 0;
}

DebuggerRunControl *DebuggerRunControlFactory::create
    (const DebuggerStartParameters &sp, RunConfiguration *runConfiguration)
{
    DebuggerRunControl *runControl =
        new DebuggerRunControl(runConfiguration, m_enabledEngines, sp);
    if (runControl->d->m_engine)
        return runControl;
    delete runControl;
    return 0;
}

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