debuggerengine.cpp 44.8 KB
Newer Older
1 2 3 4
/**************************************************************************
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 7 8
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
con's avatar
con committed
9
** No Commercial Usage
10
**
con's avatar
con committed
11 12 13 14
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
15 16 17 18 19 20 21 22 23 24
**
** GNU Lesser General Public License Usage
**
** 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.
**
con's avatar
con committed
25 26 27 28 29 30
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
31 32 33 34 35 36
**
**************************************************************************/

#include "debuggerengine.h"

#include "debuggeractions.h"
37
#include "debuggercore.h"
38
#include "debuggerplugin.h"
39
#include "debuggerrunner.h"
40
#include "debuggerstringutils.h"
41
#include "debuggertooltip.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
42
#include "debuggerstartparameters.h"
43

44 45
#include "memoryagent.h"
#include "disassembleragent.h"
46 47 48 49 50 51 52 53 54
#include "breakhandler.h"
#include "moduleshandler.h"
#include "registerhandler.h"
#include "snapshothandler.h"
#include "sourcefileshandler.h"
#include "stackhandler.h"
#include "threadshandler.h"
#include "watchhandler.h"

hjk's avatar
hjk committed
55
#include <coreplugin/icore.h>
56
#include <coreplugin/ifile.h>
hjk's avatar
hjk committed
57
#include <coreplugin/editormanager/editormanager.h>
58 59
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
hjk's avatar
hjk committed
60

hjk's avatar
hjk committed
61
#include <projectexplorer/toolchain.h>
62
#include <projectexplorer/toolchaintype.h>
63

hjk's avatar
hjk committed
64
#include <texteditor/itexteditor.h>
65
#include <texteditor/basetextmark.h>
hjk's avatar
hjk committed
66

67 68 69 70 71
#include <utils/savedaction.h>
#include <utils/qtcassert.h>

#include <QtCore/QDebug>
#include <QtCore/QTimer>
72
#include <QtCore/QFutureInterface>
73

74
#include <QtGui/QMessageBox>
75

hjk's avatar
hjk committed
76
using namespace Core;
77
using namespace Debugger::Internal;
hjk's avatar
hjk committed
78 79
using namespace ProjectExplorer;
using namespace TextEditor;
80

81 82 83 84
enum { debug = 0 };

#define SDEBUG(s) if (!debug) {} else qDebug() << s;
#define XSDEBUG(s) qDebug() << s
85

86

87 88 89 90 91 92
///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
//
///////////////////////////////////////////////////////////////////////

93 94
namespace Debugger {

Friedemann Kleint's avatar
Friedemann Kleint committed
95 96 97 98 99 100 101 102 103 104 105
Internal::Location::Location(const StackFrame &frame, bool marker)
{
    init();
    m_fileName = frame.file;
    m_lineNumber = frame.line;
    m_needsMarker = marker;
    m_functionName = frame.function;
    m_hasDebugInfo = frame.isUsable();
    m_address = frame.address;
}

106 107
QDebug operator<<(QDebug d, DebuggerState state)
{
hjk's avatar
hjk committed
108 109
    //return d << DebuggerEngine::stateName(state) << '(' << int(state) << ')';
    return d << DebuggerEngine::stateName(state);
110 111 112 113 114 115 116
}

QDebug operator<<(QDebug str, const DebuggerStartParameters &sp)
{
    QDebug nospace = str.nospace();
    nospace << "executable=" << sp.executable
            << " coreFile=" << sp.coreFile
117
            << " processArgs=" << sp.processArgs
118 119 120 121 122 123 124
            << " environment=<" << sp.environment.size() << " variables>"
            << " workingDir=" << sp.workingDirectory
            << " attachPID=" << sp.attachPID
            << " useTerminal=" << sp.useTerminal
            << " remoteChannel=" << sp.remoteChannel
            << " remoteArchitecture=" << sp.remoteArchitecture
            << " symbolFileName=" << sp.symbolFileName
hjk's avatar
hjk committed
125
            << " useServerStartScript=" << sp.useServerStartScript
126 127 128 129 130
            << " serverStartScript=" << sp.serverStartScript
            << " toolchain=" << sp.toolChainType << '\n';
    return str;
}

131

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
///////////////////////////////////////////////////////////////////////
//
// LocationMark
//
///////////////////////////////////////////////////////////////////////

// Used in "real" editors
class LocationMark : public TextEditor::BaseTextMark
{
public:
    LocationMark(const QString &fileName, int linenumber)
        : BaseTextMark(fileName, linenumber)
    {}

    QIcon icon() const { return debuggerCore()->locationMarkIcon(); }
    void updateLineNumber(int /*lineNumber*/) {}
    void updateBlock(const QTextBlock & /*block*/) {}
    void removedFromEditor() {}
};



154 155 156 157 158 159
//////////////////////////////////////////////////////////////////////
//
// DebuggerEnginePrivate
//
//////////////////////////////////////////////////////////////////////

160
class DebuggerEnginePrivate : public QObject
161
{
162 163
    Q_OBJECT

164
public:
165 166 167
    DebuggerEnginePrivate(DebuggerEngine *engine,
            DebuggerEngine *masterEngine,
            const DebuggerStartParameters &sp)
168
      : m_engine(engine),
169
        m_masterEngine(masterEngine),
170 171 172
        m_runControl(0),
        m_startParameters(sp),
        m_state(DebuggerNotReady),
hjk's avatar
hjk committed
173
        m_lastGoodState(DebuggerNotReady),
Friedemann Kleint's avatar
Friedemann Kleint committed
174
        m_targetState(DebuggerNotReady),
175
        m_modulesHandler(),
176
        m_registerHandler(),
177 178
        m_sourceFilesHandler(),
        m_stackHandler(),
hjk's avatar
hjk committed
179
        m_threadsHandler(),
180
        m_watchHandler(engine),
181
        m_disassemblerAgent(engine),
182 183
        m_memoryAgent(engine),
        m_isStateDebugging(false)
184
    {
185
        connect(&m_locationTimer, SIGNAL(timeout()), SLOT(resetLocation()));
186
    }
187 188

    ~DebuggerEnginePrivate() {}
189

190
public slots:
191
    void doSetupEngine();
hjk's avatar
hjk committed
192 193
    void doSetupInferior();
    void doRunEngine();
hjk's avatar
hjk committed
194 195
    void doShutdownEngine();
    void doShutdownInferior();
196
    void doInterruptInferior();
hjk's avatar
hjk committed
197
    void doFinishDebugger();
hjk's avatar
hjk committed
198

199 200 201 202 203 204 205 206 207 208 209 210 211 212
    void queueSetupEngine()
    {
        m_engine->setState(EngineSetupRequested);
        m_engine->showMessage(_("QUEUE: SETUP ENGINE"));
        QTimer::singleShot(0, this, SLOT(doSetupEngine()));
    }

    void queueSetupInferior()
    {
        m_engine->setState(InferiorSetupRequested);
        m_engine->showMessage(_("QUEUE: SETUP INFERIOR"));
        QTimer::singleShot(0, this, SLOT(doSetupInferior()));
    }

213 214
    void queueRunEngine()
    {
hjk's avatar
hjk committed
215 216 217 218 219
        m_engine->setState(EngineRunRequested);
        m_engine->showMessage(_("QUEUE: RUN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doRunEngine()));
    }

220 221
    void queueShutdownEngine()
    {
hjk's avatar
hjk committed
222 223 224 225 226
        m_engine->setState(EngineShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doShutdownEngine()));
    }

227 228
    void queueShutdownInferior()
    {
hjk's avatar
hjk committed
229 230 231 232 233
        m_engine->setState(InferiorShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
        QTimer::singleShot(0, this, SLOT(doShutdownInferior()));
    }

234 235
    void queueFinishDebugger()
    {
236 237 238 239
        QTC_ASSERT(state() == EngineShutdownOk
            || state() == EngineShutdownFailed, qDebug() << state());
        m_engine->setState(DebuggerFinished);
        m_engine->showMessage(_("QUEUE: FINISH DEBUGGER"));
hjk's avatar
hjk committed
240 241 242
        QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
    }

243 244
    void raiseApplication()
    {
245 246
        QTC_ASSERT(runControl(), return);
        runControl()->bringApplicationToForeground(m_inferiorPid);
247 248
    }

249
    void scheduleResetLocation()
250
    {
251
        m_stackHandler.scheduleResetLocation();
252 253 254 255
        m_locationTimer.setSingleShot(true);
        m_locationTimer.start(80);
    }

256
    void resetLocation()
257 258 259
    {
        m_locationTimer.stop();
        m_locationMark.reset();
260 261
        m_stackHandler.resetLocation();
        m_disassemblerAgent.resetLocation();
262 263
    }

264
public:
hjk's avatar
hjk committed
265
    DebuggerState state() const { return m_state; }
266 267 268
    bool isMasterEngine() const { return m_engine->isMasterEngine(); }
    DebuggerRunControl *runControl() const
        { return m_masterEngine ? m_masterEngine->runControl() : m_runControl; }
hjk's avatar
hjk committed
269

270
    DebuggerEngine *m_engine; // Not owned.
271
    DebuggerEngine *m_masterEngine; // Not owned
272 273 274
    DebuggerRunControl *m_runControl;  // Not owned.

    DebuggerStartParameters m_startParameters;
hjk's avatar
hjk committed
275 276

    // The current state.
277 278
    DebuggerState m_state;

hjk's avatar
hjk committed
279 280 281 282 283 284
    // The state we had before something unexpected happend.
    DebuggerState m_lastGoodState;

    // The state we are aiming for.
    DebuggerState m_targetState;

285 286 287 288 289 290 291 292
    qint64 m_inferiorPid;

    ModulesHandler m_modulesHandler;
    RegisterHandler m_registerHandler;
    SourceFilesHandler m_sourceFilesHandler;
    StackHandler m_stackHandler;
    ThreadsHandler m_threadsHandler;
    WatchHandler m_watchHandler;
293
    QFutureInterface<void> m_progress;
294

295 296
    DisassemblerAgent m_disassemblerAgent;
    MemoryAgent m_memoryAgent;
297 298
    QScopedPointer<TextEditor::BaseTextMark> m_locationMark;
    QTimer m_locationTimer;
299 300

    bool m_isStateDebugging;
301 302 303 304 305 306 307 308 309
};


//////////////////////////////////////////////////////////////////////
//
// DebuggerEngine
//
//////////////////////////////////////////////////////////////////////

310 311 312
DebuggerEngine::DebuggerEngine(const DebuggerStartParameters &startParameters,
        DebuggerEngine *parentEngine)
  : d(new DebuggerEnginePrivate(this, parentEngine, startParameters))
313 314 315 316 317
{
}

DebuggerEngine::~DebuggerEngine()
{
318 319
    disconnect();
    delete d;
320 321
}

322 323 324 325 326 327 328 329 330 331 332
const char *DebuggerEngine::stateName(int s)
{
#    define SN(x) case x: return #x;
    switch (s) {
        SN(DebuggerNotReady)
        SN(EngineSetupRequested)
        SN(EngineSetupOk)
        SN(EngineSetupFailed)
        SN(EngineRunFailed)
        SN(InferiorSetupRequested)
        SN(InferiorSetupFailed)
333
        SN(InferiorSetupOk)
334 335 336 337 338 339 340 341
        SN(EngineRunRequested)
        SN(InferiorRunRequested)
        SN(InferiorRunOk)
        SN(InferiorRunFailed)
        SN(InferiorUnrunnable)
        SN(InferiorStopRequested)
        SN(InferiorStopOk)
        SN(InferiorStopFailed)
342
        SN(InferiorExitOk)
343 344 345 346 347 348 349 350 351 352 353 354
        SN(InferiorShutdownRequested)
        SN(InferiorShutdownOk)
        SN(InferiorShutdownFailed)
        SN(EngineShutdownRequested)
        SN(EngineShutdownOk)
        SN(EngineShutdownFailed)
        SN(DebuggerFinished)
    }
    return "<unknown>";
#    undef SN
}

355
void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
356
{
357
    showMessage(msg, StatusBar, timeout);
358
}
359

360 361 362 363 364 365
void DebuggerEngine::removeTooltip()
{
    watchHandler()->removeTooltip();
    hideDebuggerToolTip();
}

366 367 368 369 370 371 372 373 374 375 376 377 378 379
void DebuggerEngine::frameUp()
{
    int currentIndex = stackHandler()->currentIndex();
    activateFrame(qMin(currentIndex + 1, stackHandler()->stackSize() - 1));
}

void DebuggerEngine::frameDown()
{
    int currentIndex = stackHandler()->currentIndex();
    activateFrame(qMax(currentIndex - 1, 0));
}

ModulesHandler *DebuggerEngine::modulesHandler() const
{
380 381 382
    return d->m_masterEngine
        ? d->m_masterEngine->modulesHandler()
        : &d->m_modulesHandler;
383 384 385 386
}

RegisterHandler *DebuggerEngine::registerHandler() const
{
387 388 389
    return d->m_masterEngine
        ? d->m_masterEngine->registerHandler()
        : &d->m_registerHandler;
390 391 392 393
}

StackHandler *DebuggerEngine::stackHandler() const
{
394 395 396
    return d->m_masterEngine
        ? d->m_masterEngine->stackHandler()
        : &d->m_stackHandler;
397 398 399 400
}

ThreadsHandler *DebuggerEngine::threadsHandler() const
{
401 402 403
    return d->m_masterEngine
        ? d->m_masterEngine->threadsHandler()
        : &d->m_threadsHandler;
404 405 406 407
}

WatchHandler *DebuggerEngine::watchHandler() const
{
408 409 410
    return d->m_masterEngine
        ? d->m_masterEngine->watchHandler()
        : &d->m_watchHandler;
411 412 413 414
}

SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
{
415 416 417
    return d->m_masterEngine
        ? d->m_masterEngine->sourceFilesHandler()
        : &d->m_sourceFilesHandler;
418 419 420 421
}

QAbstractItemModel *DebuggerEngine::modulesModel() const
{
422
    QAbstractItemModel *model = modulesHandler()->model();
Friedemann Kleint's avatar
Friedemann Kleint committed
423 424 425
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ModulesModel"));
    return model;
426 427 428 429
}

QAbstractItemModel *DebuggerEngine::registerModel() const
{
430
    QAbstractItemModel *model = registerHandler()->model();
Friedemann Kleint's avatar
Friedemann Kleint committed
431 432 433
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("RegisterModel"));
    return model;
434 435 436 437
}

QAbstractItemModel *DebuggerEngine::stackModel() const
{
438
    QAbstractItemModel *model = stackHandler()->model();
Friedemann Kleint's avatar
Friedemann Kleint committed
439 440 441
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("StackModel"));
    return model;
442 443 444 445
}

QAbstractItemModel *DebuggerEngine::threadsModel() const
{
446
    QAbstractItemModel *model = threadsHandler()->model();
Friedemann Kleint's avatar
Friedemann Kleint committed
447 448 449
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ThreadsModel"));
    return model;
450 451 452 453
}

QAbstractItemModel *DebuggerEngine::localsModel() const
{
454
    QAbstractItemModel *model = watchHandler()->model(LocalsWatch);
Friedemann Kleint's avatar
Friedemann Kleint committed
455 456 457
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("LocalsModel"));
    return model;
458 459 460 461
}

QAbstractItemModel *DebuggerEngine::watchersModel() const
{
462
    QAbstractItemModel *model = watchHandler()->model(WatchersWatch);
Friedemann Kleint's avatar
Friedemann Kleint committed
463 464 465
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("WatchersModel"));
    return model;
466 467 468 469
}

QAbstractItemModel *DebuggerEngine::returnModel() const
{
470
    QAbstractItemModel *model = watchHandler()->model(ReturnWatch);
Friedemann Kleint's avatar
Friedemann Kleint committed
471 472 473
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ReturnModel"));
    return model;
474 475 476 477
}

QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
{
478
    QAbstractItemModel *model = sourceFilesHandler()->model();
Friedemann Kleint's avatar
Friedemann Kleint committed
479 480 481
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("SourceFilesModel"));
    return model;
482 483
}

484
void DebuggerEngine::fetchMemory(MemoryAgent *, QObject *,
485 486 487 488 489 490 491 492 493 494 495 496 497 498
        quint64 addr, quint64 length)
{
    Q_UNUSED(addr);
    Q_UNUSED(length);
}

void DebuggerEngine::setRegisterValue(int regnr, const QString &value)
{
    Q_UNUSED(regnr);
    Q_UNUSED(value);
}

void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
{
499 500 501 502
    if (d->m_masterEngine) {
        d->m_masterEngine->showMessage(msg, channel, timeout);
        return;
    }
503 504
    //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
    //    qDebug() << qPrintable(msg) << "IN STATE" << state();
505
    debuggerCore()->showMessage(msg, channel, timeout);
506 507 508 509 510
    if (d->m_runControl) {
        d->m_runControl->showMessage(msg, channel);
    } else {
        qWarning("Warning: %s (no active run control)", qPrintable(msg));
    }
511 512 513 514
}

void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
{
515 516
    QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
    QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
517

518 519 520 521 522 523 524
    d->m_progress.setProgressRange(0, 1000);
    Core::FutureProgress *fp = Core::ICore::instance()->progressManager()
        ->addTask(d->m_progress.future(),
        tr("Launching"), _("Debugger.Launcher"));
    fp->setKeepOnFinish(Core::FutureProgress::DontKeepOnFinish);
    d->m_progress.reportStarted();

525 526 527 528 529
    d->m_runControl = runControl;

    d->m_inferiorPid = d->m_startParameters.attachPID > 0
        ? d->m_startParameters.attachPID : 0;

530 531
    if (!d->m_startParameters.environment.size())
        d->m_startParameters.environment = Utils::Environment();
532 533

    const unsigned engineCapabilities = debuggerCapabilities();
hjk's avatar
hjk committed
534
    debuggerCore()->action(OperateByInstruction)
535 536
        ->setEnabled(engineCapabilities & DisassemblerCapability);

537 538
    QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
         qDebug() << state());
539 540
    d->m_lastGoodState = DebuggerNotReady;
    d->m_targetState = DebuggerNotReady;
541
    d->m_progress.setProgressValue(200);
542
    d->queueSetupEngine();
543 544 545 546
}

void DebuggerEngine::resetLocation()
{
547 548
    // Do it after some delay to avoid flicker.
    d->scheduleResetLocation();
549 550
}

551
void DebuggerEngine::gotoLocation(const Location &loc)
552
{
553 554 555 556 557
    if (debuggerCore()->boolSetting(OperateByInstruction) || !loc.hasDebugInfo()) {
        d->m_disassemblerAgent.setTryMixed(true);
        d->m_disassemblerAgent.setLocation(loc);
        return;
    }
558 559 560 561
    // CDB might hit on breakpoints while shutting down.
    //if (m_shuttingDown)
    //    return;

562
    d->resetLocation();
563

564 565
    const QString file = loc.fileName();
    const int line = loc.lineNumber();
hjk's avatar
hjk committed
566 567
    EditorManager *editorManager = EditorManager::instance();
    QList<IEditor *> editors = editorManager->editorsForFileName(file);
568
    IEditor *editor = 0;
hjk's avatar
hjk committed
569
    if (editors.isEmpty()) {
570 571 572 573 574 575 576 577
        editor = editorManager->openEditor(file, QString(),
            EditorManager::IgnoreNavigationHistory);
        if (editor) {
            editors.append(editor);
            editor->setProperty(Constants::OPENED_BY_DEBUGGER, true);
        }
    } else {
        editor = editors.back();
hjk's avatar
hjk committed
578
    }
579
    ITextEditor *texteditor = qobject_cast<ITextEditor *>(editor);
hjk's avatar
hjk committed
580 581 582
    if (texteditor)
        texteditor->gotoLine(line, 0);

583
    if (loc.needsMarker())
584
        d->m_locationMark.reset(new LocationMark(file, line));
585 586

    // FIXME: Breaks with split views.
587
    if (!d->m_memoryAgent.hasVisibleEditor() || loc.needsRaise())
588
        editorManager->activateEditor(editor);
589
    //qDebug() << "MEMORY: " << d->m_memoryAgent.hasVisibleEditor();
590 591
}

592 593 594
// Called from RunControl.
void DebuggerEngine::handleStartFailed()
{
595
    showMessage("HANDLE RUNCONTROL START FAILED");
596
    d->m_runControl = 0;
597
    d->m_progress.setProgressValue(900);
598 599
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
600 601
}

602 603
// Called from RunControl.
void DebuggerEngine::handleFinished()
604
{
605
    showMessage("HANDLE RUNCONTROL FINISHED");
606
    d->m_runControl = 0;
607 608 609 610
    modulesHandler()->removeAll();
    stackHandler()->removeAll();
    threadsHandler()->removeAll();
    watchHandler()->cleanup();
611
    d->m_progress.setProgressValue(1000);
612
    d->m_progress.reportFinished();
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
}

const DebuggerStartParameters &DebuggerEngine::startParameters() const
{
    return d->m_startParameters;
}

DebuggerStartParameters &DebuggerEngine::startParameters()
{
    return d->m_startParameters;
}


//////////////////////////////////////////////////////////////////////
//
// Dumpers. "Custom dumpers" are a library compiled against the current
// Qt containing functions to evaluate values of Qt classes
// (such as QString, taking pointers to their addresses).
// The library must be loaded into the debuggee.
//
//////////////////////////////////////////////////////////////////////

bool DebuggerEngine::qtDumperLibraryEnabled() const
{
hjk's avatar
hjk committed
637
    return debuggerCore()->boolSetting(UseDebuggingHelpers);
638 639 640 641
}

QStringList DebuggerEngine::qtDumperLibraryLocations() const
{
hjk's avatar
hjk committed
642
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool()) {
643
        const QString customLocation =
hjk's avatar
hjk committed
644
            debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
645 646 647 648 649 650 651 652 653
        const QString location =
            tr("%1 (explicitly set in the Debugger Options)").arg(customLocation);
        return QStringList(location);
    }
    return d->m_startParameters.dumperLibraryLocations;
}

void DebuggerEngine::showQtDumperLibraryWarning(const QString &details)
{
654
    debuggerCore()->showQtDumperLibraryWarning(details);
655 656 657 658
}

QString DebuggerEngine::qtDumperLibraryName() const
{
hjk's avatar
hjk committed
659 660
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool())
        return debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
661 662 663 664 665 666 667 668
    return startParameters().dumperLibrary;
}

DebuggerState DebuggerEngine::state() const
{
    return d->m_state;
}

hjk's avatar
hjk committed
669
DebuggerState DebuggerEngine::lastGoodState() const
670
{
hjk's avatar
hjk committed
671 672 673 674 675 676 677
    return d->m_lastGoodState;
}

DebuggerState DebuggerEngine::targetState() const
{
    return d->m_targetState;
}
678

hjk's avatar
hjk committed
679 680 681
static bool isAllowedTransition(DebuggerState from, DebuggerState to)
{
    switch (from) {
682
    case DebuggerNotReady:
683
        return to == EngineSetupRequested;
684

hjk's avatar
hjk committed
685
    case EngineSetupRequested:
686 687
        return to == EngineSetupOk || to == EngineSetupFailed;
    case EngineSetupFailed:
688 689 690
        // In is the engine's task to go into a proper "Shutdown"
        // state before calling notifyEngineSetupFailed
        return to == DebuggerFinished;
691
    case EngineSetupOk:
hjk's avatar
hjk committed
692
        return to == InferiorSetupRequested || to == EngineShutdownRequested;
693

hjk's avatar
hjk committed
694
    case InferiorSetupRequested:
695
        return to == InferiorSetupOk || to == InferiorSetupFailed;
hjk's avatar
hjk committed
696
    case InferiorSetupFailed:
hjk's avatar
hjk committed
697
        return to == EngineShutdownRequested;
698 699
    case InferiorSetupOk:
        return to == EngineRunRequested;
hjk's avatar
hjk committed
700 701

    case EngineRunRequested:
hjk's avatar
hjk committed
702 703 704 705
        return to == EngineRunFailed
            || to == InferiorRunOk
            || to == InferiorStopOk
            || to == InferiorUnrunnable;
hjk's avatar
hjk committed
706
    case EngineRunFailed:
707
        return to == EngineShutdownRequested;
hjk's avatar
hjk committed
708 709 710 711 712 713

    case InferiorRunRequested:
        return to == InferiorRunOk || to == InferiorRunFailed;
    case InferiorRunFailed:
        return to == InferiorStopOk;
    case InferiorRunOk:
714 715 716
        return to == InferiorStopRequested
            || to == InferiorStopOk // A spontaneous stop.
            || to == InferiorExitOk;
hjk's avatar
hjk committed
717 718 719 720 721

    case InferiorStopRequested:
        return to == InferiorStopOk || to == InferiorStopFailed;
    case InferiorStopOk:
        return to == InferiorRunRequested || to == InferiorShutdownRequested
722
            || to == InferiorStopOk || InferiorExitOk;
723
    case InferiorStopFailed:
hjk's avatar
hjk committed
724
        return to == EngineShutdownRequested;
725

726 727 728
    case InferiorExitOk:
        return to == InferiorShutdownOk;

729
    case InferiorUnrunnable:
hjk's avatar
hjk committed
730 731 732 733 734
        return to == InferiorShutdownRequested;
    case InferiorShutdownRequested:
        return to == InferiorShutdownOk || to == InferiorShutdownFailed;
    case InferiorShutdownOk:
        return to == EngineShutdownRequested;
735
    case InferiorShutdownFailed:
hjk's avatar
hjk committed
736
        return to == EngineShutdownRequested;
737

hjk's avatar
hjk committed
738
    case EngineShutdownRequested:
739
        return to == EngineShutdownOk || to == EngineShutdownFailed;
hjk's avatar
hjk committed
740 741 742 743 744 745
    case EngineShutdownOk:
        return to == DebuggerFinished;
    case EngineShutdownFailed:
        return to == DebuggerFinished;

    case DebuggerFinished:
746
        return to == EngineSetupRequested; // Happens on restart.
747 748
    }

749
    qDebug() << "UNKNOWN DEBUGGER STATE:" << from;
750 751 752
    return false;
}

753 754 755 756 757 758 759 760 761 762 763 764 765
void DebuggerEngine::setupSlaveEngine()
{
    QTC_ASSERT(state() == DebuggerNotReady, /**/);
    d->queueSetupEngine();
}

void DebuggerEnginePrivate::doSetupEngine()
{
    m_engine->showMessage(_("CALL: SETUP ENGINE"));
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << m_engine << state());
    m_engine->setupEngine();
}

766
void DebuggerEngine::notifyEngineSetupFailed()
hjk's avatar
hjk committed
767
{
hjk's avatar
hjk committed
768
    showMessage(_("NOTE: ENGINE SETUP FAILED"));
769
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
770
    setState(EngineSetupFailed);
771 772
    if (isMasterEngine())
        runControl()->startFailed();
hjk's avatar
hjk committed
773
    setState(DebuggerFinished);
hjk's avatar
hjk committed
774 775
}

776
void DebuggerEngine::notifyEngineSetupOk()
777
{
hjk's avatar
hjk committed
778
    showMessage(_("NOTE: ENGINE SETUP OK"));
779
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
780
    setState(EngineSetupOk);
hjk's avatar
hjk committed
781
    showMessage(_("QUEUE: SETUP INFERIOR"));
782
    if (isMasterEngine())
783 784 785 786 787 788 789
        d->queueSetupInferior();
}

void DebuggerEngine::setupSlaveInferior()
{
    QTC_ASSERT(state() == EngineSetupOk, /**/);
    d->queueSetupInferior();
790 791
}

hjk's avatar
hjk committed
792
void DebuggerEnginePrivate::doSetupInferior()
793
{
794
    m_engine->showMessage(_("CALL: SETUP INFERIOR"));
795
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << m_engine << state());
796
    m_progress.setProgressValue(250);
hjk's avatar
hjk committed
797 798 799 800 801
    m_engine->setupInferior();
}

void DebuggerEngine::notifyInferiorSetupFailed()
{
hjk's avatar
hjk committed
802
    showMessage(_("NOTE: INFERIOR SETUP FAILED"));
803
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state());
hjk's avatar
hjk committed
804
    setState(InferiorSetupFailed);
805 806
    if (isMasterEngine())
        d->queueShutdownEngine();
hjk's avatar
hjk committed
807 808 809 810
}

void DebuggerEngine::notifyInferiorSetupOk()
{
hjk's avatar
hjk committed
811
    showMessage(_("NOTE: INFERIOR SETUP OK"));
812 813 814 815
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state());
    setState(InferiorSetupOk);
    if (isMasterEngine())
        d->queueRunEngine();
hjk's avatar
hjk committed
816 817
}

818 819 820 821 822 823 824
void DebuggerEngine::runSlaveEngine()
{
    QTC_ASSERT(isSlaveEngine(), return);
    QTC_ASSERT(state() == InferiorSetupOk, /**/);
    d->queueRunEngine();
}

hjk's avatar
hjk committed
825 826
void DebuggerEnginePrivate::doRunEngine()
{
hjk's avatar
hjk committed
827
    m_engine->showMessage(_("CALL: RUN ENGINE"));
828
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << m_engine << state());
829
    m_progress.setProgressValue(300);
hjk's avatar
hjk committed
830 831 832
    m_engine->runEngine();
}

hjk's avatar
hjk committed
833 834
void DebuggerEngine::notifyInferiorUnrunnable()
{
hjk's avatar
hjk committed
835
    showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
836 837
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
838
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
839 840 841 842 843
    setState(InferiorUnrunnable);
}

void DebuggerEngine::notifyEngineRunFailed()
{
hjk's avatar
hjk committed
844
    showMessage(_("NOTE: ENGINE RUN FAILED"));
845
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
846 847 848
    d->m_progress.setProgressValue(900);
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
849
    setState(EngineRunFailed);
850 851
    if (isMasterEngine())
        d->queueShutdownEngine();
hjk's avatar
hjk committed
852 853 854 855
}

void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
{
hjk's avatar
hjk committed
856
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR RUN OK"));
857 858
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
859
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
860
    setState(InferiorRunOk);
hjk's avatar
hjk committed
861 862 863 864
}

void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
{
hjk's avatar
hjk committed
865
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR STOP OK"));
866 867
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
868
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
869
    setState(InferiorStopOk);
hjk's avatar
hjk committed
870 871 872 873
}

void DebuggerEngine::notifyInferiorRunRequested()
{
hjk's avatar
hjk committed
874
    showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
875
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << this << state());
hjk's avatar
hjk committed
876 877 878 879 880
    setState(InferiorRunRequested);
}

void DebuggerEngine::notifyInferiorRunOk()
{
hjk's avatar
hjk committed
881
    showMessage(_("NOTE: INFERIOR RUN OK"));
882
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
883 884 885 886 887
    setState(InferiorRunOk);
}

void DebuggerEngine::notifyInferiorRunFailed()
{
hjk's avatar
hjk committed
888
    showMessage(_("NOTE: INFERIOR RUN FAILED"));
889
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
890 891
    setState(InferiorRunFailed);
    setState(InferiorStopOk);
hjk's avatar
hjk committed
892 893
    if (isDying())
        d->queueShutdownInferior();
hjk's avatar
hjk committed
894 895 896 897
}

void DebuggerEngine::notifyInferiorStopOk()
{
hjk's avatar
hjk committed
898 899
    showMessage(_("NOTE: INFERIOR STOP OK"));
    // Ignore spurious notifications after we are set to die.
hjk's avatar
hjk committed
900
    if (isDying()) {
hjk's avatar
hjk committed
901 902 903 904 905 906 907 908 909 910 911 912 913
        showMessage(_("NOTE: ... WHILE DYING. "));
        // Forward state to "StopOk" if needed.
        if (state() == InferiorStopRequested
                || state() == InferiorRunRequested
                || state() == InferiorRunOk) {
            showMessage(_("NOTE: ... FORWARDING TO 'STOP OK'. "));
            setState(InferiorStopOk);
        }
        if (state() == InferiorStopOk || state() == InferiorStopFailed) {
            d->queueShutdownInferior();
        }
        showMessage(_("NOTE: ... IGNORING STOP MESSAGE"));
        return;
hjk's avatar
hjk committed
914
    }
915
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
hjk's avatar
hjk committed
916
    setState(InferiorStopOk);
hjk's avatar
hjk committed
917 918
}

hjk's avatar
hjk committed
919
void DebuggerEngine::notifyInferiorSpontaneousStop()
920
{
hjk's avatar
hjk committed
921
    showMessage(_("NOTE: INFERIOR SPONTANEOUES STOP"));
922
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state());
923
    setState(InferiorStopOk);
924 925
}

hjk's avatar
hjk committed
926
void DebuggerEngine::notifyInferiorStopFailed()
927
{