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
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
{
370 371 372
    return d->m_masterEngine
        ? d->m_masterEngine->modulesHandler()
        : &d->m_modulesHandler;
373 374 375 376
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

483
void DebuggerEngine::fetchMemory(MemoryAgent *, QObject *,
484 485 486 487 488 489 490 491 492 493 494 495 496 497
        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
{
498 499 500 501
    if (d->m_masterEngine) {
        d->m_masterEngine->showMessage(msg, channel, timeout);
        return;
    }
502 503
    //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
    //    qDebug() << qPrintable(msg) << "IN STATE" << state();
504
    debuggerCore()->showMessage(msg, channel, timeout);
505 506 507 508 509
    if (d->m_runControl) {
        d->m_runControl->showMessage(msg, channel);
    } else {
        qWarning("Warning: %s (no active run control)", qPrintable(msg));
    }
510 511 512 513
}

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

517 518 519 520 521 522 523
    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();

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

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

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

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

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

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

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

561
    d->resetLocation();
562

563 564
    const QString file = loc.fileName();
    const int line = loc.lineNumber();
hjk's avatar
hjk committed
565 566
    EditorManager *editorManager = EditorManager::instance();
    QList<IEditor *> editors = editorManager->editorsForFileName(file);
567
    IEditor *editor = 0;
hjk's avatar
hjk committed
568
    if (editors.isEmpty()) {
569 570 571 572 573 574 575 576
        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
577
    }
578
    ITextEditor *texteditor = qobject_cast<ITextEditor *>(editor);
hjk's avatar
hjk committed
579 580 581
    if (texteditor)
        texteditor->gotoLine(line, 0);

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

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

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

601 602
// Called from RunControl.
void DebuggerEngine::handleFinished()
603
{
604
    showMessage("HANDLE RUNCONTROL FINISHED");
605
    d->m_runControl = 0;
606 607
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
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
    modulesHandler()->removeAll();
    stackHandler()->removeAll();
    threadsHandler()->removeAll();
    watchHandler()->cleanup();
}

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
636
    return debuggerCore()->boolSetting(UseDebuggingHelpers);
637 638 639 640
}

QStringList DebuggerEngine::qtDumperLibraryLocations() const
{
hjk's avatar
hjk committed
641
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool()) {
642
        const QString customLocation =
hjk's avatar
hjk committed
643
            debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
644 645 646 647 648 649 650 651 652
        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)
{
653
    debuggerCore()->showQtDumperLibraryWarning(details);
654 655 656 657
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

752 753 754 755 756 757 758 759 760 761 762 763 764
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();
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

void DebuggerEngine::notifyInferiorStopOk()
{
hjk's avatar
hjk committed
897 898
    showMessage(_("NOTE: INFERIOR STOP OK"));
    // Ignore spurious notifications after we are set to die.
hjk's avatar
hjk committed
899
    if (isDying()) {
hjk's avatar
hjk committed
900 901 902 903 904 905 906 907 908 909 910 911 912
        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
913
    }
914
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
hjk's avatar
hjk committed
915
    setState(InferiorStopOk);
hjk's avatar
hjk committed
916 917
}

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

hjk's avatar
hjk committed
925
void DebuggerEngine::notifyInferiorStopFailed()
926
{
hjk's avatar
hjk committed
927
    showMessage(_("NOTE: INFERIOR STOP FAILED"));
928
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());