debuggerengine.cpp 45.1 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
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
8 9 10 11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** 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.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28 29
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
30 31 32 33 34 35
**
**************************************************************************/

#include "debuggerengine.h"

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

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

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

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

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

69
#include <QtGui/QMessageBox>
70

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

76 77 78 79
enum { debug = 0 };

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

81

82 83 84 85 86 87
///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
//
///////////////////////////////////////////////////////////////////////

88 89
namespace Debugger {

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

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

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

126

127 128 129 130 131 132
//////////////////////////////////////////////////////////////////////
//
// DebuggerEnginePrivate
//
//////////////////////////////////////////////////////////////////////

133
class DebuggerEnginePrivate : public QObject
134
{
135 136
    Q_OBJECT

137
public:
138 139 140
    DebuggerEnginePrivate(DebuggerEngine *engine,
            DebuggerEngine *masterEngine,
            const DebuggerStartParameters &sp)
141
      : m_engine(engine),
142
        m_masterEngine(masterEngine),
143 144 145
        m_runControl(0),
        m_startParameters(sp),
        m_state(DebuggerNotReady),
hjk's avatar
hjk committed
146
        m_lastGoodState(DebuggerNotReady),
Friedemann Kleint's avatar
Friedemann Kleint committed
147
        m_targetState(DebuggerNotReady),
148
        m_modulesHandler(),
149
        m_registerHandler(),
150 151
        m_sourceFilesHandler(),
        m_stackHandler(),
hjk's avatar
hjk committed
152
        m_threadsHandler(),
153
        m_watchHandler(engine),
154
        m_disassemblerAgent(engine),
155 156
        m_memoryAgent(engine),
        m_isStateDebugging(false)
157
    {
158
        connect(&m_locationTimer, SIGNAL(timeout()), SLOT(resetLocation()));
159
    }
160 161

    ~DebuggerEnginePrivate() {}
162

163
public slots:
164
    void doSetupEngine();
hjk's avatar
hjk committed
165 166
    void doSetupInferior();
    void doRunEngine();
hjk's avatar
hjk committed
167 168
    void doShutdownEngine();
    void doShutdownInferior();
169
    void doInterruptInferior();
hjk's avatar
hjk committed
170
    void doFinishDebugger();
hjk's avatar
hjk committed
171

172 173 174 175 176 177 178 179 180 181 182 183 184 185
    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()));
    }

186 187
    void queueRunEngine()
    {
hjk's avatar
hjk committed
188 189 190 191 192
        m_engine->setState(EngineRunRequested);
        m_engine->showMessage(_("QUEUE: RUN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doRunEngine()));
    }

193 194
    void queueShutdownEngine()
    {
hjk's avatar
hjk committed
195 196 197 198 199
        m_engine->setState(EngineShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doShutdownEngine()));
    }

200 201
    void queueShutdownInferior()
    {
hjk's avatar
hjk committed
202 203 204 205 206
        m_engine->setState(InferiorShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
        QTimer::singleShot(0, this, SLOT(doShutdownInferior()));
    }

207 208
    void queueFinishDebugger()
    {
209 210 211 212
        QTC_ASSERT(state() == EngineShutdownOk
            || state() == EngineShutdownFailed, qDebug() << state());
        m_engine->setState(DebuggerFinished);
        m_engine->showMessage(_("QUEUE: FINISH DEBUGGER"));
hjk's avatar
hjk committed
213 214 215
        QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
    }

216 217
    void raiseApplication()
    {
218 219
        QTC_ASSERT(runControl(), return);
        runControl()->bringApplicationToForeground(m_inferiorPid);
220 221
    }

222
    void scheduleResetLocation()
223
    {
224
        m_stackHandler.scheduleResetLocation();
225
        m_disassemblerAgent.scheduleResetLocation();
226 227 228 229
        m_locationTimer.setSingleShot(true);
        m_locationTimer.start(80);
    }

230
    void resetLocation()
231 232 233
    {
        m_locationTimer.stop();
        m_locationMark.reset();
234 235
        m_stackHandler.resetLocation();
        m_disassemblerAgent.resetLocation();
236 237
    }

238
public:
hjk's avatar
hjk committed
239
    DebuggerState state() const { return m_state; }
240 241 242
    bool isMasterEngine() const { return m_engine->isMasterEngine(); }
    DebuggerRunControl *runControl() const
        { return m_masterEngine ? m_masterEngine->runControl() : m_runControl; }
hjk's avatar
hjk committed
243

244
    DebuggerEngine *m_engine; // Not owned.
245
    DebuggerEngine *m_masterEngine; // Not owned
246 247 248
    DebuggerRunControl *m_runControl;  // Not owned.

    DebuggerStartParameters m_startParameters;
hjk's avatar
hjk committed
249 250

    // The current state.
251 252
    DebuggerState m_state;

hjk's avatar
hjk committed
253 254 255 256 257 258
    // The state we had before something unexpected happend.
    DebuggerState m_lastGoodState;

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

259 260 261 262 263 264 265 266
    qint64 m_inferiorPid;

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

269 270
    DisassemblerAgent m_disassemblerAgent;
    MemoryAgent m_memoryAgent;
271 272
    QScopedPointer<TextEditor::BaseTextMark> m_locationMark;
    QTimer m_locationTimer;
273 274

    bool m_isStateDebugging;
275 276 277 278 279 280 281 282 283
};


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

284 285 286
DebuggerEngine::DebuggerEngine(const DebuggerStartParameters &startParameters,
        DebuggerEngine *parentEngine)
  : d(new DebuggerEnginePrivate(this, parentEngine, startParameters))
287 288 289 290 291
{
}

DebuggerEngine::~DebuggerEngine()
{
292 293
    disconnect();
    delete d;
294 295
}

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

329
void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
330
{
331
    showMessage(msg, StatusBar, timeout);
332
}
333

334 335 336 337 338 339 340 341 342 343 344 345 346 347
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
{
348 349 350
    return d->m_masterEngine
        ? d->m_masterEngine->modulesHandler()
        : &d->m_modulesHandler;
351 352 353 354
}

RegisterHandler *DebuggerEngine::registerHandler() const
{
355 356 357
    return d->m_masterEngine
        ? d->m_masterEngine->registerHandler()
        : &d->m_registerHandler;
358 359 360 361
}

StackHandler *DebuggerEngine::stackHandler() const
{
hjk's avatar
hjk committed
362 363 364 365
    //return d->m_masterEngine
    //    ? d->m_masterEngine->stackHandler()
    //    : &d->m_stackHandler;
    return &d->m_stackHandler;
366 367 368 369
}

ThreadsHandler *DebuggerEngine::threadsHandler() const
{
370 371 372
    return d->m_masterEngine
        ? d->m_masterEngine->threadsHandler()
        : &d->m_threadsHandler;
373 374 375 376
}

WatchHandler *DebuggerEngine::watchHandler() const
{
377 378 379
    return d->m_masterEngine
        ? d->m_masterEngine->watchHandler()
        : &d->m_watchHandler;
380 381 382 383
}

SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
{
384 385 386
    return d->m_masterEngine
        ? d->m_masterEngine->sourceFilesHandler()
        : &d->m_sourceFilesHandler;
387 388 389 390
}

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

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

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

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

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

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

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

445 446 447 448 449 450 451 452
QAbstractItemModel *DebuggerEngine::toolTipsModel() const
{
    QAbstractItemModel *model = watchHandler()->model(TooltipsWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("TooltipsModel"));
    return model;
}

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

461
void DebuggerEngine::fetchMemory(MemoryAgent *, QObject *,
462 463 464 465 466 467
        quint64 addr, quint64 length)
{
    Q_UNUSED(addr);
    Q_UNUSED(length);
}

hjk's avatar
hjk committed
468 469 470 471 472 473 474
void DebuggerEngine::changeMemory(MemoryAgent *, QObject *,
        quint64 addr, const QByteArray &data)
{
    Q_UNUSED(addr);
    Q_UNUSED(data);
}

475 476 477 478 479 480 481 482
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
{
483 484 485 486
    if (d->m_masterEngine) {
        d->m_masterEngine->showMessage(msg, channel, timeout);
        return;
    }
487 488
    //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
    //    qDebug() << qPrintable(msg) << "IN STATE" << state();
489
    debuggerCore()->showMessage(msg, channel, timeout);
490 491 492 493 494
    if (d->m_runControl) {
        d->m_runControl->showMessage(msg, channel);
    } else {
        qWarning("Warning: %s (no active run control)", qPrintable(msg));
    }
495 496 497 498
}

void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
{
499 500
    QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
    QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
501

502 503 504 505 506 507 508
    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();

509 510 511 512 513
    d->m_runControl = runControl;

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

514 515
    if (!d->m_startParameters.environment.size())
        d->m_startParameters.environment = Utils::Environment();
516 517

    const unsigned engineCapabilities = debuggerCapabilities();
hjk's avatar
hjk committed
518
    debuggerCore()->action(OperateByInstruction)
519 520
        ->setEnabled(engineCapabilities & DisassemblerCapability);

521 522
    QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
         qDebug() << state());
523 524
    d->m_lastGoodState = DebuggerNotReady;
    d->m_targetState = DebuggerNotReady;
525
    d->m_progress.setProgressValue(200);
526
    d->queueSetupEngine();
527 528 529 530
}

void DebuggerEngine::resetLocation()
{
531 532
    // Do it after some delay to avoid flicker.
    d->scheduleResetLocation();
533 534
}

535
void DebuggerEngine::gotoLocation(const Location &loc)
536
{
537 538 539 540 541
    if (debuggerCore()->boolSetting(OperateByInstruction) || !loc.hasDebugInfo()) {
        d->m_disassemblerAgent.setTryMixed(true);
        d->m_disassemblerAgent.setLocation(loc);
        return;
    }
542 543 544 545
    // CDB might hit on breakpoints while shutting down.
    //if (m_shuttingDown)
    //    return;

546
    d->resetLocation();
547

548 549
    const QString file = loc.fileName();
    const int line = loc.lineNumber();
hjk's avatar
hjk committed
550 551
    EditorManager *editorManager = EditorManager::instance();
    QList<IEditor *> editors = editorManager->editorsForFileName(file);
552
    IEditor *editor = 0;
hjk's avatar
hjk committed
553
    if (editors.isEmpty()) {
554 555 556 557 558 559 560 561
        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
562
    }
563
    ITextEditor *texteditor = qobject_cast<ITextEditor *>(editor);
hjk's avatar
hjk committed
564 565 566
    if (texteditor)
        texteditor->gotoLine(line, 0);

567 568 569 570 571 572
    if (loc.needsMarker()) {
        d->m_locationMark.reset(new TextEditor::BaseTextMark);
        d->m_locationMark->setLocation(file, line);
        d->m_locationMark->setIcon(debuggerCore()->locationMarkIcon());
        d->m_locationMark->setPriority(TextEditor::ITextMark::HighPriority);
    }
573 574

    // FIXME: Breaks with split views.
575
    if (!d->m_memoryAgent.hasVisibleEditor() || loc.needsRaise())
576
        editorManager->activateEditor(editor);
577
    //qDebug() << "MEMORY: " << d->m_memoryAgent.hasVisibleEditor();
578 579
}

580 581 582
// Called from RunControl.
void DebuggerEngine::handleStartFailed()
{
583
    showMessage("HANDLE RUNCONTROL START FAILED");
584
    d->m_runControl = 0;
585
    d->m_progress.setProgressValue(900);
586 587
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
588 589
}

590 591
// Called from RunControl.
void DebuggerEngine::handleFinished()
592
{
593
    showMessage("HANDLE RUNCONTROL FINISHED");
594
    d->m_runControl = 0;
595 596
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
    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
625
    return debuggerCore()->boolSetting(UseDebuggingHelpers);
626 627 628 629
}

QStringList DebuggerEngine::qtDumperLibraryLocations() const
{
hjk's avatar
hjk committed
630
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool()) {
631
        const QString customLocation =
hjk's avatar
hjk committed
632
            debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
633 634 635 636 637 638 639 640 641
        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)
{
642
    debuggerCore()->showQtDumperLibraryWarning(details);
643 644 645 646
}

QString DebuggerEngine::qtDumperLibraryName() const
{
hjk's avatar
hjk committed
647 648
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool())
        return debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
649 650 651 652 653 654 655 656
    return startParameters().dumperLibrary;
}

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

hjk's avatar
hjk committed
657
DebuggerState DebuggerEngine::lastGoodState() const
658
{
hjk's avatar
hjk committed
659 660 661 662 663 664 665
    return d->m_lastGoodState;
}

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

hjk's avatar
hjk committed
667 668 669
static bool isAllowedTransition(DebuggerState from, DebuggerState to)
{
    switch (from) {
670
    case DebuggerNotReady:
671
        return to == EngineSetupRequested;
672

hjk's avatar
hjk committed
673
    case EngineSetupRequested:
674 675
        return to == EngineSetupOk || to == EngineSetupFailed;
    case EngineSetupFailed:
676 677 678
        // In is the engine's task to go into a proper "Shutdown"
        // state before calling notifyEngineSetupFailed
        return to == DebuggerFinished;
679
    case EngineSetupOk:
hjk's avatar
hjk committed
680
        return to == InferiorSetupRequested || to == EngineShutdownRequested;
681

hjk's avatar
hjk committed
682
    case InferiorSetupRequested:
683
        return to == InferiorSetupOk || to == InferiorSetupFailed;
hjk's avatar
hjk committed
684
    case InferiorSetupFailed:
hjk's avatar
hjk committed
685
        return to == EngineShutdownRequested;
686 687
    case InferiorSetupOk:
        return to == EngineRunRequested;
hjk's avatar
hjk committed
688 689

    case EngineRunRequested:
hjk's avatar
hjk committed
690 691 692 693
        return to == EngineRunFailed
            || to == InferiorRunOk
            || to == InferiorStopOk
            || to == InferiorUnrunnable;
hjk's avatar
hjk committed
694
    case EngineRunFailed:
695
        return to == EngineShutdownRequested;
hjk's avatar
hjk committed
696 697 698 699 700 701

    case InferiorRunRequested:
        return to == InferiorRunOk || to == InferiorRunFailed;
    case InferiorRunFailed:
        return to == InferiorStopOk;
    case InferiorRunOk:
702 703 704
        return to == InferiorStopRequested
            || to == InferiorStopOk // A spontaneous stop.
            || to == InferiorExitOk;
hjk's avatar
hjk committed
705 706 707 708 709

    case InferiorStopRequested:
        return to == InferiorStopOk || to == InferiorStopFailed;
    case InferiorStopOk:
        return to == InferiorRunRequested || to == InferiorShutdownRequested
710
            || to == InferiorStopOk || InferiorExitOk;
711
    case InferiorStopFailed:
hjk's avatar
hjk committed
712
        return to == EngineShutdownRequested;
713

714 715 716
    case InferiorExitOk:
        return to == InferiorShutdownOk;

717
    case InferiorUnrunnable:
hjk's avatar
hjk committed
718 719 720 721 722
        return to == InferiorShutdownRequested;
    case InferiorShutdownRequested:
        return to == InferiorShutdownOk || to == InferiorShutdownFailed;
    case InferiorShutdownOk:
        return to == EngineShutdownRequested;
723
    case InferiorShutdownFailed:
hjk's avatar
hjk committed
724
        return to == EngineShutdownRequested;
725

hjk's avatar
hjk committed
726
    case EngineShutdownRequested:
727
        return to == EngineShutdownOk || to == EngineShutdownFailed;
hjk's avatar
hjk committed
728 729 730 731 732 733
    case EngineShutdownOk:
        return to == DebuggerFinished;
    case EngineShutdownFailed:
        return to == DebuggerFinished;

    case DebuggerFinished:
734
        return to == EngineSetupRequested; // Happens on restart.
735 736
    }

737
    qDebug() << "UNKNOWN DEBUGGER STATE:" << from;
738 739 740
    return false;
}

741 742 743 744 745 746 747 748 749 750 751 752 753
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();
}

754
void DebuggerEngine::notifyEngineSetupFailed()
hjk's avatar
hjk committed
755
{
hjk's avatar
hjk committed
756
    showMessage(_("NOTE: ENGINE SETUP FAILED"));
757
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
758
    setState(EngineSetupFailed);
hjk's avatar
hjk committed
759
    if (isMasterEngine() && runControl())
760
        runControl()->startFailed();
hjk's avatar
hjk committed
761
    setState(DebuggerFinished);
hjk's avatar
hjk committed
762 763
}

764
void DebuggerEngine::notifyEngineSetupOk()
765
{
hjk's avatar
hjk committed
766
    showMessage(_("NOTE: ENGINE SETUP OK"));
767
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
768
    setState(EngineSetupOk);
hjk's avatar
hjk committed
769
    showMessage(_("QUEUE: SETUP INFERIOR"));
770
    if (isMasterEngine())
771 772 773 774 775 776 777
        d->queueSetupInferior();
}

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

hjk's avatar
hjk committed
780
void DebuggerEnginePrivate::doSetupInferior()
781
{
782
    m_engine->showMessage(_("CALL: SETUP INFERIOR"));
783
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << m_engine << state());
784
    m_progress.setProgressValue(250);
hjk's avatar
hjk committed
785 786 787 788 789
    m_engine->setupInferior();
}

void DebuggerEngine::notifyInferiorSetupFailed()
{
hjk's avatar
hjk committed
790
    showMessage(_("NOTE: INFERIOR SETUP FAILED"));
791
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state());
hjk's avatar
hjk committed
792
    setState(InferiorSetupFailed);
793 794
    if (isMasterEngine())
        d->queueShutdownEngine();
hjk's avatar
hjk committed
795 796 797 798
}

void DebuggerEngine::notifyInferiorSetupOk()
{
hjk's avatar
hjk committed
799
    showMessage(_("NOTE: INFERIOR SETUP OK"));
800 801 802 803
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state());
    setState(InferiorSetupOk);
    if (isMasterEngine())
        d->queueRunEngine();
hjk's avatar
hjk committed
804 805
}

806 807 808 809 810 811 812
void DebuggerEngine::runSlaveEngine()
{
    QTC_ASSERT(isSlaveEngine(), return);
    QTC_ASSERT(state() == InferiorSetupOk, /**/);
    d->queueRunEngine();
}

hjk's avatar
hjk committed
813 814
void DebuggerEnginePrivate::doRunEngine()
{
hjk's avatar
hjk committed
815
    m_engine->showMessage(_("CALL: RUN ENGINE"));
816
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << m_engine << state());
817
    m_progress.setProgressValue(300);
hjk's avatar
hjk committed
818 819 820
    m_engine->runEngine();
}

hjk's avatar
hjk committed
821 822
void DebuggerEngine::notifyInferiorUnrunnable()
{
hjk's avatar
hjk committed
823
    showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
824 825
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
826
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
827 828 829 830 831
    setState(InferiorUnrunnable);
}

void DebuggerEngine::notifyEngineRunFailed()
{
hjk's avatar
hjk committed
832
    showMessage(_("NOTE: ENGINE RUN FAILED"));
833
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
834 835 836
    d->m_progress.setProgressValue(900);
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
837
    setState(EngineRunFailed);
838 839
    if (isMasterEngine())
        d->queueShutdownEngine();
hjk's avatar
hjk committed
840 841 842 843
}

void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
{
hjk's avatar
hjk committed
844
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR RUN OK"));
845 846
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
847
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
848
    setState(InferiorRunOk);
hjk's avatar
hjk committed
849 850 851 852
}

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

void DebuggerEngine::notifyInferiorRunRequested()
{
hjk's avatar
hjk committed
862
    showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
863
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << this << state());
hjk's avatar
hjk committed
864 865 866 867 868
    setState(InferiorRunRequested);
}

void DebuggerEngine::notifyInferiorRunOk()
{
hjk's avatar
hjk committed
869
    showMessage(_("NOTE: INFERIOR RUN OK"));
870
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
871 872 873 874 875
    setState(InferiorRunOk);
}

void DebuggerEngine::notifyInferiorRunFailed()
{
hjk's avatar
hjk committed
876
    showMessage(_("NOTE: INFERIOR RUN FAILED"));
877
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
878 879
    setState(InferiorRunFailed);
    setState(InferiorStopOk);
hjk's avatar
hjk committed
880 881
    if (isDying())
        d->queueShutdownInferior();
hjk's avatar
hjk committed
882 883 884 885
}

void DebuggerEngine::notifyInferiorStopOk()
{
hjk's avatar
hjk committed
886 887
    showMessage(_("NOTE: INFERIOR STOP OK"));
    // Ignore spurious notifications after we are set to die.
hjk's avatar
hjk committed
888
    if (isDying()) {
hjk's avatar
hjk committed
889 890 891 892 893 894 895 896 897 898 899 900 901
        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
902
    }
903
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
hjk's avatar
hjk committed
904
    setState(InferiorStopOk);
hjk's avatar
hjk committed
905 906
}

hjk's avatar
hjk committed
907
void DebuggerEngine::notifyInferiorSpontaneousStop()
908
{
909
    showMessage(_("NOTE: INFERIOR SPONTANEOUS STOP"));
910
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state());
911
    setState(InferiorStopOk);
912 913
}

hjk's avatar
hjk committed
914
void DebuggerEngine::notifyInferiorStopFailed()
915
{