debuggerengine.cpp 45.4 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
        QTC_ASSERT(state() == EngineShutdownOk
            || state() == EngineShutdownFailed, qDebug() << state());
        m_engine->setState(DebuggerFinished);
212 213 214 215 216
        resetLocation();
        if (isMasterEngine()) {
            m_engine->showMessage(_("QUEUE: FINISH DEBUGGER"));
            QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
        }
hjk's avatar
hjk committed
217 218
    }

219 220
    void raiseApplication()
    {
221 222
        QTC_ASSERT(runControl(), return);
        runControl()->bringApplicationToForeground(m_inferiorPid);
223 224
    }

225
    void scheduleResetLocation()
226
    {
227
        m_stackHandler.scheduleResetLocation();
228
        m_threadsHandler.scheduleResetLocation();
229
        m_disassemblerAgent.scheduleResetLocation();
230 231 232 233
        m_locationTimer.setSingleShot(true);
        m_locationTimer.start(80);
    }

234
    void resetLocation()
235 236 237
    {
        m_locationTimer.stop();
        m_locationMark.reset();
238
        m_stackHandler.resetLocation();
239
        m_threadsHandler.resetLocation();
240
        m_disassemblerAgent.resetLocation();
241 242
    }

243
public:
hjk's avatar
hjk committed
244
    DebuggerState state() const { return m_state; }
245 246 247
    bool isMasterEngine() const { return m_engine->isMasterEngine(); }
    DebuggerRunControl *runControl() const
        { return m_masterEngine ? m_masterEngine->runControl() : m_runControl; }
hjk's avatar
hjk committed
248

249
    DebuggerEngine *m_engine; // Not owned.
250
    DebuggerEngine *m_masterEngine; // Not owned
251 252 253
    DebuggerRunControl *m_runControl;  // Not owned.

    DebuggerStartParameters m_startParameters;
hjk's avatar
hjk committed
254 255

    // The current state.
256 257
    DebuggerState m_state;

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

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

264 265 266 267 268 269 270 271
    qint64 m_inferiorPid;

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

274 275
    DisassemblerAgent m_disassemblerAgent;
    MemoryAgent m_memoryAgent;
276 277
    QScopedPointer<TextEditor::BaseTextMark> m_locationMark;
    QTimer m_locationTimer;
278 279

    bool m_isStateDebugging;
280 281 282 283 284 285 286 287 288
};


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

289 290 291
DebuggerEngine::DebuggerEngine(const DebuggerStartParameters &startParameters,
        DebuggerEngine *parentEngine)
  : d(new DebuggerEnginePrivate(this, parentEngine, startParameters))
292 293 294 295 296
{
}

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

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

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

339 340 341 342 343 344 345 346 347 348 349 350 351 352
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
{
353 354 355
    return d->m_masterEngine
        ? d->m_masterEngine->modulesHandler()
        : &d->m_modulesHandler;
356 357 358 359
}

RegisterHandler *DebuggerEngine::registerHandler() const
{
360 361 362
    return d->m_masterEngine
        ? d->m_masterEngine->registerHandler()
        : &d->m_registerHandler;
363 364 365 366
}

StackHandler *DebuggerEngine::stackHandler() const
{
hjk's avatar
hjk committed
367 368 369 370
    //return d->m_masterEngine
    //    ? d->m_masterEngine->stackHandler()
    //    : &d->m_stackHandler;
    return &d->m_stackHandler;
371 372 373 374
}

ThreadsHandler *DebuggerEngine::threadsHandler() const
{
375 376 377
    return d->m_masterEngine
        ? d->m_masterEngine->threadsHandler()
        : &d->m_threadsHandler;
378 379 380 381
}

WatchHandler *DebuggerEngine::watchHandler() const
{
382 383 384
    return d->m_masterEngine
        ? d->m_masterEngine->watchHandler()
        : &d->m_watchHandler;
385 386 387 388
}

SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
{
389 390 391
    return d->m_masterEngine
        ? d->m_masterEngine->sourceFilesHandler()
        : &d->m_sourceFilesHandler;
392 393 394 395
}

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

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

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

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

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

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

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

450 451 452 453 454 455 456 457
QAbstractItemModel *DebuggerEngine::toolTipsModel() const
{
    QAbstractItemModel *model = watchHandler()->model(TooltipsWatch);
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("TooltipsModel"));
    return model;
}

458 459
QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
{
460
    QAbstractItemModel *model = sourceFilesHandler()->model();
Friedemann Kleint's avatar
Friedemann Kleint committed
461 462 463
    if (model->objectName().isEmpty()) // Make debugging easier.
        model->setObjectName(objectName() + QLatin1String("SourceFilesModel"));
    return model;
464 465
}

466
void DebuggerEngine::fetchMemory(MemoryAgent *, QObject *,
467 468 469 470 471 472
        quint64 addr, quint64 length)
{
    Q_UNUSED(addr);
    Q_UNUSED(length);
}

hjk's avatar
hjk committed
473 474 475 476 477 478 479
void DebuggerEngine::changeMemory(MemoryAgent *, QObject *,
        quint64 addr, const QByteArray &data)
{
    Q_UNUSED(addr);
    Q_UNUSED(data);
}

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

void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
{
504 505
    QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
    QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
506

507 508 509 510 511 512 513
    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();

514 515 516 517 518
    d->m_runControl = runControl;

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

519 520
    if (!d->m_startParameters.environment.size())
        d->m_startParameters.environment = Utils::Environment();
521 522

    const unsigned engineCapabilities = debuggerCapabilities();
hjk's avatar
hjk committed
523
    debuggerCore()->action(OperateByInstruction)
524 525
        ->setEnabled(engineCapabilities & DisassemblerCapability);

526 527
    QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
         qDebug() << state());
528 529
    d->m_lastGoodState = DebuggerNotReady;
    d->m_targetState = DebuggerNotReady;
530
    d->m_progress.setProgressValue(200);
531
    d->queueSetupEngine();
532 533 534 535
}

void DebuggerEngine::resetLocation()
{
536 537
    // Do it after some delay to avoid flicker.
    d->scheduleResetLocation();
538 539
}

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

551
    d->resetLocation();
552

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

572 573 574 575 576 577
    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);
    }
578 579

    // FIXME: Breaks with split views.
580
    if (!d->m_memoryAgent.hasVisibleEditor() || loc.needsRaise())
581
        editorManager->activateEditor(editor);
582
    //qDebug() << "MEMORY: " << d->m_memoryAgent.hasVisibleEditor();
583 584
}

585 586 587
// Called from RunControl.
void DebuggerEngine::handleStartFailed()
{
588
    showMessage("HANDLE RUNCONTROL START FAILED");
589
    d->m_runControl = 0;
590
    d->m_progress.setProgressValue(900);
591 592
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
593 594
}

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

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

QString DebuggerEngine::qtDumperLibraryName() const
{
hjk's avatar
hjk committed
652 653
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool())
        return debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
654 655 656 657 658 659 660 661
    return startParameters().dumperLibrary;
}

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

hjk's avatar
hjk committed
662
DebuggerState DebuggerEngine::lastGoodState() const
663
{
hjk's avatar
hjk committed
664 665 666 667 668 669 670
    return d->m_lastGoodState;
}

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

hjk's avatar
hjk committed
672 673 674
static bool isAllowedTransition(DebuggerState from, DebuggerState to)
{
    switch (from) {
675
    case DebuggerNotReady:
676
        return to == EngineSetupRequested;
677

hjk's avatar
hjk committed
678
    case EngineSetupRequested:
679 680
        return to == EngineSetupOk || to == EngineSetupFailed;
    case EngineSetupFailed:
681 682 683
        // In is the engine's task to go into a proper "Shutdown"
        // state before calling notifyEngineSetupFailed
        return to == DebuggerFinished;
684
    case EngineSetupOk:
hjk's avatar
hjk committed
685
        return to == InferiorSetupRequested || to == EngineShutdownRequested;
686

hjk's avatar
hjk committed
687
    case InferiorSetupRequested:
688
        return to == InferiorSetupOk || to == InferiorSetupFailed;
hjk's avatar
hjk committed
689
    case InferiorSetupFailed:
hjk's avatar
hjk committed
690
        return to == EngineShutdownRequested;
691 692
    case InferiorSetupOk:
        return to == EngineRunRequested;
hjk's avatar
hjk committed
693 694

    case EngineRunRequested:
hjk's avatar
hjk committed
695 696 697 698
        return to == EngineRunFailed
            || to == InferiorRunOk
            || to == InferiorStopOk
            || to == InferiorUnrunnable;
hjk's avatar
hjk committed
699
    case EngineRunFailed:
700
        return to == EngineShutdownRequested;
hjk's avatar
hjk committed
701 702 703 704 705 706

    case InferiorRunRequested:
        return to == InferiorRunOk || to == InferiorRunFailed;
    case InferiorRunFailed:
        return to == InferiorStopOk;
    case InferiorRunOk:
707 708 709
        return to == InferiorStopRequested
            || to == InferiorStopOk // A spontaneous stop.
            || to == InferiorExitOk;
hjk's avatar
hjk committed
710 711 712 713 714

    case InferiorStopRequested:
        return to == InferiorStopOk || to == InferiorStopFailed;
    case InferiorStopOk:
        return to == InferiorRunRequested || to == InferiorShutdownRequested
715
            || to == InferiorStopOk || InferiorExitOk;
716
    case InferiorStopFailed:
hjk's avatar
hjk committed
717
        return to == EngineShutdownRequested;
718

719 720 721
    case InferiorExitOk:
        return to == InferiorShutdownOk;

722
    case InferiorUnrunnable:
hjk's avatar
hjk committed
723 724 725 726 727
        return to == InferiorShutdownRequested;
    case InferiorShutdownRequested:
        return to == InferiorShutdownOk || to == InferiorShutdownFailed;
    case InferiorShutdownOk:
        return to == EngineShutdownRequested;
728
    case InferiorShutdownFailed:
hjk's avatar
hjk committed
729
        return to == EngineShutdownRequested;
730

hjk's avatar
hjk committed
731
    case EngineShutdownRequested:
732
        return to == EngineShutdownOk || to == EngineShutdownFailed;
hjk's avatar
hjk committed
733 734 735 736 737 738
    case EngineShutdownOk:
        return to == DebuggerFinished;
    case EngineShutdownFailed:
        return to == DebuggerFinished;

    case DebuggerFinished:
739
        return to == EngineSetupRequested; // Happens on restart.
740 741
    }

742
    qDebug() << "UNKNOWN DEBUGGER STATE:" << from;
743 744 745
    return false;
}

746 747 748 749 750 751 752 753 754 755 756 757 758
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();
}

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

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

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

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

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

void DebuggerEngine::notifyInferiorSetupOk()
{
hjk's avatar
hjk committed
804
    showMessage(_("NOTE: INFERIOR SETUP OK"));
805 806 807 808
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state());
    setState(InferiorSetupOk);
    if (isMasterEngine())
        d->queueRunEngine();
hjk's avatar
hjk committed
809 810
}

811 812 813 814 815 816 817
void DebuggerEngine::runSlaveEngine()
{
    QTC_ASSERT(isSlaveEngine(), return);
    QTC_ASSERT(state() == InferiorSetupOk, /**/);
    d->queueRunEngine();
}

hjk's avatar
hjk committed
818 819
void DebuggerEnginePrivate::doRunEngine()
{
hjk's avatar
hjk committed
820
    m_engine->showMessage(_("CALL: RUN ENGINE"));
821
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << m_engine << state());
822
    m_progress.setProgressValue(300);
hjk's avatar
hjk committed
823 824 825
    m_engine->runEngine();
}

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

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

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

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

void DebuggerEngine::notifyInferiorRunRequested()
{
hjk's avatar
hjk committed
867
    showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
868
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << this << state());
hjk's avatar
hjk committed
869 870 871 872 873
    setState(InferiorRunRequested);
}

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

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

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

hjk's avatar
hjk committed
912
void DebuggerEngine::notifyInferiorSpontaneousStop()
913
{
914
    showMessage(_("NOTE: INFERIOR SPONTANEOUS STOP"));
915
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state());