From bae65259762ae24619491440e2803e1af7ee7c52 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint <Friedemann.Kleint@nokia.com> Date: Tue, 5 May 2009 16:39:51 +0200 Subject: [PATCH] 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. --- share/qtcreator/gdbmacros/gdbmacros.cpp | 21 +++-- share/qtcreator/gdbmacros/gdbmacros.pro | 4 + share/qtcreator/gdbmacros/test/dumpertest.pro | 5 ++ share/qtcreator/gdbmacros/test/main.cpp | 46 ++++++++++ src/plugins/debugger/watchutils.cpp | 88 +++++++++++++------ src/plugins/debugger/watchutils.h | 5 ++ 6 files changed, 138 insertions(+), 31 deletions(-) diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp index 5cd7ed519ce..6277c5477cd 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.cpp +++ b/share/qtcreator/gdbmacros/gdbmacros.cpp @@ -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. diff --git a/share/qtcreator/gdbmacros/gdbmacros.pro b/share/qtcreator/gdbmacros/gdbmacros.pro index 00c7b2403c8..5aacbfb84ad 100644 --- a/share/qtcreator/gdbmacros/gdbmacros.pro +++ b/share/qtcreator/gdbmacros/gdbmacros.pro @@ -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 +} diff --git a/share/qtcreator/gdbmacros/test/dumpertest.pro b/share/qtcreator/gdbmacros/test/dumpertest.pro index 6f59409d5ca..7b5fd3e582a 100644 --- a/share/qtcreator/gdbmacros/test/dumpertest.pro +++ b/share/qtcreator/gdbmacros/test/dumpertest.pro @@ -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 +} + diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp index ae56cb0955f..f760e40aa98 100644 --- a/share/qtcreator/gdbmacros/test/main.cpp +++ b/share/qtcreator/gdbmacros/test/main.cpp @@ -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(); } diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp index 27b4fe2551b..5693c2c2159 100644 --- a/src/plugins/debugger/watchutils.cpp +++ b/src/plugins/debugger/watchutils.cpp @@ -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; } diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h index 47f73a8bb79..af0a20c3b7c 100644 --- a/src/plugins/debugger/watchutils.h +++ b/src/plugins/debugger/watchutils.h @@ -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; -- GitLab