debuggerengine.cpp 41.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** 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.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "debuggerengine.h"

#include "debuggeractions.h"
33
#include "debuggercore.h"
34
#include "debuggerplugin.h"
35
#include "debuggerrunner.h"
36
#include "debuggerstringutils.h"
37
#include "debuggertooltip.h"
38

39 40
#include "memoryagent.h"
#include "disassembleragent.h"
41 42 43 44 45 46 47 48 49
#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
50
#include <coreplugin/icore.h>
51
#include <coreplugin/ifile.h>
52 53
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
hjk's avatar
hjk committed
54

hjk's avatar
hjk committed
55
#include <projectexplorer/toolchain.h>
56
#include <projectexplorer/toolchaintype.h>
57

hjk's avatar
hjk committed
58
#include <texteditor/itexteditor.h>
59 60
#include <texteditor/basetexteditor.h>
#include <texteditor/basetextmark.h>
hjk's avatar
hjk committed
61

62
#include <utils/environment.h>
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

hjk's avatar
hjk committed
77 78 79 80 81 82 83
//#define DEBUG_STATE 1
#if DEBUG_STATE
#   define SDEBUG(s) qDebug() << s
#else
#   define SDEBUG(s)
#endif
# define XSDEBUG(s) qDebug() << s
84

85

86 87 88 89 90 91
///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
//
///////////////////////////////////////////////////////////////////////

92 93
namespace Debugger {

94
DebuggerStartParameters::DebuggerStartParameters() :
95
    isSnapshot(false),
96 97
    attachPID(-1),
    useTerminal(false),
98 99
    breakAtMain(false),
    qmlServerAddress("127.0.0.1"),
100
    qmlServerPort(0),
hjk's avatar
hjk committed
101
    useServerStartScript(false),
102
    connParams(SshConnectionParameters::NoProxy),
103
    toolChainType(ToolChain_UNKNOWN),
104 105
    startMode(NoStartMode),
    executableUid(0)
106 107
{}

hjk's avatar
hjk committed
108
QString DebuggerStartParameters::toolChainName() const
109
{
hjk's avatar
hjk committed
110
    return ToolChain::toolChainName(ProjectExplorer::ToolChainType(toolChainType));
111 112 113 114
}

QDebug operator<<(QDebug d, DebuggerState state)
{
hjk's avatar
hjk committed
115 116
    //return d << DebuggerEngine::stateName(state) << '(' << int(state) << ')';
    return d << DebuggerEngine::stateName(state);
117 118 119 120 121 122 123
}

QDebug operator<<(QDebug str, const DebuggerStartParameters &sp)
{
    QDebug nospace = str.nospace();
    nospace << "executable=" << sp.executable
            << " coreFile=" << sp.coreFile
124
            << " processArgs=" << sp.processArgs
125 126 127 128 129 130 131
            << " 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
132
            << " useServerStartScript=" << sp.useServerStartScript
133 134 135 136 137 138 139 140 141 142
            << " serverStartScript=" << sp.serverStartScript
            << " toolchain=" << sp.toolChainType << '\n';
    return str;
}

const char *DebuggerEngine::stateName(int s)
{
#    define SN(x) case x: return #x;
    switch (s) {
        SN(DebuggerNotReady)
hjk's avatar
hjk committed
143
        SN(EngineSetupRequested)
144 145
        SN(EngineSetupOk)
        SN(EngineSetupFailed)
hjk's avatar
hjk committed
146 147
        SN(EngineRunFailed)
        SN(InferiorSetupRequested)
hjk's avatar
hjk committed
148
        SN(InferiorSetupFailed)
hjk's avatar
hjk committed
149 150 151 152
        SN(EngineRunRequested)
        SN(InferiorRunRequested)
        SN(InferiorRunOk)
        SN(InferiorRunFailed)
153
        SN(InferiorUnrunnable)
hjk's avatar
hjk committed
154 155
        SN(InferiorStopRequested)
        SN(InferiorStopOk)
156
        SN(InferiorStopFailed)
hjk's avatar
hjk committed
157 158
        SN(InferiorShutdownRequested)
        SN(InferiorShutdownOk)
159
        SN(InferiorShutdownFailed)
hjk's avatar
hjk committed
160 161 162 163
        SN(EngineShutdownRequested)
        SN(EngineShutdownOk)
        SN(EngineShutdownFailed)
        SN(DebuggerFinished)
164 165 166 167 168
    }
    return "<unknown>";
#    undef SN
}

169

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
///////////////////////////////////////////////////////////////////////
//
// 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() {}
};



192 193 194 195 196 197
//////////////////////////////////////////////////////////////////////
//
// DebuggerEnginePrivate
//
//////////////////////////////////////////////////////////////////////

198
class DebuggerEnginePrivate : public QObject
199
{
200 201
    Q_OBJECT

202 203 204 205 206 207
public:
    DebuggerEnginePrivate(DebuggerEngine *engine, const DebuggerStartParameters &sp)
      : m_engine(engine),
        m_runControl(0),
        m_startParameters(sp),
        m_state(DebuggerNotReady),
hjk's avatar
hjk committed
208
        m_lastGoodState(DebuggerNotReady),
Friedemann Kleint's avatar
Friedemann Kleint committed
209
        m_targetState(DebuggerNotReady),
210
        m_modulesHandler(),
211
        m_registerHandler(),
212 213
        m_sourceFilesHandler(),
        m_stackHandler(),
hjk's avatar
hjk committed
214
        m_threadsHandler(),
215
        m_watchHandler(engine),
216
        m_isSlaveEngine(false),
217
        m_disassemblerViewAgent(engine),
218
        m_memoryViewAgent(engine)
219 220 221
    {
        connect(&m_locationTimer, SIGNAL(timeout()), SLOT(doRemoveLocationMark()));
    }
222 223

    ~DebuggerEnginePrivate() {}
224

225
public slots:
hjk's avatar
hjk committed
226 227
    void doSetupInferior();
    void doRunEngine();
hjk's avatar
hjk committed
228 229
    void doShutdownEngine();
    void doShutdownInferior();
230
    void doInterruptInferior();
hjk's avatar
hjk committed
231
    void doFinishDebugger();
hjk's avatar
hjk committed
232

233 234
    void queueRunEngine()
    {
hjk's avatar
hjk committed
235 236 237 238 239
        m_engine->setState(EngineRunRequested);
        m_engine->showMessage(_("QUEUE: RUN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doRunEngine()));
    }

240 241
    void queueShutdownEngine()
    {
hjk's avatar
hjk committed
242 243 244 245 246
        m_engine->setState(EngineShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doShutdownEngine()));
    }

247 248
    void queueShutdownInferior()
    {
hjk's avatar
hjk committed
249 250 251 252 253
        m_engine->setState(InferiorShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
        QTimer::singleShot(0, this, SLOT(doShutdownInferior()));
    }

254 255
    void queueFinishDebugger()
    {
256 257 258 259
        QTC_ASSERT(state() == EngineShutdownOk
            || state() == EngineShutdownFailed, qDebug() << state());
        m_engine->setState(DebuggerFinished);
        m_engine->showMessage(_("QUEUE: FINISH DEBUGGER"));
hjk's avatar
hjk committed
260 261 262
        QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
    }

263 264
    void raiseApplication()
    {
hjk's avatar
hjk committed
265
        QTC_ASSERT(m_runControl, return);
266 267 268
        m_runControl->bringApplicationToForeground(m_inferiorPid);
    }

269 270 271 272 273 274 275 276 277 278 279 280
    void removeLocationMark()
    {
        m_locationTimer.setSingleShot(true);
        m_locationTimer.start(80);
    }

    void doRemoveLocationMark()
    {
        m_locationTimer.stop();
        m_locationMark.reset();
    }

281
public:
hjk's avatar
hjk committed
282 283
    DebuggerState state() const { return m_state; }

284 285 286 287
    DebuggerEngine *m_engine; // Not owned.
    DebuggerRunControl *m_runControl;  // Not owned.

    DebuggerStartParameters m_startParameters;
hjk's avatar
hjk committed
288 289

    // The current state.
290 291
    DebuggerState m_state;

hjk's avatar
hjk committed
292 293 294 295 296 297
    // The state we had before something unexpected happend.
    DebuggerState m_lastGoodState;

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

298 299 300 301 302 303 304 305
    qint64 m_inferiorPid;

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

308
    bool m_isSlaveEngine;
309 310
    DisassemblerViewAgent m_disassemblerViewAgent;
    MemoryViewAgent m_memoryViewAgent;
311 312
    QScopedPointer<TextEditor::BaseTextMark> m_locationMark;
    QTimer m_locationTimer;
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
};


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

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

DebuggerEngine::~DebuggerEngine()
{
329 330
    disconnect();
    delete d;
331 332
}

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

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

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
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;
}

381 382 383 384
//SnapshotHandler *DebuggerEngine::snapshotHandler() const
//{
//    return &d->m_snapshotHandler;
//}
385 386 387 388 389 390 391 392

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

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

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

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

QAbstractItemModel *DebuggerEngine::threadsModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
417 418 419 420
    QAbstractItemModel *model = d->m_threadsHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("ThreadsModel"));
    return model;
421 422 423 424
}

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

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

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

QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
{
Friedemann Kleint's avatar
Friedemann Kleint committed
449 450 451 452
    QAbstractItemModel *model = d->m_sourceFilesHandler.model();
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("SourceFilesModel"));
    return model;
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
}

void DebuggerEngine::fetchMemory(MemoryViewAgent *, QObject *,
        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
{
470 471
    //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
    //    qDebug() << qPrintable(msg) << "IN STATE" << state();
472
    debuggerCore()->showMessage(msg, channel, timeout);
473 474 475 476 477
    if (d->m_runControl) {
        d->m_runControl->showMessage(msg, channel);
    } else {
        qWarning("Warning: %s (no active run control)", qPrintable(msg));
    }
478 479 480 481
}

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

    d->m_runControl = runControl;

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

498 499
    if (!d->m_startParameters.environment.size())
        d->m_startParameters.environment = Utils::Environment();
500 501 502 503 504

    if (d->m_startParameters.breakAtMain)
        breakByFunctionMain();

    const unsigned engineCapabilities = debuggerCapabilities();
hjk's avatar
hjk committed
505
    debuggerCore()->action(OperateByInstruction)
506 507
        ->setEnabled(engineCapabilities & DisassemblerCapability);

508 509
    QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
         qDebug() << state());
510 511
    d->m_lastGoodState = DebuggerNotReady;
    d->m_targetState = DebuggerNotReady;
hjk's avatar
hjk committed
512
    setState(EngineSetupRequested);
513

514
    d->m_progress.setProgressValue(200);
hjk's avatar
hjk committed
515
    setupEngine();
516 517 518 519 520 521 522 523 524 525 526 527 528 529
}

void DebuggerEngine::breakByFunctionMain()
{
#ifdef Q_OS_WIN
    // FIXME: wrong on non-Qt based binaries
    emit breakByFunction("qMain");
#else
    emit breakByFunction("main");
#endif
}

void DebuggerEngine::breakByFunction(const QString &functionName)
{
530
    breakHandler()->breakByFunction(functionName);
531 532 533 534 535
}

void DebuggerEngine::resetLocation()
{
    d->m_disassemblerViewAgent.resetLocation();
536
    d->removeLocationMark();
537 538
}

539
void DebuggerEngine::gotoLocation(const QString &file, int line, bool setMarker)
540
{
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
    // CDB might hit on breakpoints while shutting down.
    //if (m_shuttingDown)
    //    return;

    d->doRemoveLocationMark();

    bool newEditor = false;
    ITextEditor *editor =
        BaseTextEditor::openEditorAt(file, line, 0, QString(),
            EditorManager::IgnoreNavigationHistory, &newEditor);
    if (!editor)
        return;
    if (newEditor)
        editor->setProperty(Constants::OPENED_BY_DEBUGGER, true);
    if (setMarker)
        d->m_locationMark.reset(new LocationMark(file, line));
557 558 559 560
}

void DebuggerEngine::gotoLocation(const StackFrame &frame, bool setMarker)
{
561 562 563
    if (debuggerCore()->boolSetting(OperateByInstruction) || !frame.isUsable())
        d->m_disassemblerViewAgent.setFrame(frame, true, setMarker);
    else
564
        gotoLocation(frame.file, frame.line, setMarker);
565 566
}

567 568 569
// Called from RunControl.
void DebuggerEngine::handleStartFailed()
{
570
    showMessage("HANDLE RUNCONTROL START FAILED");
571
    d->m_runControl = 0;
572
    d->m_progress.setProgressValue(900);
573 574
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
575 576
}

577 578
// Called from RunControl.
void DebuggerEngine::handleFinished()
579
{
580
    showMessage("HANDLE RUNCONTROL FINISHED");
581
    d->m_runControl = 0;
582 583 584 585
    modulesHandler()->removeAll();
    stackHandler()->removeAll();
    threadsHandler()->removeAll();
    watchHandler()->cleanup();
586
    d->m_progress.setProgressValue(1000);
587
    d->m_progress.reportFinished();
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
}

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
612
    return debuggerCore()->boolSetting(UseDebuggingHelpers);
613 614 615 616
}

QStringList DebuggerEngine::qtDumperLibraryLocations() const
{
hjk's avatar
hjk committed
617
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool()) {
618
        const QString customLocation =
hjk's avatar
hjk committed
619
            debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
620 621 622 623 624 625 626 627 628
        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)
{
629
    debuggerCore()->showQtDumperLibraryWarning(details);
630 631 632 633
}

QString DebuggerEngine::qtDumperLibraryName() const
{
hjk's avatar
hjk committed
634 635
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool())
        return debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
636 637 638 639 640 641 642 643
    return startParameters().dumperLibrary;
}

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

hjk's avatar
hjk committed
644
DebuggerState DebuggerEngine::lastGoodState() const
645
{
hjk's avatar
hjk committed
646 647 648 649 650 651 652
    return d->m_lastGoodState;
}

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

hjk's avatar
hjk committed
654 655 656
static bool isAllowedTransition(DebuggerState from, DebuggerState to)
{
    switch (from) {
657
    case DebuggerNotReady:
658
        return to == EngineSetupRequested;
659

hjk's avatar
hjk committed
660
    case EngineSetupRequested:
661 662
        return to == EngineSetupOk || to == EngineSetupFailed;
    case EngineSetupFailed:
663 664 665
        // In is the engine's task to go into a proper "Shutdown"
        // state before calling notifyEngineSetupFailed
        return to == DebuggerFinished;
666
    case EngineSetupOk:
hjk's avatar
hjk committed
667
        return to == InferiorSetupRequested || to == EngineShutdownRequested;
668

hjk's avatar
hjk committed
669 670
    case InferiorSetupRequested:
        return to == EngineRunRequested || to == InferiorSetupFailed;
hjk's avatar
hjk committed
671
    case InferiorSetupFailed:
hjk's avatar
hjk committed
672 673 674 675 676 677 678
        return to == EngineShutdownRequested;

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

    case EngineRunFailed:
679
        return to == EngineShutdownRequested;
hjk's avatar
hjk committed
680 681 682 683 684 685 686 687 688 689 690 691 692

    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;
693
    case InferiorStopFailed:
hjk's avatar
hjk committed
694
        return to == EngineShutdownRequested;
695 696

    case InferiorUnrunnable:
hjk's avatar
hjk committed
697 698 699 700 701
        return to == InferiorShutdownRequested;
    case InferiorShutdownRequested:
        return to == InferiorShutdownOk || to == InferiorShutdownFailed;
    case InferiorShutdownOk:
        return to == EngineShutdownRequested;
702
    case InferiorShutdownFailed:
hjk's avatar
hjk committed
703
        return to == EngineShutdownRequested;
704

hjk's avatar
hjk committed
705
    case EngineShutdownRequested:
706
        return to == EngineShutdownOk || to == EngineShutdownFailed;
hjk's avatar
hjk committed
707 708 709 710 711 712
    case EngineShutdownOk:
        return to == DebuggerFinished;
    case EngineShutdownFailed:
        return to == DebuggerFinished;

    case DebuggerFinished:
713
        return to == EngineSetupRequested; // Happens on restart.
714 715
    }

716
    qDebug() << "UNKNOWN DEBUGGER STATE:" << from;
717 718 719
    return false;
}

720
void DebuggerEngine::notifyEngineSetupFailed()
hjk's avatar
hjk committed
721
{
hjk's avatar
hjk committed
722
    showMessage(_("NOTE: ENGINE SETUP FAILED"));
hjk's avatar
hjk committed
723
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
724
    setState(EngineSetupFailed);
hjk's avatar
hjk committed
725 726
    QTC_ASSERT(d->m_runControl, return);
    d->m_runControl->startFailed();
hjk's avatar
hjk committed
727
    setState(DebuggerFinished);
hjk's avatar
hjk committed
728 729
}

730
void DebuggerEngine::notifyEngineSetupOk()
731
{
hjk's avatar
hjk committed
732
    showMessage(_("NOTE: ENGINE SETUP OK"));
hjk's avatar
hjk committed
733
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
734
    setState(EngineSetupOk);
hjk's avatar
hjk committed
735
    QTC_ASSERT(d->m_runControl, return);
hjk's avatar
hjk committed
736
    showMessage(_("QUEUE: SETUP INFERIOR"));
hjk's avatar
hjk committed
737
    QTimer::singleShot(0, d, SLOT(doSetupInferior()));
738 739
}

hjk's avatar
hjk committed
740
void DebuggerEnginePrivate::doSetupInferior()
741
{
742
    m_engine->showMessage(_("CALL: SETUP INFERIOR"));
hjk's avatar
hjk committed
743
    QTC_ASSERT(state() == EngineSetupOk, qDebug() << state());
744
    m_progress.setProgressValue(250);
hjk's avatar
hjk committed
745
    m_engine->setState(InferiorSetupRequested);
hjk's avatar
hjk committed
746 747 748 749 750
    m_engine->setupInferior();
}

void DebuggerEngine::notifyInferiorSetupFailed()
{
hjk's avatar
hjk committed
751
    showMessage(_("NOTE: INFERIOR SETUP FAILED"));
hjk's avatar
hjk committed
752
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
753
    setState(InferiorSetupFailed);
hjk's avatar
hjk committed
754
    d->queueShutdownEngine();
hjk's avatar
hjk committed
755 756 757 758
}

void DebuggerEngine::notifyInferiorSetupOk()
{
hjk's avatar
hjk committed
759
    showMessage(_("NOTE: INFERIOR SETUP OK"));
hjk's avatar
hjk committed
760
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
761
    d->queueRunEngine();
hjk's avatar
hjk committed
762 763 764 765
}

void DebuggerEnginePrivate::doRunEngine()
{
hjk's avatar
hjk committed
766
    m_engine->showMessage(_("CALL: RUN ENGINE"));
hjk's avatar
hjk committed
767
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
768
    m_progress.setProgressValue(300);
hjk's avatar
hjk committed
769 770 771
    m_engine->runEngine();
}

hjk's avatar
hjk committed
772 773
void DebuggerEngine::notifyInferiorUnrunnable()
{
hjk's avatar
hjk committed
774
    showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
775 776
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
777 778 779 780 781 782
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    setState(InferiorUnrunnable);
}

void DebuggerEngine::notifyEngineRunFailed()
{
hjk's avatar
hjk committed
783
    showMessage(_("NOTE: ENGINE RUN FAILED"));
hjk's avatar
hjk committed
784
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
785 786 787
    d->m_progress.setProgressValue(900);
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
788
    setState(EngineRunFailed);
789
    d->queueShutdownEngine();
hjk's avatar
hjk committed
790 791 792 793
}

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

void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
{
hjk's avatar
hjk committed
804
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR STOP OK"));
805 806
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
807 808 809 810 811 812 813
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    setState(InferiorStopRequested);
    notifyInferiorStopOk();
}

void DebuggerEngine::notifyInferiorRunRequested()
{
hjk's avatar
hjk committed
814
    showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
hjk's avatar
hjk committed
815 816 817 818 819 820
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
    setState(InferiorRunRequested);
}

void DebuggerEngine::notifyInferiorRunOk()
{
hjk's avatar
hjk committed
821
    showMessage(_("NOTE: INFERIOR RUN OK"));
hjk's avatar
hjk committed
822 823 824 825 826 827
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
    setState(InferiorRunOk);
}

void DebuggerEngine::notifyInferiorRunFailed()
{
hjk's avatar
hjk committed
828
    showMessage(_("NOTE: INFERIOR RUN FAILED"));
hjk's avatar
hjk committed
829 830 831
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
    setState(InferiorRunFailed);
    setState(InferiorStopOk);
hjk's avatar
hjk committed
832 833
    if (isDying())
        d->queueShutdownInferior();
hjk's avatar
hjk committed
834 835 836 837
}

void DebuggerEngine::notifyInferiorStopOk()
{
hjk's avatar
hjk committed
838 839
    showMessage(_("NOTE: INFERIOR STOP OK"));
    // Ignore spurious notifications after we are set to die.
hjk's avatar
hjk committed
840
    if (isDying()) {
hjk's avatar
hjk committed
841 842 843 844 845 846 847 848 849 850 851 852 853
        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
854
    }
hjk's avatar
hjk committed
855 856
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
    setState(InferiorStopOk);
hjk's avatar
hjk committed
857 858
}

hjk's avatar
hjk committed
859
void DebuggerEngine::notifyInferiorSpontaneousStop()
860
{
hjk's avatar
hjk committed
861
    showMessage(_("NOTE: INFERIOR SPONTANEOUES STOP"));
hjk's avatar
hjk committed
862 863
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
    setState(InferiorStopOk);
864 865
}

hjk's avatar
hjk committed
866
void DebuggerEngine::notifyInferiorStopFailed()
867
{
hjk's avatar
hjk committed
868
    showMessage(_("NOTE: INFERIOR STOP FAILED"));
hjk's avatar
hjk committed
869 870
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
    setState(InferiorStopFailed);
hjk's avatar
hjk committed
871
    d->queueShutdownEngine();
872 873 874 875
}

void DebuggerEnginePrivate::doInterruptInferior()
{
hjk's avatar
hjk committed
876 877
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
    m_engine->setState(InferiorStopRequested);
hjk's avatar
hjk committed
878
    m_engine->showMessage(_("CALL: INTERRUPT INFERIOR"));
879 880 881
    m_engine->interruptInferior();
}

hjk's avatar
hjk committed
882 883
void DebuggerEnginePrivate::doShutdownInferior()
{
884
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
885 886
    m_engine->resetLocation();
    m_targetState = DebuggerFinished;
hjk's avatar
hjk committed
887
    m_engine->showMessage(_("CALL: SHUTDOWN INFERIOR"));
hjk's avatar
hjk committed
888 889 890 891 892 893
    m_engine->shutdownInferior();
}

void DebuggerEngine::notifyInferiorShutdownOk()
{
    showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
hjk's avatar
hjk committed
894
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
895 896
    d->m_lastGoodState = DebuggerNotReady; // A "neutral" value.
    setState(InferiorShutdownOk);
hjk's avatar
hjk committed
897
    d->queueShutdownEngine();
hjk's avatar
hjk committed
898 899 900 901 902
}

void DebuggerEngine::notifyInferiorShutdownFailed()
{
    showMessage(_("INFERIOR SHUTDOWN FAILED"));
Friedemann Kleint's avatar
Friedemann Kleint committed
903
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
hjk's avatar
hjk committed
904
    setState(InferiorShutdownFailed);
hjk's avatar
hjk committed
905
    d->queueShutdownEngine();
hjk's avatar
hjk committed
906 907 908 909
}

void DebuggerEngine::notifyInferiorIll()
{
hjk's avatar
hjk committed
910
    showMessage(_("NOTE: INFERIOR ILL"));
hjk's avatar
hjk committed
911 912 913 914 915 916 917 918 919 920 921
    // 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
922
    d->queueShutdownInferior();
hjk's avatar
hjk committed
923 924 925 926
}

void DebuggerEnginePrivate::doShutdownEngine()
{
927
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
928
    m_targetState = DebuggerFinished;
hjk's avatar
hjk committed
929
    m_engine->showMessage(_("CALL: SHUTDOWN ENGINE"));
hjk's avatar
hjk committed
930 931 932 933 934
    m_engine->shutdownEngine();
}

void DebuggerEngine::notifyEngineShutdownOk()
{
hjk's avatar
hjk committed
935
    showMessage(_("NOTE: ENGINE SHUTDOWN OK"));
hjk's avatar
hjk committed
936 937
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
    setState(EngineShutdownOk);
938
    d->queueFinishDebugger();
hjk's avatar
hjk committed
939 940 941
}

void DebuggerEngine::notifyEngineShutdownFailed()
hjk's avatar
hjk committed
942
{
hjk's avatar
hjk committed
943
    showMessage(_("NOTE: ENGINE SHUTDOWN FAILED"));
hjk's avatar
hjk committed
944 945
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
    setState(EngineShutdownFailed);
946
    d->queueFinishDebugger();
hjk's avatar
hjk committed
947 948 949 950
}

void DebuggerEnginePrivate::doFinishDebugger()
{
hjk's avatar
hjk committed
951
    m_engine->showMessage(_("NOTE: FINISH DEBUGGER"));
952
    QTC_ASSERT(state() == DebuggerFinished, qDebug() << state());
hjk's avatar
hjk committed
953
    m_engine->resetLocation();
954 955 956 957
    if (!m_engine->isSlaveEngine()) {
        QTC_ASSERT(m_runControl, return);
        m_runControl->debuggingFinished();
    }
hjk's avatar
hjk committed
958 959 960 961
}

void DebuggerEngine::notifyEngineIll()
{
hjk's avatar
hjk committed
962
    showMessage(_("NOTE: ENGINE ILL ******"));
hjk's avatar
hjk committed
963 964
    d->m_targetState = DebuggerFinished;
    d->m_lastGoodState = d->m_state;
hjk's avatar
hjk committed
965 966 967
    switch (state()) {
        case InferiorRunRequested:
        case InferiorRunOk:
968 969 970 971 972 973 974
            // The engine does not look overly ill right now, so attempt to
            // properly interrupt at least once. If that fails, we are on the
            // shutdown path due to d->m_targetState anyways.
            setState(InferiorStopRequested, true);
            showMessage(_("ATTEMPT TO INTERRUPT INFERIOR"));
            interruptInferior();
            break;
hjk's avatar
hjk committed
975 976
        case InferiorStopRequested:
        case InferiorStopOk: