Started on QObject dumping for CDB, make it smarter.

Try to find qobject_p.h, if it exists and use its structures
to determine the child offset.
This commit is contained in:
Friedemann Kleint
2009-05-05 16:39:51 +02:00
parent a24e3b70b3
commit bae6525976
6 changed files with 138 additions and 31 deletions

View File

@@ -32,6 +32,9 @@
// this relies on contents copied from qobject_p.h
#define PRIVATE_OBJECT_ALLOWED 1
#ifdef HAS_QOBJECT_P_H
# include <QtCore/private/qobject_p.h>
#endif
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QDir>
@@ -146,8 +149,7 @@ int qtGhVersion = QT_VERSION;
# define NSY ""
#endif
#if PRIVATE_OBJECT_ALLOWED
#if PRIVATE_OBJECT_ALLOWED && !HAS_QOBJECT_P_H
#if defined(QT_BEGIN_NAMESPACE)
QT_BEGIN_NAMESPACE
@@ -1532,6 +1534,13 @@ static void qDumpQObject(QDumper &d)
const QObject *ob = reinterpret_cast<const QObject *>(d.data);
const QMetaObject *mo = ob->metaObject();
unsigned childrenOffset = d.extraInt[0];
#ifdef HAS_QOBJECT_P_H
// QObject child offset if known
if (!childrenOffset) {
QObjectPrivate qop;
childrenOffset = (char*)&qop.children - (char*)&qop;
}
#endif
P(d, "value", ob->objectName());
P(d, "valueencoded", "2");
P(d, "type", NS"QObject");
@@ -1588,7 +1597,8 @@ static void qDumpQObject(QDumper &d)
P(d, "numchild", slotCount);
d.endHash();
#endif
d.beginHash();
if (childrenOffset) {
d.beginHash();
P(d, "name", "children");
// works always, but causes additional traffic on the list
//P(d, "exp", "((class '"NS"QObject'*)" << d.data << ")->children()");
@@ -1597,9 +1607,10 @@ static void qDumpQObject(QDumper &d)
//P(d, "type", NS"QList<QObject *>");
//P(d, "value", "<" << children.size() << " items>");
qDumpInnerValue(d, NS"QList<"NS"QObject *>",
addOffset(dfunc(ob), childrenOffset));
addOffset(dfunc(ob), childrenOffset));
P(d, "numchild", children.size());
d.endHash();
d.endHash();
}
#if 0
// Unneeded (and not working): Connections are listes as childen
// of the signal or slot they are connected to.

View File

@@ -5,3 +5,7 @@ CONFIG -= release
CONFIG += debug
}
SOURCES=gdbmacros.cpp
exists($$QMAKE_INCDIR_QT/QtCore/private/qobject_p.h) {
DEFINES+=HAS_QOBJECT_P_H
}

View File

@@ -14,3 +14,8 @@ TEMPLATE = app
SOURCES += main.cpp \
../gdbmacros.cpp
exists($$QMAKE_INCDIR_QT/QtCore/private/qobject_p.h) {
DEFINES+=HAS_QOBJECT_P_H
}

View File

@@ -133,6 +133,17 @@ static int dumpStdString()
return 0;
}
static int dumpStdWString()
{
std::wstring test = L"hallo";
prepareInBuffer("std::wstring", "local.wstring", "local.wstring", "");
qDumpObjectData440(2, 42, &test, 1, 0, 0, 0, 0);
fputs(qDumpOutBuffer, stdout);
fputc('\n', stdout);
return 0;
}
static int dumpStdStringList()
{
std::list<std::string> test;
@@ -145,6 +156,18 @@ static int dumpStdStringList()
return 0;
}
static int dumpStdStringQList()
{
QList<std::string> test;
test.push_back("item1");
test.push_back("item2");
prepareInBuffer("QList", "local.stringqlist", "local.stringqlist", "std::string");
qDumpObjectData440(2, 42, &test, 1, sizeof(std::string), 0, 0, 0);
fputs(qDumpOutBuffer, stdout);
fputc('\n', stdout);
return 0;
}
static int dumpStdIntList()
{
std::list<int> test;
@@ -169,11 +192,28 @@ static int dumpStdIntVector()
return 0;
}
static int dumpStdStringVector()
{
std::vector<std::string> test;
test.push_back("item1");
test.push_back("item2");
prepareInBuffer("std::vector", "local.stringvector", "local.stringvector", "std::string");
qDumpObjectData440(2, 42, &test, 1, sizeof(std::string), sizeof(std::list<int>::allocator_type), 0, 0);
fputs(qDumpOutBuffer, stdout);
fputc('\n', stdout);
return 0;
}
static int dumpQObject()
{
QTimer t;
QObjectPrivate *tp = reinterpret_cast<QObjectPrivate *>(&t);
#ifdef KNOWS_OFFSET
const int childOffset = (char*)&tp->children - (char*)tp;
#else
const int childOffset = 0;
#endif
printf("Qt version %s Child offset: %d\n", QT_VERSION_STR, childOffset);
prepareInBuffer("QObject", "local.qobject", "local.qobject", "");
qDumpObjectData440(2, 42, &t, 1, childOffset, 0, 0, 0);
@@ -200,16 +240,22 @@ int main(int argc, char *argv[])
dumpQStringList();
if (!qstrcmp(arg, "QList<int>"))
dumpQIntList();
if (!qstrcmp(arg, "QList<std::string>"))
dumpStdStringQList();
if (!qstrcmp(arg, "QVector<int>"))
dumpQIntVector();
if (!qstrcmp(arg, "string"))
dumpStdString();
if (!qstrcmp(arg, "wstring"))
dumpStdWString();
if (!qstrcmp(arg, "list<int>"))
dumpStdIntList();
if (!qstrcmp(arg, "list<string>"))
dumpStdStringList();
if (!qstrcmp(arg, "vector<int>"))
dumpStdIntVector();
if (!qstrcmp(arg, "vector<string>"))
dumpStdStringVector();
if (!qstrcmp(arg, "QObject"))
dumpQObject();
}

View File

@@ -367,7 +367,9 @@ QString decodeData(const QByteArray &ba, int encoding)
// --------------- QtDumperResult
QtDumperResult::Child::Child() :
valueEncoded(0)
valueEncoded(0),
childCount(0),
valuedisabled(false)
{
}
@@ -385,6 +387,7 @@ void QtDumperResult::clear()
value.clear();
address.clear();
type.clear();
displayedType.clear();
valueEncoded = 0;
valuedisabled = false;
childCount = 0;
@@ -403,7 +406,7 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
const int lastDotIndex = root.iname.lastIndexOf(dot);
root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1);
root.setValue(decodeData(value, valueEncoded));
root.setType(type);
root.setType(displayedType.isEmpty() ? type : displayedType);
root.valuedisabled = valuedisabled;
root.setAddress(address);
root.source = source;
@@ -419,8 +422,10 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
wchild.iname = iname;
wchild.iname += dot;
wchild.iname += dchild.name;
wchild.exp = wchild.name = dchild.name;
wchild.setType(childType);
wchild.name = dchild.name;
wchild.exp = dchild.exp;
wchild.valuedisabled = dchild.valuedisabled;
wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
wchild.setAddress(dchild.address);
wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
wchild.setChildCount(0);
@@ -436,19 +441,23 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
QDebug operator<<(QDebug in, const QtDumperResult &d)
{
QDebug nospace = in.nospace();
nospace << " iname=" << d.iname << " type=" << d.type << " address=" << d.address
nospace << " iname=" << d.iname << " type=" << d.type << " displayed=" << d.displayedType
<< " address=" << d.address
<< " value=" << d.value
<< " disabled=" << d.valuedisabled
<< " encoded=" << d.valueEncoded << " internal=" << d.internal;
if (d.childCount) {
nospace << " childCount=" << d.childCount
const int realChildCount = d.children.size();
if (d.childCount || realChildCount) {
nospace << " childCount=" << d.childCount << '/' << realChildCount
<< " childType=" << d.childType << '\n';
const int childCount = d.children.size();
for (int i = 0; i < childCount; i++) {
for (int i = 0; i < realChildCount; i++) {
const QtDumperResult::Child &c = d.children.at(i);
nospace << " #" << i << " addr=" << c.address
<< " disabled=" << c.valuedisabled
<< " type=" << c.type
<< " name=" << c.name << " encoded=" << c.valueEncoded
<< " value=" << c.value << '\n';
<< " value=" << c.value
<< "childcount=" << c.childCount << '\n';
}
}
return in;
@@ -602,8 +611,6 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s)
bool QtDumperHelper::needsExpressionSyntax(Type t)
{
switch (t) {
case QObjectType:
case QWidgetType:
case QObjectSlotType:
case QObjectSignalType:
case QMapType:
@@ -1064,12 +1071,14 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
switch (td.type) {
case QObjectType:
case QWidgetType:
extraArgs[0] = QLatin1String("(char*)&((('");
extraArgs[0] += m_qtNamespace;
extraArgs[0] += QLatin1String("QObjectPrivate'*)&");
extraArgs[0] += data.exp;
extraArgs[0] += QLatin1String(")->children)-(char*)&");
extraArgs[0] += data.exp;
if (debugger == GdbDebugger) {
extraArgs[0] = QLatin1String("(char*)&((('");
extraArgs[0] += m_qtNamespace;
extraArgs[0] += QLatin1String("QObjectPrivate'*)&");
extraArgs[0] += data.exp;
extraArgs[0] += QLatin1String(")->children)-(char*)&");
extraArgs[0] += data.exp;
}
break;
case QVectorType:
extraArgs[1] = QLatin1String("(char*)&((");
@@ -1201,13 +1210,16 @@ protected:
private:
enum Mode { None, ExpectingIName, ExpectingAddress, ExpectingValue,
ExpectingType, ExpectingInternal,
ExpectingType, ExpectingDisplayedType, ExpectingInternal,
ExpectingValueDisabled, ExpectingValueEncoded,
ExpectingChildType, ExpectingChildCount,
ExpectingCommonChildType, ExpectingChildCount,
IgnoreNext,
ChildModeStart,
ExpectingChildren,ExpectingChildName, ExpectingChildAddress,
ExpectingChildValue, ExpectingChildValueEncoded };
ExpectingChildExpression, ExpectingChildType,
ExpectingChildValue, ExpectingChildValueEncoded,
ExpectingChildValueDisabled, ExpectingChildChildCount
};
static inline Mode nextMode(Mode in, const char *keyword, int size);
@@ -1226,11 +1238,15 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
{
// Careful with same prefix
switch (size) {
case 3:
if (!qstrncmp(keyword, "exp", size))
return ExpectingChildExpression;
break;
case 4:
if (!qstrncmp(keyword, "addr", size))
return in > ChildModeStart ? ExpectingChildAddress : ExpectingAddress;
if (!qstrncmp(keyword, "type", size))
return ExpectingType;
return in > ChildModeStart ? ExpectingChildType : ExpectingType;
if (!qstrncmp(keyword, "name", size))
return ExpectingChildName;
break;
@@ -1244,13 +1260,13 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
if (!qstrncmp(keyword, "children", size))
return ExpectingChildren;
if (!qstrncmp(keyword, "numchild", size))
return ExpectingChildCount;
return in > ChildModeStart ? ExpectingChildChildCount : ExpectingChildCount;
if (!qstrncmp(keyword, "internal", size))
return ExpectingInternal;
break;
case 9:
if (!qstrncmp(keyword, "childtype", size))
return ExpectingChildType;
return ExpectingCommonChildType;
break;
case 12:
if (!qstrncmp(keyword, "valueencoded", size))
@@ -1258,7 +1274,9 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
break;
case 13:
if (!qstrncmp(keyword, "valuedisabled", size))
return ExpectingValueDisabled;
return in > ChildModeStart ? ExpectingChildValueDisabled : ExpectingValueDisabled;
if (!qstrncmp(keyword, "displayedtype", size))
return ExpectingDisplayedType;
if (!qstrncmp(keyword, "childnumchild", size))
return IgnoreNext;
break;
@@ -1306,10 +1324,13 @@ bool ValueDumperParser::handleValue(const char *k, int size)
case ExpectingType:
m_result.type = QString::fromLatin1(valueBA);
break;
case ExpectingDisplayedType:
m_result.displayedType = QString::fromLatin1(valueBA);
break;
case ExpectingInternal:
m_result.internal = valueBA == "true";
break;
case ExpectingChildType:
case ExpectingCommonChildType:
m_result.childType = QString::fromLatin1(valueBA);
break;
case ExpectingChildCount:
@@ -1327,9 +1348,21 @@ bool ValueDumperParser::handleValue(const char *k, int size)
case ExpectingChildValue:
m_result.children.back().value = valueBA;
break;
case ExpectingChildExpression:
m_result.children.back().exp = QString::fromLatin1(valueBA);
break;
case ExpectingChildValueEncoded:
m_result.children.back().valueEncoded = QString::fromLatin1(valueBA).toInt();
break;
case ExpectingChildValueDisabled:
m_result.children.back().valuedisabled = valueBA == "true";
break;
case ExpectingChildType:
m_result.children.back().type = QString::fromLatin1(valueBA);
break;
case ExpectingChildChildCount:
m_result.children.back().childCount = QString::fromLatin1(valueBA).toInt();
break;
}
return true;
}
@@ -1340,6 +1373,9 @@ bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r)
if (!parser.run())
return false;
*r = parser.result();
// Sanity
if (r->childCount < r->children.size())
r->childCount = r->children.size();
return true;
}

View File

@@ -76,8 +76,12 @@ struct QtDumperResult
Child();
int valueEncoded;
int childCount;
bool valuedisabled;
QString name;
QString address;
QString exp;
QString type;
QByteArray value;
};
@@ -88,6 +92,7 @@ struct QtDumperResult
QString iname;
QString address;
QString type;
QString displayedType;
QByteArray value;
int valueEncoded;
bool valuedisabled;