File indexing completed on 2024-04-28 04:38:35

0001 /*
0002     SPDX-FileCopyrightText: 1999-2001 John Birch <jbb@kdevelop.org>
0003     SPDX-FileCopyrightText: 2001 Bernd Gehrmann <bernd@kdevelop.org>
0004     SPDX-FileCopyrightText: 2006 Vladimir Prus <ghost@cs.msu.su>
0005     SPDX-FileCopyrightText: 2007 Hamish Rodda <rodda@kde.org>
0006     SPDX-FileCopyrightText: 2009 Niko Sams <niko.sams@gmail.com>
0007     SPDX-FileCopyrightText: 2016 Aetf <aetf@unlimitedcodeworks.xyz>
0008 
0009     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0010 */
0011 
0012 #include "midebugsession.h"
0013 
0014 #include "debuglog.h"
0015 #include "midebugger.h"
0016 #include "midebuggerplugin.h"
0017 #include "mivariable.h"
0018 #include "mi/mi.h"
0019 #include "mi/micommand.h"
0020 #include "mi/micommandqueue.h"
0021 #include "stty.h"
0022 
0023 #include <debugger/interfaces/iframestackmodel.h>
0024 #include <execute/iexecuteplugin.h>
0025 #include <interfaces/icore.h>
0026 #include <interfaces/idocument.h>
0027 #include <interfaces/idocumentcontroller.h>
0028 #include <interfaces/ilaunchconfiguration.h>
0029 #include <interfaces/iuicontroller.h>
0030 #include <sublime/message.h>
0031 #include <util/processlinemaker.h>
0032 
0033 #include <KConfigGroup>
0034 #include <KLocalizedString>
0035 #include <KSharedConfig>
0036 #include <KShell>
0037 
0038 #include <QApplication>
0039 #include <QFileInfo>
0040 #include <QMetaEnum>
0041 #include <QRegularExpression>
0042 #include <QUrl>
0043 #include <QTimer>
0044 
0045 using namespace KDevelop;
0046 using namespace KDevMI;
0047 using namespace KDevMI::MI;
0048 
0049 namespace {
0050 constexpr DBGStateFlags notStartedDebuggerFlags{s_dbgNotStarted | s_appNotStarted};
0051 }
0052 
0053 MIDebugSession::MIDebugSession(MIDebuggerPlugin *plugin)
0054     : m_procLineMaker(new ProcessLineMaker(this))
0055     , m_commandQueue(new CommandQueue)
0056     , m_debuggerState{notStartedDebuggerFlags}
0057     , m_tty(nullptr)
0058     , m_plugin(plugin)
0059 {
0060     qCDebug(DEBUGGERCOMMON) << "Creating" << this;
0061 
0062     // setup signals
0063     connect(m_procLineMaker, &ProcessLineMaker::receivedStdoutLines,
0064             this, &MIDebugSession::inferiorStdoutLines);
0065     connect(m_procLineMaker, &ProcessLineMaker::receivedStderrLines,
0066             this, &MIDebugSession::inferiorStderrLines);
0067 
0068     // forward tty output to process line maker
0069     connect(this, &MIDebugSession::inferiorTtyStdout,
0070             m_procLineMaker, &ProcessLineMaker::slotReceivedStdout);
0071     connect(this, &MIDebugSession::inferiorTtyStderr,
0072             m_procLineMaker, &ProcessLineMaker::slotReceivedStderr);
0073 
0074     // FIXME: see if this still works
0075     //connect(statusBarIndicator, SIGNAL(doubleClicked()),
0076     //        controller, SLOT(explainDebuggerStatus()));
0077 
0078     // FIXME: reimplement / re-enable
0079     //connect(this, SIGNAL(addWatchVariable(QString)), controller->variables(), SLOT(slotAddWatchVariable(QString)));
0080     //connect(this, SIGNAL(evaluateExpression(QString)), controller->variables(), SLOT(slotEvaluateExpression(QString)));
0081 }
0082 
0083 MIDebugSession::~MIDebugSession()
0084 {
0085     qCDebug(DEBUGGERCOMMON) << "Destroying" << this;
0086     // Deleting the session involves shutting down gdb nicely.
0087     // When were attached to a process, we must first detach so that the process
0088     // can continue running as it was before being attached. gdb is quite slow to
0089     // detach from a process, so we must process events within here to get a "clean"
0090     // shutdown.
0091     if (!debuggerStateIsOn(s_dbgNotStarted)) {
0092         stopDebugger();
0093     }
0094 }
0095 
0096 IDebugSession::DebuggerState MIDebugSession::state() const
0097 {
0098     return m_sessionState;
0099 }
0100 
0101 QMap<QString, MIVariable*> & MIDebugSession::variableMapping()
0102 {
0103     return m_allVariables;
0104 }
0105 
0106 MIVariable* MIDebugSession::findVariableByVarobjName(const QString &varobjName) const
0107 {
0108     if (m_allVariables.count(varobjName) == 0)
0109         return nullptr;
0110     return m_allVariables.value(varobjName);
0111 }
0112 
0113 void MIDebugSession::markAllVariableDead()
0114 {
0115     for (auto* variable : qAsConst(m_allVariables)) {
0116         variable->markAsDead();
0117     }
0118     m_allVariables.clear();
0119 }
0120 
0121 bool MIDebugSession::restartAvaliable() const
0122 {
0123     if (debuggerStateIsOn(s_attached) || debuggerStateIsOn(s_core)) {
0124         return false;
0125     } else {
0126         return true;
0127     }
0128 }
0129 
0130 bool MIDebugSession::startDebugger(ILaunchConfiguration *cfg)
0131 {
0132     qCDebug(DEBUGGERCOMMON) << "Starting new debugger instance";
0133     if (m_debugger) {
0134         qCWarning(DEBUGGERCOMMON) << "m_debugger object still exists";
0135         delete m_debugger;
0136         m_debugger = nullptr;
0137     }
0138     m_debugger = createDebugger();
0139     m_debugger->setParent(this);
0140 
0141     // output signals
0142     connect(m_debugger, &MIDebugger::applicationOutput, this, [this](const QString& output) {
0143         auto lines = output.split(QRegularExpression(QStringLiteral("[\r\n]")), Qt::SkipEmptyParts);
0144         for (auto& line : lines) {
0145             int p = line.length();
0146             while (p >= 1 && (line[p - 1] == QLatin1Char('\r') || line[p - 1] == QLatin1Char('\n'))) {
0147                 p--;
0148             }
0149             if (p != line.length())
0150                 line.truncate(p);
0151         }
0152         emit inferiorStdoutLines(lines);
0153     });
0154     connect(m_debugger, &MIDebugger::userCommandOutput, this, &MIDebugSession::debuggerUserCommandOutput);
0155     connect(m_debugger, &MIDebugger::internalCommandOutput, this, &MIDebugSession::debuggerInternalCommandOutput);
0156     connect(m_debugger, &MIDebugger::debuggerInternalOutput, this, &MIDebugSession::debuggerInternalOutput);
0157 
0158     // state signals
0159     connect(m_debugger, &MIDebugger::programStopped, this, &MIDebugSession::inferiorStopped);
0160     connect(m_debugger, &MIDebugger::programRunning, this, &MIDebugSession::inferiorRunning);
0161 
0162     // internal handlers
0163     connect(m_debugger, &MIDebugger::ready, this, &MIDebugSession::slotDebuggerReady);
0164     connect(m_debugger, &MIDebugger::exited, this, &MIDebugSession::slotDebuggerExited);
0165     connect(m_debugger, &MIDebugger::programStopped, this, &MIDebugSession::slotInferiorStopped);
0166     connect(m_debugger, &MIDebugger::programRunning, this, &MIDebugSession::slotInferiorRunning);
0167     connect(m_debugger, &MIDebugger::notification, this, &MIDebugSession::processNotification);
0168 
0169 
0170     // start the debugger. Do this after connecting all signals so that initial
0171     // debugger output, and important events like the debugger died are reported.
0172     QStringList extraArguments;
0173     if (!m_sourceInitFile)
0174         extraArguments << QStringLiteral("--nx");
0175 
0176     auto config = cfg ? cfg->config()
0177                 // FIXME: this is only used when attachToProcess or examineCoreFile.
0178                 // Change to use a global launch configuration when calling
0179                 : KConfigGroup(KSharedConfig::openConfig(), "GDB Config");
0180 
0181     if (!m_debugger->start(config, extraArguments)) {
0182         // debugger failed to start, ensure debugger and session state are correctly updated.
0183         setDebuggerStateOn(s_dbgFailedStart);
0184         return false;
0185     }
0186 
0187     // FIXME: here, we should wait until the debugger is up and waiting for input.
0188     // Then, clear s_dbgNotStarted
0189     // It's better to do this right away so that the state bit is always correct.
0190     setDebuggerStateOff(s_dbgNotStarted);
0191 
0192     // Initialise debugger. At this stage debugger is sitting wondering what to do,
0193     // and to whom.
0194     initializeDebugger();
0195 
0196     qCDebug(DEBUGGERCOMMON) << "Debugger instance started";
0197     return true;
0198 }
0199 
0200 bool MIDebugSession::startDebugging(ILaunchConfiguration* cfg, IExecutePlugin* iexec)
0201 {
0202     qCDebug(DEBUGGERCOMMON) << "Starting new debug session";
0203     Q_ASSERT(cfg);
0204     Q_ASSERT(iexec);
0205 
0206     // Ensure debugger is started first
0207     if (debuggerStateIsOn(s_appNotStarted)) {
0208         emit showMessage(i18n("Running program"), 1000);
0209     }
0210 
0211     if (debuggerStateIsOn(s_dbgNotStarted)) {
0212         if (!startDebugger(cfg))
0213             return false;
0214     }
0215 
0216     if (debuggerStateIsOn(s_shuttingDown)) {
0217         qCDebug(DEBUGGERCOMMON) << "Tried to run when debugger shutting down";
0218         return false;
0219     }
0220 
0221     // Only dummy err here, actual errors have been checked already in the job and we don't get here if there were any
0222     QString err;
0223     QString executable = iexec->executable(cfg, err).toLocalFile();
0224     configInferior(cfg, iexec, executable);
0225 
0226     // Set up the tty for the inferior
0227     bool config_useExternalTerminal = iexec->useTerminal(cfg);
0228     QString config_ternimalName = iexec->terminal(cfg);
0229     if (!config_ternimalName.isEmpty()) {
0230         // the external terminal cmd contains additional arguments, just get the terminal name
0231         config_ternimalName = KShell::splitArgs(config_ternimalName).first();
0232     }
0233 
0234     m_tty.reset(new STTY(config_useExternalTerminal, config_ternimalName));
0235     if (!config_useExternalTerminal) {
0236         connect(m_tty.get(), &STTY::OutOutput, this, &MIDebugSession::inferiorTtyStdout);
0237         connect(m_tty.get(), &STTY::ErrOutput, this, &MIDebugSession::inferiorTtyStderr);
0238     }
0239     QString tty(m_tty->getSlave());
0240 #ifndef Q_OS_WIN
0241     if (tty.isEmpty()) {
0242         auto* const message = new Sublime::Message(m_tty->lastError(), Sublime::Message::Error);
0243         ICore::self()->uiController()->postMessage(message);
0244 
0245         m_tty.reset(nullptr);
0246 
0247         qCDebug(DEBUGGERCOMMON) << "no TTY slave, stopping debugger";
0248         // Cannot simply call stopDebugger() here, because for some reason the interruptDebugger() call in
0249         // stopDebugger() makes the "Debugger Crashed" error dialog appear. KDevelop itself crashes then
0250         // unless the error dialog is dismissed promptly - before the GDB process is killed at the 5-second
0251         // timeout set up in stopDebugger(). Duplicate the relevant parts of stopDebugger() definition here.
0252         m_commandQueue->clear();
0253         setDebuggerStateOn(s_shuttingDown);
0254         addGdbExitCommand();
0255         emit reset();
0256         return false;
0257     }
0258 #endif
0259     addCommand(InferiorTtySet, tty);
0260 
0261     // Change the working directory to the correct one
0262     QString dir = iexec->workingDirectory(cfg).toLocalFile();
0263     if (dir.isEmpty()) {
0264         dir = QFileInfo(executable).absolutePath();
0265     }
0266     addCommand(EnvironmentCd, QLatin1Char('"') + dir + QLatin1Char('"'));
0267 
0268     // Set the run arguments
0269     QStringList arguments = iexec->arguments(cfg, err);
0270     if (!arguments.isEmpty())
0271         addCommand(ExecArguments, KShell::joinArgs(arguments));
0272 
0273     // Do other debugger specific config options and actually start the inferior program
0274     if (!execInferior(cfg, iexec, executable)) {
0275         return false;
0276     }
0277 
0278     QString config_startWith = cfg->config().readEntry(Config::StartWithEntry, QStringLiteral("ApplicationOutput"));
0279     if (config_startWith == QLatin1String("GdbConsole")) {
0280         emit raiseDebuggerConsoleViews();
0281     } else if (config_startWith == QLatin1String("FrameStack")) {
0282         emit raiseFramestackViews();
0283     } else {
0284         // ApplicationOutput is raised in DebugJob (by setting job to Verbose/Silent)
0285     }
0286 
0287     return true;
0288 }
0289 
0290 // FIXME: use same configuration process as startDebugging
0291 bool MIDebugSession::attachToProcess(int pid)
0292 {
0293     qCDebug(DEBUGGERCOMMON) << "Attach to process" << pid;
0294 
0295     emit showMessage(i18n("Attaching to process %1", pid), 1000);
0296 
0297     if (debuggerStateIsOn(s_dbgNotStarted)) {
0298         // FIXME: use global launch configuration rather than nullptr
0299         if (!startDebugger(nullptr)) {
0300             return false;
0301         }
0302     }
0303 
0304     setDebuggerStateOn(s_attached);
0305 
0306     //set current state to running, after attaching we will get *stopped response
0307     setDebuggerStateOn(s_appRunning);
0308 
0309     addCommand(TargetAttach, QString::number(pid),
0310                this, &MIDebugSession::handleTargetAttach,
0311                CmdHandlesError);
0312 
0313     addCommand(std::make_unique<SentinelCommand>(breakpointController(), &MIBreakpointController::initSendBreakpoints));
0314 
0315     raiseEvent(connected_to_program);
0316 
0317     emit raiseFramestackViews();
0318 
0319     return true;
0320 }
0321 
0322 void MIDebugSession::handleTargetAttach(const MI::ResultRecord& r)
0323 {
0324     if (r.reason == QLatin1String("error")) {
0325         const QString messageText =
0326             i18n("<b>Could not attach debugger:</b><br />")+
0327                  r[QStringLiteral("msg")].literal();
0328         auto* message = new Sublime::Message(messageText, Sublime::Message::Error);
0329         ICore::self()->uiController()->postMessage(message);
0330         stopDebugger();
0331     }
0332 }
0333 
0334 bool MIDebugSession::examineCoreFile(const QUrl &debugee, const QUrl &coreFile)
0335 {
0336     emit showMessage(i18n("Examining core file %1", coreFile.toLocalFile()), 1000);
0337 
0338     if (debuggerStateIsOn(s_dbgNotStarted)) {
0339         // FIXME: use global launch configuration rather than nullptr
0340         if (!startDebugger(nullptr)) {
0341             return false;
0342         }
0343     }
0344 
0345     // FIXME: support non-local URLs
0346     if (!loadCoreFile(nullptr, debugee.toLocalFile(), coreFile.toLocalFile())) {
0347         return false;
0348     }
0349 
0350     raiseEvent(program_state_changed);
0351 
0352     return true;
0353 }
0354 
0355 #define ENUM_NAME(o,e,v) (o::staticMetaObject.enumerator(o::staticMetaObject.indexOfEnumerator(#e)).valueToKey((v)))
0356 void MIDebugSession::setSessionState(DebuggerState state)
0357 {
0358     qCDebug(DEBUGGERCOMMON) << "Session state changed to"
0359                             << ENUM_NAME(IDebugSession, DebuggerState, state)
0360                             << "(" << state << ")";
0361     if (state != m_sessionState) {
0362         m_sessionState = state;
0363         emit stateChanged(state);
0364     }
0365 }
0366 
0367 bool MIDebugSession::debuggerStateIsOn(DBGStateFlags state) const
0368 {
0369     return m_debuggerState & state;
0370 }
0371 
0372 DBGStateFlags MIDebugSession::debuggerState() const
0373 {
0374     return m_debuggerState;
0375 }
0376 
0377 void MIDebugSession::setDebuggerStateOn(DBGStateFlags stateOn)
0378 {
0379     DBGStateFlags oldState = m_debuggerState;
0380     m_debuggerState |= stateOn;
0381     handleDebuggerStateChange(oldState, m_debuggerState);
0382 }
0383 
0384 void MIDebugSession::setDebuggerStateOff(DBGStateFlags stateOff)
0385 {
0386     DBGStateFlags oldState = m_debuggerState;
0387     m_debuggerState &= ~stateOff;
0388     handleDebuggerStateChange(oldState, m_debuggerState);
0389 }
0390 
0391 void MIDebugSession::setDebuggerState(DBGStateFlags newState)
0392 {
0393     DBGStateFlags oldState = m_debuggerState;
0394     m_debuggerState = newState;
0395     handleDebuggerStateChange(oldState, m_debuggerState);
0396 }
0397 
0398 void MIDebugSession::handleDebuggerStateChange(DBGStateFlags oldState, DBGStateFlags newState)
0399 {
0400     QString message;
0401 
0402     DebuggerState oldSessionState = state();
0403     DebuggerState newSessionState = oldSessionState;
0404     DBGStateFlags changedState = oldState ^ newState;
0405 
0406     if (newState & s_dbgNotStarted) {
0407         if (changedState & s_dbgNotStarted) {
0408             message = i18n("Debugger stopped");
0409             emit finished();
0410         }
0411         if (oldSessionState != NotStartedState || newState & s_dbgFailedStart) {
0412             newSessionState = EndedState;
0413         }
0414     } else {
0415         if (newState & s_appNotStarted) {
0416             if (oldSessionState == NotStartedState || oldSessionState == StartingState) {
0417                 newSessionState = StartingState;
0418             } else {
0419                 newSessionState = StoppedState;
0420             }
0421         } else if (newState & s_programExited) {
0422             if (changedState & s_programExited) {
0423                 message = i18n("Process exited");
0424             }
0425             newSessionState = StoppedState;
0426         } else if (newState & s_appRunning) {
0427             if (changedState & s_appRunning) {
0428                 message = i18n("Application is running");
0429             }
0430             newSessionState = ActiveState;
0431         } else {
0432             if (changedState & s_appRunning) {
0433                 message = i18n("Application is paused");
0434             }
0435             newSessionState = PausedState;
0436         }
0437     }
0438 
0439     // And now? :-)
0440     qCDebug(DEBUGGERCOMMON) << "Debugger state changed to:" << newState << message << "- changes:" << changedState;
0441 
0442     if (!message.isEmpty())
0443         emit showMessage(message, 3000);
0444 
0445     emit debuggerStateChanged(oldState, newState);
0446 
0447     // must be last, since it can lead to deletion of the DebugSession
0448     if (newSessionState != oldSessionState) {
0449         setSessionState(newSessionState);
0450     }
0451 }
0452 
0453 void MIDebugSession::restartDebugger()
0454 {
0455     // We implement restart as kill + slotRun, as opposed as plain "run"
0456     // command because kill + slotRun allows any special logic in slotRun
0457     // to apply for restart.
0458     //
0459     // That includes:
0460     // - checking for out-of-date project
0461     // - special setup for remote debugging.
0462     //
0463     // Had we used plain 'run' command, restart for remote debugging simply
0464     // would not work.
0465     if (!debuggerStateIsOn(s_dbgNotStarted|s_shuttingDown)) {
0466         // FIXME: s_dbgBusy or m_debugger->isReady()?
0467         if (debuggerStateIsOn(s_dbgBusy)) {
0468             interruptDebugger();
0469         }
0470         // The -exec-abort is not implemented in gdb
0471         // addCommand(ExecAbort);
0472         addCommand(NonMI, QStringLiteral("kill"));
0473     }
0474     run();
0475 }
0476 
0477 void MIDebugSession::stopDebugger()
0478 {
0479     if (debuggerStateIsOn(s_dbgNotStarted)) {
0480         qCDebug(DEBUGGERCOMMON) << "Stopping debugger when it's not started";
0481         if (debuggerState() != notStartedDebuggerFlags) {
0482             setDebuggerState(notStartedDebuggerFlags);
0483         }
0484         // Transition into EndedState to let DebugController destroy this session.
0485         if (state() != EndedState) {
0486             setSessionState(EndedState);
0487         }
0488         return;
0489     }
0490 
0491     m_commandQueue->clear();
0492 
0493     qCDebug(DEBUGGERCOMMON) << "try stopping debugger";
0494     if (debuggerStateIsOn(s_shuttingDown) || !m_debugger)
0495         return;
0496 
0497     setDebuggerStateOn(s_shuttingDown);
0498     qCDebug(DEBUGGERCOMMON) << "stopping debugger";
0499 
0500     // Get debugger's attention if it's busy. We need debugger to be at the
0501     // command line so we can stop it.
0502     if (!m_debugger->isReady()) {
0503         qCDebug(DEBUGGERCOMMON) << "debugger busy on shutdown - interrupting";
0504         interruptDebugger();
0505     }
0506 
0507     // If the app is attached then we release it here. This doesn't stop
0508     // the app running.
0509     if (debuggerStateIsOn(s_attached)) {
0510         addCommand(TargetDetach);
0511         emit debuggerUserCommandOutput(QStringLiteral("(gdb) detach\n"));
0512     }
0513 
0514     // Now try to stop debugger running.
0515     addGdbExitCommand();
0516 
0517     // We cannot wait forever, kill gdb after 5 seconds if it's not yet quit
0518     QTimer::singleShot(5000, this, [this]() {
0519         if (!debuggerStateIsOn(s_programExited) && debuggerStateIsOn(s_shuttingDown)) {
0520             qCDebug(DEBUGGERCOMMON) << "debugger not shutdown - killing";
0521             killDebuggerImpl();
0522         }
0523     });
0524 
0525     emit reset();
0526 }
0527 
0528 void MIDebugSession::addGdbExitCommand()
0529 {
0530     addCommand(GdbExit);
0531     emit debuggerUserCommandOutput(QStringLiteral("(gdb) quit"));
0532 }
0533 
0534 void MIDebugSession::killDebuggerNow()
0535 {
0536     if (!debuggerStateIsOn(s_dbgNotStarted)) {
0537         qCDebug(DEBUGGERCOMMON) << "killing debugger now";
0538         killDebuggerImpl();
0539     }
0540 }
0541 
0542 void MIDebugSession::killDebuggerImpl()
0543 {
0544     Q_ASSERT(m_debugger);
0545     m_debugger->kill();
0546     setDebuggerState(notStartedDebuggerFlags);
0547     raiseEvent(debugger_exited);
0548 }
0549 
0550 void MIDebugSession::interruptDebugger()
0551 {
0552     Q_ASSERT(m_debugger);
0553 
0554     // Explicitly send the interrupt in case something went wrong with the usual
0555     // ensureGdbListening logic.
0556     m_debugger->interrupt();
0557     addCommand(ExecInterrupt, QString(), CmdInterrupt);
0558 }
0559 
0560 void MIDebugSession::run()
0561 {
0562     if (debuggerStateIsOn(s_appNotStarted|s_dbgNotStarted|s_shuttingDown))
0563         return;
0564 
0565     addCommand(MI::ExecContinue, QString(), CmdMaybeStartsRunning);
0566 }
0567 
0568 void MIDebugSession::runToCursor()
0569 {
0570     if (IDocument* doc = ICore::self()->documentController()->activeDocument()) {
0571         KTextEditor::Cursor cursor = doc->cursorPosition();
0572         if (cursor.isValid())
0573             runUntil(doc->url(), cursor.line() + 1);
0574     }
0575 }
0576 
0577 void MIDebugSession::jumpToCursor()
0578 {
0579     if (IDocument* doc = ICore::self()->documentController()->activeDocument()) {
0580         KTextEditor::Cursor cursor = doc->cursorPosition();
0581         if (cursor.isValid())
0582             jumpTo(doc->url(), cursor.line() + 1);
0583     }
0584 }
0585 
0586 void MIDebugSession::stepOver()
0587 {
0588     if (debuggerStateIsOn(s_appNotStarted|s_shuttingDown))
0589         return;
0590 
0591     addCommand(ExecNext, QString(), CmdMaybeStartsRunning | CmdTemporaryRun);
0592 }
0593 
0594 void MIDebugSession::stepIntoInstruction()
0595 {
0596     if (debuggerStateIsOn(s_appNotStarted|s_shuttingDown))
0597         return;
0598 
0599     addCommand(ExecStepInstruction, QString(),
0600                CmdMaybeStartsRunning | CmdTemporaryRun);
0601 }
0602 
0603 void MIDebugSession::stepInto()
0604 {
0605     if (debuggerStateIsOn(s_appNotStarted|s_shuttingDown))
0606         return;
0607 
0608     addCommand(ExecStep, QString(), CmdMaybeStartsRunning | CmdTemporaryRun);
0609 }
0610 
0611 void MIDebugSession::stepOverInstruction()
0612 {
0613     if (debuggerStateIsOn(s_appNotStarted|s_shuttingDown))
0614         return;
0615 
0616     addCommand(ExecNextInstruction, QString(),
0617                CmdMaybeStartsRunning | CmdTemporaryRun);
0618 }
0619 
0620 void MIDebugSession::stepOut()
0621 {
0622     if (debuggerStateIsOn(s_appNotStarted|s_shuttingDown))
0623         return;
0624 
0625     addCommand(ExecFinish, QString(), CmdMaybeStartsRunning | CmdTemporaryRun);
0626 }
0627 
0628 void MIDebugSession::runUntil(const QUrl& url, int line)
0629 {
0630     if (debuggerStateIsOn(s_dbgNotStarted|s_shuttingDown))
0631         return;
0632 
0633     if (!url.isValid()) {
0634         addCommand(ExecUntil, QString::number(line),
0635                    CmdMaybeStartsRunning | CmdTemporaryRun);
0636     } else {
0637         addCommand(ExecUntil,
0638                    QStringLiteral("%1:%2").arg(url.toLocalFile()).arg(line),
0639                    CmdMaybeStartsRunning | CmdTemporaryRun);
0640     }
0641 }
0642 
0643 void MIDebugSession::runUntil(const QString& address)
0644 {
0645     if (debuggerStateIsOn(s_dbgNotStarted|s_shuttingDown))
0646         return;
0647 
0648     if (!address.isEmpty()) {
0649         addCommand(ExecUntil, QStringLiteral("*%1").arg(address),
0650                    CmdMaybeStartsRunning | CmdTemporaryRun);
0651     }
0652 }
0653 
0654 void MIDebugSession::jumpTo(const QUrl& url, int line)
0655 {
0656     if (debuggerStateIsOn(s_dbgNotStarted|s_shuttingDown))
0657         return;
0658 
0659     if (url.isValid()) {
0660         addCommand(NonMI, QStringLiteral("tbreak %1:%2").arg(url.toLocalFile()).arg(line));
0661         addCommand(NonMI, QStringLiteral("jump %1:%2").arg(url.toLocalFile()).arg(line));
0662     }
0663 }
0664 
0665 void MIDebugSession::jumpToMemoryAddress(const QString& address)
0666 {
0667     if (debuggerStateIsOn(s_dbgNotStarted|s_shuttingDown))
0668         return;
0669 
0670     if (!address.isEmpty()) {
0671         addCommand(NonMI, QStringLiteral("tbreak *%1").arg(address));
0672         addCommand(NonMI, QStringLiteral("jump *%1").arg(address));
0673     }
0674 }
0675 
0676 void MIDebugSession::addUserCommand(const QString& cmd)
0677 {
0678     auto usercmd = createUserCommand(cmd);
0679     if (!usercmd)
0680         return;
0681 
0682     queueCmd(std::move(usercmd));
0683     // User command can theoretically modify absolutely everything,
0684     // so need to force a reload.
0685 
0686     // We can do it right now, and don't wait for user command to finish
0687     // since commands used to reload all view will be executed after
0688     // user command anyway.
0689     if (!debuggerStateIsOn(s_appNotStarted) && !debuggerStateIsOn(s_programExited))
0690         raiseEvent(program_state_changed);
0691 }
0692 
0693 std::unique_ptr<MICommand> MIDebugSession::createUserCommand(const QString& cmd) const
0694 {
0695     if (!cmd.isEmpty() && cmd[0].isDigit()) {
0696         // Add a space to the beginning, so debugger won't get confused if the
0697         // command starts with a number (won't mix it up with command token added)
0698         return std::make_unique<UserCommand>(MI::NonMI, QLatin1Char(' ') + cmd);
0699     } else {
0700         return std::make_unique<UserCommand>(MI::NonMI, cmd);
0701     }
0702 }
0703 
0704 std::unique_ptr<MICommand> MIDebugSession::createCommand(CommandType type, const QString& arguments,
0705                                                          CommandFlags flags) const
0706 {
0707     // uses protected ctor, only accessible to MIDebugSession via friendship - cannot use make_unique :(
0708     return std::unique_ptr<MICommand>(new MICommand(type, arguments, flags));
0709 }
0710 
0711 void MIDebugSession::addCommand(std::unique_ptr<MICommand> cmd)
0712 {
0713     queueCmd(std::move(cmd));
0714 }
0715 
0716 void MIDebugSession::addCommand(MI::CommandType type, const QString& arguments, MI::CommandFlags flags)
0717 {
0718     queueCmd(createCommand(type, arguments, flags));
0719 }
0720 
0721 void MIDebugSession::addCommand(MI::CommandType type, const QString& arguments,
0722                 MI::MICommandHandler *handler,
0723                 MI::CommandFlags flags)
0724 {
0725     auto cmd = createCommand(type, arguments, flags);
0726     cmd->setHandler(handler);
0727     queueCmd(std::move(cmd));
0728 }
0729 
0730 void MIDebugSession::addCommand(MI::CommandType type, const QString& arguments,
0731                 const MI::FunctionCommandHandler::Function& callback,
0732                 MI::CommandFlags flags)
0733 {
0734     auto cmd = createCommand(type, arguments, flags);
0735     cmd->setHandler(callback);
0736     queueCmd(std::move(cmd));
0737 }
0738 
0739 // Fairly obvious that we'll add whatever command you give me to a queue
0740 // Not quite so obvious though is that if we are going to run again. then any
0741 // information requests become redundant and must be removed.
0742 // We also try and run whatever command happens to be at the head of
0743 // the queue.
0744 void MIDebugSession::queueCmd(std::unique_ptr<MICommand> cmd)
0745 {
0746     if (debuggerStateIsOn(s_dbgNotStarted)) {
0747         const QString messageText =
0748             i18n("<b>Gdb command sent when debugger is not running</b><br>"
0749                  "The command was:<br> %1", cmd->initialString());
0750         auto* message = new Sublime::Message(messageText, Sublime::Message::Information);
0751         ICore::self()->uiController()->postMessage(message);
0752         return;
0753     }
0754 
0755     if (m_stateReloadInProgress)
0756         cmd->setStateReloading(true);
0757 
0758     qCDebug(DEBUGGERCOMMON) << "QUEUE: " << cmd->initialString()
0759                             << (m_stateReloadInProgress ? "(state reloading)" : "")
0760                             << m_commandQueue->count() << "pending";
0761 
0762     bool varCommandWithContext= (cmd->type() >= MI::VarAssign
0763                                  && cmd->type() <= MI::VarUpdate
0764                                  && cmd->type() != MI::VarDelete);
0765 
0766     bool stackCommandWithContext = (cmd->type() >= MI::StackInfoDepth
0767                                     && cmd->type() <= MI::StackListLocals);
0768 
0769     if (varCommandWithContext || stackCommandWithContext) {
0770         if (cmd->thread() == -1)
0771             qCDebug(DEBUGGERCOMMON) << "\t--thread will be added on execution";
0772 
0773         if (cmd->frame() == -1)
0774             qCDebug(DEBUGGERCOMMON) << "\t--frame will be added on execution";
0775     }
0776 
0777     m_commandQueue->enqueue(std::move(cmd));
0778 
0779     setDebuggerStateOn(s_dbgBusy);
0780     raiseEvent(debugger_busy);
0781 
0782     executeCmd();
0783 }
0784 
0785 void MIDebugSession::executeCmd()
0786 {
0787     Q_ASSERT(m_debugger);
0788 
0789     if (debuggerStateIsOn(s_dbgNotListening) && m_commandQueue->haveImmediateCommand()) {
0790         // We may have to call this even while a command is currently executing, because
0791         // debugger can get into a state where a command such as ExecRun does not send a response
0792         // while the inferior is running.
0793         ensureDebuggerListening();
0794     }
0795 
0796     if (!m_debugger->isReady())
0797         return;
0798 
0799     auto currentCmd = m_commandQueue->nextCommand();
0800     if (!currentCmd)
0801         return;
0802 
0803     if (currentCmd->flags() & (CmdMaybeStartsRunning | CmdInterrupt)) {
0804         setDebuggerStateOff(s_automaticContinue);
0805     }
0806 
0807     if (currentCmd->flags() & CmdMaybeStartsRunning) {
0808         // GDB can be in a state where it is listening for commands while the program is running.
0809         // However, when we send a command such as ExecContinue in this state, GDB may return to
0810         // the non-listening state without acknowledging that the ExecContinue command has even
0811         // finished, let alone sending a new notification about the program's running state.
0812         // So let's be extra cautious about ensuring that we will wake GDB up again if required.
0813         setDebuggerStateOn(s_dbgNotListening);
0814     }
0815 
0816     bool varCommandWithContext= (currentCmd->type() >= MI::VarAssign
0817                                  && currentCmd->type() <= MI::VarUpdate
0818                                  && currentCmd->type() != MI::VarDelete);
0819 
0820     bool stackCommandWithContext = (currentCmd->type() >= MI::StackInfoDepth
0821                                     && currentCmd->type() <= MI::StackListLocals);
0822 
0823     if (varCommandWithContext || stackCommandWithContext) {
0824         // Most var commands should be executed in the context
0825         // of the selected thread and frame.
0826         if (currentCmd->thread() == -1)
0827             currentCmd->setThread(frameStackModel()->currentThread());
0828 
0829         if (currentCmd->frame() == -1)
0830             currentCmd->setFrame(frameStackModel()->currentFrame());
0831     }
0832 
0833     QString commandText = currentCmd->cmdToSend();
0834     bool bad_command = false;
0835     QString message;
0836 
0837     int length = commandText.length();
0838     // No i18n for message since it's mainly for debugging.
0839     if (length == 0) {
0840         // The command might decide it's no longer necessary to send
0841         // it.
0842         if (auto* sc = dynamic_cast<SentinelCommand*>(currentCmd.get())) {
0843             qCDebug(DEBUGGERCOMMON) << "SEND: sentinel command, not sending";
0844             sc->invokeHandler();
0845         } else {
0846             qCDebug(DEBUGGERCOMMON) << "SEND: command " << currentCmd->initialString()
0847                           << "changed its mind, not sending";
0848         }
0849 
0850         executeCmd();
0851         return;
0852     } else {
0853         if (commandText[length-1] != QLatin1Char('\n')) {
0854             bad_command = true;
0855             message = QStringLiteral("Debugger command does not end with newline");
0856         }
0857     }
0858 
0859     if (bad_command) {
0860         const QString messageText = i18n("<b>Invalid debugger command</b><br>%1", message);
0861         auto* message = new Sublime::Message(messageText, Sublime::Message::Information);
0862         ICore::self()->uiController()->postMessage(message);
0863         executeCmd();
0864         return;
0865     }
0866 
0867     m_debugger->execute(std::move(currentCmd));
0868 }
0869 
0870 void MIDebugSession::ensureDebuggerListening()
0871 {
0872     Q_ASSERT(m_debugger);
0873 
0874     // Note: we don't use interruptDebugger() here since
0875     // we don't want to queue more commands before queuing a command
0876     m_debugger->interrupt();
0877 
0878     setDebuggerStateOn(s_interruptSent);
0879     if (debuggerStateIsOn(s_appRunning))
0880         setDebuggerStateOn(s_automaticContinue);
0881     setDebuggerStateOff(s_dbgNotListening);
0882 }
0883 
0884 void MIDebugSession::destroyCmds()
0885 {
0886     m_commandQueue->clear();
0887 }
0888 
0889 // FIXME: I don't fully remember what is the business with
0890 // m_stateReloadInProgress and whether we can lift it to the
0891 // generic level.
0892 void MIDebugSession::raiseEvent(event_t e)
0893 {
0894     if (e == program_exited || e == debugger_exited) {
0895         m_stateReloadInProgress = false;
0896     }
0897 
0898     if (e == program_state_changed) {
0899         m_stateReloadInProgress = true;
0900         qCDebug(DEBUGGERCOMMON) << "State reload in progress\n";
0901     }
0902 
0903     IDebugSession::raiseEvent(e);
0904 
0905     if (e == program_state_changed) {
0906         m_stateReloadInProgress = false;
0907     }
0908 }
0909 
0910 bool KDevMI::MIDebugSession::hasCrashed() const
0911 {
0912     return m_hasCrashed;
0913 }
0914 
0915 void MIDebugSession::slotDebuggerReady()
0916 {
0917     Q_ASSERT(m_debugger);
0918 
0919     m_stateReloadInProgress = false;
0920 
0921     executeCmd();
0922     if (m_debugger->isReady()) {
0923         /* There is nothing in the command queue and no command is currently executing. */
0924         if (debuggerStateIsOn(s_automaticContinue)) {
0925             if (!debuggerStateIsOn(s_appRunning)) {
0926                 qCDebug(DEBUGGERCOMMON) << "Posting automatic continue";
0927                 addCommand(ExecContinue, QString(), CmdMaybeStartsRunning);
0928             }
0929             setDebuggerStateOff(s_automaticContinue);
0930             return;
0931         }
0932 
0933         if (m_stateReloadNeeded && !debuggerStateIsOn(s_appRunning)) {
0934             qCDebug(DEBUGGERCOMMON) << "Finishing program stop";
0935             // Set to false right now, so that if 'actOnProgramPauseMI_part2'
0936             // sends some commands, we won't call it again when handling replies
0937             // from that commands.
0938             m_stateReloadNeeded = false;
0939             reloadProgramState();
0940         }
0941 
0942         qCDebug(DEBUGGERCOMMON) << "No more commands";
0943         setDebuggerStateOff(s_dbgBusy);
0944         raiseEvent(debugger_ready);
0945     }
0946 }
0947 
0948 void MIDebugSession::slotDebuggerExited(bool abnormal, const QString &msg)
0949 {
0950     /* Technically speaking, GDB is likely not to kill the application, and
0951        we should have some backup mechanism to make sure the application is
0952        killed by KDevelop.  But even if application stays around, we no longer
0953        can control it in any way, so mark it as exited.  */
0954     setDebuggerStateOn(s_appNotStarted);
0955     setDebuggerStateOn(s_dbgNotStarted);
0956     setDebuggerStateOn(s_programExited);
0957     setDebuggerStateOff(s_shuttingDown);
0958 
0959     if (!msg.isEmpty())
0960         emit showMessage(msg, 3000);
0961 
0962     if (abnormal) {
0963         /* The error is reported to user in MIDebugger now.
0964         KMessageBox::information(
0965             KDevelop::ICore::self()->uiController()->activeMainWindow(),
0966             i18n("<b>Debugger exited abnormally</b>"
0967                 "<p>This is likely a bug in GDB. "
0968                 "Examine the gdb output window and then stop the debugger"),
0969             i18n("Debugger exited abnormally"));
0970         */
0971         // FIXME: not sure if the following still applies.
0972         // Note: we don't stop the debugger here, because that will hide gdb
0973         // window and prevent the user from finding the exact reason of the
0974         // problem.
0975     }
0976 
0977     /* FIXME: raiseEvent is handled across multiple places where we explicitly
0978      * stop/kill the debugger, a better way is to let the debugger itself report
0979      * its exited event.
0980      */
0981     // raiseEvent(debugger_exited);
0982 }
0983 
0984 void MIDebugSession::slotInferiorStopped(const MI::AsyncRecord& r)
0985 {
0986     /* By default, reload all state on program stop.  */
0987     m_stateReloadNeeded = true;
0988     setDebuggerStateOff(s_appRunning);
0989     setDebuggerStateOff(s_dbgNotListening);
0990 
0991     QString reason;
0992     if (r.hasField(QStringLiteral("reason"))) reason = r[QStringLiteral("reason")].literal();
0993 
0994     if (reason == QLatin1String("exited-normally") || reason == QLatin1String("exited")) {
0995         if (r.hasField(QStringLiteral("exit-code"))) {
0996             programNoApp(i18n("Exited with return code: %1", r[QStringLiteral("exit-code")].literal()));
0997         } else {
0998             programNoApp(i18n("Exited normally"));
0999         }
1000         m_stateReloadNeeded = false;
1001         return;
1002     }
1003 
1004     if (reason == QLatin1String("exited-signalled")) {
1005         programNoApp(i18n("Exited on signal %1", r[QStringLiteral("signal-name")].literal()));
1006         m_stateReloadNeeded = false;
1007         return;
1008     }
1009 
1010     if (reason == QLatin1String("watchpoint-scope")) {
1011         // FIXME: should remove this watchpoint
1012         // But first, we should consider if removing all
1013         // watchpoints on program exit is the right thing to
1014         // do.
1015 
1016         addCommand(ExecContinue, QString(), CmdMaybeStartsRunning);
1017 
1018         m_stateReloadNeeded = false;
1019         return;
1020     }
1021 
1022     bool wasInterrupt = false;
1023 
1024     if (reason == QLatin1String("signal-received")) {
1025         QString name = r[QStringLiteral("signal-name")].literal();
1026         QString user_name = r[QStringLiteral("signal-meaning")].literal();
1027 
1028         // SIGINT is a "break into running program".
1029         // We do this when the user set/mod/clears a breakpoint but the
1030         // application is running.
1031         // And the user does this to stop the program also.
1032         if (name == QLatin1String("SIGINT") && debuggerStateIsOn(s_interruptSent)) {
1033             wasInterrupt = true;
1034         } else {
1035             // Whenever we have a signal raised then tell the user, but don't
1036             // end the program as we want to allow the user to look at why the
1037             // program has a signal that's caused the prog to stop.
1038             // Continuing from SIG FPE/SEGV will cause a "Cannot ..." and
1039             // that'll end the program.
1040             programFinished(i18n("Program received signal %1 (%2)", name, user_name));
1041 
1042             m_hasCrashed = true;
1043         }
1044     }
1045 
1046     if (!reason.contains(QLatin1String("exited"))) {
1047         // FIXME: we should immediately update the current thread and
1048         // frame in the framestackmodel, so that any user actions
1049         // are in that thread. However, the way current framestack model
1050         // is implemented, we can't change thread id until we refresh
1051         // the entire list of threads -- otherwise we might set a thread
1052         // id that is not already in the list, and it will be upset.
1053 
1054         //Indicates if program state should be reloaded immediately.
1055         bool updateState = false;
1056 
1057         if (r.hasField(QStringLiteral("frame"))) {
1058             const MI::Value& frame = r[QStringLiteral("frame")];
1059             QString file, line, addr;
1060 
1061             if (frame.hasField(QStringLiteral("fullname"))) file = frame[QStringLiteral("fullname")].literal();
1062             if (frame.hasField(QStringLiteral("line")))     line = frame[QStringLiteral("line")].literal();
1063             if (frame.hasField(QStringLiteral("addr")))     addr = frame[QStringLiteral("addr")].literal();
1064 
1065             // gdb counts lines from 1 and we don't
1066             setCurrentPosition(QUrl::fromLocalFile(file), line.toInt() - 1, addr);
1067 
1068             updateState = true;
1069         }
1070 
1071         if (updateState) {
1072             reloadProgramState();
1073         }
1074     }
1075 
1076     setDebuggerStateOff(s_interruptSent);
1077     if (!wasInterrupt)
1078         setDebuggerStateOff(s_automaticContinue);
1079 }
1080 
1081 void MIDebugSession::slotInferiorRunning()
1082 {
1083     setDebuggerStateOn(s_appRunning);
1084     raiseEvent(program_running);
1085 
1086     if (m_commandQueue->haveImmediateCommand() ||
1087         (m_debugger->currentCommand() && (m_debugger->currentCommand()->flags() & (CmdImmediately | CmdInterrupt)))) {
1088         ensureDebuggerListening();
1089     } else {
1090         setDebuggerStateOn(s_dbgNotListening);
1091     }
1092 }
1093 
1094 void MIDebugSession::processNotification(const MI::AsyncRecord & async)
1095 {
1096     if (async.reason == QLatin1String("thread-group-started")) {
1097         setDebuggerStateOff(s_appNotStarted | s_programExited);
1098     } else if (async.reason == QLatin1String("thread-group-exited")) {
1099         setDebuggerStateOn(s_programExited);
1100     } else if (async.reason == QLatin1String("library-loaded")) {
1101         // do nothing
1102     } else if (async.reason == QLatin1String("breakpoint-created")) {
1103         breakpointController()->notifyBreakpointCreated(async);
1104     } else if (async.reason == QLatin1String("breakpoint-modified")) {
1105         breakpointController()->notifyBreakpointModified(async);
1106     } else if (async.reason == QLatin1String("breakpoint-deleted")) {
1107         breakpointController()->notifyBreakpointDeleted(async);
1108     } else {
1109         qCDebug(DEBUGGERCOMMON) << "Unhandled notification: " << async.reason;
1110     }
1111 }
1112 
1113 void MIDebugSession::reloadProgramState()
1114 {
1115     raiseEvent(program_state_changed);
1116     m_stateReloadNeeded = false;
1117 }
1118 
1119 // There is no app anymore. This can be caused by program exiting
1120 // an invalid program specified or ...
1121 // gdb is still running though, but only the run command (may) make sense
1122 // all other commands are disabled.
1123 void MIDebugSession::programNoApp(const QString& msg)
1124 {
1125     qCDebug(DEBUGGERCOMMON) << msg;
1126 
1127     setDebuggerState(s_appNotStarted | s_programExited | (m_debuggerState & s_shuttingDown));
1128 
1129     destroyCmds();
1130 
1131     // The application has existed, but it's possible that
1132     // some of application output is still in the pipe. We use
1133     // different pipes to communicate with gdb and to get application
1134     // output, so "exited" message from gdb might have arrived before
1135     // last application output. Get this last bit.
1136 
1137     // Note: this method can be called when we open an invalid
1138     // core file. In that case, tty_ won't be set.
1139     if (m_tty){
1140         m_tty->readRemaining();
1141         // Tty is no longer usable, delete it. Without this, QSocketNotifier
1142         // will continuously bomd STTY with signals, so we need to either disable
1143         // QSocketNotifier, or delete STTY. The latter is simpler, since we can't
1144         // reuse it for future debug sessions anyway.
1145         m_tty.reset(nullptr);
1146     }
1147 
1148     stopDebugger();
1149 
1150     raiseEvent(program_exited);
1151     raiseEvent(debugger_exited);
1152 
1153     emit showMessage(msg, 0);
1154 
1155     programFinished(msg);
1156 }
1157 
1158 void MIDebugSession::programFinished(const QString& msg)
1159 {
1160     QString m = QStringLiteral("*** %0 ***").arg(msg.trimmed());
1161     emit inferiorStderrLines(QStringList(m));
1162 
1163     /* Also show message in gdb window, so that users who
1164        prefer to look at gdb window know what's up.  */
1165     emit debuggerUserCommandOutput(m);
1166 }
1167 
1168 void MIDebugSession::explainDebuggerStatus()
1169 {
1170     MICommand* currentCmd_ = m_debugger->currentCommand();
1171     QString information =
1172         i18np("1 command in queue\n", "%1 commands in queue\n", m_commandQueue->count()) +
1173         i18ncp("Only the 0 and 1 cases need to be translated", "1 command being processed by gdb\n", "%1 commands being processed by gdb\n", (currentCmd_ ? 1 : 0)) +
1174         i18n("Debugger state: %1\n", m_debuggerState);
1175 
1176     if (currentCmd_) {
1177         QString extra = i18n("Current command class: '%1'\n"
1178                              "Current command text: '%2'\n"
1179                              "Current command original text: '%3'\n",
1180                              QString::fromUtf8(typeid(*currentCmd_).name()),
1181                              currentCmd_->cmdToSend(),
1182                              currentCmd_->initialString());
1183 
1184         information += extra;
1185     }
1186 
1187     auto* message = new Sublime::Message(information, Sublime::Message::Information);
1188     ICore::self()->uiController()->postMessage(message);
1189 }
1190 
1191 // There is no app anymore. This can be caused by program exiting
1192 // an invalid program specified or ...
1193 // gdb is still running though, but only the run command (may) make sense
1194 // all other commands are disabled.
1195 void MIDebugSession::handleNoInferior(const QString& msg)
1196 {
1197     qCDebug(DEBUGGERCOMMON) << msg;
1198 
1199     setDebuggerState(s_appNotStarted | s_programExited | (debuggerState() & s_shuttingDown));
1200 
1201     destroyCmds();
1202 
1203     // The application has existed, but it's possible that
1204     // some of application output is still in the pipe. We use
1205     // different pipes to communicate with gdb and to get application
1206     // output, so "exited" message from gdb might have arrived before
1207     // last application output. Get this last bit.
1208 
1209     // Note: this method can be called when we open an invalid
1210     // core file. In that case, tty_ won't be set.
1211     if (m_tty){
1212         m_tty->readRemaining();
1213         // Tty is no longer usable, delete it. Without this, QSocketNotifier
1214         // will continuously bomd STTY with signals, so we need to either disable
1215         // QSocketNotifier, or delete STTY. The latter is simpler, since we can't
1216         // reuse it for future debug sessions anyway.
1217         m_tty.reset(nullptr);
1218     }
1219 
1220     stopDebugger();
1221 
1222     raiseEvent(program_exited);
1223     raiseEvent(debugger_exited);
1224 
1225     emit showMessage(msg, 0);
1226 
1227     handleInferiorFinished(msg);
1228 }
1229 
1230 void MIDebugSession::handleInferiorFinished(const QString& msg)
1231 {
1232     QString m = QStringLiteral("*** %0 ***").arg(msg.trimmed());
1233     emit inferiorStderrLines(QStringList(m));
1234 
1235     /* Also show message in gdb window, so that users who
1236        prefer to look at gdb window know what's up.  */
1237     emit debuggerUserCommandOutput(m);
1238 }
1239 
1240 // FIXME: connect to debugger's slot.
1241 void MIDebugSession::defaultErrorHandler(const MI::ResultRecord& result)
1242 {
1243     QString msg = result[QStringLiteral("msg")].literal();
1244 
1245     if (msg.contains(QLatin1String("No such process")))
1246     {
1247         setDebuggerState(s_appNotStarted|s_programExited);
1248         raiseEvent(program_exited);
1249         return;
1250     }
1251 
1252     const QString messageText =
1253         i18n("<b>Debugger error</b>"
1254              "<p>Debugger reported the following error:"
1255              "<p><tt>%1", result[QStringLiteral("msg")].literal());
1256     auto* message = new Sublime::Message(messageText, Sublime::Message::Error);
1257     ICore::self()->uiController()->postMessage(message);
1258 
1259     // Error most likely means that some change made in GUI
1260     // was not communicated to the gdb, so GUI is now not
1261     // in sync with gdb. Resync it.
1262     //
1263     // Another approach is to make each widget reload it content
1264     // on errors from commands that it sent, but that's too complex.
1265     // Errors are supposed to happen rarely, so full reload on error
1266     // is not a big deal. Well, maybe except for memory view, but
1267     // it's no auto-reloaded anyway.
1268     //
1269     // Also, don't reload state on errors appeared during state
1270     // reloading!
1271     if (!m_debugger->currentCommand()->stateReloading())
1272         raiseEvent(program_state_changed);
1273 }
1274 
1275 void MIDebugSession::setSourceInitFile(bool enable)
1276 {
1277     m_sourceInitFile = enable;
1278 }
1279 
1280 #include "moc_midebugsession.cpp"