forked from qt-creator/qt-creator
Since we also license under GPL-3.0 WITH Qt-GPL-exception-1.0,
this applies only to a hypothetical newer version of GPL, that doesn't
exist yet. If such a version emerges, we can still decide to relicense...
While at it, replace (deprecated) GPL-3.0 with more explicit GPL-3.0-only
Change was done by running
find . -type f -exec perl -pi -e "s/LicenseRef-Qt-Commercial OR GPL-3.0\+ OR GPL-3.0 WITH Qt-GPL-exception-1.0/LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0/g" {} \;
Change-Id: I5097e6ce8d10233993ee30d7e25120e2659eb10b
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
331 lines
10 KiB
C++
331 lines
10 KiB
C++
// Copyright (C) 2016 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
#pragma once
|
|
|
|
#include <QByteArray>
|
|
#include <QList>
|
|
#include <QString>
|
|
#include <QJsonValue>
|
|
#include <QJsonObject>
|
|
#include <QVector>
|
|
|
|
#include <utils/filepath.h>
|
|
|
|
namespace Utils { class ProcessHandle; }
|
|
|
|
namespace Debugger::Internal {
|
|
|
|
class DebuggerResponse;
|
|
|
|
// Convenience structure to build up backend commands.
|
|
class DebuggerCommand
|
|
{
|
|
public:
|
|
using Callback = std::function<void (const DebuggerResponse &)>;
|
|
|
|
DebuggerCommand() = default;
|
|
DebuggerCommand(const QString &f) : function(f) {}
|
|
DebuggerCommand(const QString &f, const QJsonValue &a) : function(f), args(a) {}
|
|
DebuggerCommand(const QString &f, int fl) : function(f), flags(fl) {}
|
|
DebuggerCommand(const QString &f, int fl, const Callback &cb) : function(f), callback(cb), flags(fl) {}
|
|
DebuggerCommand(const QString &f, const Callback &cb) : function(f), callback(cb) {}
|
|
|
|
void arg(const char *value);
|
|
void arg(const char *name, bool value);
|
|
void arg(const char *name, int value);
|
|
void arg(const char *name, qlonglong value);
|
|
void arg(const char *name, qulonglong value);
|
|
void arg(const char *name, const QString &value);
|
|
void arg(const char *name, const char *value);
|
|
void arg(const char *name, const QList<int> &list);
|
|
void arg(const char *name, const QStringList &list); // Note: Hex-encodes.
|
|
void arg(const char *name, const QJsonValue &value);
|
|
|
|
QString argsToPython() const;
|
|
QString argsToString() const;
|
|
|
|
enum CommandFlag {
|
|
NoFlags = 0,
|
|
// The command needs a stopped inferior.
|
|
NeedsTemporaryStop = 1,
|
|
// No need to wait for the reply before continuing inferior.
|
|
Discardable = 2,
|
|
// Needs a dummy extra command to force GDB output flushing.
|
|
NeedsFlush = 4,
|
|
// The command needs a stopped inferior and will stay stopped afterward.
|
|
NeedsFullStop = 8,
|
|
// Callback expects ResultRunning instead of ResultDone.
|
|
RunRequest = 16,
|
|
// Callback expects ResultExit instead of ResultDone.
|
|
ExitRequest = 32,
|
|
// Auto-set inferior shutdown related states.
|
|
LosesChild = 64,
|
|
// This is a native (non-Python) command that's handled directly by the backend.
|
|
NativeCommand = 256,
|
|
// This is a command that needs to be wrapped into -interpreter-exec console
|
|
ConsoleCommand = 512,
|
|
// This is the UpdateLocals commannd during which we ignore notifications
|
|
InUpdateLocals = 1024,
|
|
// Do not echo to log.
|
|
Silent = 4096
|
|
};
|
|
|
|
Q_DECLARE_FLAGS(CommandFlags, CommandFlag)
|
|
|
|
QString function;
|
|
QJsonValue args;
|
|
Callback callback;
|
|
uint postTime = 0; // msecsSinceStartOfDay
|
|
int flags = 0;
|
|
|
|
private:
|
|
void argHelper(const char *name, const QByteArray &value);
|
|
};
|
|
|
|
class DebuggerCommandSequence
|
|
{
|
|
public:
|
|
DebuggerCommandSequence() = default;
|
|
bool isEmpty() const { return m_commands.isEmpty(); }
|
|
bool wantContinue() const { return m_continue; }
|
|
const QList<DebuggerCommand> &commands() const { return m_commands; }
|
|
void append(const DebuggerCommand &cmd, bool wantContinue) {
|
|
m_commands.append(cmd);
|
|
m_continue = wantContinue;
|
|
}
|
|
|
|
public:
|
|
QList<DebuggerCommand> m_commands;
|
|
bool m_continue = false;
|
|
};
|
|
|
|
class DebuggerOutputParser
|
|
{
|
|
public:
|
|
explicit DebuggerOutputParser(const QString &output);
|
|
|
|
QChar current() const { return *from; }
|
|
bool isCurrent(QChar c) const { return *from == c; }
|
|
bool isAtEnd() const { return from >= to; }
|
|
|
|
void advance() { ++from; }
|
|
void advance(int n) { from += n; }
|
|
QChar lookAhead(int offset) const { return from[offset]; }
|
|
|
|
int readInt();
|
|
QChar readChar();
|
|
QString readCString();
|
|
QString readString(const std::function<bool(char)> &isValidChar);
|
|
|
|
QString buffer() const { return QString(from, to - from); }
|
|
int remainingChars() const { return int(to - from); }
|
|
|
|
void skipCommas();
|
|
void skipSpaces();
|
|
|
|
private:
|
|
const QChar *from = nullptr;
|
|
const QChar *to = nullptr;
|
|
};
|
|
|
|
class GdbMi
|
|
{
|
|
public:
|
|
GdbMi() = default;
|
|
|
|
QString m_name;
|
|
QString m_data;
|
|
|
|
using Children = QVector<GdbMi>;
|
|
enum Type { Invalid, Const, Tuple, List };
|
|
Type m_type = Invalid;
|
|
|
|
void addChild(const GdbMi &child) { m_children.push_back(child); }
|
|
|
|
Type type() const { return m_type; }
|
|
const QString &name() const { return m_name; }
|
|
bool hasName(const QString &name) const { return m_name == name; }
|
|
|
|
bool isValid() const { return m_type != Invalid; }
|
|
bool isList() const { return m_type == List; }
|
|
|
|
const QString &data() const { return m_data; }
|
|
Children::const_iterator begin() const { return m_children.begin(); }
|
|
Children::const_iterator end() const { return m_children.end(); }
|
|
int childCount() const { return int(m_children.size()); }
|
|
|
|
const GdbMi &childAt(int index) const { return m_children[index]; }
|
|
const GdbMi &operator[](const char *name) const;
|
|
|
|
QString toString(bool multiline = false, int indent = 0) const;
|
|
qulonglong toAddress() const;
|
|
Utils::ProcessHandle toProcessHandle() const;
|
|
int toInt() const { return m_data.toInt(); }
|
|
qint64 toLongLong() const { return m_data.toLongLong(); }
|
|
void fromString(const QString &str);
|
|
void fromStringMultiple(const QString &str);
|
|
|
|
static QString escapeCString(const QString &ba);
|
|
void parseResultOrValue(DebuggerOutputParser &state);
|
|
void parseValue(DebuggerOutputParser &state);
|
|
void parseTuple(DebuggerOutputParser &state);
|
|
void parseTuple_helper(DebuggerOutputParser &state);
|
|
void parseList(DebuggerOutputParser &state);
|
|
|
|
private:
|
|
void dumpChildren(QString *str, bool multiline, int indent) const;
|
|
Children m_children;
|
|
};
|
|
|
|
QString fromHex(const QString &str);
|
|
QString toHex(const QString &str);
|
|
|
|
|
|
enum ResultClass
|
|
{
|
|
// "done" | "running" | "connected" | "error" | "exit"
|
|
ResultUnknown,
|
|
ResultDone,
|
|
ResultRunning,
|
|
ResultConnected,
|
|
ResultError,
|
|
ResultExit
|
|
};
|
|
|
|
class DebuggerResponse
|
|
{
|
|
public:
|
|
DebuggerResponse() = default;
|
|
QString toString() const;
|
|
static QString stringFromResultClass(ResultClass resultClass);
|
|
|
|
int token = -1;
|
|
ResultClass resultClass = ResultUnknown;
|
|
GdbMi data;
|
|
QString logStreamOutput;
|
|
QString consoleStreamOutput;
|
|
};
|
|
|
|
void extractGdbVersion(const QString &msg,
|
|
int *gdbVersion, int *gdbBuildVersion, bool *isMacGdb, bool *isQnxGdb);
|
|
|
|
|
|
class DebuggerEncoding
|
|
{
|
|
public:
|
|
enum EncodingType {
|
|
Unencoded,
|
|
HexEncodedLocal8Bit,
|
|
HexEncodedLatin1,
|
|
HexEncodedUtf8,
|
|
HexEncodedUtf16,
|
|
HexEncodedUcs4,
|
|
HexEncodedSignedInteger,
|
|
HexEncodedUnsignedInteger,
|
|
HexEncodedFloat,
|
|
JulianDate,
|
|
MillisecondsSinceMidnight,
|
|
JulianDateAndMillisecondsSinceMidnight,
|
|
IPv6AddressAndHexScopeId,
|
|
DateTimeInternal,
|
|
};
|
|
|
|
DebuggerEncoding() = default;
|
|
explicit DebuggerEncoding(const QString &data);
|
|
QString toString() const;
|
|
|
|
EncodingType type = Unencoded;
|
|
int size = 0;
|
|
bool quotes = false;
|
|
};
|
|
|
|
// Decode string data as returned by the dumper helpers.
|
|
QString decodeData(const QString &baIn, const QString &encoding);
|
|
|
|
|
|
// These enum values correspond to possible value display format requests,
|
|
// typically selected by the user using the L&E context menu, under
|
|
// "Change Value Display Format". They are passed from the frontend to
|
|
// the dumpers.
|
|
//
|
|
// Keep in sync with share/qtcreator/debugger/utils.py
|
|
//
|
|
// \note Add new enum values only with increasing numeric values as they are
|
|
// persisted in user settings.
|
|
|
|
enum DisplayFormat
|
|
{
|
|
AutomaticFormat = 0, // Based on type for individuals, dumper default for types.
|
|
// Could be anything reasonably cheap.
|
|
RawFormat = 1, // No formatting at all.
|
|
|
|
SimpleFormat = 2, // Typical simple format (e.g. for QModelIndex row/column)
|
|
EnhancedFormat = 3, // Enhanced format (e.g. for QModelIndex with resolved display)
|
|
SeparateFormat = 4, // Display in separate Window
|
|
|
|
Latin1StringFormat = 5,
|
|
SeparateLatin1StringFormat = 6,
|
|
Utf8StringFormat = 7,
|
|
SeparateUtf8StringFormat = 8,
|
|
Local8BitStringFormat = 9,
|
|
Utf16StringFormat = 10,
|
|
Ucs4StringFormat = 11,
|
|
|
|
Array10Format = 12,
|
|
Array100Format = 13,
|
|
Array1000Format = 14,
|
|
Array10000Format = 15,
|
|
ArrayPlotFormat = 16,
|
|
|
|
CompactMapFormat = 17,
|
|
DirectQListStorageFormat = 18,
|
|
IndirectQListStorageFormat = 19,
|
|
|
|
BoolTextFormat = 20, // Bools as "true" or "false" - Frontend internal only.
|
|
BoolIntegerFormat = 21, // Bools as "0" or "1" - Frontend internal only
|
|
|
|
DecimalIntegerFormat = 22, // Frontend internal only
|
|
HexadecimalIntegerFormat = 23, // Frontend internal only
|
|
BinaryIntegerFormat = 24, // Frontend internal only
|
|
OctalIntegerFormat = 25, // Frontend internal only
|
|
CharCodeIntegerFormat = 28, // Frontend internal only
|
|
|
|
CompactFloatFormat = 26, // Frontend internal only
|
|
ScientificFloatFormat = 27, // Frontend internal only
|
|
HexFloatFormat = 29, // Frontend internal only
|
|
NormalizedTwoFloatFormat = 30, // Frontend internal only
|
|
};
|
|
|
|
|
|
// These values are passed from the dumper to the frontend,
|
|
// typically as a result of passing a related DisplayFormat value.
|
|
// They are never stored in settings.
|
|
|
|
const char DisplayLatin1String[] = "latin1:separate";
|
|
const char DisplayUtf8String[] = "utf8:separate";
|
|
const char DisplayUtf16String[] = "utf16:separate";
|
|
const char DisplayUcs4String[] = "ucs4:separate";
|
|
const char DisplayImageData[] = "imagedata:separate";
|
|
const char DisplayImageFile[] = "imagefile:separate";
|
|
const char DisplayPlotData[] = "plotdata:separate";
|
|
const char DisplayArrayData[] = "arraydata:separate";
|
|
|
|
enum LocationType { UnknownLocation, LocationByFile, LocationByAddress };
|
|
|
|
class ContextData
|
|
{
|
|
public:
|
|
bool isValid() const { return type != UnknownLocation; }
|
|
|
|
public:
|
|
LocationType type = UnknownLocation;
|
|
Utils::FilePath fileName;
|
|
int lineNumber = 0;
|
|
quint64 address = 0;
|
|
};
|
|
|
|
} // Debugger::Internal
|
|
|
|
Q_DECLARE_OPERATORS_FOR_FLAGS(Debugger::Internal::DebuggerCommand::CommandFlags)
|