📄 gdbmacros.cpp
字号:
/***************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Qt Software Information (qt-info@nokia.com)
**
**
** Non-Open Source Usage
**
** Licensees may use this file in accordance with the Qt Beta Version
** License Agreement, Agreement version 2.2 provided with the Software or,
** alternatively, in accordance with the terms contained in a written
** agreement between you and Nokia.
**
** GNU General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU General
** Public License versions 2.0 or 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the packaging
** of this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
**
** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
** http://www.gnu.org/copyleft/gpl.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt GPL Exception
** version 1.3, included in the file GPL_EXCEPTION.txt in this package.
**
***************************************************************************/
#include <qglobal.h>
// this relies on contents copied from qobject_p.h
#define PRIVATE_OBJECT_ALLOWED 1
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QHash>
#include <QLocale>
#include <QMap>
#include <QMetaObject>
#include <QMetaProperty>
#include <QModelIndex>
#include <QObject>
#include <QPointer>
#include <QString>
#include <QTextCodec>
#include <QVector>
/*!
\class QDumper
\brief Helper class for producing "nice" output in Qt Creator's debugger.
\internal
The whole "custom dumper" implementation is currently far less modular
than it could be. But as the code is still in a flux, making it nicer
from a pure archtectural point of view seems still be a waste of resources.
Some hints:
New dumpers for non-templated classes should be mentioned in
\c{qDumpObjectData440()} in the \c{protocolVersion == 1} branch.
Templated classes need extra support on the IDE level
(see plugins/debugger/gdbengine.cpp) and should not be mentiond in
\c{qDumpObjectData440()}.
In any case, dumper processesing should end up in
\c{handleProtocolVersion2and3()} and needs an entry in the bis switch there.
Next step is to create a suitable \c{static void qDumpFoo(QDumper &d)}
function. At the bare minimum it should contain something like:
\c{
const Foo &foo = *reinterpret_cast<const Foo *>(d.data);
P(d, "value", ...);
P(d, "type", "Foo");
P(d, "numchild", "0");
}
'P(d, name, value)' roughly expands to:
d << (name) << "=\"" << value << "\"";
Useful (i.e. understood by the IDE) names include:
\list
\o "name" shows up in the first column in the Locals&Watchers view.
\o "value" shows up in the second column.
\o "valueencoded" should be set to "1" if the value is base64 encoded.
Always base64-encode values that might use unprintable or otherwise
"confuse" the protocol (like spaces and quotes). [A-Za-z0-9] is "safe".
A value of "3" is used for base64-encoded UCS4, "2" denotes
base64-encoded UTF16.
\o "numchild" return the number of children in the view. Effectively, only
0 and != 0 will be used, so don't try too hard to get the number right.
\endlist
If the current item has children, it might be queried to produce information
about thes children. In this case the dumper should use something like
\c{
if (d.dumpChildren) {
d << ",children=[";
}
*/
int qtGhVersion = QT_VERSION;
#ifdef QT_GUI_LIB
# include <QPixmap>
# include <QImage>
#endif
#include <list>
#include <map>
#include <string>
#include <vector>
#include <ctype.h>
#include <stdio.h>
#ifdef Q_OS_WIN
# include <windows.h>
#endif
#undef NS
#ifdef QT_NAMESPACE
# define STRINGIFY0(s) #s
# define STRINGIFY1(s) STRINGIFY0(s)
# define NS STRINGIFY1(QT_NAMESPACE) "::"
# define NSX "'" STRINGIFY1(QT_NAMESPACE) "::"
# define NSY "'"
#else
# define NS ""
# define NSX ""
# define NSY ""
#endif
#if PRIVATE_OBJECT_ALLOWED
#if defined(QT_BEGIN_NAMESPACE)
QT_BEGIN_NAMESPACE
#endif
class QVariant;
class QThreadData;
class QObjectConnectionListVector;
class QObjectPrivate : public QObjectData
{
Q_DECLARE_PUBLIC(QObject)
public:
QObjectPrivate() {}
virtual ~QObjectPrivate() {}
// preserve binary compatibility with code compiled without Qt 3 support
QList<QObject *> pendingChildInsertedEvents; // unused
// id of the thread that owns the object
QThreadData *threadData;
struct Sender
{
QObject *sender;
int signal;
int ref;
};
Sender *currentSender; // object currently activating the object
QObject *currentChildBeingDeleted;
QList<QPointer<QObject> > eventFilters;
struct ExtraData;
ExtraData *extraData;
mutable quint32 connectedSignals;
QString objectName;
struct Connection
{
QObject *receiver;
int method;
uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
QBasicAtomicPointer<int> argumentTypes;
};
typedef QList<Connection> ConnectionList;
QObjectConnectionListVector *connectionLists;
QList<Sender> senders;
int *deleteWatch;
};
#if defined(QT_BEGIN_NAMESPACE)
QT_END_NAMESPACE
#endif
#endif // PRIVATE_OBJECT_ALLOWED
// this can be mangled typenames of nested templates, each char-by-char
// comma-separated integer list
static char qDumpInBuffer[10000];
static char qDumpBuffer[1000];
namespace {
static bool isPointerType(const QByteArray &type)
{
return type.endsWith("*") || type.endsWith("* const");
}
static QByteArray stripPointerType(QByteArray type)
{
if (type.endsWith("*"))
type.chop(1);
if (type.endsWith("* const"))
type.chop(7);
if (type.endsWith(' '))
type.chop(1);
return type;
}
// This is used to abort evaluation of custom data dumpers in a "coordinated"
// way. Abortion will happen anyway when we try to access a non-initialized
// non-trivial object, so there is no way to prevent this from occuring at all
// conceptionally. Gdb will catch SIGSEGV and return to the calling frame.
// This is just fine provided we only _read_ memory in the custom handlers
// below.
volatile int qProvokeSegFaultHelper;
static const void *addOffset(const void *p, int offset)
{
return offset + reinterpret_cast<const char *>(p);
}
static const void *skipvtable(const void *p)
{
return sizeof(void*) + reinterpret_cast<const char *>(p);
}
static const void *deref(const void *p)
{
return *reinterpret_cast<const char* const*>(p);
}
static const void *dfunc(const void *p)
{
return deref(skipvtable(p));
}
static bool isEqual(const char *s, const char *t)
{
return qstrcmp(s, t) == 0;
}
static bool startsWith(const char *s, const char *t)
{
return qstrncmp(s, t, strlen(t)) == 0;
}
// provoke segfault when address is not readable
#define qCheckAccess(d) do { qProvokeSegFaultHelper = *(char*)d; } while (0)
#define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
// provoke segfault unconditionally
#define qCheck(b) do { if (!(b)) qProvokeSegFaultHelper = *(char*)0; } while (0)
const char *stripNamespace(const char *type)
{
static const size_t nslen = strlen(NS);
return startsWith(type, NS) ? type + nslen : type;
}
static bool isSimpleType(const char *type)
{
switch (type[0]) {
case 'c':
return isEqual(type, "char");
case 'd':
return isEqual(type, "double");
case 'f':
return isEqual(type, "float");
case 'i':
return isEqual(type, "int");
case 'l':
return isEqual(type, "long") || startsWith(type, "long ");
case 's':
return isEqual(type, "short") || isEqual(type, "signed")
|| startsWith(type, "signed ");
case 'u':
return isEqual(type, "unsigned") || startsWith(type, "unsigned ");
}
return false;
}
static bool isShortKey(const char *type)
{
return isSimpleType(type) || isEqual(type, "QString");
}
static bool isMovableType(const char *type)
{
if (isPointerType(type))
return true;
if (isSimpleType(type))
return true;
type = stripNamespace(type);
switch (type[1]) {
case 'B':
return isEqual(type, "QBrush")
|| isEqual(type, "QBitArray")
|| isEqual(type, "QByteArray") ;
case 'C':
return isEqual(type, "QCustomTypeInfo");
case 'D':
return isEqual(type, "QDate")
|| isEqual(type, "QDateTime");
case 'F':
return isEqual(type, "QFileInfo")
|| isEqual(type, "QFixed")
|| isEqual(type, "QFixedPoint")
|| isEqual(type, "QFixedSize");
case 'H':
return isEqual(type, "QHashDummyValue");
case 'I':
return isEqual(type, "QIcon")
|| isEqual(type, "QImage");
case 'L':
return isEqual(type, "QLine")
|| isEqual(type, "QLineF")
|| isEqual(type, "QLocal");
case 'M':
return isEqual(type, "QMatrix")
|| isEqual(type, "QModelIndex");
case 'P':
return isEqual(type, "QPoint")
|| isEqual(type, "QPointF")
|| isEqual(type, "QPen")
|| isEqual(type, "QPersistentModelIndex");
case 'R':
return isEqual(type, "QResourceRoot")
|| isEqual(type, "QRect")
|| isEqual(type, "QRectF")
|| isEqual(type, "QRegExp");
case 'S':
return isEqual(type, "QSize")
|| isEqual(type, "QSizeF")
|| isEqual(type, "QString");
case 'T':
return isEqual(type, "QTime")
|| isEqual(type, "QTextBlock");
case 'U':
return isEqual(type, "QUrl");
case 'V':
return isEqual(type, "QVariant");
case 'X':
return isEqual(type, "QXmlStreamAttribute")
|| isEqual(type, "QXmlStreamNamespaceDeclaration")
|| isEqual(type, "QXmlStreamNotationDeclaration")
|| isEqual(type, "QXmlStreamEntityDeclaration");
}
return false;
}
struct QDumper
{
explicit QDumper();
~QDumper();
void flush();
void checkFill();
QDumper &operator<<(long c);
QDumper &operator<<(int i);
QDumper &operator<<(double d);
QDumper &operator<<(float d);
QDumper &operator<<(unsigned long c);
QDumper &operator<<(unsigned int i);
QDumper &operator<<(const void *p);
QDumper &operator<<(qulonglong c);
QDumper &operator<<(const char *str);
QDumper &operator<<(const QByteArray &ba);
QDumper &operator<<(const QString &str);
void put(char c);
void addCommaIfNeeded();
void putBase64Encoded(const char *buf, int n);
void putEllipsis();
void disarm();
void beginHash(); // start of data hash output
void endHash(); // start of data hash output
void write(const void *buf, int len); // raw write to stdout
// the dumper arguments
int protocolVersion; // dumper protocol version
int token; // some token to show on success
const char *outertype; // object type
const char *iname; // object name used for display
const char *exp; // object expression
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -