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: 2007 Hamish Rodda <rodda@kde.org>
0005     SPDX-FileCopyrightText: 2009 Niko Sams <niko.sams@gmail.com>
0006     SPDX-FileCopyrightText: 2016 Aetf <aetf@unlimitedcodeworks.xyz>
0007 
0008     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0009 */
0010 
0011 #ifndef MIDEBUGSESSION_H
0012 #define MIDEBUGSESSION_H
0013 
0014 #include <debugger/interfaces/idebugsession.h>
0015 
0016 #include "dbgglobal.h"
0017 #include "mibreakpointcontroller.h"
0018 #include "mi/mi.h"
0019 #include "mi/micommand.h"
0020 
0021 #include <QMap>
0022 #include <QPointer>
0023 
0024 #include <memory>
0025 
0026 class IExecutePlugin;
0027 namespace KDevelop {
0028 class ILaunchConfiguration;
0029 class ProcessLineMaker;
0030 }
0031 
0032 namespace KDevMI {
0033 
0034 namespace MI {
0035 class CommandQueue;
0036 }
0037 
0038 class MIDebugger;
0039 class MIDebuggerPlugin;
0040 class MIVariable;
0041 class STTY;
0042 class MIDebugSession : public KDevelop::IDebugSession
0043 {
0044     Q_OBJECT
0045 public:
0046     explicit MIDebugSession(MIDebuggerPlugin *plugin = nullptr);
0047     ~MIDebugSession() override;
0048 
0049 Q_SIGNALS:
0050     /**
0051      * Emits when received standard output lines from inferior
0052      */
0053     void inferiorStdoutLines(const QStringList& lines);
0054 
0055     /**
0056      * Emits when received standard error lines from inferior
0057      */
0058     void inferiorStderrLines(const QStringList& lines);
0059 
0060     void inferiorStopped(const MI::AsyncRecord& r);
0061 
0062     void inferiorRunning();
0063 
0064     /**
0065      * Emits when received standard output from debugger for user commands
0066      */
0067     void debuggerUserCommandOutput(const QString &output);
0068 
0069     /**
0070      * Emits when received standard output from debugger for internal commands
0071      */
0072     void debuggerInternalCommandOutput(const QString& output);
0073 
0074     /**
0075      * Emits when received internal output from debugger
0076      */
0077     void debuggerInternalOutput(const QString& output) const;
0078 
0079     /**
0080      * Emits when received standard output from inferior's tty
0081      */
0082     void inferiorTtyStdout(const QByteArray& output);
0083 
0084     /**
0085      * Emits when received standard output from inferior's tty
0086      */
0087     void inferiorTtyStderr(const QByteArray& output);
0088 
0089     /**
0090      * Emits when the debugger instance state changes
0091      */
0092     void debuggerStateChanged(DBGStateFlags oldState, DBGStateFlags newState);
0093 
0094     /**
0095      * Emits when there's message needed to be show to user.
0096      */
0097     void showMessage(const QString& message, int timeout);
0098 
0099     /**
0100      * Emits when the debugger console view need to be raised.
0101      */
0102     void raiseDebuggerConsoleViews();
0103 
0104     /**
0105      * Emits when need to reset
0106      */
0107     void reset();
0108 
0109 public:
0110     bool debuggerStateIsOn(DBGStateFlags state) const;
0111     DBGStateFlags debuggerState() const;
0112 
0113     bool hasCrashed() const;
0114 
0115 // BEGIN IDebugSession overrides
0116 public:
0117     DebuggerState state() const override;
0118     bool restartAvaliable() const override;
0119 
0120     MIBreakpointController * breakpointController() const override = 0;
0121 
0122 public Q_SLOTS:
0123     void restartDebugger() override;
0124     void stopDebugger() override;
0125     void killDebuggerNow() override;
0126     void interruptDebugger() override;
0127     void run() override;
0128     void runToCursor() override;
0129     void jumpToCursor() override;
0130     void stepOver() override;
0131     void stepIntoInstruction() override;
0132     void stepInto() override;
0133     void stepOverInstruction() override;
0134     void stepOut() override;
0135 // END IDebugSession overrides
0136 
0137 public Q_SLOTS:
0138     /**
0139      * Run currently executing program to the given \a url and \a line.
0140      */
0141     void runUntil(const QUrl& url, int line);
0142 
0143     /**
0144      * Run currently executing program to the given \a address
0145      */
0146     void runUntil(const QString& address);
0147 
0148     /**
0149      * Move the execution point of the currently executing program to the given \a url and \a line.
0150      */
0151     void jumpTo(const QUrl& url, int line);
0152 
0153     /**
0154      * Move the execution point of the currently executing program to the given \a address.
0155      *Note: It can be really very dangerous, so use jumpTo instead.
0156      */
0157     void jumpToMemoryAddress(const QString& address);
0158 
0159     /**
0160      * Start the debugger, and execute the inferior program specified by \a cfg.
0161      */
0162     bool startDebugging(KDevelop::ILaunchConfiguration *cfg, IExecutePlugin *iexec);
0163 
0164     /**
0165      * Start the debugger, and examine the core file given by \a coreFile.
0166      */
0167     bool examineCoreFile(const QUrl &debugee, const QUrl &coreFile);
0168 
0169     /**
0170      * Start the debugger, and attach to a currently running process with the given \a pid.
0171      */
0172     bool attachToProcess(int pid);
0173 
0174 public:
0175     virtual std::unique_ptr<MI::MICommand> createCommand(MI::CommandType type, const QString& arguments,
0176                                                          MI::CommandFlags flags = {}) const;
0177     virtual std::unique_ptr<MI::MICommand> createUserCommand(const QString& cmd) const;
0178     /** Adds a command to the end of queue of commands to be executed
0179         by debugger. The command will be actually sent to debugger only when
0180         replies from all previous commands are received and full processed.
0181 
0182         The literal command sent to debugger is obtained by calling
0183         cmd->cmdToSend. The call is made immediately before sending the
0184         command, so it's possible to use results of prior commands when
0185         computing the exact command to send.
0186     */
0187     void addUserCommand(const QString &cmd);
0188 
0189     void addCommand(std::unique_ptr<MI::MICommand> cmd);
0190 
0191     /** Same as above, but internally constructs MICommand using createCommand() */
0192     void addCommand(MI::CommandType type, const QString& arguments = QString(),
0193                     MI::CommandFlags flags = {});
0194 
0195     void addCommand(MI::CommandType type, const QString& arguments,
0196                     MI::MICommandHandler* handler,
0197                     MI::CommandFlags flags = {});
0198 
0199     void addCommand(MI::CommandType type, const QString& arguments,
0200                     const MI::FunctionCommandHandler::Function& callback,
0201                     MI::CommandFlags flags = {});
0202 
0203     template<class Handler>
0204     void addCommand(MI::CommandType type, const QString& arguments,
0205                     Handler* handler_this,
0206                     void (Handler::* handler_method)(const MI::ResultRecord&),
0207                     MI::CommandFlags flags = {});
0208 
0209     QMap<QString, MIVariable*> & variableMapping();
0210     MIVariable* findVariableByVarobjName(const QString &varobjName) const;
0211     void markAllVariableDead();
0212 
0213 protected Q_SLOTS:
0214     virtual void slotDebuggerReady();
0215     virtual void slotDebuggerExited(bool abnormal, const QString &msg);
0216     virtual void slotInferiorStopped(const MI::AsyncRecord &r);
0217     /**
0218      * Triggered every time program begins/continues it's execution.
0219      */
0220     virtual void slotInferiorRunning();
0221 
0222     /**
0223      * Handle MI async notifications.
0224      */
0225     virtual void processNotification(const MI::AsyncRecord &n);
0226 
0227     /** Default handler for errors.
0228         Tries to guess is the error message is telling that target is
0229         gone, if so, informs the user.
0230         Otherwise, shows a dialog box and reloads view state.  */
0231     virtual void defaultErrorHandler(const MI::ResultRecord &result);
0232 
0233     /**
0234      * Update session state when debugger state changes, and show messages
0235      */
0236     virtual void handleDebuggerStateChange(DBGStateFlags oldState, DBGStateFlags newState);
0237 
0238     void handleNoInferior(const QString &msg);
0239     void handleInferiorFinished(const QString &msg);
0240 
0241 protected:
0242     void queueCmd(std::unique_ptr<MI::MICommand> cmd);
0243 
0244     /** Try to execute next command in the queue.  If GDB is not
0245         busy with previous command, and there's a command in the
0246         queue, sends it.  */
0247     void executeCmd();
0248     void destroyCmds();
0249 
0250     virtual void ensureDebuggerListening();
0251 
0252     /**
0253      * Start the debugger instance
0254      */
0255     bool startDebugger(KDevelop::ILaunchConfiguration *cfg);
0256 
0257     /**
0258      * MIDebugSession takes the ownership of the created instance.
0259      */
0260     virtual MIDebugger *createDebugger() const = 0;
0261 
0262     /**
0263      * Initialize debugger and set default configurations.
0264      */
0265     virtual void initializeDebugger() = 0;
0266 
0267     /**
0268      * Do per launch configuration.
0269      */
0270     virtual void configInferior(KDevelop::ILaunchConfiguration *cfg, IExecutePlugin *iexec,
0271                                 const QString &executable) = 0;
0272 
0273     /**
0274      * Start the inferior program (either local or remote).
0275      */
0276     virtual bool execInferior(KDevelop::ILaunchConfiguration *cfg, IExecutePlugin *iexec,
0277                               const QString &executable) = 0;
0278 
0279     /**
0280      * Further config the debugger and load the core dump
0281      */
0282     virtual bool loadCoreFile(KDevelop::ILaunchConfiguration *cfg,
0283                               const QString &debugee, const QString &corefile) = 0;
0284 
0285     /**
0286      * Manipulate debugger instance state
0287      */
0288     void setDebuggerStateOn(DBGStateFlags stateOn);
0289     void setDebuggerStateOff(DBGStateFlags stateOff);
0290     void setDebuggerState(DBGStateFlags newState);
0291 
0292     /**
0293      * Manipulate the session state
0294      */
0295     void setSessionState(DebuggerState state);
0296 
0297     void raiseEvent(event_t e) override;
0298 
0299     /** Called when there are no pending commands and 'm_stateReloadNeeded'
0300         is true. Also can be used to immediately reload program state.
0301         Issues commands to completely reload all program state shown
0302         to the user.
0303     */
0304     void reloadProgramState();
0305 
0306     void programNoApp(const QString &msg);
0307     void programFinished(const QString &msg);
0308 
0309     // FIXME: Whether let the debugger source init files when starting,
0310     // only used in unit test currently, potentially could be made a user
0311     // configurable option
0312     void setSourceInitFile(bool enable);
0313 
0314 private Q_SLOTS:
0315     void handleTargetAttach(const MI::ResultRecord& r);
0316     // Pops up a dialog box with some hopefully
0317     // detailed information about which state debugger
0318     // is in, which commands were sent and so on.
0319     void explainDebuggerStatus();
0320 
0321 protected:
0322     KDevelop::ProcessLineMaker *m_procLineMaker;
0323 
0324     std::unique_ptr<MI::CommandQueue> m_commandQueue;
0325 
0326     // Though the misleading class name, this is the session level state.
0327     // see m_debuggerState for debugger instance state
0328     DebuggerState m_sessionState = NotStartedState;
0329 
0330     MIDebugger *m_debugger = nullptr;
0331     DBGStateFlags m_debuggerState;
0332 
0333     bool m_stateReloadInProgress = false;
0334     bool m_stateReloadNeeded = false;
0335 
0336     std::unique_ptr<STTY> m_tty;
0337 
0338     bool m_hasCrashed = false;
0339     bool m_sourceInitFile = true;
0340 
0341     // Map from GDB varobj name to MIVariable.
0342     QMap<QString, MIVariable*> m_allVariables;
0343 
0344     QPointer<MIDebuggerPlugin> m_plugin;
0345 
0346 private:
0347     void addGdbExitCommand();
0348     void killDebuggerImpl();
0349 };
0350 
0351 template<class Handler>
0352 void MIDebugSession::addCommand(MI::CommandType type, const QString& arguments,
0353                                 Handler* handler_this,
0354                                 void (Handler::* handler_method)(const MI::ResultRecord&),
0355                                 MI::CommandFlags flags)
0356 {
0357     auto cmd = createCommand(type, arguments, flags);
0358     cmd->setHandler(handler_this, handler_method);
0359     queueCmd(std::move(cmd));
0360 }
0361 
0362 } // end of namespace KDevMI
0363 
0364 #endif // MIDEBUGSESSION_H