debuggerengine.cpp 41.7 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

hjk's avatar
hjk committed
81 82 83 84 85 86 87
//#define DEBUG_STATE 1
#if DEBUG_STATE
#   define SDEBUG(s) qDebug() << s
#else
#   define SDEBUG(s)
#endif
# define XSDEBUG(s) qDebug() << s
88

89

90 91 92 93 94 95
///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
//
///////////////////////////////////////////////////////////////////////

96 97
namespace Debugger {

Friedemann Kleint's avatar
Friedemann Kleint committed
98 99 100 101 102 103 104 105 106 107 108
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;
}

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

QDebug operator<<(QDebug str, const DebuggerStartParameters &sp)
{
    QDebug nospace = str.nospace();
    nospace << "executable=" << sp.executable
            << " coreFile=" << sp.coreFile
120
            << " processArgs=" << sp.processArgs
121 122 123 124 125 126 127
            << " 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
128
            << " useServerStartScript=" << sp.useServerStartScript
129 130 131 132 133
            << " serverStartScript=" << sp.serverStartScript
            << " toolchain=" << sp.toolChainType << '\n';
    return str;
}

134

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
///////////////////////////////////////////////////////////////////////
//
// 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() {}
};



157 158 159 160 161 162
//////////////////////////////////////////////////////////////////////
//
// DebuggerEnginePrivate
//
//////////////////////////////////////////////////////////////////////

163
class DebuggerEnginePrivate : public QObject
164
{
165 166
    Q_OBJECT

167 168 169 170 171 172
public:
    DebuggerEnginePrivate(DebuggerEngine *engine, const DebuggerStartParameters &sp)
      : m_engine(engine),
        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_isSlaveEngine(false),
182 183
        m_disassemblerAgent(engine),
        m_memoryAgent(engine)
184
    {
185
        connect(&m_locationTimer, SIGNAL(timeout()), SLOT(resetLocation()));
186
    }
187 188

    ~DebuggerEnginePrivate() {}
189

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

198 199
    void queueRunEngine()
    {
hjk's avatar
hjk committed
200 201 202 203 204
        m_engine->setState(EngineRunRequested);
        m_engine->showMessage(_("QUEUE: RUN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doRunEngine()));
    }

205 206
    void queueShutdownEngine()
    {
hjk's avatar
hjk committed
207 208 209 210 211
        m_engine->setState(EngineShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doShutdownEngine()));
    }

212 213
    void queueShutdownInferior()
    {
hjk's avatar
hjk committed
214 215 216 217 218
        m_engine->setState(InferiorShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
        QTimer::singleShot(0, this, SLOT(doShutdownInferior()));
    }

219 220
    void queueFinishDebugger()
    {
221 222 223 224
        QTC_ASSERT(state() == EngineShutdownOk
            || state() == EngineShutdownFailed, qDebug() << state());
        m_engine->setState(DebuggerFinished);
        m_engine->showMessage(_("QUEUE: FINISH DEBUGGER"));
hjk's avatar
hjk committed
225 226 227
        QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
    }

228 229
    void raiseApplication()
    {
hjk's avatar
hjk committed
230
        QTC_ASSERT(m_runControl, return);
231 232 233
        m_runControl->bringApplicationToForeground(m_inferiorPid);
    }

234
    void scheduleResetLocation()
235
    {
236
        m_stackHandler.scheduleResetLocation();
237 238 239 240
        m_locationTimer.setSingleShot(true);
        m_locationTimer.start(80);
    }

241
    void resetLocation()
242 243 244
    {
        m_locationTimer.stop();
        m_locationMark.reset();
245 246
        m_stackHandler.resetLocation();
        m_disassemblerAgent.resetLocation();
247 248
    }

249
public:
hjk's avatar
hjk committed
250 251
    DebuggerState state() const { return m_state; }

252 253 254 255
    DebuggerEngine *m_engine; // Not owned.
    DebuggerRunControl *m_runControl;  // Not owned.

    DebuggerStartParameters m_startParameters;
hjk's avatar
hjk committed
256 257

    // The current state.
258 259
    DebuggerState m_state;

hjk's avatar
hjk committed
260 261 262 263 264 265
    // The state we had before something unexpected happend.
    DebuggerState m_lastGoodState;

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

266 267 268 269 270 271 272 273
    qint64 m_inferiorPid;

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

276
    bool m_isSlaveEngine;
277 278
    DisassemblerAgent m_disassemblerAgent;
    MemoryAgent m_memoryAgent;
279 280
    QScopedPointer<TextEditor::BaseTextMark> m_locationMark;
    QTimer m_locationTimer;
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
};


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

DebuggerEngine::DebuggerEngine(const DebuggerStartParameters &startParameters)
  : d(new DebuggerEnginePrivate(this, startParameters))
{
}

DebuggerEngine::~DebuggerEngine()
{
297 298
    disconnect();
    delete d;
299 300
}

301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
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)
        SN(EngineRunRequested)
        SN(InferiorRunRequested)
        SN(InferiorRunOk)
        SN(InferiorRunFailed)
        SN(InferiorUnrunnable)
        SN(InferiorStopRequested)
        SN(InferiorStopOk)
        SN(InferiorStopFailed)
        SN(InferiorShutdownRequested)
        SN(InferiorShutdownOk)
        SN(InferiorShutdownFailed)
        SN(EngineShutdownRequested)
        SN(EngineShutdownOk)
        SN(EngineShutdownFailed)
        SN(DebuggerFinished)
    }
    return "<unknown>";
#    undef SN
}

332
void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
333
{
334
    showMessage(msg, StatusBar, timeout);
335
}
336

337 338 339 340 341 342
void DebuggerEngine::removeTooltip()
{
    watchHandler()->removeTooltip();
    hideDebuggerToolTip();
}

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
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
{
    return &d->m_modulesHandler;
}

RegisterHandler *DebuggerEngine::registerHandler() const
{
    return &d->m_registerHandler;
}

StackHandler *DebuggerEngine::stackHandler() const
{
    return &d->m_stackHandler;
}

ThreadsHandler *DebuggerEngine::threadsHandler() const
{
    return &d->m_threadsHandler;
}

WatchHandler *DebuggerEngine::watchHandler() const
{
    return &d->m_watchHandler;
}

SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
{
    return &d->m_sourceFilesHandler;
}

QAbstractItemModel *DebuggerEngine::modulesModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
387 388 389 390
    QAbstractItemModel *model = d->m_modulesHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ModulesModel"));
    return model;
391 392 393 394
}

QAbstractItemModel *DebuggerEngine::registerModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
395 396 397 398
    QAbstractItemModel *model = d->m_registerHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("RegisterModel"));
    return model;
399 400 401 402
}

QAbstractItemModel *DebuggerEngine::stackModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
403 404 405 406
    QAbstractItemModel *model = d->m_stackHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("StackModel"));
    return model;
407 408 409 410
}

QAbstractItemModel *DebuggerEngine::threadsModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
411 412 413 414
    QAbstractItemModel *model = d->m_threadsHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ThreadsModel"));
    return model;
415 416 417 418
}

QAbstractItemModel *DebuggerEngine::localsModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
419 420 421 422
    QAbstractItemModel *model = d->m_watchHandler.model(LocalsWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("LocalsModel"));
    return model;
423 424 425 426
}

QAbstractItemModel *DebuggerEngine::watchersModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
427 428 429 430
    QAbstractItemModel *model = d->m_watchHandler.model(WatchersWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("WatchersModel"));
    return model;
431 432 433 434
}

QAbstractItemModel *DebuggerEngine::returnModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
435 436 437 438
    QAbstractItemModel *model = d->m_watchHandler.model(ReturnWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ReturnModel"));
    return model;
439 440 441 442
}

QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
443 444 445 446
    QAbstractItemModel *model = d->m_sourceFilesHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("SourceFilesModel"));
    return model;
447 448
}

449
void DebuggerEngine::fetchMemory(MemoryAgent *, QObject *,
450 451 452 453 454 455 456 457 458 459 460 461 462 463
        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
{
464 465
    //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
    //    qDebug() << qPrintable(msg) << "IN STATE" << state();
466
    debuggerCore()->showMessage(msg, channel, timeout);
467 468 469 470 471
    if (d->m_runControl) {
        d->m_runControl->showMessage(msg, channel);
    } else {
        qWarning("Warning: %s (no active run control)", qPrintable(msg));
    }
472 473 474 475
}

void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
{
hjk's avatar
hjk committed
476
    if (!isSlaveEngine()) {
477
        d->m_progress.setProgressRange(0, 1000);
478 479 480
        Core::FutureProgress *fp = Core::ICore::instance()->progressManager()
            ->addTask(d->m_progress.future(),
            tr("Launching"), _("Debugger.Launcher"));
481
        fp->setKeepOnFinish(Core::FutureProgress::DontKeepOnFinish);
482 483
        d->m_progress.reportStarted();
    }
484 485
    QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
    QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
486 487 488 489 490 491

    d->m_runControl = runControl;

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

492 493
    if (!d->m_startParameters.environment.size())
        d->m_startParameters.environment = Utils::Environment();
494 495

    const unsigned engineCapabilities = debuggerCapabilities();
hjk's avatar
hjk committed
496
    debuggerCore()->action(OperateByInstruction)
497 498
        ->setEnabled(engineCapabilities & DisassemblerCapability);

499 500
    QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
         qDebug() << state());
501 502
    d->m_lastGoodState = DebuggerNotReady;
    d->m_targetState = DebuggerNotReady;
hjk's avatar
hjk committed
503
    setState(EngineSetupRequested);
504

505
    d->m_progress.setProgressValue(200);
hjk's avatar
hjk committed
506
    setupEngine();
507 508 509 510
}

void DebuggerEngine::resetLocation()
{
511 512
    // Do it after some delay to avoid flicker.
    d->scheduleResetLocation();
513 514
}

515
void DebuggerEngine::gotoLocation(const Location &loc)
516
{
517 518 519 520 521
    if (debuggerCore()->boolSetting(OperateByInstruction) || !loc.hasDebugInfo()) {
        d->m_disassemblerAgent.setTryMixed(true);
        d->m_disassemblerAgent.setLocation(loc);
        return;
    }
522 523 524 525
    // CDB might hit on breakpoints while shutting down.
    //if (m_shuttingDown)
    //    return;

526
    d->resetLocation();
527

528 529
    const QString file = loc.fileName();
    const int line = loc.lineNumber();
hjk's avatar
hjk committed
530 531
    EditorManager *editorManager = EditorManager::instance();
    QList<IEditor *> editors = editorManager->editorsForFileName(file);
532
    IEditor *editor = 0;
hjk's avatar
hjk committed
533
    if (editors.isEmpty()) {
534 535 536 537 538 539 540 541
        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
542
    }
543
    ITextEditor *texteditor = qobject_cast<ITextEditor *>(editor);
hjk's avatar
hjk committed
544 545 546
    if (texteditor)
        texteditor->gotoLine(line, 0);

547
    if (loc.needsMarker())
548
        d->m_locationMark.reset(new LocationMark(file, line));
549 550

    // FIXME: Breaks with split views.
551
    if (!d->m_memoryAgent.hasVisibleEditor() || loc.needsRaise())
552
        editorManager->activateEditor(editor);
553
    //qDebug() << "MEMORY: " << d->m_memoryAgent.hasVisibleEditor();
554 555
}

556 557 558
// Called from RunControl.
void DebuggerEngine::handleStartFailed()
{
559
    showMessage("HANDLE RUNCONTROL START FAILED");
560
    d->m_runControl = 0;
561
    d->m_progress.setProgressValue(900);
562 563
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
564 565
}

566 567
// Called from RunControl.
void DebuggerEngine::handleFinished()
568
{
569
    showMessage("HANDLE RUNCONTROL FINISHED");
570
    d->m_runControl = 0;
571 572 573 574
    modulesHandler()->removeAll();
    stackHandler()->removeAll();
    threadsHandler()->removeAll();
    watchHandler()->cleanup();
575
    d->m_progress.setProgressValue(1000);
576
    d->m_progress.reportFinished();
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
}

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
601
    return debuggerCore()->boolSetting(UseDebuggingHelpers);
602 603 604 605
}

QStringList DebuggerEngine::qtDumperLibraryLocations() const
{
hjk's avatar
hjk committed
606
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool()) {
607
        const QString customLocation =
hjk's avatar
hjk committed
608
            debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
609 610 611 612 613 614 615 616 617
        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)
{
618
    debuggerCore()->showQtDumperLibraryWarning(details);
619 620 621 622
}

QString DebuggerEngine::qtDumperLibraryName() const
{
hjk's avatar
hjk committed
623 624
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool())
        return debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
625 626 627 628 629 630 631 632
    return startParameters().dumperLibrary;
}

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

hjk's avatar
hjk committed
633
DebuggerState DebuggerEngine::lastGoodState() const
634
{
hjk's avatar
hjk committed
635 636 637 638 639 640 641
    return d->m_lastGoodState;
}

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

hjk's avatar
hjk committed
643 644 645
static bool isAllowedTransition(DebuggerState from, DebuggerState to)
{
    switch (from) {
646
    case DebuggerNotReady:
647
        return to == EngineSetupRequested;
648

hjk's avatar
hjk committed
649
    case EngineSetupRequested:
650 651
        return to == EngineSetupOk || to == EngineSetupFailed;
    case EngineSetupFailed:
652 653 654
        // In is the engine's task to go into a proper "Shutdown"
        // state before calling notifyEngineSetupFailed
        return to == DebuggerFinished;
655
    case EngineSetupOk:
hjk's avatar
hjk committed
656
        return to == InferiorSetupRequested || to == EngineShutdownRequested;
657

hjk's avatar
hjk committed
658 659
    case InferiorSetupRequested:
        return to == EngineRunRequested || to == InferiorSetupFailed;
hjk's avatar
hjk committed
660
    case InferiorSetupFailed:
hjk's avatar
hjk committed
661 662 663 664 665 666 667
        return to == EngineShutdownRequested;

    case EngineRunRequested:
        return to == InferiorRunRequested || to == InferiorStopRequested
            || to == InferiorUnrunnable || to == EngineRunFailed;

    case EngineRunFailed:
668
        return to == EngineShutdownRequested;
hjk's avatar
hjk committed
669 670 671 672 673 674 675 676 677 678 679 680 681

    case InferiorRunRequested:
        return to == InferiorRunOk || to == InferiorRunFailed;
    case InferiorRunFailed:
        return to == InferiorStopOk;
    case InferiorRunOk:
        return to == InferiorStopRequested || to == InferiorStopOk;

    case InferiorStopRequested:
        return to == InferiorStopOk || to == InferiorStopFailed;
    case InferiorStopOk:
        return to == InferiorRunRequested || to == InferiorShutdownRequested
            || to == InferiorStopOk;
682
    case InferiorStopFailed:
hjk's avatar
hjk committed
683
        return to == EngineShutdownRequested;
684 685

    case InferiorUnrunnable:
hjk's avatar
hjk committed
686 687 688 689 690
        return to == InferiorShutdownRequested;
    case InferiorShutdownRequested:
        return to == InferiorShutdownOk || to == InferiorShutdownFailed;
    case InferiorShutdownOk:
        return to == EngineShutdownRequested;
691
    case InferiorShutdownFailed:
hjk's avatar
hjk committed
692
        return to == EngineShutdownRequested;
693

hjk's avatar
hjk committed
694
    case EngineShutdownRequested:
695
        return to == EngineShutdownOk || to == EngineShutdownFailed;
hjk's avatar
hjk committed
696 697 698 699 700 701
    case EngineShutdownOk:
        return to == DebuggerFinished;
    case EngineShutdownFailed:
        return to == DebuggerFinished;

    case DebuggerFinished:
702
        return to == EngineSetupRequested; // Happens on restart.
703 704
    }

705
    qDebug() << "UNKNOWN DEBUGGER STATE:" << from;
706 707 708
    return false;
}

709
void DebuggerEngine::notifyEngineSetupFailed()
hjk's avatar
hjk committed
710
{
hjk's avatar
hjk committed
711
    showMessage(_("NOTE: ENGINE SETUP FAILED"));
hjk's avatar
hjk committed
712
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
713
    setState(EngineSetupFailed);
hjk's avatar
hjk committed
714 715
    QTC_ASSERT(d->m_runControl, return);
    d->m_runControl->startFailed();
hjk's avatar
hjk committed
716
    setState(DebuggerFinished);
hjk's avatar
hjk committed
717 718
}

719
void DebuggerEngine::notifyEngineSetupOk()
720
{
hjk's avatar
hjk committed
721
    showMessage(_("NOTE: ENGINE SETUP OK"));
hjk's avatar
hjk committed
722
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
723
    setState(EngineSetupOk);
hjk's avatar
hjk committed
724
    QTC_ASSERT(d->m_runControl, return);
hjk's avatar
hjk committed
725
    showMessage(_("QUEUE: SETUP INFERIOR"));
hjk's avatar
hjk committed
726
    QTimer::singleShot(0, d, SLOT(doSetupInferior()));
727 728
}

hjk's avatar
hjk committed
729
void DebuggerEnginePrivate::doSetupInferior()
730
{
731
    m_engine->showMessage(_("CALL: SETUP INFERIOR"));
hjk's avatar
hjk committed
732
    QTC_ASSERT(state() == EngineSetupOk, qDebug() << state());
733
    m_progress.setProgressValue(250);
hjk's avatar
hjk committed
734
    m_engine->setState(InferiorSetupRequested);
hjk's avatar
hjk committed
735 736 737 738 739
    m_engine->setupInferior();
}

void DebuggerEngine::notifyInferiorSetupFailed()
{
hjk's avatar
hjk committed
740
    showMessage(_("NOTE: INFERIOR SETUP FAILED"));
hjk's avatar
hjk committed
741
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
742
    setState(InferiorSetupFailed);
hjk's avatar
hjk committed
743
    d->queueShutdownEngine();
hjk's avatar
hjk committed
744 745 746 747
}

void DebuggerEngine::notifyInferiorSetupOk()
{
hjk's avatar
hjk committed
748
    showMessage(_("NOTE: INFERIOR SETUP OK"));
hjk's avatar
hjk committed
749
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
750
    d->queueRunEngine();
hjk's avatar
hjk committed
751 752 753 754
}

void DebuggerEnginePrivate::doRunEngine()
{
hjk's avatar
hjk committed
755
    m_engine->showMessage(_("CALL: RUN ENGINE"));
hjk's avatar
hjk committed
756
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
757
    m_progress.setProgressValue(300);
hjk's avatar
hjk committed
758 759 760
    m_engine->runEngine();
}

hjk's avatar
hjk committed
761 762
void DebuggerEngine::notifyInferiorUnrunnable()
{
hjk's avatar
hjk committed
763
    showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
764 765
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
766 767 768 769 770 771
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    setState(InferiorUnrunnable);
}

void DebuggerEngine::notifyEngineRunFailed()
{
hjk's avatar
hjk committed
772
    showMessage(_("NOTE: ENGINE RUN FAILED"));
hjk's avatar
hjk committed
773
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
774 775 776
    d->m_progress.setProgressValue(900);
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
777
    setState(EngineRunFailed);
778
    d->queueShutdownEngine();
hjk's avatar
hjk committed
779 780 781 782
}

void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
{
hjk's avatar
hjk committed
783
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR RUN OK"));
784 785
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
786 787 788 789 790 791 792
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    setState(InferiorRunRequested);
    notifyInferiorRunOk();
}

void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
{
hjk's avatar
hjk committed
793
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR STOP OK"));
794 795
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
796 797 798 799 800 801 802
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    setState(InferiorStopRequested);
    notifyInferiorStopOk();
}

void DebuggerEngine::notifyInferiorRunRequested()
{
hjk's avatar
hjk committed
803
    showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
hjk's avatar
hjk committed
804 805 806 807 808 809
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
    setState(InferiorRunRequested);
}

void DebuggerEngine::notifyInferiorRunOk()
{
hjk's avatar
hjk committed
810
    showMessage(_("NOTE: INFERIOR RUN OK"));
hjk's avatar
hjk committed
811 812 813 814 815 816
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
    setState(InferiorRunOk);
}

void DebuggerEngine::notifyInferiorRunFailed()
{
hjk's avatar
hjk committed
817
    showMessage(_("NOTE: INFERIOR RUN FAILED"));
hjk's avatar
hjk committed
818 819 820
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
    setState(InferiorRunFailed);
    setState(InferiorStopOk);
hjk's avatar
hjk committed
821 822
    if (isDying())
        d->queueShutdownInferior();
hjk's avatar
hjk committed
823 824 825 826
}

void DebuggerEngine::notifyInferiorStopOk()
{
hjk's avatar
hjk committed
827 828
    showMessage(_("NOTE: INFERIOR STOP OK"));
    // Ignore spurious notifications after we are set to die.
hjk's avatar
hjk committed
829
    if (isDying()) {
hjk's avatar
hjk committed
830 831 832 833 834 835 836 837 838 839 840 841 842
        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
843
    }
hjk's avatar
hjk committed
844 845
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
    setState(InferiorStopOk);
hjk's avatar
hjk committed
846 847
}

hjk's avatar
hjk committed
848
void DebuggerEngine::notifyInferiorSpontaneousStop()
849
{
hjk's avatar
hjk committed
850
    showMessage(_("NOTE: INFERIOR SPONTANEOUES STOP"));
hjk's avatar
hjk committed
851 852
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
    setState(InferiorStopOk);
853 854
}

hjk's avatar
hjk committed
855
void DebuggerEngine::notifyInferiorStopFailed()
856
{
hjk's avatar
hjk committed
857
    showMessage(_("NOTE: INFERIOR STOP FAILED"));
hjk's avatar
hjk committed
858 859
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
    setState(InferiorStopFailed);
hjk's avatar
hjk committed
860
    d->queueShutdownEngine();
861 862 863 864
}

void DebuggerEnginePrivate::doInterruptInferior()
{
hjk's avatar
hjk committed
865 866
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
    m_engine->setState(InferiorStopRequested);
hjk's avatar
hjk committed
867
    m_engine->showMessage(_("CALL: INTERRUPT INFERIOR"));
868 869 870
    m_engine->interruptInferior();
}

hjk's avatar
hjk committed
871 872
void DebuggerEnginePrivate::doShutdownInferior()
{
873
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
874
    resetLocation();
hjk's avatar
hjk committed
875
    m_targetState = DebuggerFinished;
hjk's avatar
hjk committed
876
    m_engine->showMessage(_("CALL: SHUTDOWN INFERIOR"));
hjk's avatar
hjk committed
877 878 879 880 881 882
    m_engine->shutdownInferior();
}

void DebuggerEngine::notifyInferiorShutdownOk()
{
    showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
hjk's avatar
hjk committed
883
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
884 885
    d->m_lastGoodState = DebuggerNotReady; // A "neutral" value.
    setState(InferiorShutdownOk);
hjk's avatar
hjk committed
886
    d->queueShutdownEngine();
hjk's avatar
hjk committed
887 888 889 890 891
}

void DebuggerEngine::notifyInferiorShutdownFailed()
{
    showMessage(_("INFERIOR SHUTDOWN FAILED"));
Friedemann Kleint's avatar
Friedemann Kleint committed
892
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
hjk's avatar
hjk committed
893
    setState(InferiorShutdownFailed);
hjk's avatar
hjk committed
894
    d->queueShutdownEngine();
hjk's avatar
hjk committed
895 896 897 898
}

void DebuggerEngine::notifyInferiorIll()
{
hjk's avatar
hjk committed
899
    showMessage(_("NOTE: INFERIOR ILL"));
hjk's avatar
hjk committed
900 901 902 903 904 905 906 907 908 909 910
    // This can be issued in almost any state. The inferior could still be
    // alive as some previous notifications might have been bogus.
    d->m_targetState = DebuggerFinished;
    d->m_lastGoodState = d->m_state;
    if (state() == InferiorRunRequested) {
        // We asked for running, but did not see a response.
        // Assume the inferior is dead.
        // FIXME: Use timeout?
        setState(InferiorRunFailed);
        setState(InferiorStopOk);
    }
hjk's avatar
hjk committed
911
    d->queueShutdownInferior();
hjk's avatar
hjk committed
912 913 914 915
}

void DebuggerEnginePrivate::doShutdownEngine()
{
916
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
917
    m_targetState = DebuggerFinished;
hjk's avatar
hjk committed
918
    m_engine->showMessage(_("CALL: SHUTDOWN ENGINE"));
hjk's avatar
hjk committed
919 920 921 922 923
    m_engine->shutdownEngine();
}

void DebuggerEngine::notifyEngineShutdownOk()
{
hjk's avatar
hjk committed
924
    showMessage(_("NOTE: ENGINE SHUTDOWN OK"));
hjk's avatar
hjk committed
925 926
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
    setState(EngineShutdownOk);
927
    d->queueFinishDebugger();
hjk's avatar
hjk committed
928 929 930
}

void DebuggerEngine::notifyEngineShutdownFailed()
hjk's avatar
hjk committed
931
{
hjk's avatar
hjk committed
932
    showMessage(_("NOTE: ENGINE SHUTDOWN FAILED"));
hjk's avatar
hjk committed
933 934
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
    setState(EngineShutdownFailed);
935
    d->queueFinishDebugger();
hjk's avatar
hjk committed
936 937 938 939
}

void DebuggerEnginePrivate::doFinishDebugger()
{
hjk's avatar
hjk committed
940
    m_engine->showMessage(_("NOTE: FINISH DEBUGGER"));
941
    QTC_ASSERT(state() == DebuggerFinished, qDebug() << state());
942
    resetLocation();
943 944 945 946
    if (!m_engine->isSlaveEngine()) {
        QTC_ASSERT(m_runControl, return);
        m_runControl->debuggingFinished();
    }
hjk's avatar
hjk committed
947 948 949 950
}

void DebuggerEngine::notifyEngineIll()
{
hjk's avatar
hjk committed
951
    showMessage(_("NOTE: ENGINE ILL ******"));
hjk's avatar
hjk committed
952 953
    d->m_targetState = DebuggerFinished;
    d->m_lastGoodState = d->m_state;
hjk's avatar
hjk committed
954 955 956
    switch (state<