summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2009-05-05 16:39:51 +0200
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2009-05-05 16:39:51 +0200
commitbae65259762ae24619491440e2803e1af7ee7c52 (patch)
tree7e9488d53ae4839cc0e40207e635925c4dc09a23
parenta24e3b70b38251d0e6fc33c0be0722fc978a301d (diff)
downloadqt-creator-bae65259762ae24619491440e2803e1af7ee7c52.tar.gz
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.
-rw-r--r--share/qtcreator/gdbmacros/gdbmacros.cpp21
-rw-r--r--share/qtcreator/gdbmacros/gdbmacros.pro4
-rw-r--r--share/qtcreator/gdbmacros/test/dumpertest.pro5
-rw-r--r--share/qtcreator/gdbmacros/test/main.cpp46
-rw-r--r--src/plugins/debugger/watchutils.cpp88
-rw-r--r--src/plugins/debugger/watchutils.h5
6 files changed, 138 insertions, 31 deletions
diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp
index 5cd7ed519c..6277c5477c 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 00c7b2403c..5aacbfb84a 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 6f59409d5c..7b5fd3e582 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 ae56cb0955..f760e40aa9 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 27b4fe2551..5693c2c215 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 47f73a8bb7..af0a20c3b7 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;