File indexing completed on 2024-04-28 05:48:33

0001 //
0002 // gdbbackend.h
0003 //
0004 // Description: Manages the interaction with GDB
0005 //
0006 //
0007 // SPDX-FileCopyrightText: 2008-2010 Ian Wakeling <ian.wakeling@ntlworld.com>
0008 // SPDX-FileCopyrightText: 2010 Kåre Särs <kare.sars@iki.fi>
0009 //
0010 //  SPDX-License-Identifier: LGPL-2.0-only
0011 
0012 #pragma once
0013 
0014 #include <QObject>
0015 
0016 #include <QList>
0017 #include <QProcess>
0018 #include <QUrl>
0019 #include <optional>
0020 #include <sys/types.h>
0021 
0022 #include "backendinterface.h"
0023 #include "configview.h"
0024 #include "dap/entities.h"
0025 #include "gdbmi/parser.h"
0026 #include "gdbmi/records.h"
0027 #include "gdbvariableparser.h"
0028 
0029 struct GdbCommand {
0030     QStringList arguments;
0031     enum RequestType {
0032         None,
0033         BreakpointList,
0034         Continue,
0035         Step,
0036         ThreadInfo,
0037         StackListFrames,
0038         StackListVariables,
0039         BreakInsert,
0040         BreakDelete,
0041         ListFeatures,
0042         DataEvaluateExpression,
0043         InfoGdbMiCommand,
0044         Exit,
0045         Kill,
0046         LldbVersion,
0047         RegisterNames,
0048         RegisterValues,
0049         ChangedRegisters,
0050     };
0051     RequestType type = None;
0052     std::optional<QJsonValue> data = std::nullopt;
0053 
0054     bool isMachineInterface() const;
0055     bool check(const QString &command) const;
0056     bool check(const QString &part1, const QString &part2) const;
0057     static GdbCommand parse(const QString &request);
0058 };
0059 
0060 struct BreakPoint {
0061     int number;
0062     QUrl file;
0063     int line;
0064 
0065     static BreakPoint parse(const QJsonObject &);
0066 };
0067 
0068 class GdbBackend : public BackendInterface
0069 {
0070     Q_OBJECT
0071 public:
0072     GdbBackend(QObject *parent);
0073     ~GdbBackend() override;
0074 
0075     void runDebugger(const GDBTargetConf &conf, const QStringList &ioFifos);
0076     bool debuggerRunning() const override;
0077     bool debuggerBusy() const override;
0078     bool hasBreakpoint(QUrl const &url, int line) const override;
0079 
0080     bool supportsMovePC() const override;
0081     bool supportsRunToCursor() const override;
0082     bool canSetBreakpoints() const override;
0083     bool canMove() const override;
0084     bool canContinue() const override;
0085 
0086     void toggleBreakpoint(QUrl const &url, int line) override;
0087     void movePC(QUrl const &url, int line) override;
0088     void runToCursor(QUrl const &url, int line) override;
0089 
0090     void issueCommand(QString const &cmd) override;
0091 
0092     QString targetName() const override;
0093     void setFileSearchPaths(const QStringList &paths) override;
0094 
0095 public Q_SLOTS:
0096     void slotInterrupt() override;
0097     void slotStepInto() override;
0098     void slotStepOver() override;
0099     void slotStepOut() override;
0100     void slotContinue() override;
0101     void slotKill() override;
0102     void slotReRun() override;
0103     QString slotPrintVariable(const QString &variable) override;
0104 
0105     void slotQueryLocals(bool display) override;
0106     void changeStackFrame(int index) override;
0107     void changeThread(int index) override;
0108     void changeScope(int scopeId) override;
0109 
0110 private Q_SLOTS:
0111     void slotError();
0112     void slotReadDebugStdOut();
0113     void slotReadDebugStdErr();
0114     void slotDebugFinished(int exitCode, QProcess::ExitStatus status);
0115     void issueNextCommand();
0116 
0117 private:
0118     enum State { none, ready, executingCmd };
0119 
0120     enum GdbState { Disconnected, Connected, Running, Stopped };
0121 
0122 private:
0123     QUrl resolveFileName(const QString &fileName, bool silent = false);
0124 
0125     void setState(State newState, std::optional<GdbState> newGdbState = std::nullopt);
0126     void setGdbState(GdbState newState);
0127     void resetSession();
0128     void clearFrames();
0129     void clearVariables();
0130     void updateInspectable(bool inspectable);
0131 
0132     BreakPoint parseBreakpoint(const QJsonObject &item);
0133     int findFirstBreakpoint(const QUrl &url, int line) const;
0134     QStringList findAllBreakpoints(const QUrl &url, int line) const;
0135     void deleteBreakpoint(const int bpNumber);
0136     void insertBreakpoint(const QJsonObject &item);
0137     QString makeCmdBreakInsert(const QUrl &url, int line, bool pending = false, bool temporal = false) const;
0138     QString makeFrameFlags() const;
0139 
0140     bool inferiorRunning() const;
0141     void onMIParserError(const QString &error);
0142     void processMIStreamOutput(const gdbmi::StreamOutput &record);
0143     void processMIRecord(const gdbmi::Record &record);
0144     void processMIExec(const gdbmi::Record &record);
0145     void processMINotify(const gdbmi::Record &record);
0146     void processMIResult(const gdbmi::Record &record);
0147     void processMIPrompt();
0148     bool responseMIBreakpointList(const gdbmi::Record &record);
0149     bool responseMIThreadInfo(const gdbmi::Record &record);
0150     bool responseMIStackListFrames(const gdbmi::Record &record);
0151     bool responseMIStackListVariables(const gdbmi::Record &record);
0152     bool responseMIBreakInsert(const gdbmi::Record &record);
0153     bool responseMIBreakDelete(const gdbmi::Record &record, const QStringList &args);
0154     void notifyMIBreakpointDeleted(const gdbmi::Record &record);
0155     void notifyMIBreakpointModified(const gdbmi::Record &record);
0156     bool responseMIListFeatures(const gdbmi::Record &record);
0157     bool responseMIDataEvaluateExpression(const gdbmi::Record &record, const std::optional<QJsonValue> &data);
0158     bool responseMIRegisterNames(const gdbmi::Record &record);
0159     bool responseMIRegisterValues(const gdbmi::Record &record);
0160     bool responseMIChangedRegisters(const gdbmi::Record &record);
0161     bool responseMIExit(const gdbmi::Record &record);
0162     bool responseMIKill(const gdbmi::Record &record);
0163     bool responseMIInfoGdbCommand(const gdbmi::Record &record, const QStringList &args);
0164     bool responseMILldbVersion(const gdbmi::Record &record);
0165     void responseMIScopes(const gdbmi::Record &record);
0166     void responseMIThisScope(const gdbmi::Record &record);
0167     void informStackFrame();
0168     dap::StackFrame parseFrame(const QJsonObject &object);
0169 
0170     void enqueueScopeVariables();
0171     void enqueueScopes();
0172     void enqueueProtocolHandshake();
0173     QStringList makeInitSequence();
0174     void enqueueThreadInfo();
0175     QStringList makeRunSequence(bool stop);
0176     void enqueue(const QString &command);
0177     void enqueue(const QString &command, const QJsonValue &data, uint8_t captureMode = CaptureMode::Default);
0178     void enqueue(const QStringList &commands, bool prepend = false);
0179     void prepend(const QString &command);
0180     void issueCommand(const QString &cmd, const std::optional<QJsonValue> &data, uint8_t captureMode = CaptureMode::Default);
0181     void issueNextCommandLater(const std::optional<State> &state);
0182     void updateInputReady(bool newState, bool force = false);
0183     void clearDebugLocation();
0184 
0185     void cmdKateInit();
0186     void cmdKateTryRun(const GdbCommand &cmd, const QJsonValue &data);
0187 
0188 private:
0189     QProcess m_debugProcess;
0190     GDBTargetConf m_targetConf;
0191     QString m_ioPipeString;
0192 
0193     State m_state;
0194 
0195     struct PendingCommand {
0196         QString command;
0197         std::optional<QJsonValue> data;
0198         uint8_t captureMode;
0199     };
0200     QList<PendingCommand> m_nextCommands;
0201     QString m_lastCommand;
0202     bool m_debugLocationChanged;
0203     QHash<int, BreakPoint> m_breakpointTable;
0204     QByteArray m_outBuffer;
0205     QString m_errBuffer;
0206     bool m_queryLocals;
0207 
0208     GDBVariableParser m_variableParser;
0209 
0210     gdbmi::GdbmiParser *m_parser;
0211     QHash<int, GdbCommand> m_requests;
0212     int m_seq = 0;
0213     GdbState m_gdbState = Disconnected;
0214     QList<dap::StackFrame> m_stackFrames;
0215     QList<QString> m_registerNames;
0216     QSet<int> m_changedRegisters;
0217     bool m_lastInputReady = false;
0218     bool m_pointerThis = false;
0219 
0220     enum CaptureMode { Default = 0x0, CaptureConsole = 0x1, MuteLog = 0x2 };
0221     uint8_t m_captureOutput = Default;
0222     QStringList m_capturedOutput;
0223     bool m_inspectable = false;
0224     std::optional<int> m_currentThread;
0225     std::optional<int> m_currentFrame;
0226     std::optional<int> m_currentScope;
0227     std::optional<int> m_watchedScope;
0228     int m_errorCounter = 0;
0229 
0230     enum DebuggerFamily { Unknown, GDB, LLDB };
0231     struct {
0232         DebuggerFamily family;
0233         std::optional<bool> async;
0234         std::optional<bool> execRunStart;
0235         std::optional<bool> threadInfo;
0236         std::optional<bool> breakList;
0237         std::optional<bool> pendingBreakpoints;
0238         std::optional<bool> execJump;
0239         std::optional<bool> changedRegisters;
0240     } m_capabilities;
0241 };