1 /*
2     SPDX-FileCopyrightText: 2004 Roberto Raggi <roberto@kdevelop.org>
3     SPDX-FileCopyrightText: 2005-2006 Vladimir Prus <ghost@cs.msu.su>
4     SPDX-FileCopyrightText: 2016 Aetf <aetf@unlimitedcodeworks.xyz>
5 
6     SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #ifndef GDBMI_H
10 #define GDBMI_H
11 
12 #include <QString>
13 #include <QMap>
14 
15 #include <stdexcept>
16 
17 /**
18 @author Roberto Raggi
19 @author Vladimir Prus
20 */
21 namespace KDevMI { namespace MI {
22     enum CommandType {
23         NonMI,
24 
25         BreakAfter,
26         BreakCommands,
27         BreakCondition,
28         BreakDelete,
29         BreakDisable,
30         BreakEnable,
31         BreakInfo,
32         BreakInsert,
33         BreakList,
34         BreakWatch,
35 
36         DataDisassemble,
37         DataEvaluateExpression,
38         DataListChangedRegisters,
39         DataListRegisterNames,
40         DataListRegisterValues,
41         DataReadMemory,
42         DataWriteMemory,
43         DataWriteRegisterVariables,
44 
45         EnablePrettyPrinting,
46         EnableTimings,
47 
48         EnvironmentCd,
49         EnvironmentDirectory,
50         EnvironmentPath,
51         EnvironmentPwd,
52 
53         ExecAbort,
54         ExecArguments,
55         ExecContinue,
56         ExecFinish,
57         ExecInterrupt,
58         ExecNext,
59         ExecNextInstruction,
60         ExecRun,
61         ExecStep,
62         ExecStepInstruction,
63         ExecUntil,
64 
65         FileExecAndSymbols,
66         FileExecFile,
67         FileListExecSourceFile,
68         FileListExecSourceFiles,
69         FileSymbolFile,
70 
71         GdbExit,
72         GdbSet,
73         GdbShow,
74         GdbVersion,
75 
76         InferiorTtySet,
77         InferiorTtyShow,
78 
79         InterpreterExec,
80 
81         ListFeatures,
82 
83         SignalHandle,
84 
85         StackInfoDepth,
86         StackInfoFrame,
87         StackListArguments,
88         StackListFrames,
89         StackListLocals,
90         StackSelectFrame,
91 
92         SymbolListLines,
93 
94         TargetAttach,
95         TargetDetach,
96         TargetDisconnect,
97         TargetDownload,
98         TargetSelect,
99 
100         ThreadInfo,
101         ThreadListIds,
102         ThreadSelect,
103 
104         TraceFind,
105         TraceStart,
106         TraceStop,
107 
108         VarAssign,
109         VarCreate,
110         VarDelete,
111         VarEvaluateExpression,
112         VarInfoPathExpression,
113         VarInfoNumChildren,
114         VarInfoType,
115         VarListChildren,
116         VarSetFormat,
117         VarSetFrozen,
118         VarShowAttributes,
119         VarShowFormat,
120         VarUpdate
121     };
122 
123     /** Exception that is thrown when we're trying to invoke an
124         operation that is not supported by specific MI value. For
125         example, trying to index a string literal.
126 
127         Such errors are conceptually the same as assert, but in GUI
128         we can't use regular assert, and Q_ASSERT, which only prints
129         a message, is not suitable either. We need to break processing,
130         and the higher-level code can report "Internal parsing error",
131         or something.
132 
133         Being glorified assert, this exception does not cary any
134         useful information.
135     */
136     class type_error : public std::logic_error
137     {
138     public:
139         type_error();
140     };
141 
142     /** Base class for all MI values.
143         MI values are of three kinds:
144         - String literals
145         - Lists (indexed by integer)
146         - Tuple (set of named values, indexed by name)
147 
148         The structure of response to a specific gdb command is fixed.
149         While any tuples in response may omit certain named fields, the
150         kind of each item never changes. That is, response to specific
151         command can't contains sometimes string and sometimes tuple in
152         specific position.
153 
154         Because of that static structure, it's almost never needed to query
155         dynamic type of a MI value. Most often we know it's say, tuple, and
156         can subscripts it.
157 
158         So, the Value class has methods for accessing all kinds of values.
159         Attempting to call a method that is not applicable to specific value
160         will result in exception. The client code will almost never need to
161         cast from 'Value' to its derived classes.
162 
163         Note also that all methods in this class are const and return
164         const Value&. That's by design -- there's no need to modify gdb
165         responses in GUI.
166      */
167     struct Value
168     {
169         enum Kind {
170             StringLiteral,
171             Tuple,
172             List
173         };
174 
175     protected:
ValueValue176         constexpr explicit Value(Kind k) : kind(k) {}
177 
178     public:
179         virtual ~Value() = default;
180 
181         Value() = delete;
182         // Copy disabled to prevent slicing.
183         Value(const Value&) = delete;
184         Value& operator=(const Value&) = delete;
185 
186         const Kind kind = StringLiteral;
187 
188         /** If this value is a string literals, returns the string value.
189             Otherwise, throws type_error.
190         */
191         virtual QString literal() const;
192 
193         //NOTE: Wouldn't it be better to use literal().toInt and get rid of that?
194         /** If the value is a string literal, converts it to int and
195             returns. If conversion fails, or the value cannot be
196             converted to int, throws type_error.
197         */
198         virtual int toInt(int base = 10) const;
199 
200         /** If this value is a tuple, returns true if the tuple
201             has a field named 'variable'. Otherwise,
202             throws type_error.
203         */
204         virtual bool hasField(const QString& variable) const;
205 
206         /** If this value is a tuple, and contains named field 'variable',
207             returns it. Otherwise, throws 'type_error'.
208             This method is virtual, and derived in base class, so that
209             we can save on casting, when we know for sure that instance
210             is TupleValue, or ListValue.
211         */
212         virtual const Value& operator[](const QString& variable) const;
213 
214         /** If this value is a list, returns true if the list is empty.
215             If this value is not a list, throws 'type_error'.
216         */
217         virtual bool empty() const;
218 
219         /** If this value is a list, returns it's size.
220             Otherwise, throws 'type_error'.
221         */
222         virtual int size() const;
223 
224         /** If this value is a list, returns the element at
225             'index'. Otherwise, throws 'type_error'.
226         */
227         virtual const Value& operator[](int index) const;
228     };
229 
230     /** @internal
231         Internal class to represent name-value pair in tuples.
232     */
233     struct Result
234     {
235         Result() = default;
~ResultResult236         ~Result() { delete value; value = nullptr; }
237 
238         QString variable;
239         Value *value = nullptr;
240 
241     private:
242         Q_DISABLE_COPY(Result)
243     };
244 
245     struct StringLiteralValue : public Value
246     {
StringLiteralValueStringLiteralValue247         explicit StringLiteralValue(const QString &lit)
248             : Value(StringLiteral)
249             , literal_(lit)
250         {}
251 
252     public: // Value overrides
253 
254         QString literal() const override;
255         int toInt(int base) const override;
256 
257     private:
258         QString literal_;
259     };
260 
261     struct TupleValue : public Value
262     {
TupleValueTupleValue263         TupleValue() : Value(Tuple) {}
264         ~TupleValue() override;
265 
266         bool hasField(const QString&) const override;
267 
268         using Value::operator[];
269         const Value& operator[](const QString& variable) const override;
270 
271         QList<Result*> results;
272         QMap<QString, Result*> results_by_name;
273     };
274 
275     struct ListValue : public Value
276     {
ListValueListValue277         ListValue() : Value(List) {}
278         ~ListValue() override;
279 
280         bool empty() const override;
281 
282         int size() const override;
283 
284         using Value::operator[];
285         const Value& operator[](int index) const override;
286 
287         QList<Result*> results;
288     };
289 
290     struct Record
291     {
292         enum Kind {
293             Prompt,
294             Stream,
295             Result,
296             Async
297         };
298 
299     protected:
RecordRecord300         constexpr explicit Record(Kind k) : kind(k) {}
301 
302     public:
303         Record() = delete;
304         Record(const Record&) = delete;
305         Record& operator=(const Record&) = delete;
306 
307         virtual ~Record() = default;
toStringRecord308         virtual QString toString() const { Q_ASSERT( 0 ); return QString(); }
309 
310         const Kind kind;
311     };
312 
313     struct TupleRecord : public Record, public TupleValue
314     {
315     protected:
TupleRecordTupleRecord316         explicit TupleRecord(Record::Kind k) : Record(k) {}
317     };
318 
319     struct ResultRecord : public TupleRecord
320     {
ResultRecordResultRecord321         explicit ResultRecord(const QString& reason)
322             : TupleRecord(Result)
323             , reason(reason)
324         {
325         }
326 
327         uint32_t token = 0;
328         QString reason;
329     };
330 
331     struct AsyncRecord : public TupleRecord
332     {
333         enum Subkind {
334             Exec,
335             Status,
336             Notify
337         };
338 
AsyncRecordAsyncRecord339         AsyncRecord(Subkind subkind, const QString& reason)
340             : TupleRecord(Async)
341             , subkind(subkind)
342             , reason(reason)
343         {
344         }
345 
346         Subkind subkind;
347         QString reason;
348     };
349 
350     struct PromptRecord : public Record
351     {
PromptRecordPromptRecord352         PromptRecord() : Record(Prompt) {}
353 
toStringPromptRecord354         QString toString() const override
355         { return QStringLiteral("(prompt)\n"); }
356     };
357 
358     struct StreamRecord : public Record
359     {
360         enum Subkind {
361             /// Console stream: usual CLI output of GDB in response to non-MI commands
362             Console,
363 
364             /// Target output stream (stdout/stderr of the inferior process, only in some
365             /// scenarios - usually we get stdout/stderr via other means)
366             Target,
367 
368             /// Log stream: GDB internal messages that should be displayed as part of an error log
369             Log
370         };
371 
StreamRecordStreamRecord372         explicit StreamRecord(Subkind subkind)
373             : Record(Stream)
374             , subkind(subkind)
375         {
376         }
377 
378         Subkind subkind;
379         QString message;
380     };
381 } // end of namespace MI
382 } // end of namespace KDevMI
383 
384 #endif
385