debuggerengine.cpp 45.2 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"
Friedemann Kleint's avatar
Friedemann Kleint committed
41
#include "debuggerstartparameters.h"
42

43 44
#include "memoryagent.h"
#include "disassembleragent.h"
45 46 47 48 49 50 51 52 53
#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
54
#include <coreplugin/icore.h>
55
#include <coreplugin/ifile.h>
hjk's avatar
hjk committed
56
#include <coreplugin/editormanager/editormanager.h>
57 58
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
hjk's avatar
hjk committed
59 60

#include <texteditor/itexteditor.h>
61
#include <texteditor/basetextmark.h>
hjk's avatar
hjk committed
62

63 64 65 66 67
#include <utils/savedaction.h>
#include <utils/qtcassert.h>

#include <QtCore/QDebug>
#include <QtCore/QTimer>
68
#include <QtCore/QFutureInterface>
69

70
#include <QtGui/QMessageBox>
71

hjk's avatar
hjk committed
72
using namespace Core;
73
using namespace Debugger::Internal;
hjk's avatar
hjk committed
74 75
using namespace ProjectExplorer;
using namespace TextEditor;
76

77 78 79 80
enum { debug = 0 };

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

82

83 84 85 86 87 88
///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
//
///////////////////////////////////////////////////////////////////////

89 90
namespace Debugger {

Friedemann Kleint's avatar
Friedemann Kleint committed
91 92 93 94 95 96 97 98 99 100 101
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;
}

102 103
QDebug operator<<(QDebug d, DebuggerState state)
{
hjk's avatar
hjk committed
104 105
    //return d << DebuggerEngine::stateName(state) << '(' << int(state) << ')';
    return d << DebuggerEngine::stateName(state);
106 107 108 109 110 111 112
}

QDebug operator<<(QDebug str, const DebuggerStartParameters &sp)
{
    QDebug nospace = str.nospace();
    nospace << "executable=" << sp.executable
            << " coreFile=" << sp.coreFile
113
            << " processArgs=" << sp.processArgs
114 115 116 117 118 119 120
            << " 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
121
            << " useServerStartScript=" << sp.useServerStartScript
122
            << " serverStartScript=" << sp.serverStartScript
123
            << " abi=" << sp.toolChainAbi.toString() << '\n';
124 125 126
    return str;
}

127

128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
///////////////////////////////////////////////////////////////////////
//
// 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() {}
};



150 151 152 153 154 155
//////////////////////////////////////////////////////////////////////
//
// DebuggerEnginePrivate
//
//////////////////////////////////////////////////////////////////////

156
class DebuggerEnginePrivate : public QObject
157
{
158 159
    Q_OBJECT

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

    ~DebuggerEnginePrivate() {}
185

186
public slots:
187
    void doSetupEngine();
hjk's avatar
hjk committed
188 189
    void doSetupInferior();
    void doRunEngine();
hjk's avatar
hjk committed
190 191
    void doShutdownEngine();
    void doShutdownInferior();
192
    void doInterruptInferior();
hjk's avatar
hjk committed
193
    void doFinishDebugger();
hjk's avatar
hjk committed
194

195 196 197 198 199 200 201 202 203 204 205 206 207 208
    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()));
    }

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

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

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

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

239 240
    void raiseApplication()
    {
241 242
        QTC_ASSERT(runControl(), return);
        runControl()->bringApplicationToForeground(m_inferiorPid);
243 244
    }

245
    void scheduleResetLocation()
246
    {
247
        m_stackHandler.scheduleResetLocation();
248 249 250 251
        m_locationTimer.setSingleShot(true);
        m_locationTimer.start(80);
    }

252
    void resetLocation()
253 254 255
    {
        m_locationTimer.stop();
        m_locationMark.reset();
256 257
        m_stackHandler.resetLocation();
        m_disassemblerAgent.resetLocation();
258 259
    }

260
public:
hjk's avatar
hjk committed
261
    DebuggerState state() const { return m_state; }
262 263 264
    bool isMasterEngine() const { return m_engine->isMasterEngine(); }
    DebuggerRunControl *runControl() const
        { return m_masterEngine ? m_masterEngine->runControl() : m_runControl; }
hjk's avatar
hjk committed
265

266
    DebuggerEngine *m_engine; // Not owned.
267
    DebuggerEngine *m_masterEngine; // Not owned
268 269 270
    DebuggerRunControl *m_runControl;  // Not owned.

    DebuggerStartParameters m_startParameters;
hjk's avatar
hjk committed
271 272

    // The current state.
273 274
    DebuggerState m_state;

hjk's avatar
hjk committed
275 276 277 278 279 280
    // The state we had before something unexpected happend.
    DebuggerState m_lastGoodState;

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

281 282 283 284 285 286 287 288
    qint64 m_inferiorPid;

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

291 292
    DisassemblerAgent m_disassemblerAgent;
    MemoryAgent m_memoryAgent;
293 294
    QScopedPointer<TextEditor::BaseTextMark> m_locationMark;
    QTimer m_locationTimer;
295 296

    bool m_isStateDebugging;
297 298 299 300 301 302 303 304 305
};


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

306 307 308
DebuggerEngine::DebuggerEngine(const DebuggerStartParameters &startParameters,
        DebuggerEngine *parentEngine)
  : d(new DebuggerEnginePrivate(this, parentEngine, startParameters))
309 310 311 312 313
{
}

DebuggerEngine::~DebuggerEngine()
{
314 315
    disconnect();
    delete d;
316 317
}

318 319 320 321 322 323 324 325 326 327 328
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)
329
        SN(InferiorSetupOk)
330 331 332 333 334 335 336 337
        SN(EngineRunRequested)
        SN(InferiorRunRequested)
        SN(InferiorRunOk)
        SN(InferiorRunFailed)
        SN(InferiorUnrunnable)
        SN(InferiorStopRequested)
        SN(InferiorStopOk)
        SN(InferiorStopFailed)
338
        SN(InferiorExitOk)
339 340 341 342 343 344 345 346 347 348 349 350
        SN(InferiorShutdownRequested)
        SN(InferiorShutdownOk)
        SN(InferiorShutdownFailed)
        SN(EngineShutdownRequested)
        SN(EngineShutdownOk)
        SN(EngineShutdownFailed)
        SN(DebuggerFinished)
    }
    return "<unknown>";
#    undef SN
}

351
void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
352
{
353
    showMessage(msg, StatusBar, timeout);
354
}
355

356

357 358 359 360 361 362 363 364 365 366 367 368 369 370
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
{
371 372 373
    return d->m_masterEngine
        ? d->m_masterEngine->modulesHandler()
        : &d->m_modulesHandler;
374 375 376 377
}

RegisterHandler *DebuggerEngine::registerHandler() const
{
378 379 380
    return d->m_masterEngine
        ? d->m_masterEngine->registerHandler()
        : &d->m_registerHandler;
381 382 383 384
}

StackHandler *DebuggerEngine::stackHandler() const
{
hjk's avatar
hjk committed
385 386 387 388
    //return d->m_masterEngine
    //    ? d->m_masterEngine->stackHandler()
    //    : &d->m_stackHandler;
    return &d->m_stackHandler;
389 390 391 392
}

ThreadsHandler *DebuggerEngine::threadsHandler() const
{
393 394 395
    return d->m_masterEngine
        ? d->m_masterEngine->threadsHandler()
        : &d->m_threadsHandler;
396 397 398 399
}

WatchHandler *DebuggerEngine::watchHandler() const
{
400 401 402
    return d->m_masterEngine
        ? d->m_masterEngine->watchHandler()
        : &d->m_watchHandler;
403 404 405 406
}

SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
{
407 408 409
    return d->m_masterEngine
        ? d->m_masterEngine->sourceFilesHandler()
        : &d->m_sourceFilesHandler;
410 411 412 413
}

QAbstractItemModel *DebuggerEngine::modulesModel() const
{
414
    QAbstractItemModel *model = modulesHandler()->model();
Friedemann Kleint's avatar
Friedemann Kleint committed
415 416 417
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ModulesModel"));
    return model;
418 419 420 421
}

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

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

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

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

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

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

468 469 470 471 472 473 474 475
QAbstractItemModel *DebuggerEngine::toolTipsModel() const
{
    QAbstractItemModel *model = watchHandler()->model(TooltipsWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("TooltipsModel"));
    return model;
}

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);
hjk's avatar
hjk committed
771
    if (isMasterEngine() && runControl())
772
        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()