debuggerengine.cpp 56.2 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11 12
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
Eike Ziller's avatar
Eike Ziller committed
13 14
** conditions see http://www.qt.io/licensing.  For further information
** use the contact form at http://www.qt.io/contact-us.
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
hjk's avatar
hjk committed
24 25 26
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
30 31 32

#include "debuggerengine.h"

33
#include "debuggerinternalconstants.h"
34
#include "debuggeractions.h"
35
#include "debuggercore.h"
36
#include "debuggerruncontrol.h"
37
#include "debuggerstringutils.h"
Friedemann Kleint's avatar
Friedemann Kleint committed
38
#include "debuggerstartparameters.h"
39
#include "debuggertooltipmanager.h"
40 41

#include "breakhandler.h"
David Schulz's avatar
David Schulz committed
42 43
#include "disassembleragent.h"
#include "memoryagent.h"
44 45 46 47 48 49
#include "moduleshandler.h"
#include "registerhandler.h"
#include "sourcefileshandler.h"
#include "stackhandler.h"
#include "threadshandler.h"
#include "watchhandler.h"
50
#include <debugger/shared/peutils.h>
51

hjk's avatar
hjk committed
52
#include <coreplugin/editormanager/editormanager.h>
53
#include <coreplugin/editormanager/ieditor.h>
hjk's avatar
hjk committed
54
#include <coreplugin/icore.h>
55 56
#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/progressmanager/futureprogress.h>
hjk's avatar
hjk committed
57

hjk's avatar
hjk committed
58
#include <projectexplorer/projectexplorer.h>
59 60
#include <projectexplorer/taskhub.h>

61
#include <texteditor/texteditor.h>
62

63
#include <utils/fileinprojectfinder.h>
hjk's avatar
hjk committed
64 65 66
#include <utils/macroexpander.h>
#include <utils/qtcassert.h>
#include <utils/savedaction.h>
67

68
#include <qmljs/consolemanagerinterface.h>
69

70 71 72
#include <QDebug>
#include <QTimer>
#include <QFileInfo>
73
#include <QDir>
74

75
#include <QMessageBox>
76

hjk's avatar
hjk committed
77
using namespace Core;
78
using namespace Debugger::Internal;
hjk's avatar
hjk committed
79 80
using namespace ProjectExplorer;
using namespace TextEditor;
81

82 83 84 85
enum { debug = 0 };

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

87 88 89 90
//#define WITH_BENCHMARK
#ifdef WITH_BENCHMARK
#include <valgrind/callgrind.h>
#endif
91

92 93 94 95 96 97
///////////////////////////////////////////////////////////////////////
//
// DebuggerStartParameters
//
///////////////////////////////////////////////////////////////////////

hjk's avatar
hjk committed
98 99 100
// VariableManager Prefix
const char PrefixDebugExecutable[]  = "DebuggedExecutable";

101 102
namespace Debugger {

Friedemann Kleint's avatar
Friedemann Kleint committed
103 104 105 106 107 108 109 110 111
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;
112
    m_from = frame.from;
Friedemann Kleint's avatar
Friedemann Kleint committed
113 114
}

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

QDebug operator<<(QDebug str, const DebuggerStartParameters &sp)
{
    QDebug nospace = str.nospace();
    nospace << "executable=" << sp.executable
            << " coreFile=" << sp.coreFile
126
            << " processArgs=" << sp.processArgs
127 128 129 130 131 132
            << " environment=<" << sp.environment.size() << " variables>"
            << " workingDir=" << sp.workingDirectory
            << " attachPID=" << sp.attachPID
            << " useTerminal=" << sp.useTerminal
            << " remoteChannel=" << sp.remoteChannel
            << " serverStartScript=" << sp.serverStartScript
133
            << " abi=" << sp.toolChainAbi.toString() << '\n';
134 135 136
    return str;
}

137

138 139 140 141 142 143
//////////////////////////////////////////////////////////////////////
//
// DebuggerEnginePrivate
//
//////////////////////////////////////////////////////////////////////

144 145 146 147 148 149 150 151 152
// transitions:
//   None->Requested
//   Requested->Succeeded
//   Requested->Failed
//   Requested->Cancelled
enum RemoteSetupState { RemoteSetupNone, RemoteSetupRequested,
                        RemoteSetupSucceeded, RemoteSetupFailed,
                        RemoteSetupCancelled };

153
class DebuggerEnginePrivate : public QObject
154
{
155 156
    Q_OBJECT

157
public:
158
    DebuggerEnginePrivate(DebuggerEngine *engine, const DebuggerStartParameters &sp)
159
      : m_engine(engine),
160
        m_masterEngine(0),
161 162 163
        m_runControl(0),
        m_startParameters(sp),
        m_state(DebuggerNotReady),
hjk's avatar
hjk committed
164
        m_lastGoodState(DebuggerNotReady),
Friedemann Kleint's avatar
Friedemann Kleint committed
165
        m_targetState(DebuggerNotReady),
166
        m_remoteSetupState(RemoteSetupNone),
167
        m_inferiorPid(0),
168
        m_modulesHandler(engine),
169
        m_registerHandler(),
170 171
        m_sourceFilesHandler(),
        m_stackHandler(),
hjk's avatar
hjk committed
172
        m_threadsHandler(),
173
        m_watchHandler(engine),
174
        m_disassemblerAgent(engine),
175
        m_memoryAgent(engine),
176
        m_isStateDebugging(false)
177
    {
178
        connect(&m_locationTimer, SIGNAL(timeout()), SLOT(resetLocation()));
hjk's avatar
hjk committed
179
        connect(action(IntelFlavor), SIGNAL(valueChanged(QVariant)),
180
                SLOT(reloadDisassembly()));
181

hjk's avatar
hjk committed
182
        Utils::globalMacroExpander()->registerFileVariables(PrefixDebugExecutable,
183
            tr("Debugged executable"),
Orgad Shaneh's avatar
Orgad Shaneh committed
184
            [this]() { return m_startParameters.executable; });
185
    }
186

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

196 197 198 199 200
    void reloadDisassembly()
    {
        m_disassemblerAgent.reload();
    }

201 202 203 204 205 206 207 208 209 210 211 212 213 214
    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()));
    }

215 216
    void queueRunEngine()
    {
hjk's avatar
hjk committed
217 218 219 220 221
        m_engine->setState(EngineRunRequested);
        m_engine->showMessage(_("QUEUE: RUN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doRunEngine()));
    }

222 223
    void queueShutdownEngine()
    {
hjk's avatar
hjk committed
224 225 226 227 228
        m_engine->setState(EngineShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN ENGINE"));
        QTimer::singleShot(0, this, SLOT(doShutdownEngine()));
    }

229 230
    void queueShutdownInferior()
    {
hjk's avatar
hjk committed
231 232 233 234 235
        m_engine->setState(InferiorShutdownRequested);
        m_engine->showMessage(_("QUEUE: SHUTDOWN INFERIOR"));
        QTimer::singleShot(0, this, SLOT(doShutdownInferior()));
    }

236 237
    void queueFinishDebugger()
    {
238 239 240
        QTC_ASSERT(state() == EngineShutdownOk
            || state() == EngineShutdownFailed, qDebug() << state());
        m_engine->setState(DebuggerFinished);
241 242 243 244 245
        resetLocation();
        if (isMasterEngine()) {
            m_engine->showMessage(_("QUEUE: FINISH DEBUGGER"));
            QTimer::singleShot(0, this, SLOT(doFinishDebugger()));
        }
hjk's avatar
hjk committed
246 247
    }

248 249
    void raiseApplication()
    {
250 251
        QTC_ASSERT(runControl(), return);
        runControl()->bringApplicationToForeground(m_inferiorPid);
252 253
    }

254
    void scheduleResetLocation()
255
    {
256
        m_stackHandler.scheduleResetLocation();
257
        m_watchHandler.scheduleResetLocation();
258
        m_threadsHandler.scheduleResetLocation();
259
        m_disassemblerAgent.scheduleResetLocation();
260 261 262 263
        m_locationTimer.setSingleShot(true);
        m_locationTimer.start(80);
    }

264
    void resetLocation()
265 266 267
    {
        m_locationTimer.stop();
        m_locationMark.reset();
268
        m_stackHandler.resetLocation();
269
        m_watchHandler.resetLocation();
270
        m_threadsHandler.resetLocation();
271
        m_disassemblerAgent.resetLocation();
272 273
    }

274
public:
hjk's avatar
hjk committed
275
    DebuggerState state() const { return m_state; }
276
    RemoteSetupState remoteSetupState() const { return m_remoteSetupState; }
277 278 279
    bool isMasterEngine() const { return m_engine->isMasterEngine(); }
    DebuggerRunControl *runControl() const
        { return m_masterEngine ? m_masterEngine->runControl() : m_runControl; }
280
    void setRemoteSetupState(RemoteSetupState state);
hjk's avatar
hjk committed
281

282
    DebuggerEngine *m_engine; // Not owned.
283
    DebuggerEngine *m_masterEngine; // Not owned
284 285 286
    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
    // State of RemoteSetup signal/slots.
    RemoteSetupState m_remoteSetupState;

300 301 302 303 304 305 306 307
    qint64 m_inferiorPid;

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

310 311
    DisassemblerAgent m_disassemblerAgent;
    MemoryAgent m_memoryAgent;
hjk's avatar
hjk committed
312
    QScopedPointer<TextEditor::TextMark> m_locationMark;
313
    QTimer m_locationTimer;
314 315

    bool m_isStateDebugging;
316

317
    Utils::FileInProjectFinder m_fileFinder;
318 319 320 321 322 323 324 325 326
};


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

327 328
DebuggerEngine::DebuggerEngine(const DebuggerStartParameters &startParameters)
  : d(new DebuggerEnginePrivate(this, startParameters))
329
{}
330 331 332

DebuggerEngine::~DebuggerEngine()
{
333 334
    disconnect();
    delete d;
335 336
}

337 338 339 340 341 342 343 344 345 346 347
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)
348
        SN(InferiorSetupOk)
349 350 351 352 353 354 355 356
        SN(EngineRunRequested)
        SN(InferiorRunRequested)
        SN(InferiorRunOk)
        SN(InferiorRunFailed)
        SN(InferiorUnrunnable)
        SN(InferiorStopRequested)
        SN(InferiorStopOk)
        SN(InferiorStopFailed)
357
        SN(InferiorExitOk)
358 359 360 361 362 363 364 365 366 367 368 369
        SN(InferiorShutdownRequested)
        SN(InferiorShutdownOk)
        SN(InferiorShutdownFailed)
        SN(EngineShutdownRequested)
        SN(EngineShutdownOk)
        SN(EngineShutdownFailed)
        SN(DebuggerFinished)
    }
    return "<unknown>";
#    undef SN
}

370
void DebuggerEngine::showStatusMessage(const QString &msg, int timeout) const
371
{
372
    showMessage(msg, StatusBar, timeout);
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));
}

387 388 389 390 391
void DebuggerEngine::setTargetState(DebuggerState state)
{
    d->m_targetState = state;
}

392 393
ModulesHandler *DebuggerEngine::modulesHandler() const
{
394 395 396
    return d->m_masterEngine
        ? d->m_masterEngine->modulesHandler()
        : &d->m_modulesHandler;
397 398 399 400
}

RegisterHandler *DebuggerEngine::registerHandler() const
{
401 402 403
    return d->m_masterEngine
        ? d->m_masterEngine->registerHandler()
        : &d->m_registerHandler;
404 405 406 407
}

StackHandler *DebuggerEngine::stackHandler() const
{
Aurindam Jana's avatar
Aurindam Jana committed
408 409 410
    return d->m_masterEngine
        ? d->m_masterEngine->stackHandler()
        : &d->m_stackHandler;
411 412 413 414
}

ThreadsHandler *DebuggerEngine::threadsHandler() const
{
415 416 417
    return d->m_masterEngine
        ? d->m_masterEngine->threadsHandler()
        : &d->m_threadsHandler;
418 419 420 421
}

WatchHandler *DebuggerEngine::watchHandler() const
{
422 423 424
    return d->m_masterEngine
        ? d->m_masterEngine->watchHandler()
        : &d->m_watchHandler;
425 426 427 428
}

SourceFilesHandler *DebuggerEngine::sourceFilesHandler() const
{
429 430 431
    return d->m_masterEngine
        ? d->m_masterEngine->sourceFilesHandler()
        : &d->m_sourceFilesHandler;
432 433 434 435
}

QAbstractItemModel *DebuggerEngine::modulesModel() const
{
436
   return modulesHandler()->model();
437 438 439 440
}

QAbstractItemModel *DebuggerEngine::registerModel() const
{
441
    return registerHandler()->model();
442 443 444 445
}

QAbstractItemModel *DebuggerEngine::stackModel() const
{
446
    return stackHandler()->model();
447 448 449 450
}

QAbstractItemModel *DebuggerEngine::threadsModel() const
{
451
    return threadsHandler()->model();
452 453
}

hjk's avatar
hjk committed
454 455 456
QAbstractItemModel *DebuggerEngine::watchModel() const
{
    return watchHandler()->model();
457 458
}

459 460
QAbstractItemModel *DebuggerEngine::sourceFilesModel() const
{
461
    return sourceFilesHandler()->model();
462 463
}

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

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

478 479 480 481 482 483 484 485
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
{
486 487 488 489
    if (d->m_masterEngine) {
        d->m_masterEngine->showMessage(msg, channel, timeout);
        return;
    }
490 491
    //if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
    //    qDebug() << qPrintable(msg) << "IN STATE" << state();
492
    QmlJS::ConsoleManagerInterface *consoleManager = QmlJS::ConsoleManagerInterface::instance();
493
    if (channel == ConsoleOutput && consoleManager)
494
        consoleManager->printToConsolePane(QmlJS::ConsoleItem::UndefinedType, msg);
495

496
    debuggerCore()->showMessage(msg, channel, timeout);
497 498 499 500 501 502 503 504 505 506 507 508 509
    if (d->m_runControl) {
        switch (channel) {
            case AppOutput:
                d->m_runControl->appendMessage(msg, Utils::StdOutFormatSameLine);
                break;
            case AppError:
                d->m_runControl->appendMessage(msg, Utils::StdErrFormatSameLine);
                break;
            case AppStuff:
                d->m_runControl->appendMessage(msg, Utils::DebugFormat);
                break;
        }
    } else {
510
        qWarning("Warning: %s (no active run control)", qPrintable(msg));
511
    }
512 513 514 515
}

void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
{
516 517
    QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
    QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
518

519
    d->m_progress.setProgressRange(0, 1000);
520
    FutureProgress *fp = ProgressManager::addTask(d->m_progress.future(),
521
        tr("Launching Debugger"), "Debugger.Launcher");
522
    connect(fp, SIGNAL(canceled()), this, SLOT(quitDebugger()));
523
    fp->setKeepOnFinish(FutureProgress::HideOnFinish);
524 525
    d->m_progress.reportStarted();

526 527 528 529
    d->m_runControl = runControl;

    d->m_inferiorPid = d->m_startParameters.attachPID > 0
        ? d->m_startParameters.attachPID : 0;
530 531
    if (d->m_inferiorPid)
        d->m_runControl->setApplicationProcessHandle(ProcessHandle(d->m_inferiorPid));
532

533 534
    if (!d->m_startParameters.environment.size())
        d->m_startParameters.environment = Utils::Environment();
535

hjk's avatar
hjk committed
536
    action(OperateByInstruction)->setEnabled(hasCapability(DisassemblerCapability));
537

538 539
    QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished,
         qDebug() << state());
540 541
    d->m_lastGoodState = DebuggerNotReady;
    d->m_targetState = DebuggerNotReady;
542
    d->m_progress.setProgressValue(200);
543
    d->queueSetupEngine();
544 545 546 547
}

void DebuggerEngine::resetLocation()
{
548 549
    // Do it after some delay to avoid flicker.
    d->scheduleResetLocation();
550 551
}

552
void DebuggerEngine::gotoLocation(const Location &loc)
553
{
Aurindam Jana's avatar
Aurindam Jana committed
554 555
     d->resetLocation();

Aurindam Jana's avatar
Aurindam Jana committed
556
    if ((hasCapability(OperateByInstructionCapability) &&
hjk's avatar
hjk committed
557
            boolSetting(OperateByInstruction)) || !loc.hasDebugInfo()) {
558 559 560
        d->m_disassemblerAgent.setLocation(loc);
        return;
    }
561 562 563 564 565
    // CDB might hit on breakpoints while shutting down.
    //if (m_shuttingDown)
    //    return;


566
    const QString file = QDir::cleanPath(loc.fileName());
567
    const int line = loc.lineNumber();
568
    bool newEditor = false;
569
    IEditor *editor = EditorManager::openEditor(file, Id(),
570 571
                                                EditorManager::IgnoreNavigationHistory, &newEditor);
    QTC_ASSERT(editor, return); // Unreadable file?
572

hjk's avatar
hjk committed
573
    editor->gotoLine(line, 0, !boolSetting(StationaryEditorWhileStepping));
574

575 576
    if (newEditor)
        editor->document()->setProperty(Constants::OPENED_BY_DEBUGGER, true);
hjk's avatar
hjk committed
577

578
    if (loc.needsMarker()) {
hjk's avatar
hjk committed
579
        d->m_locationMark.reset(new TextEditor::TextMark(file, line));
580
        d->m_locationMark->setIcon(debuggerCore()->locationMarkIcon());
hjk's avatar
hjk committed
581
        d->m_locationMark->setPriority(TextEditor::TextMark::HighPriority);
582
    }
583 584

    //qDebug() << "MEMORY: " << d->m_memoryAgent.hasVisibleEditor();
585 586
}

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

597 598
// Called from RunControl.
void DebuggerEngine::handleFinished()
599
{
600
    showMessage(QLatin1String("HANDLE RUNCONTROL FINISHED"));
601
    d->m_runControl = 0;
602 603
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
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;
}

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

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

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

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

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

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

    case EngineRunRequested:
hjk's avatar
hjk committed
658
        return to == EngineRunFailed
659
            || to == InferiorRunRequested
hjk's avatar
hjk committed
660 661 662
            || to == InferiorRunOk
            || to == InferiorStopOk
            || to == InferiorUnrunnable;
hjk's avatar
hjk committed
663
    case EngineRunFailed:
664
        return to == EngineShutdownRequested;
hjk's avatar
hjk committed
665 666 667 668 669 670

    case InferiorRunRequested:
        return to == InferiorRunOk || to == InferiorRunFailed;
    case InferiorRunFailed:
        return to == InferiorStopOk;
    case InferiorRunOk:
671 672 673
        return to == InferiorStopRequested
            || to == InferiorStopOk // A spontaneous stop.
            || to == InferiorExitOk;
hjk's avatar
hjk committed
674 675 676 677 678

    case InferiorStopRequested:
        return to == InferiorStopOk || to == InferiorStopFailed;
    case InferiorStopOk:
        return to == InferiorRunRequested || to == InferiorShutdownRequested
Orgad Shaneh's avatar
Orgad Shaneh committed
679
            || to == InferiorStopOk || to == InferiorExitOk;
680
    case InferiorStopFailed:
hjk's avatar
hjk committed
681
        return to == EngineShutdownRequested;
682

683 684 685
    case InferiorExitOk:
        return to == InferiorShutdownOk;

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

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

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

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

710 711
void DebuggerEngine::setupSlaveEngine()
{
712
    QTC_CHECK(state() == DebuggerNotReady);
713 714 715 716 717 718 719
    d->queueSetupEngine();
}

void DebuggerEnginePrivate::doSetupEngine()
{
    m_engine->showMessage(_("CALL: SETUP ENGINE"));
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << m_engine << state());
720
    m_engine->validateExecutable(&m_startParameters);
721 722 723
    m_engine->setupEngine();
}

724
void DebuggerEngine::notifyEngineSetupFailed()
hjk's avatar
hjk committed
725
{
hjk's avatar
hjk committed
726
    showMessage(_("NOTE: ENGINE SETUP FAILED"));
727 728 729 730 731 732 733
    QTC_ASSERT(d->remoteSetupState() == RemoteSetupNone
               || d->remoteSetupState() == RemoteSetupRequested
               || d->remoteSetupState() == RemoteSetupSucceeded,
               qDebug() << this << "remoteSetupState" << d->remoteSetupState());
    if (d->remoteSetupState() == RemoteSetupRequested)
        d->setRemoteSetupState(RemoteSetupCancelled);

734
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
735
    setState(EngineSetupFailed);
hjk's avatar
hjk committed
736
    if (isMasterEngine() && runControl())
737
        runControl()->startFailed();
hjk's avatar
hjk committed
738
    setState(DebuggerFinished);
hjk's avatar
hjk committed
739 740
}

741
void DebuggerEngine::notifyEngineSetupOk()
742
{
hjk's avatar
hjk committed
743
    showMessage(_("NOTE: ENGINE SETUP OK"));
744 745 746 747
    QTC_ASSERT(d->remoteSetupState() == RemoteSetupNone
               || d->remoteSetupState() == RemoteSetupSucceeded,
               qDebug() << this << "remoteSetupState" << d->remoteSetupState());

748
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
749
    setState(EngineSetupOk);
hjk's avatar
hjk committed
750
    showMessage(_("QUEUE: SETUP INFERIOR"));
751
    if (isMasterEngine())
752 753 754 755 756
        d->queueSetupInferior();
}

void DebuggerEngine::setupSlaveInferior()
{
757
    QTC_CHECK(state() == EngineSetupOk);
758
    d->queueSetupInferior();
759 760
}

hjk's avatar
hjk committed
761
void DebuggerEnginePrivate::doSetupInferior()
762
{
763
    m_engine->showMessage(_("CALL: SETUP INFERIOR"));
764
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << m_engine << state());
765
    m_progress.setProgressValue(250);
hjk's avatar
hjk committed
766 767 768 769 770
    m_engine->setupInferior();
}

void DebuggerEngine::notifyInferiorSetupFailed()
{
hjk's avatar
hjk committed
771
    showMessage(_("NOTE: INFERIOR SETUP FAILED"));
772
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state());
773
    showStatusMessage(tr("Setup failed."));
hjk's avatar
hjk committed
774
    setState(InferiorSetupFailed);
775 776
    if (isMasterEngine())
        d->queueShutdownEngine();
hjk's avatar
hjk committed
777 778 779 780
}

void DebuggerEngine::notifyInferiorSetupOk()
{
781 782 783
#ifdef WITH_BENCHMARK
    CALLGRIND_START_INSTRUMENTATION;
#endif
hjk's avatar
hjk committed
784
    showMessage(_("NOTE: INFERIOR SETUP OK"));
785 786 787 788
    QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state());
    setState(InferiorSetupOk);
    if (isMasterEngine())
        d->queueRunEngine();
hjk's avatar
hjk committed
789 790
}

791 792 793
void DebuggerEngine::runSlaveEngine()
{
    QTC_ASSERT(isSlaveEngine(), return);
794
    QTC_CHECK(state() == InferiorSetupOk);
795 796 797
    d->queueRunEngine();
}

hjk's avatar
hjk committed
798 799
void DebuggerEnginePrivate::doRunEngine()
{
hjk's avatar
hjk committed
800
    m_engine->showMessage(_("CALL: RUN ENGINE"));
801
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << m_engine << state());
802
    m_progress.setProgressValue(300);
hjk's avatar
hjk committed
803 804 805
    m_engine->runEngine();
}

hjk's avatar
hjk committed
806 807
void DebuggerEngine::notifyInferiorUnrunnable()
{
hjk's avatar
hjk committed
808
    showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
809 810
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
811
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
812
    showStatusMessage(tr("Loading finished."));
hjk's avatar
hjk committed
813 814 815 816 817
    setState(InferiorUnrunnable);
}

void DebuggerEngine::notifyEngineRunFailed()
{
hjk's avatar
hjk committed
818
    showMessage(_("NOTE: ENGINE RUN FAILED"));
819
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
820 821 822
    d->m_progress.setProgressValue(900);
    d->m_progress.reportCanceled();
    d->m_progress.reportFinished();
823
    showStatusMessage(tr("Run failed."));
hjk's avatar
hjk committed
824
    setState(EngineRunFailed);
825 826
    if (isMasterEngine())
        d->queueShutdownEngine();
hjk's avatar
hjk committed
827 828
}

829 830 831 832 833 834 835 836 837 838 839
void DebuggerEngine::notifyEngineRequestRemoteSetup()
{
    showMessage(_("NOTE: REQUEST REMOTE SETUP"));
    QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
    QTC_ASSERT(d->remoteSetupState() == RemoteSetupNone, qDebug() << this
               << "remoteSetupState" << d->remoteSetupState());

    d->setRemoteSetupState(RemoteSetupRequested);
    emit requestRemoteSetup();
}

hjk's avatar
hjk committed
840 841 842 843 844
void DebuggerEngine::notifyEngineRemoteServerRunning(const QByteArray &, int /*pid*/)
{
    showMessage(_("NOTE: REMOTE SERVER RUNNING IN MULTIMODE"));
}

845
void DebuggerEngine::notifyEngineRemoteSetupFinished(const RemoteSetupResult &result)
846 847 848 849 850 851 852 853 854
{
    QTC_ASSERT(state() == EngineSetupRequested
               || state() == EngineSetupFailed
               || state() == DebuggerFinished, qDebug() << this << state());

    QTC_ASSERT(d->remoteSetupState() == RemoteSetupRequested
               || d->remoteSetupState() == RemoteSetupCancelled,
               qDebug() << this << "remoteSetupState" << d->remoteSetupState());

855 856 857
    if (result.success) {
        showMessage(_("NOTE: REMOTE SETUP DONE: GDB SERVER PORT: %1  QML PORT %2")
                    .arg(result.gdbServerPort).arg(result.qmlServerPort));
858

859 860
        if (d->remoteSetupState() != RemoteSetupCancelled)
            d->setRemoteSetupState(RemoteSetupSucceeded);
hjk's avatar
hjk committed
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875

        if (result.gdbServerPort != InvalidPid) {
            QString &rc = d->m_startParameters.remoteChannel;
            const int sepIndex = rc.lastIndexOf(QLatin1Char(':'));
            if (sepIndex != -1) {
                rc.replace(sepIndex + 1, rc.count() - sepIndex - 1,
                           QString::number(result.gdbServerPort));
            }
        }

        if (result.qmlServerPort != InvalidPort) {
            d->m_startParameters.qmlServerPort = result.qmlServerPort;
            d->m_startParameters.processArgs.replace(_("%qml_port%"), QString::number(result.qmlServerPort));
        }

876 877 878
    } else {
        showMessage(_("NOTE: REMOTE SETUP FAILED: ") + result.reason);
    }
879 880
}

881 882 883 884 885 886 887 888 889 890
void DebuggerEngine::notifyEngineRunOkAndInferiorRunRequested()
{
    showMessage(_("NOTE: ENGINE RUN OK AND INFERIOR RUN REQUESTED"));
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
    showStatusMessage(tr("Running."));
    setState(InferiorRunRequested);
}

hjk's avatar
hjk committed
891 892
void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
{
hjk's avatar
hjk committed
893
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR RUN OK"));
894 895
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
896
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
897
    showStatusMessage(tr("Running."));
hjk's avatar
hjk committed
898
    setState(InferiorRunOk);
hjk's avatar
hjk committed
899 900 901 902
}

void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
{
hjk's avatar
hjk committed
903
    showMessage(_("NOTE: ENGINE RUN AND INFERIOR STOP OK"));
904 905
    d->m_progress.setProgressValue(1000);
    d->m_progress.reportFinished();
906
    QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
907
    showStatusMessage(tr("Stopped."));
hjk's avatar
hjk committed
908
    setState(InferiorStopOk);
hjk's avatar
hjk committed
909 910 911 912
}

void DebuggerEngine::notifyInferiorRunRequested()
{
hjk's avatar
hjk committed
913
    showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
914
    QTC_ASSERT(state() == InferiorStopOk, qDebug() << this << state());
915
    showStatusMessage(tr("Run requested..."));
hjk's avatar
hjk committed
916 917 918 919 920
    setState(InferiorRunRequested);
}

void DebuggerEngine::notifyInferiorRunOk()
{
921 922 923 924
    if (state() == InferiorRunOk) {
        showMessage(_("NOTE: INFERIOR RUN OK - REPEATED."));
        return;
    }
hjk's avatar
hjk committed
925
    showMessage(_("NOTE: INFERIOR RUN OK"));
926
    showStatusMessage(tr("Running."));
927
    // Transition from StopRequested can happen in remotegdbadapter.
928
    QTC_ASSERT(state() == InferiorRunRequested
929
        || state() == InferiorStopOk
930
        || state() == InferiorStopRequested, qDebug() << this << state());
hjk's avatar
hjk committed
931 932 933 934 935
    setState(InferiorRunOk);
}

void DebuggerEngine::notifyInferiorRunFailed()
{
hjk's avatar
hjk committed
936
    showMessage(_("NOTE: INFERIOR RUN FAILED"));
937
    QTC_ASSERT(state() == InferiorRunRequested, qDebug() << this << state());
hjk's avatar
hjk committed
938 939
    setState(InferiorRunFailed);
    setState(InferiorStopOk);
hjk's avatar
hjk committed
940 941
    if (isDying())
        d->queueShutdownInferior();
hjk's avatar
hjk committed
942 943 944 945
}

void DebuggerEngine::notifyInferiorStopOk()
{
hjk's avatar
hjk committed
946 947
    showMessage(_("NOTE: INFERIOR STOP OK"));
    // Ignore spurious notifications after we are set to die.
hjk's avatar
hjk committed
948
    if (isDying()) {
hjk's avatar
hjk committed
949 950 951 952 953 954 955 956
        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);
        }
957
        if (state() == InferiorStopOk || state() == InferiorStopFailed)
hjk's avatar
hjk committed
958 959 960
            d->queueShutdownInferior();
        showMessage(_("NOTE: ... IGNORING STOP MESSAGE"));
        return;
hjk's avatar
hjk committed
961
    }
962
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
963
    showStatusMessage(tr("Stopped."));
hjk's avatar
hjk committed
964
    setState(InferiorStopOk);
hjk's avatar
hjk committed
965 966
}

hjk's avatar
hjk committed
967
void DebuggerEngine::notifyInferiorSpontaneousStop()
968
{
969
    showMessage(_("NOTE: INFERIOR SPONTANEOUS STOP"));
970
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state());
971
    showStatusMessage(tr("Stopped."));
972
    setState(InferiorStopOk);
hjk's avatar
hjk committed
973
    if (boolSetting(RaiseOnInterrupt))
hjk's avatar
hjk committed
974
        ICore::raiseWindow(debuggerCore()->mainWindow());
975 976
}

hjk's avatar
hjk committed
977
void DebuggerEngine::notifyInferiorStopFailed()
978
{
hjk's avatar
hjk committed
979
    showMessage(_("NOTE: INFERIOR STOP FAILED"));
980
    QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
hjk's avatar
hjk committed
981
    setState(InferiorStopFailed);
982 983
    if (isMasterEngine())
        d->queueShutdownEngine();
984 985 986 987
}

void DebuggerEnginePrivate::doInterruptInferior()
{
988 989
    //QTC_ASSERT(isMasterEngine(), return);
    QTC_ASSERT(state() == InferiorRunOk, qDebug() << m_engine << state());
hjk's avatar
hjk committed
990
    m_engine->setState(InferiorStopRequested);
hjk's avatar
hjk committed
991
    m_engine->showMessage(_("CALL: INTERRUPT INFERIOR"));
992
    m_engine->showStatusMessage(tr("Attempting to interrupt."));
993 994 995
    m_engine->interruptInferior();
}

hjk's avatar
hjk committed
996 997
void DebuggerEnginePrivate::doShutdownInferior()
{
998 999
    //QTC_ASSERT(isMasterEngine(), return);
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << m_engine << state());
1000
    resetLocation();
hjk's avatar
hjk committed
1001
    m_targetState = DebuggerFinished;
hjk's avatar
hjk committed
1002
    m_engine->showMessage(_("CALL: SHUTDOWN INFERIOR"));
hjk's avatar
hjk committed
1003 1004 1005 1006 1007 1008
    m_engine->shutdownInferior();
}

void DebuggerEngine::notifyInferiorShutdownOk()
{
    showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
1009
    QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
hjk's avatar
hjk committed
1010 1011
    d->m_lastGoodState = DebuggerNotReady; // A "neutral" value.
    setState(InferiorShutdownOk);
1012 1013
    if (isMasterEngine())
        d->queueShutdownEngine();