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