debuggerengine.cpp 41.3 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>
hjk's avatar
hjk committed
52
#include <coreplugin/editormanager/editormanager.h>
53
54
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
hjk's avatar
hjk committed
55

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

hjk's avatar
hjk committed
59
#include <texteditor/itexteditor.h>
60
#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
    qmlServerAddress("127.0.0.1"),
99
    qmlServerPort(0),
hjk's avatar
hjk committed
100
    useServerStartScript(false),
101
    connParams(SshConnectionParameters::NoProxy),
102
    toolChainType(ToolChain_UNKNOWN),
103
104
    startMode(NoStartMode),
    executableUid(0)
105
106
{}

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

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

QDebug operator<<(QDebug str, const DebuggerStartParameters &sp)
{
    QDebug nospace = str.nospace();
    nospace << "executable=" << sp.executable
            << " coreFile=" << sp.coreFile
123
            << " processArgs=" << sp.processArgs
124
125
126
127
128
129
130
            << " 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
131
            << " useServerStartScript=" << sp.useServerStartScript
132
133
134
135
136
137
138
139
140
141
            << " 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
142
        SN(EngineSetupRequested)
143
144
        SN(EngineSetupOk)
        SN(EngineSetupFailed)
hjk's avatar
hjk committed
145
146
        SN(EngineRunFailed)
        SN(InferiorSetupRequested)
hjk's avatar
hjk committed
147
        SN(InferiorSetupFailed)
hjk's avatar
hjk committed
148
149
150
151
        SN(EngineRunRequested)
        SN(InferiorRunRequested)
        SN(InferiorRunOk)
        SN(InferiorRunFailed)
152
        SN(InferiorUnrunnable)
hjk's avatar
hjk committed
153
154
        SN(InferiorStopRequested)
        SN(InferiorStopOk)
155
        SN(InferiorStopFailed)
hjk's avatar
hjk committed
156
157
        SN(InferiorShutdownRequested)
        SN(InferiorShutdownOk)
158
        SN(InferiorShutdownFailed)
hjk's avatar
hjk committed
159
160
161
162
        SN(EngineShutdownRequested)
        SN(EngineShutdownOk)
        SN(EngineShutdownFailed)
        SN(DebuggerFinished)
163
164
165
166
167
    }
    return "<unknown>";
#    undef SN
}

168

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



191
192
193
194
195
196
//////////////////////////////////////////////////////////////////////
//
// DebuggerEnginePrivate
//
//////////////////////////////////////////////////////////////////////

197
class DebuggerEnginePrivate : public QObject
198
{
199
200
    Q_OBJECT

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

    ~DebuggerEnginePrivate() {}
223

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

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

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

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

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

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

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

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

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

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

    DebuggerStartParameters m_startParameters;
hjk's avatar
hjk committed
287
288

    // The current state.
289
290
    DebuggerState m_state;

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

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

297
298
299
300
301
302
303
304
    qint64 m_inferiorPid;

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

307
    bool m_isSlaveEngine;
308
309
    DisassemblerAgent m_disassemblerAgent;
    MemoryAgent m_memoryAgent;
310
311
    QScopedPointer<TextEditor::BaseTextMark> m_locationMark;
    QTimer m_locationTimer;
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
};


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

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

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

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

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

343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
void DebuggerEngine::frameUp()
{
    int currentIndex = stackHandler()->currentIndex();
    activateFrame(qMin(currentIndex + 1, stackHandler()->stackSize() - 1));
}

void DebuggerEngine::frameDown()
{
    int currentIndex = stackHandler()->currentIndex();
    activateFrame(qMax(currentIndex - 1, 0));
}

ModulesHandler *DebuggerEngine::modulesHandler() const
{
    return &d->m_modulesHandler;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

449
void DebuggerEngine::fetchMemory(MemoryAgent *, QObject *,
450
451
452
453
454
455
456
457
458
459
460
461
462
463
        quint64 addr, quint64 length)
{
    Q_UNUSED(addr);
    Q_UNUSED(length);
}

void DebuggerEngine::setRegisterValue(int regnr, const QString &value)
{
    Q_UNUSED(regnr);
    Q_UNUSED(value);
}

void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
{
464
465
    //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
    //    qDebug() << qPrintable(msg) << "IN STATE" << state();
466
    debuggerCore()->showMessage(msg, channel, timeout);
467
468
469
470
471
    if (d->m_runControl) {
        d->m_runControl->showMessage(msg, channel);
    } else {
        qWarning("Warning: %s (no active run control)", qPrintable(msg));
    }
472
473
474
475
}

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

    d->m_runControl = runControl;

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

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

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

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

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

void DebuggerEngine::resetLocation()
{
511
    d->m_disassemblerAgent.resetLocation();
512
    d->removeLocationMark();
513
514
}

515
void DebuggerEngine::gotoLocation(const QString &file, int line, bool setMarker)
516
{
517
518
519
520
521
522
    // CDB might hit on breakpoints while shutting down.
    //if (m_shuttingDown)
    //    return;

    d->doRemoveLocationMark();

hjk's avatar
hjk committed
523
524
525
526
527
528
529
530
531
532
533
    EditorManager *editorManager = EditorManager::instance();
    QList<IEditor *> editors = editorManager->editorsForFileName(file);
    if (editors.isEmpty()) {
        editors.append(editorManager->openEditor(file, QString(),
            EditorManager::IgnoreNavigationHistory));
        editors.back()->setProperty(Constants::OPENED_BY_DEBUGGER, true);
    }
    ITextEditor *texteditor = qobject_cast<ITextEditor *>(editors.back());
    if (texteditor)
        texteditor->gotoLine(line, 0);

534
535
    if (setMarker)
        d->m_locationMark.reset(new LocationMark(file, line));
536
537
538
539
}

void DebuggerEngine::gotoLocation(const StackFrame &frame, bool setMarker)
{
540
    if (debuggerCore()->boolSetting(OperateByInstruction) || !frame.isUsable())
541
        d->m_disassemblerAgent.setFrame(frame, true, setMarker);
542
    else
543
        gotoLocation(frame.file, frame.line, setMarker);
544
545
}

546
547
548
// Called from RunControl.
void DebuggerEngine::handleStartFailed()
{
549
    showMessage("HANDLE RUNCONTROL START FAILED");
550
    d->m_runControl = 0;
551
    d->m_progress.setProgressValue(900);
552
553
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
554
555
}

556
557
// Called from RunControl.
void DebuggerEngine::handleFinished()
558
{
559
    showMessage("HANDLE RUNCONTROL FINISHED");
560
    d->m_runControl = 0;
561
562
563
564
    modulesHandler()->removeAll();
    stackHandler()->removeAll();
    threadsHandler()->removeAll();
    watchHandler()->cleanup();
565
    d->m_progress.setProgressValue(1000);
566
    d->m_progress.reportFinished();
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
}

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
591
    return debuggerCore()->boolSetting(UseDebuggingHelpers);
592
593
594
595
}

QStringList DebuggerEngine::qtDumperLibraryLocations() const
{
hjk's avatar
hjk committed
596
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool()) {
597
        const QString customLocation =
hjk's avatar
hjk committed
598
            debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
599
600
601
602
603
604
605
606
607
        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)
{
608
    debuggerCore()->showQtDumperLibraryWarning(details);
609
610
611
612
}

QString DebuggerEngine::qtDumperLibraryName() const
{
hjk's avatar
hjk committed
613
614
    if (debuggerCore()->action(UseCustomDebuggingHelperLocation)->value().toBool())
        return debuggerCore()->action(CustomDebuggingHelperLocation)->value().toString();
615
616
617
618
619
620
621
622
    return startParameters().dumperLibrary;
}

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

hjk's avatar
hjk committed
623
DebuggerState DebuggerEngine::lastGoodState() const
624
{
hjk's avatar
hjk committed
625
626
627
628
629
630
631
    return d->m_lastGoodState;
}

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

hjk's avatar
hjk committed
633
634
635
static bool isAllowedTransition(DebuggerState from, DebuggerState to)
{
    switch (from) {
636
    case DebuggerNotReady:
637
        return to == EngineSetupRequested;
638

hjk's avatar
hjk committed
639
    case EngineSetupRequested:
640
641
        return to == EngineSetupOk || to == EngineSetupFailed;
    case EngineSetupFailed:
642
643
644
        // In is the engine's task to go into a proper "Shutdown"
        // state before calling notifyEngineSetupFailed
        return to == DebuggerFinished;
645
    case EngineSetupOk:
hjk's avatar
hjk committed
646
        return to == InferiorSetupRequested || to == EngineShutdownRequested;
647

hjk's avatar
hjk committed
648
649
    case InferiorSetupRequested:
        return to == EngineRunRequested || to == InferiorSetupFailed;
hjk's avatar
hjk committed
650
    case InferiorSetupFailed:
hjk's avatar
hjk committed
651
652
653
654
655
656
657
        return to == EngineShutdownRequested;

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

    case EngineRunFailed:
658
        return to == EngineShutdownRequested;
hjk's avatar
hjk committed
659
660
661
662
663
664
665
666
667
668
669
670
671

    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;
672
    case InferiorStopFailed:
hjk's avatar
hjk committed
673
        return to == EngineShutdownRequested;
674
675

    case InferiorUnrunnable:
hjk's avatar
hjk committed
676
677
678
679
680
        return to == InferiorShutdownRequested;
    case InferiorShutdownRequested:
        return to == InferiorShutdownOk || to == InferiorShutdownFailed;
    case InferiorShutdownOk:
        return to == EngineShutdownRequested;
681
    case InferiorShutdownFailed:
hjk's avatar
hjk committed
682
        return to == EngineShutdownRequested;
683

hjk's avatar
hjk committed
684
    case EngineShutdownRequested:
685
        return to == EngineShutdownOk || to == EngineShutdownFailed;
hjk's avatar
hjk committed
686
687
688
689
690
691
    case EngineShutdownOk:
        return to == DebuggerFinished;
    case EngineShutdownFailed:
        return to == DebuggerFinished;

    case DebuggerFinished:
692
        return to == EngineSetupRequested; // Happens on restart.
693
694
    }

695
    qDebug() << "UNKNOWN DEBUGGER STATE:" << from;
696
697
698
    return false;
}

699
void DebuggerEngine::notifyEngineSetupFailed()
hjk's avatar
hjk committed
700
{
hjk's avatar
hjk committed
701
    showMessage(_("NOTE: ENGINE SETUP FAILED"));
hjk's avatar
hjk committed
702
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
703
    setState(EngineSetupFailed);
hjk's avatar
hjk committed
704
705
    QTC_ASSERT(d->m_runControl, return);
    d->m_runControl->startFailed();
hjk's avatar
hjk committed
706
    setState(DebuggerFinished);
hjk's avatar
hjk committed
707
708
}

709
void DebuggerEngine::notifyEngineSetupOk()
710
{
hjk's avatar
hjk committed
711
    showMessage(_("NOTE: ENGINE SETUP OK"));
hjk's avatar
hjk committed
712
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
713
    setState(EngineSetupOk);
hjk's avatar
hjk committed
714
    QTC_ASSERT(d->m_runControl, return);
hjk's avatar
hjk committed
715
    showMessage(_("QUEUE: SETUP INFERIOR"));
hjk's avatar
hjk committed
716
    QTimer::singleShot(0, d, SLOT(doSetupInferior()));
717
718
}

hjk's avatar
hjk committed
719
void DebuggerEnginePrivate::doSetupInferior()
720
{
721
    m_engine->showMessage(_("CALL: SETUP INFERIOR"));
hjk's avatar
hjk committed
722
    QTC_ASSERT(state() == EngineSetupOk, qDebug() << state());
723
    m_progress.setProgressValue(250);
hjk's avatar
hjk committed
724
    m_engine->setState(InferiorSetupRequested);
hjk's avatar
hjk committed
725
726
727
728
729
    m_engine->setupInferior();
}

void DebuggerEngine::notifyInferiorSetupFailed()
{
hjk's avatar
hjk committed
730
    showMessage(_("NOTE: INFERIOR SETUP FAILED"));
hjk's avatar
hjk committed
731
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
732
    setState(InferiorSetupFailed);
hjk's avatar
hjk committed
733
    d->queueShutdownEngine();
hjk's avatar
hjk committed
734
735
736
737
}

void DebuggerEngine::notifyInferiorSetupOk()
{
hjk's avatar
hjk committed
738
    showMessage(_("NOTE: INFERIOR SETUP OK"));
hjk's avatar
hjk committed
739
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
hjk's avatar
hjk committed
740
    d->queueRunEngine();
hjk's avatar
hjk committed
741
742
743
744
}

void DebuggerEnginePrivate::doRunEngine()
{
hjk's avatar
hjk committed
745
    m_engine->showMessage(_("CALL: RUN ENGINE"));
hjk's avatar
hjk committed
746
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
747
    m_progress.setProgressValue(300);
hjk's avatar
hjk committed
748
749
750
    m_engine->runEngine();
}

hjk's avatar
hjk committed
751
752
void DebuggerEngine::notifyInferiorUnrunnable()
{
hjk's avatar
hjk committed
753
    showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
754
755
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
756
757
758
759
760
761
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
    setState(InferiorUnrunnable);
}

void DebuggerEngine::notifyEngineRunFailed()
{
hjk's avatar
hjk committed
762
    showMessage(_("NOTE: ENGINE RUN FAILED"));
hjk's avatar
hjk committed
763
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
764
765
766
    d->m_progress.setProgressValue(900);
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
hjk's avatar
hjk committed
767
    setState(EngineRunFailed);
768
    d->queueShutdownEngine();
hjk's avatar
hjk committed
769
770
771
772
}

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

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

void DebuggerEngine::notifyInferiorRunRequested()
{
hjk's avatar
hjk committed
793
    showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
hjk's avatar
hjk committed
794
795
796
797
798
799
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
    setState(InferiorRunRequested);
}

void DebuggerEngine::notifyInferiorRunOk()
{
hjk's avatar
hjk committed
800
    showMessage(_("NOTE: INFERIOR RUN OK"));
hjk's avatar
hjk committed
801
802
803
804
805
806
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
    setState(InferiorRunOk);
}

void DebuggerEngine::notifyInferiorRunFailed()
{
hjk's avatar
hjk committed
807
    showMessage(_("NOTE: INFERIOR RUN FAILED"));
hjk's avatar
hjk committed
808
809
810
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
    setState(InferiorRunFailed);
    setState(InferiorStopOk);
hjk's avatar
hjk committed
811
812
    if (isDying())
        d->queueShutdownInferior();
hjk's avatar
hjk committed
813
814
815
816
}

void DebuggerEngine::notifyInferiorStopOk()
{
hjk's avatar
hjk committed
817
818
    showMessage(_("NOTE: INFERIOR STOP OK"));
    // Ignore spurious notifications after we are set to die.
hjk's avatar
hjk committed
819
    if (isDying()) {
hjk's avatar
hjk committed
820
821
822
823
824
825
826
827
828
829
830
831
832
        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
833
    }
hjk's avatar
hjk committed
834
835
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
    setState(InferiorStopOk);
hjk's avatar
hjk committed
836
837
}

hjk's avatar
hjk committed
838
void DebuggerEngine::notifyInferiorSpontaneousStop()
839
{
hjk's avatar
hjk committed
840
    showMessage(_("NOTE: INFERIOR SPONTANEOUES STOP"));
hjk's avatar
hjk committed
841
842
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
    setState(InferiorStopOk);
843
844
}

hjk's avatar
hjk committed
845
void DebuggerEngine::notifyInferiorStopFailed()
846
{
hjk's avatar
hjk committed
847
    showMessage(_("NOTE: INFERIOR STOP FAILED"));
hjk's avatar
hjk committed
848
849
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
    setState(InferiorStopFailed);
hjk's avatar
hjk committed
850
    d->queueShutdownEngine();
851
852
853
854
}

void DebuggerEnginePrivate::doInterruptInferior()
{
hjk's avatar
hjk committed
855
856
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
    m_engine->setState(InferiorStopRequested);
hjk's avatar
hjk committed
857
    m_engine->showMessage(_("CALL: INTERRUPT INFERIOR"));
858
859
860
    m_engine->interruptInferior();
}

hjk's avatar
hjk committed
861
862
void DebuggerEnginePrivate::doShutdownInferior()
{
863
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
864
865
    m_engine->resetLocation();
    m_targetState = DebuggerFinished;
hjk's avatar
hjk committed
866
    m_engine->showMessage(_("CALL: SHUTDOWN INFERIOR"));
hjk's avatar
hjk committed
867
868
869
870
871
872
    m_engine->shutdownInferior();
}

void DebuggerEngine::notifyInferiorShutdownOk()
{
    showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
hjk's avatar
hjk committed
873
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
874
875
    d->m_lastGoodState = DebuggerNotReady; // A "neutral" value.
    setState(InferiorShutdownOk);
hjk's avatar
hjk committed
876
    d->queueShutdownEngine();
hjk's avatar
hjk committed
877
878
879
880
881
}

void DebuggerEngine::notifyInferiorShutdownFailed()
{
    showMessage(_("INFERIOR SHUTDOWN FAILED"));
Friedemann Kleint's avatar
Friedemann Kleint committed
882
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
hjk's avatar
hjk committed
883
    setState(InferiorShutdownFailed);
hjk's avatar
hjk committed
884
    d->queueShutdownEngine();
hjk's avatar
hjk committed
885
886
887
888
}

void DebuggerEngine::notifyInferiorIll()
{
hjk's avatar
hjk committed
889
    showMessage(_("NOTE: INFERIOR ILL"));
hjk's avatar
hjk committed
890
891
892
893
894
895
896
897
898
899
900
    // 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
901
    d->queueShutdownInferior();
hjk's avatar
hjk committed
902
903
904
905
}

void DebuggerEnginePrivate::doShutdownEngine()
{
906
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
hjk's avatar
hjk committed
907
    m_targetState = DebuggerFinished;
hjk's avatar
hjk committed
908
    m_engine->showMessage(_("CALL: SHUTDOWN ENGINE"));
hjk's avatar
hjk committed
909
910
911
912
913
    m_engine->shutdownEngine();
}

void DebuggerEngine::notifyEngineShutdownOk()
{
hjk's avatar
hjk committed
914
    showMessage(_("NOTE: ENGINE SHUTDOWN OK"));
hjk's avatar
hjk committed
915
916
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
    setState(EngineShutdownOk);
917
    d->queueFinishDebugger();
hjk's avatar
hjk committed
918
919
920
}

void DebuggerEngine::notifyEngineShutdownFailed()
hjk's avatar
hjk committed
921
{
hjk's avatar
hjk committed
922
    showMessage(_("NOTE: ENGINE SHUTDOWN FAILED"));
hjk's avatar
hjk committed
923
924
    QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
    setState(EngineShutdownFailed);
925
    d->queueFinishDebugger();
hjk's avatar
hjk committed
926
927
928
929
}

void DebuggerEnginePrivate::doFinishDebugger()
{
hjk's avatar
hjk committed
930
    m_engine->showMessage(_("NOTE: FINISH DEBUGGER"));
931
    QTC_ASSERT(state() == DebuggerFinished, qDebug() << state());
hjk's avatar
hjk committed
932
    m_engine->resetLocation();
933
934
935
936
    if (!m_engine->isSlaveEngine()) {
        QTC_ASSERT(m_runControl, return);
        m_runControl->debuggingFinished();
    }
hjk's avatar
hjk committed
937
938
939
940
}

void DebuggerEngine::notifyEngineIll()
{
hjk's avatar
hjk committed
941
    showMessage(_("NOTE: ENGINE ILL ******"));
hjk's avatar
hjk committed
942
943
    d->m_targetState = DebuggerFinished;
    d->m_lastGoodState = d->m_state;
hjk's avatar
hjk committed
944
945
946
    switch (state()) {
        case InferiorRunRequested:
        case InferiorRunOk:
947
948
949
950
951
952
953
            // 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
954
955
        case InferiorStopRequested:
        case InferiorStopOk:
956
            showMessage(_("FORWARDING STATE TO InferiorShutdownFailed"));
hjk's avatar
hjk committed
957
            setState(InferiorShutdownFailed, true);
958
            d->queueShutdownEngine();
hjk's avatar
hjk committed
959
960
            break;
        default:
961
            d->queueShutdownEngine();
hjk's avatar
hjk committed
962
            break;
hjk's avatar
hjk committed
963
964
965
966
967
    }
}

void DebuggerEngine::notifyEngineSpontaneousShutdown()
{
hjk's avatar
hjk committed
968
    showMessage(_("NOTE: ENGINE SPONTANEOUS SHUTDOWN"));
969
    setState(EngineShutdownOk, true);
hjk's avatar
hjk committed
970
    d->queueFinishDebugger();
hjk's avatar
hjk committed
971
972
973
974
}

void DebuggerEngine::notifyInferiorExited()
{
hjk's avatar
hjk committed
975
    showMessage(_("NOTE: INFERIOR EXITED"));
hjk's avatar
hjk committed
976
977
978
979
980
981
982
983
984
985
986
    resetLocation();

    // This can be issued in almost any state. We assume, though,
    // that at this point of time the inferior is not running anymore,
    // even if stop notification were not issued or got lost.
    if (state() == InferiorRunOk) {
        setState(InferiorStopRequested);
        setState(InferiorStopOk);
    }
    setState(InferiorShutdownRequested);
    setState(InferiorShutdownOk);
987
    d->queueShutdownEngine();
988
989
}

990
991
void DebuggerEngine::setState(DebuggerState state, bool forced)
{
hjk's avatar
hjk committed
992
993
    //qDebug() << "STATUS CHANGE: FROM " << stateName(d->m_state)
    //         << " TO " << stateName(state);
994

995
996
997
    DebuggerState oldState = d->m_state;
    d->m_state = state;

hjk's avatar
hjk committed
998
999
1000
    QString msg = _("State changed%5 from %1(%2) to %3(%4).")
     .arg(stateName(oldState)).arg(oldState).arg(stateName(state)).arg(state)
     .arg(forced ? " BY FORCE" : "");
1001
    if (!forced && !isAllowedTransition(oldState, state))
1002
1003
        qDebug() << "UNEXPECTED STATE TRANSITION: " << msg;

hjk's avatar
hjk committed
1004
1005
1006
1007
1008
1009
1010
    if (state == DebuggerFinished) {
        // Give up ownership on claimed breakpoints.
        BreakHandler *handler = breakHandler();
        foreach (BreakpointId id, handler->engineBreakpointIds(this))
            handler->notifyBreakpointReleased(id);
    }

1011
1012
1013
1014
    const bool running = d->m_state == InferiorRunOk;
    if (running)
        threadsHandler()->notifyRunning();

1015
    showMessage(msg, LogDebug);
1016
    updateViews();
1017
1018
1019
1020

    emit stateChanged(d->m_state);
}

1021
1022
void DebuggerEngine::updateViews()
{
1023
1024
1025
    // The slave engines are not entitled to change the view. Their wishes
    // should be coordinated by their master engine.
    if (isSlaveEngine())
hjk's avatar
x  
hjk committed
1026
        return;
1027
    debuggerCore()->updateState(this);
1028
1029
}

1030
1031
1032
1033
1034
1035
bool DebuggerEngine::isSlaveEngine() const
{
    return d->m_isSlaveEngine;
}

void DebuggerEngine::setSlaveEngine(bool value)
1036
{
1037
    d->m_isSlaveEngine = value;
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
}

bool DebuggerEngine::debuggerActionsEnabled() const
{
    return debuggerActionsEnabled(d->m_state);
}

bool DebuggerEngine::debugg