1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #pragma once
27 
28 #include <QByteArray>
29 #include <QList>
30 #include <QString>
31 #include <QJsonValue>
32 #include <QJsonObject>
33 #include <QVector>
34 
35 #include <utils/fileutils.h>
36 
37 namespace Utils { class ProcessHandle; }
38 
39 namespace Debugger {
40 namespace Internal {
41 
42 class DebuggerResponse;
43 
44 // Convenience structure to build up backend commands.
45 class DebuggerCommand
46 {
47 public:
48     using Callback = std::function<void (const DebuggerResponse &)>;
49 
50     DebuggerCommand() = default;
DebuggerCommand(const QString & f)51     DebuggerCommand(const QString &f) : function(f) {}
DebuggerCommand(const QString & f,const QJsonValue & a)52     DebuggerCommand(const QString &f, const QJsonValue &a) : function(f), args(a) {}
DebuggerCommand(const QString & f,int fl)53     DebuggerCommand(const QString &f, int fl) : function(f), flags(fl) {}
DebuggerCommand(const QString & f,int fl,const Callback & cb)54     DebuggerCommand(const QString &f, int fl, const Callback &cb) : function(f), callback(cb), flags(fl) {}
DebuggerCommand(const QString & f,const Callback & cb)55     DebuggerCommand(const QString &f, const Callback &cb) : function(f), callback(cb) {}
56 
57     void arg(const char *value);
58     void arg(const char *name, bool value);
59     void arg(const char *name, int value);
60     void arg(const char *name, qlonglong value);
61     void arg(const char *name, qulonglong value);
62     void arg(const char *name, const QString &value);
63     void arg(const char *name, const char *value);
64     void arg(const char *name, const QList<int> &list);
65     void arg(const char *name, const QStringList &list); // Note: Hex-encodes.
66     void arg(const char *name, const QJsonValue &value);
67     void arg(const char *name, const Utils::FilePath &filePath);
68 
69     QString argsToPython() const;
70     QString argsToString() const;
71 
72     enum CommandFlag {
73         NoFlags = 0,
74         // The command needs a stopped inferior.
75         NeedsTemporaryStop = 1,
76         // No need to wait for the reply before continuing inferior.
77         Discardable = 2,
78         // Needs a dummy extra command to force GDB output flushing.
79         NeedsFlush = 4,
80         // The command needs a stopped inferior and will stay stopped afterward.
81         NeedsFullStop = 8,
82         // Callback expects ResultRunning instead of ResultDone.
83         RunRequest = 16,
84         // Callback expects ResultExit instead of ResultDone.
85         ExitRequest = 32,
86         // Auto-set inferior shutdown related states.
87         LosesChild = 64,
88         // This is a native (non-Python) command that's handled directly by the backend.
89         NativeCommand = 256,
90         // This is a command that needs to be wrapped into -interpreter-exec console
91         ConsoleCommand = 512,
92         // This is the UpdateLocals commannd during which we ignore notifications
93         InUpdateLocals = 1024,
94         // Do not echo to log.
95         Silent = 4096
96     };
97 
98     Q_DECLARE_FLAGS(CommandFlags, CommandFlag)
99 
100     QString function;
101     QJsonValue args;
102     Callback callback;
103     uint postTime = 0; // msecsSinceStartOfDay
104     int flags = 0;
105 
106 private:
107     void argHelper(const char *name, const QByteArray &value);
108 };
109 
110 class DebuggerCommandSequence
111 {
112 public:
113     DebuggerCommandSequence() = default;
isEmpty()114     bool isEmpty() const { return m_commands.isEmpty(); }
wantContinue()115     bool wantContinue() const { return m_continue; }
commands()116     const QList<DebuggerCommand> &commands() const { return m_commands; }
append(const DebuggerCommand & cmd,bool wantContinue)117     void append(const DebuggerCommand &cmd, bool wantContinue) {
118         m_commands.append(cmd);
119         m_continue = wantContinue;
120     }
121 
122 public:
123     QList<DebuggerCommand> m_commands;
124     bool m_continue = false;
125 };
126 
127 class DebuggerOutputParser
128 {
129 public:
130     explicit DebuggerOutputParser(const QString &output);
131 
current()132     QChar current() const { return *from; }
isCurrent(QChar c)133     bool isCurrent(QChar c) const { return *from == c; }
isAtEnd()134     bool isAtEnd() const { return from >= to; }
135 
advance()136     void advance() { ++from; }
advance(int n)137     void advance(int n) { from += n; }
lookAhead(int offset)138     QChar lookAhead(int offset) const { return from[offset]; }
139 
140     int readInt();
141     QChar readChar();
142     QString readCString();
143     QString readString(const std::function<bool(char)> &isValidChar);
144 
buffer()145     QString buffer() const { return QString(from, to - from); }
remainingChars()146     int remainingChars() const { return int(to - from); }
147 
148     void skipCommas();
149     void skipSpaces();
150 
151 private:
152     const QChar *from = nullptr;
153     const QChar *to = nullptr;
154 };
155 
156 class GdbMi
157 {
158 public:
159     GdbMi() = default;
160 
161     QString m_name;
162     QString m_data;
163 
164     using Children = QVector<GdbMi>;
165     enum Type { Invalid, Const, Tuple, List };
166     Type m_type = Invalid;
167 
addChild(const GdbMi & child)168     void addChild(const GdbMi &child) { m_children.push_back(child); }
169 
type()170     Type type() const { return m_type; }
name()171     const QString &name() const { return m_name; }
hasName(const QString & name)172     bool hasName(const QString &name) const { return m_name == name; }
173 
isValid()174     bool isValid() const { return m_type != Invalid; }
isList()175     bool isList() const { return m_type == List; }
176 
data()177     const QString &data() const { return m_data; }
begin()178     Children::const_iterator begin() const { return m_children.begin(); }
end()179     Children::const_iterator end() const { return m_children.end(); }
childCount()180     int childCount() const { return int(m_children.size()); }
181 
childAt(int index)182     const GdbMi &childAt(int index) const { return m_children[index]; }
183     const GdbMi &operator[](const char *name) const;
184 
185     QString toString(bool multiline = false, int indent = 0) const;
186     qulonglong toAddress() const;
187     Utils::ProcessHandle toProcessHandle() const;
toInt()188     int toInt() const { return m_data.toInt(); }
toLongLong()189     qint64 toLongLong() const { return m_data.toLongLong(); }
190     void fromString(const QString &str);
191     void fromStringMultiple(const QString &str);
192 
193     static QString escapeCString(const QString &ba);
194     void parseResultOrValue(DebuggerOutputParser &state);
195     void parseValue(DebuggerOutputParser &state);
196     void parseTuple(DebuggerOutputParser &state);
197     void parseTuple_helper(DebuggerOutputParser &state);
198     void parseList(DebuggerOutputParser &state);
199 
200 private:
201     void dumpChildren(QString *str, bool multiline, int indent) const;
202     Children m_children;
203 };
204 
205 QString fromHex(const QString &str);
206 QString toHex(const QString &str);
207 
208 
209 enum ResultClass
210 {
211     // "done" | "running" | "connected" | "error" | "exit"
212     ResultUnknown,
213     ResultDone,
214     ResultRunning,
215     ResultConnected,
216     ResultError,
217     ResultExit
218 };
219 
220 class DebuggerResponse
221 {
222 public:
223     DebuggerResponse() = default;
224     QString toString() const;
225     static QString stringFromResultClass(ResultClass resultClass);
226 
227     int         token = -1;
228     ResultClass resultClass = ResultUnknown;
229     GdbMi       data;
230     QString     logStreamOutput;
231     QString     consoleStreamOutput;
232 };
233 
234 void extractGdbVersion(const QString &msg,
235     int *gdbVersion, int *gdbBuildVersion, bool *isMacGdb, bool *isQnxGdb);
236 
237 
238 class DebuggerEncoding
239 {
240 public:
241     enum EncodingType {
242         Unencoded,
243         HexEncodedLocal8Bit,
244         HexEncodedLatin1,
245         HexEncodedUtf8,
246         HexEncodedUtf16,
247         HexEncodedUcs4,
248         HexEncodedSignedInteger,
249         HexEncodedUnsignedInteger,
250         HexEncodedFloat,
251         JulianDate,
252         MillisecondsSinceMidnight,
253         JulianDateAndMillisecondsSinceMidnight,
254         IPv6AddressAndHexScopeId,
255         DateTimeInternal,
256     };
257 
258     DebuggerEncoding() = default;
259     explicit DebuggerEncoding(const QString &data);
260     QString toString() const;
261 
262     EncodingType type = Unencoded;
263     int size = 0;
264     bool quotes = false;
265 };
266 
267 // Decode string data as returned by the dumper helpers.
268 QString decodeData(const QString &baIn, const QString &encoding);
269 
270 
271 // These enum values correspond to possible value display format requests,
272 // typically selected by the user using the L&E context menu, under
273 // "Change Value Display Format". They are passed from the frontend to
274 // the dumpers.
275 //
276 // Keep in sync with dumper.py.
277 //
278 // \note Add new enum values only at the end, as the numeric values are
279 // persisted in user settings.
280 
281 enum DisplayFormat
282 {
283     AutomaticFormat             =  0, // Based on type for individuals, dumper default for types.
284                                       // Could be anything reasonably cheap.
285     RawFormat                   =  1, // No formatting at all.
286 
287     SimpleFormat                =  2, // Typical simple format (e.g. for QModelIndex row/column)
288     EnhancedFormat              =  3, // Enhanced format (e.g. for QModelIndex with resolved display)
289     SeparateFormat              =  4, // Display in separate Window
290 
291     Latin1StringFormat          =  5,
292     SeparateLatin1StringFormat  =  6,
293     Utf8StringFormat            =  7,
294     SeparateUtf8StringFormat    =  8,
295     Local8BitStringFormat       =  9,
296     Utf16StringFormat           = 10,
297     Ucs4StringFormat            = 11,
298 
299     Array10Format               = 12,
300     Array100Format              = 13,
301     Array1000Format             = 14,
302     Array10000Format            = 15,
303     ArrayPlotFormat             = 16,
304 
305     CompactMapFormat            = 17,
306     DirectQListStorageFormat    = 18,
307     IndirectQListStorageFormat  = 19,
308 
309     BoolTextFormat              = 20, // Bools as "true" or "false" - Frontend internal only.
310     BoolIntegerFormat           = 21, // Bools as "0" or "1" - Frontend internal only
311 
312     DecimalIntegerFormat        = 22, // Frontend internal only
313     HexadecimalIntegerFormat    = 23, // Frontend internal only
314     BinaryIntegerFormat         = 24, // Frontend internal only
315     OctalIntegerFormat          = 25, // Frontend internal only
316 
317     CompactFloatFormat          = 26, // Frontend internal only
318     ScientificFloatFormat       = 27  // Frontend internal only
319 };
320 
321 
322 // These values are passed from the dumper to the frontend,
323 // typically as a result of passing a related DisplayFormat value.
324 // They are never stored in settings.
325 
326 const char DisplayLatin1String[] = "latin1:separate";
327 const char DisplayUtf8String[]   = "utf8:separate";
328 const char DisplayUtf16String[]  = "utf16:separate";
329 const char DisplayUcs4String[]   = "ucs4:separate";
330 const char DisplayImageData[]    = "imagedata:separate";
331 const char DisplayImageFile[]    = "imagefile:separate";
332 const char DisplayPlotData[]     = "plotdata:separate";
333 const char DisplayArrayData[]    = "arraydata:separate";
334 
335 enum LocationType { UnknownLocation, LocationByFile, LocationByAddress };
336 
337 class ContextData
338 {
339 public:
isValid()340     bool isValid() const { return type != UnknownLocation; }
341 
342 public:
343     LocationType type = UnknownLocation;
344     Utils::FilePath fileName;
345     int lineNumber = 0;
346     quint64 address = 0;
347 };
348 
349 } // namespace Internal
350 } // namespace Debugger
351 
352 Q_DECLARE_OPERATORS_FOR_FLAGS(Debugger::Internal::DebuggerCommand::CommandFlags)
353