From 5bd1d2a0284d90bda180a18f45d48018999fff9b Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Mon, 6 Jul 2009 17:36:50 +0200
Subject: [PATCH] Fix up Debugger helpers to be able to dump QObject's with
 CDB.

- Make container dumper routines set "childnumchild" when known
  in order to avoid roundtrips; avoid repeated invocations of
  container.end().
- Completed dumper information in some places to avoid roundtrips.
- Extended QVariant helpers by dumpers for common GUI types
  (rectangles, points, sizes, fonts, size policies).
- Introduced artificial QObjectChildList/QObjectProperty types to
  be able to dump QObject children and properties without using
  gdb expressions.
- Fixed dumping of Signal/Slot list to pass on correct types. Avoid
  recursions if signal is connected to self.
- Replaced expressions by addresses in the dumpers to it make work
  for CDB.
- Reworked dumper test program to have -a, making it usable for tests,
  add further types.
- Gdb: Clear output buffer before calling dumpers, avoiding mixups
  in case evaluation of expression fails.
- Fix the dumper parser used by CDB, do not be fooled by
  "<synthetic>" addresses, etc.
- Pass on a "dumperVersion" in initial query.
---
 share/qtcreator/gdbmacros/gdbmacros.cpp       | 646 ++++++++++++------
 share/qtcreator/gdbmacros/test/dumpertest.pro |   2 -
 share/qtcreator/gdbmacros/test/main.cpp       | 173 +++--
 src/plugins/debugger/cdb/cdbdumperhelper.cpp  |   4 +
 .../debugger/cdb/cdbstackframecontext.cpp     |  50 +-
 src/plugins/debugger/gdb/gdbengine.cpp        |  24 +-
 src/plugins/debugger/watchhandler.cpp         |   3 +
 src/plugins/debugger/watchutils.cpp           | 192 ++++--
 src/plugins/debugger/watchutils.h             |   5 +
 9 files changed, 741 insertions(+), 358 deletions(-)

diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp
index 156bfc5e3f2..13017b01baf 100644
--- a/share/qtcreator/gdbmacros/gdbmacros.cpp
+++ b/share/qtcreator/gdbmacros/gdbmacros.cpp
@@ -46,6 +46,13 @@
 #include <QtCore/QString>
 #include <QtCore/QTextCodec>
 #include <QtCore/QVector>
+#include <QtCore/QTextStream>
+#include <QtCore/QPoint>
+#include <QtCore/QSize>
+#include <QtCore/QRect>
+#include <QtCore/QPointF>
+#include <QtCore/QSizeF>
+#include <QtCore/QRectF>
 
 #if QT_VERSION >= 0x040500
 #include <QtCore/QSharedPointer>
@@ -67,6 +74,10 @@ int qtGhVersion = QT_VERSION;
 #   include <QtGui/QImage>
 #   include <QtGui/QPixmap>
 #   include <QtGui/QWidget>
+#   include <QtGui/QFont>
+#   include <QtGui/QColor>
+#   include <QtGui/QKeySequence>
+#   include <QtGui/QSizePolicy>
 #endif
 
 #ifdef Q_OS_WIN
@@ -445,7 +456,7 @@ struct QDumper
     explicit QDumper();
     ~QDumper();
 
-    // direct write to the output 
+    // direct write to the output
     QDumper &put(long c);
     QDumper &put(int i);
     QDumper &put(double d);
@@ -454,6 +465,7 @@ struct QDumper
     QDumper &put(unsigned int i);
     QDumper &put(const void *p);
     QDumper &put(qulonglong c);
+    QDumper &put(long long c);
     QDumper &put(const char *str);
     QDumper &put(const QByteArray &ba);
     QDumper &put(const QString &str);
@@ -578,6 +590,13 @@ QDumper &QDumper::put(unsigned long long c)
     return *this;
 }
 
+QDumper &QDumper::put(long long c)
+{
+    checkFill();
+    pos += sprintf(outBuffer + pos, "%lld", c);
+    return *this;
+}
+
 QDumper &QDumper::put(unsigned long c)
 {
     checkFill();
@@ -864,7 +883,28 @@ static inline void dumpStdWStringValue(QDumper &d, const std::wstring &str)
     d.putItem("numchild", "0");
 }
 
-static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
+// Tell the calling routine whether a global "childnumchild" attribute makes sense
+enum  InnerValueResult { InnerValueNotHandled,
+                         InnerValueChildrenSpecified,
+                         InnerValueNoFurtherChildren,
+                         InnerValueFurtherChildren  };
+
+static inline void dumpChildNumChildren(QDumper &d, InnerValueResult innerValueResult)
+{
+    switch (innerValueResult) {
+    case InnerValueChildrenSpecified:
+    case InnerValueNotHandled:
+        break;
+    case InnerValueNoFurtherChildren:
+        d.putItem("childnumchild", "0");
+        break;
+    case InnerValueFurtherChildren:
+        d.putItem("childnumchild", "1");
+        break;
+    }
+}
+
+static InnerValueResult qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr,
     const char *field = "value")
 {
     char buf[30];
@@ -872,41 +912,60 @@ static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr
     switch (type[1]) {
         case 'l':
             if (isEqual(type, "float"))
-                d.putItem(field, *(float*)addr);
-            return;
+                { d.putItem(field, *(float*)addr); return InnerValueNoFurtherChildren; }
+            return InnerValueNotHandled;
         case 'n':
-            if (isEqual(type, "int"))
+            if (isEqual(type, "int")) {
                 d.putItem(field, *(int*)addr);
-            else if (isEqual(type, "unsigned"))
+                return InnerValueNoFurtherChildren;
+            }
+            if (isEqual(type, "unsigned")) {
                 d.putItem(field, *(unsigned int*)addr);
-            else if (isEqual(type, "unsigned int"))
+                return InnerValueNoFurtherChildren;
+            }
+            if (isEqual(type, "unsigned int")) {
                 d.putItem(field, *(unsigned int*)addr);
-            else if (isEqual(type, "unsigned long"))
+                return InnerValueNoFurtherChildren;
+            }
+            if (isEqual(type, "unsigned long")) {
                 d.putItem(field, *(unsigned long*)addr);
-            else if (isEqual(type, "unsigned long long"))
+                return InnerValueNoFurtherChildren;
+            }
+            if (isEqual(type, "unsigned long long")) {
                 d.putItem(field, *(qulonglong*)addr);
-            return;
+                return InnerValueNoFurtherChildren;
+            }
+            return InnerValueNotHandled;
         case 'o':
-            if (isEqual(type, "bool"))
+            if (isEqual(type, "bool")) {
                 switch (*(bool*)addr) {
-                    case 0: d.putItem(field, "false"); break;
-                    case 1: d.putItem(field, "true"); break;
-                    default: d.putItem(field, *(bool*)addr); break;
+                case 0: d.putItem(field, "false"); break;
+                case 1: d.putItem(field, "true"); break;
+                default: d.putItem(field, *(bool*)addr); break;
                 }
-            else if (isEqual(type, "double"))
+                return InnerValueNoFurtherChildren;
+            }
+            if (isEqual(type, "double")) {
                 d.putItem(field, *(double*)addr);
-            else if (isEqual(type, "long"))
+                return InnerValueNoFurtherChildren;
+            }
+            if (isEqual(type, "long")) {
                 d.putItem(field, *(long*)addr);
-            else if (isEqual(type, "long long"))
+                return InnerValueNoFurtherChildren;
+            }
+            else if (isEqual(type, "long long")) {
                 d.putItem(field, *(qulonglong*)addr);
-            return;
+                return InnerValueNoFurtherChildren;
+            }
+            return InnerValueNotHandled;
         case 'B':
             if (isEqual(type, "QByteArray")) {
                 d.putCommaIfNeeded();
                 d.put(field).put("encoded=\"1\",");
                 d.putItem(field, *(QByteArray*)addr);
+                return InnerValueFurtherChildren;
             }
-            return;
+            return InnerValueNotHandled;
         case 'C':
             if (isEqual(type, "QChar")) {
                 d.putCommaIfNeeded();
@@ -916,16 +975,18 @@ static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr
                     buf[1] = char(c.unicode());
                 d.putItem(field, buf);
                 d.putItem("numchild", 0);
+                return InnerValueNoFurtherChildren;
             }
-            return;
+            return InnerValueNotHandled;
         case 'L':
             if (startsWith(type, "QList<")) {
                 const QListData *ldata = reinterpret_cast<const QListData*>(addr);
                 d.putItemCount("value", ldata->size());
                 d.putItem("valuedisabled", "true");
                 d.putItem("numchild", ldata->size());
+                return InnerValueChildrenSpecified;
             }
-            return;
+            return InnerValueNotHandled;
         case 'O':
             if (isEqual(type, "QObject *")) {
                 if (addr) {
@@ -935,46 +996,55 @@ static void qDumpInnerValueHelper(QDumper &d, const char *type, const void *addr
                     d.putItem("valueencoded", "2");
                     d.putItem("type", NS"QObject");
                     d.putItem("displayedtype", ob->metaObject()->className());
+                    d.putItem("numchild", 1);
+                    return InnerValueChildrenSpecified;
                 } else {
                     d.putItem("value", "0x0");
                     d.putItem("type", NS"QObject *");
+                    d.putItem("numchild", 0);
+                    return InnerValueNoFurtherChildren;
                 }
             }
-            return;
+            return InnerValueNotHandled;
         case 'S':
             if (isEqual(type, "QString")) {
                 d.putCommaIfNeeded();
                 d.put(field).put("encoded=\"2\"");
                 d.putItem(field, *(QString*)addr);
+                return InnerValueNoFurtherChildren;
             }
-            return;
+            return InnerValueNotHandled;
         case 't':
             if (isEqual(type, "std::string")
                 || isEqual(type, "std::basic_string<char,std::char_traits<char>,std::allocator<char> >")) {
                 d.putCommaIfNeeded();
                 dumpStdStringValue(d, *reinterpret_cast<const std::string*>(addr));
-            } else if (isEqual(type, "std::wstring")
-                       || isEqual(type, "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >")) {
+                return InnerValueNoFurtherChildren;
+            }
+            if (isEqual(type, "std::wstring")
+                || isEqual(type, "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >")) {
                 dumpStdWStringValue(d, *reinterpret_cast<const std::wstring*>(addr));
+                return InnerValueNoFurtherChildren;
             }
-            return;
+            return InnerValueNotHandled;
         default:
-            return;
+            break;
     }
+    return InnerValueNotHandled;
 }
 
-static void qDumpInnerValue(QDumper &d, const char *type, const void *addr)
+static InnerValueResult qDumpInnerValue(QDumper &d, const char *type, const void *addr)
 {
     d.putItem("addr", addr);
     d.putItem("type", type);
 
     if (!type[0])
-        return;
+        return InnerValueNotHandled;
 
-    qDumpInnerValueHelper(d, type, addr);
+    return qDumpInnerValueHelper(d, type, addr);
 }
 
-static void qDumpInnerValueOrPointer(QDumper &d,
+static InnerValueResult qDumpInnerValueOrPointer(QDumper &d,
     const char *type, const char *strippedtype, const void *addr)
 {
     if (strippedtype) {
@@ -982,18 +1052,17 @@ static void qDumpInnerValueOrPointer(QDumper &d,
             d.putItem("addr", deref(addr));
             d.putItem("saddr", deref(addr));
             d.putItem("type", strippedtype);
-            qDumpInnerValueHelper(d, strippedtype, deref(addr));
-        } else {
-            d.putItem("addr", addr);
-            d.putItem("type", strippedtype);
-            d.putItem("value", "<null>");
-            d.putItem("numchild", "0");
+            return qDumpInnerValueHelper(d, strippedtype, deref(addr));
         }
-    } else {
         d.putItem("addr", addr);
-        d.putItem("type", type);
-        qDumpInnerValueHelper(d, type, addr);
+        d.putItem("type", strippedtype);
+        d.putItem("value", "<null>");
+        d.putItem("numchild", "0");
+        return InnerValueChildrenSpecified;
     }
+    d.putItem("addr", addr);
+    d.putItem("type", type);
+    return qDumpInnerValueHelper(d, type, addr);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1404,14 +1473,15 @@ static void qDumpQHash(QDumper &d)
 
     d.putItemCount("value", n);
     d.putItem("numchild", n);
+
     if (d.dumpChildren) {
         if (n > 1000)
             n = 1000;
-        bool isSimpleKey = isSimpleType(keyType);
-        bool isSimpleValue = isSimpleType(valueType);
-        bool opt = isOptimizedIntKey(keyType);
-        int keyOffset = hashOffset(opt, true, keySize, valueSize);
-        int valueOffset = hashOffset(opt, false, keySize, valueSize);
+        const bool isSimpleKey = isSimpleType(keyType);
+        const bool isSimpleValue = isSimpleType(valueType);
+        const bool opt = isOptimizedIntKey(keyType);
+        const int keyOffset = hashOffset(opt, true, keySize, valueSize);
+        const int valueOffset = hashOffset(opt, false, keySize, valueSize);
 
         d.beginItem("extra");
         d.put("isSimpleKey: ").put(isSimpleKey);
@@ -1436,10 +1506,7 @@ static void qDumpQHash(QDumper &d)
                     d.putItem("type", valueType);
                     d.putItem("addr", addOffset(node, valueOffset));
                 } else {
-                    d.beginItem("exp");
-                        d.put("*('"NS"QHashNode<").put(keyType).put(","
-                           ).put(valueType).put(" >'*)").put(node);
-                    d.endItem();
+                    d.putItem("addr", node);
                     d.beginItem("type");
                         d.put("'"NS"QHashNode<").put(keyType).put(",")
                             .put(valueType).put(MAP_NODE_TYPE_END"'");
@@ -1557,6 +1624,7 @@ static void qDumpQList(QDumper &d)
     d.putItem("valuedisabled", "true");
     d.putItem("numchild", n);
     d.putItem("childtype", d.innertype);
+    InnerValueResult innerValueResult = InnerValueChildrenSpecified;
     if (d.dumpChildren) {
         unsigned innerSize = d.extraInt[0];
         bool innerTypeIsPointer = isPointerType(d.innertype);
@@ -1583,7 +1651,7 @@ static void qDumpQList(QDumper &d)
                 d.putItem("saddr", p);
                 if (*(void**)p) {
                     //d.putItem("value","@").put(p);
-                    qDumpInnerValue(d, strippedInnerType.data(), deref(p));
+                    innerValueResult = qDumpInnerValue(d, strippedInnerType.data(), deref(p));
                 } else {
                     d.putItem("value", "<null>");
                     d.putItem("numchild", "0");
@@ -1593,11 +1661,11 @@ static void qDumpQList(QDumper &d)
                 if (isInternal) {
                     //qDumpInnerValue(d, d.innertype, p);
                     d.putItem("addr", p);
-                    qDumpInnerValueHelper(d, d.innertype, p);
+                    innerValueResult = qDumpInnerValueHelper(d, d.innertype, p);
                 } else {
                     //qDumpInnerValue(d, d.innertype, deref(p));
                     d.putItem("addr", deref(p));
-                    qDumpInnerValueHelper(d, d.innertype, deref(p));
+                    innerValueResult = qDumpInnerValueHelper(d, d.innertype, deref(p));
                 }
             }
             d.endHash();
@@ -1606,6 +1674,7 @@ static void qDumpQList(QDumper &d)
             d.putEllipsis();
         d.endChildren();
     }
+    dumpChildNumChildren(d, innerValueResult);
     d.disarm();
 }
 
@@ -1624,6 +1693,7 @@ static void qDumpQLinkedList(QDumper &d)
     d.putItem("valuedisabled", "true");
     d.putItem("numchild", n);
     d.putItem("childtype", d.innertype);
+    InnerValueResult innerValueResult = InnerValueChildrenSpecified;
     if (d.dumpChildren) {
         //unsigned innerSize = d.extraInt[0];
         //bool innerTypeIsPointer = isPointerType(d.innertype);
@@ -1640,7 +1710,7 @@ static void qDumpQLinkedList(QDumper &d)
             d.beginHash();
             d.putItem("name", i);
             const void *addr = addOffset(p, 2 * sizeof(void*));
-            qDumpInnerValueOrPointer(d, d.innertype, stripped, addr);
+            innerValueResult = qDumpInnerValueOrPointer(d, d.innertype, stripped, addr);
             p = deref(p);
             d.endHash();
         }
@@ -1648,6 +1718,7 @@ static void qDumpQLinkedList(QDumper &d)
             d.putEllipsis();
         d.endChildren();
     }
+    dumpChildNumChildren(d, innerValueResult);
     d.disarm();
 }
 
@@ -1795,19 +1866,12 @@ static void qDumpQMap(QDumper &d)
                     d.putItem("addr", addOffset(node, valueOffset));
                 } else {
 #if QT_VERSION >= 0x040500
+                    d.putItem("addr", node);
                     // actually, any type (even 'char') will do...
                     d.beginItem("type");
                         d.put(NS"QMapNode<").put(keyType).put(",");
                         d.put(valueType).put(MAP_NODE_TYPE_END);
                     d.endItem();
-                    d.beginItem("exp");
-                        d.put("*('"NS"QMapNode<").put(keyType).put(",");
-                        d.put(valueType).put(" >'*)").put(node);
-                    d.endItem();
-
-                    //d.putItem("exp", "*('"NS"QMapData'*)").put((void*)node);
-                    //d.putItem("exp", "*(char*)").put((void*)node);
-                    // d.putItem("addr", node);  does not work as gdb fails to parse
 #else
                     d.beginItem("type");
                         d.put(NS"QMapData::Node<").put(keyType).put(",");
@@ -1889,14 +1953,12 @@ static void qDumpQObject(QDumper &d)
 {
     const QObject *ob = reinterpret_cast<const QObject *>(d.data);
     const QMetaObject *mo = ob->metaObject();
-    unsigned childrenOffset = d.extraInt[0];
     d.putItem("value", ob->objectName());
     d.putItem("valueencoded", "2");
     d.putItem("type", NS"QObject");
     d.putItem("displayedtype", mo->className());
     d.putItem("numchild", 4);
     if (d.dumpChildren) {
-        const QObjectList &children = ob->children();
         int slotCount = 0;
         int signalCount = 0;
         for (int i = mo->methodCount(); --i >= 0; ) {
@@ -1907,61 +1969,33 @@ static void qDumpQObject(QDumper &d)
         d.beginChildren();
         d.beginHash();
             d.putItem("name", "properties");
-            // FIXME: Note that when simply using '(QObject*)'
-            // in the cast below, Gdb/MI _sometimes_ misparses
-            // expressions further down in the tree.
-            d.beginItem("exp");
-                d.put("*(class '"NS"QObject'*)").put(d.data);
-            d.endItem();
+            d.putItem("addr", d.data);
             d.putItem("type", NS"QObjectPropertyList");
             d.putItemCount("value", mo->propertyCount());
             d.putItem("numchild", mo->propertyCount());
         d.endHash();
-#if 0
-        d.beginHash();
-            d.putItem("name", "methods");
-            d.putItem("exp", "*(class '"NS"QObject'*)").put(d.data);
-            d.putItemCount("value", mo->methodCount());
-            d.putItem("numchild", mo->methodCount());
-        d.endHash();
-#endif
-#if 0
-        d.beginHash();
-            d.putItem("name", "senders");
-            d.putItem("exp", "(*(class '"NS"ObjectPrivate'*)").put(dfunc(ob)).put(")->senders");
-            d.putItem("type", NS"QList<"NS"QObjectPrivateSender>");
-        d.endHash();
-#endif
         d.beginHash();
             d.putItem("name", "signals");
-            d.beginItem("exp");
-                d.put("*(class '"NS"QObject'*)").put(d.data);
-            d.endItem();
+            d.putItem("addr", d.data);
             d.putItem("type", NS"QObjectSignalList");
             d.putItemCount("value", signalCount);
             d.putItem("numchild", signalCount);
         d.endHash();
         d.beginHash();
             d.putItem("name", "slots");
-            d.beginItem("exp");
-                d.put("*(class '"NS"QObject'*)").put(d.data);
-            d.endItem();
+            d.putItem("addr", d.data);
             d.putItem("type", NS"QObjectSlotList");
             d.putItemCount("value", slotCount);
             d.putItem("numchild", slotCount);
         d.endHash();
-        if (childrenOffset) {
+        const QObjectList objectChildren = ob->children();
+        if (!objectChildren.empty()) {
             d.beginHash();
             d.putItem("name", "children");
-            // works always, but causes additional traffic on the list
-            //d.putItem("exp", "((class '"NS"QObject'*)").put(d.data).put(")->children()");
-            //
-            //d.putItem("addr", addOffset(dfunc(ob), childrenOffset));
-            //d.putItem("type", NS"QList<QObject *>");
-            //d.putItemCount("value", children.size());
-            qDumpInnerValue(d, NS"QList<"NS"QObject *>",
-                            addOffset(dfunc(ob), childrenOffset));
-            d.putItem("numchild", children.size());
+            d.putItem("addr", d.data);
+            d.putItem("type", NS"QObjectChildList");
+            d.putItemCount("value", objectChildren.size());
+            d.putItem("numchild", objectChildren.size());
             d.endHash();
         }
         d.beginHash();
@@ -1981,37 +2015,229 @@ static void qDumpQObject(QDumper &d)
     d.disarm();
 }
 
+#if USE_QT_GUI
+static const char *sizePolicyEnumValue(QSizePolicy::Policy p)
+{
+    switch (p) {
+    case QSizePolicy::Fixed:
+        return "Fixed";
+    case QSizePolicy::Minimum:
+        return "Minimum";
+    case QSizePolicy::Maximum:
+        return "Maximum";
+    case QSizePolicy::Preferred:
+        return "Preferred";
+    case QSizePolicy::Expanding:
+        return "Expanding";
+    case QSizePolicy::MinimumExpanding:
+        return "MinimumExpanding";
+    case QSizePolicy::Ignored:
+        break;
+    }
+    return "Ignored";
+}
+
+static QString sizePolicyValue(const QSizePolicy &sp)
+{
+    QString rc;
+    QTextStream str(&rc);
+    // Display as in Designer
+    str << '[' << sizePolicyEnumValue(sp.horizontalPolicy())
+        << ", " << sizePolicyEnumValue(sp.verticalPolicy())
+        << ", " << sp.horizontalStretch() << ", " << sp.verticalStretch() << ']';
+    return rc;
+}
+#endif
+
+static void qDumpQVariantHelper(const QVariant *v, QString *value,
+    QString *exp, int *numchild)
+{
+    switch (v->type()) {
+    case QVariant::Invalid:
+        *value = QLatin1String("<invalid>");
+        *numchild = 0;
+        break;
+    case QVariant::String:
+        *value = QLatin1Char('"') + v->toString() + QLatin1Char('"');
+        *numchild = 0;
+        break;
+    #if QT_VERSION >= 0x040500
+    case QVariant::StringList:
+        *exp = QString(QLatin1String("(*('"NS"QStringList'*)%1)"))
+                    .arg((quintptr)v);
+        *numchild = v->toStringList().size();
+        break;
+    #endif
+    case QVariant::Int:
+        *value = QString::number(v->toInt());
+        *numchild= 0;
+        break;
+    case QVariant::Double:
+        *value = QString::number(v->toDouble());
+        *numchild = 0;
+        break;
+    case QVariant::Point: {
+            const QPoint p = v->toPoint();
+            *value = QString::fromLatin1("%1, %2").arg(p.x()).arg(p.y());
+        }
+        *numchild = 0;
+        break;
+    case QVariant::Size: {
+            const QSize size = v->toSize();
+            *value = QString::fromLatin1("%1x%2").arg(size.width()).arg(size.height());
+        }
+        *numchild = 0;
+        break;
+    case QVariant::Rect: {
+            const QRect rect = v->toRect();
+            *value = QString::fromLatin1("%1x%2+%3+%4").arg(rect.width()).arg(rect.height()).arg(rect.x()).arg(rect.y());
+        }
+        *numchild = 0;
+        break;
+    case QVariant::PointF: {
+            const QPointF p = v->toPointF();
+            *value = QString::fromLatin1("%1, %2").arg(p.x()).arg(p.y());
+        }
+        *numchild = 0;
+        break;
+
+    case QVariant::SizeF: {
+            const QSizeF size = v->toSizeF();
+            *value = QString::fromLatin1("%1x%2").arg(size.width()).arg(size.height());
+        }
+        *numchild = 0;
+        break;
+    case QVariant::RectF: {
+            const QRectF rect = v->toRectF();
+            *value = QString::fromLatin1("%1x%2+%3+%4").arg(rect.width()).arg(rect.height()).arg(rect.x()).arg(rect.y());
+        }
+        *numchild = 0;
+        break;
+#if USE_QT_GUI
+    case QVariant::Font:
+        *value = qvariant_cast<QFont>(*v).toString();
+        break;
+    case QVariant::Color:
+        *value = qvariant_cast<QColor>(*v).name();
+        break;
+    case QVariant::KeySequence:
+        *value = qvariant_cast<QKeySequence>(*v).toString();
+        break;
+    case QVariant::SizePolicy:
+        *value = sizePolicyValue(qvariant_cast<QSizePolicy>(*v));
+        break;
+#endif
+    default: {
+        char buf[1000];
+        const char *format = (v->typeName()[0] == 'Q')
+            ?  "'"NS"%s "NS"qVariantValue<"NS"%s >'(*('"NS"QVariant'*)%p)"
+            :  "'%s "NS"qVariantValue<%s >'(*('"NS"QVariant'*)%p)";
+        qsnprintf(buf, sizeof(buf) - 1, format, v->typeName(), v->typeName(), v);
+        *exp = QLatin1String(buf);
+        *numchild = 1;
+        break;
+        }
+    }
+}
+
+static void qDumpQVariant(QDumper &d, const QVariant *v)
+{
+    QString value;
+    QString exp;
+    int numchild = 0;
+    qDumpQVariantHelper(v, &value, &exp, &numchild);
+    bool isInvalid = (v->typeName() == 0);
+    if (isInvalid) {
+        d.putItem("value", "(invalid)");
+    } else if (value.isEmpty()) {
+        d.beginItem("value");
+            d.put("(").put(v->typeName()).put(") ");
+        d.endItem();
+    } else {
+        QByteArray ba;
+        ba += '(';
+        ba += v->typeName();
+        ba += ") ";
+        ba += qPrintable(value);
+        d.putItem("value", ba);
+        d.putItem("valueencoded", "5");
+    }
+    d.putItem("type", NS"QVariant");
+    d.putItem("numchild", (isInvalid ? "0" : "1"));
+    if (d.dumpChildren) {
+        d.beginChildren();
+        d.beginHash();
+        d.putItem("name", "value");
+        if (!exp.isEmpty())
+            d.putItem("exp", qPrintable(exp));
+        if (!value.isEmpty()) {
+            d.putItem("value", value);
+            d.putItem("valueencoded", "4");
+        }
+        d.putItem("type", v->typeName());
+        d.putItem("numchild", numchild);
+        d.endHash();
+        d.endChildren();
+    }
+    d.disarm();
+}
+
+static inline void qDumpQVariant(QDumper &d)
+{
+    qDumpQVariant(d, reinterpret_cast<const QVariant *>(d.data));
+}
+
+static void qDumpQObjectProperty(QDumper &d)
+{
+    const QObject *ob = (const QObject *)d.data;
+    // extract "local.Object.property"
+    QString iname = d.iname;
+    const int dotPos = iname.lastIndexOf(QLatin1Char('.'));
+    if (dotPos == -1)
+        return;
+    iname.remove(0, dotPos + 1);
+    const QVariant v = ob->property(iname.toAscii().constData());
+    qDumpQVariant(d, &v);
+    d.disarm();
+}
+
 static void qDumpQObjectPropertyList(QDumper &d)
 {
     const QObject *ob = (const QObject *)d.data;
     const QMetaObject *mo = ob->metaObject();
+    const int propertyCount = mo->propertyCount();
     d.putItem("addr", "<synthetic>");
     d.putItem("type", NS"QObjectPropertyList");
-    d.putItem("numchild", mo->propertyCount());
+    d.putItem("numchild", propertyCount);
+    d.putItemCount("value", propertyCount);
     if (d.dumpChildren) {
         d.beginChildren();
-        for (int i = mo->propertyCount(); --i >= 0; ) {
+        for (int i = propertyCount; --i >= 0; ) {
             const QMetaProperty & prop = mo->property(i);
             d.beginHash();
             d.putItem("name", prop.name());
-            d.beginItem("exp");
-                d.put("((").put(mo->className()).put("*)");
-                d.put(ob).put(")->").put(prop.name()).put("()");
-            d.endItem();
-            if (isEqual(prop.typeName(), "QString")) {
+            switch (prop.type()) {
+            case QVariant::String:
+                d.putItem("type", prop.typeName());
                 d.putItem("value", prop.read(ob).toString());
                 d.putItem("valueencoded", "2");
-                d.putItem("type", NS"QString");
                 d.putItem("numchild", "0");
-            } else if (isEqual(prop.typeName(), "bool")) {
+                break;
+            case QVariant::Bool:
+                d.putItem("type", prop.typeName());
                 d.putItem("value", (prop.read(ob).toBool() ? "true" : "false"));
                 d.putItem("numchild", "0");
-            } else if (isEqual(prop.typeName(), "int")) {
+                break;
+            case QVariant::Int:
                 d.putItem("value", prop.read(ob).toInt());
                 d.putItem("numchild", "0");
+                break;
+            default:
+                d.putItem("addr", d.data);
+                d.putItem("type", NS"QObjectProperty");
+                d.putItem("numchild", "1");
+                break;
             }
-            d.putItem("type", prop.typeName());
-            d.putItem("numchild", "1");
             d.endHash();
         }
         d.endChildren();
@@ -2074,6 +2300,29 @@ static const ConnectionList &qConnectionList(const QObject *ob, int signalNumber
 }
 #endif
 
+// Write party involved in a slot/signal element,
+// avoid to recursion to self.
+static inline void qDumpQObjectConnectionPart(QDumper &d,
+                                              const QObject *owner,
+                                              const QObject *partner,
+                                              int number, const char *namePostfix)
+{
+    d.beginHash();
+    d.beginItem("name");
+    d.put(number).put(namePostfix);
+    d.endItem();
+    if (partner == owner) {
+        d.putItem("value", "<this>");
+        d.putItem("valueencoded", "2");
+        d.putItem("type", owner->metaObject()->className());
+        d.putItem("numchild", 0);
+        d.putItem("addr", owner);
+    } else {
+        qDumpInnerValueHelper(d, NS"QObject *", partner);
+    }
+    d.endHash();
+}
+
 static void qDumpQObjectSignal(QDumper &d)
 {
     unsigned signalNumber = d.extraInt[0];
@@ -2089,12 +2338,7 @@ static void qDumpQObjectSignal(QDumper &d)
         const ConnectionList &connList = qConnectionList(ob, signalNumber);
         for (int i = 0; i != connList.size(); ++i) {
             const Connection &conn = connectionAt(connList, i);
-            d.beginHash();
-                d.beginItem("name");
-                    d.put(i).put(" receiver");
-                d.endItem();
-                qDumpInnerValueHelper(d, NS"QObject *", conn.receiver);
-            d.endHash();
+            qDumpQObjectConnectionPart(d, ob, conn.receiver, i, " receiver");
             d.beginHash();
                 d.beginItem("name");
                     d.put(i).put(" slot");
@@ -2129,14 +2373,17 @@ static void qDumpQObjectSignalList(QDumper &d)
     const QObject *ob = reinterpret_cast<const QObject *>(d.data);
     const QMetaObject *mo = ob->metaObject();
     int count = 0;
-    for (int i = mo->methodCount(); --i >= 0; )
+    const int methodCount = mo->methodCount();
+    for (int i = methodCount; --i >= 0; )
         count += (mo->method(i).methodType() == QMetaMethod::Signal);
+    d.putItem("type", "QObjectSignalList");
+    d.putItemCount("value", count);
     d.putItem("addr", d.data);
     d.putItem("numchild", count);
 #if QT_VERSION >= 0x040400
     if (d.dumpChildren) {
         d.beginChildren();
-        for (int i = 0; i != mo->methodCount(); ++i) {
+        for (int i = 0; i != methodCount; ++i) {
             const QMetaMethod & method = mo->method(i);
             if (method.methodType() == QMetaMethod::Signal) {
                 int k = mo->indexOfSignal(method.signature());
@@ -2145,10 +2392,7 @@ static void qDumpQObjectSignalList(QDumper &d)
                 d.putItem("name", k);
                 d.putItem("value", method.signature());
                 d.putItem("numchild", connList.size());
-                //d.putItem("numchild", "1");
-                d.beginItem("exp");
-                    d.put("*(class '"NS"QObject'*)").put(d.data);
-                d.endItem();
+                d.putItem("addr", d.data);
                 d.putItem("type", NS"QObjectSignal");
                 d.endHash();
             }
@@ -2182,12 +2426,7 @@ static void qDumpQObjectSlot(QDumper &d)
                 if (conn.receiver == ob && conn.method == slotNumber) {
                     ++numchild;
                     const QMetaMethod &method = sender->metaObject()->method(signal);
-                    d.beginHash();
-                        d.beginItem("name");
-                            d.put(s).put(" sender");
-                        d.endItem();
-                        qDumpInnerValueHelper(d, NS"QObject *", sender);
-                    d.endHash();
+                    qDumpQObjectConnectionPart(d, ob, sender, s, " sender");
                     d.beginHash();
                         d.beginItem("name");
                             d.put(s).put(" signal");
@@ -2226,14 +2465,17 @@ static void qDumpQObjectSlotList(QDumper &d)
     const QMetaObject *mo = ob->metaObject();
 
     int count = 0;
-    for (int i = mo->methodCount(); --i >= 0; )
+    const int methodCount = mo->methodCount();
+    for (int i = methodCount; --i >= 0; )
         count += (mo->method(i).methodType() == QMetaMethod::Slot);
 
     d.putItem("numchild", count);
+    d.putItemCount("value", count);
+    d.putItem("type", NS"QObjectSlotList");
     if (d.dumpChildren) {
         d.beginChildren();
 #if QT_VERSION >= 0x040400
-        for (int i = 0; i != mo->methodCount(); ++i) {
+        for (int i = 0; i != methodCount; ++i) {
             const QMetaMethod & method = mo->method(i);
             if (method.methodType() == QMetaMethod::Slot) {
                 d.beginHash();
@@ -2254,9 +2496,7 @@ static void qDumpQObjectSlotList(QDumper &d)
                     }
                 }
                 d.putItem("numchild", numchild);
-                d.beginItem("exp");
-                    d.put("*(class '"NS"QObject'*)").put(d.data);
-                d.endItem();
+                d.putItem("addr", d.data);
                 d.putItem("type", NS"QObjectSlot");
                 d.endHash();
             }
@@ -2267,6 +2507,27 @@ static void qDumpQObjectSlotList(QDumper &d)
     d.disarm();
 }
 
+static void qDumpQObjectChildList(QDumper &d)
+{
+    const QObject *ob = reinterpret_cast<const QObject *>(d.data);
+    const QObjectList children = ob->children();
+    const int size = children.size();
+
+    d.putItem("numchild", size);
+    d.putItemCount("value", size);
+    d.putItem("type", NS"QObjectChildList");
+    if (d.dumpChildren) {
+        d.beginChildren();
+        for (int i = 0; i != size; ++i) {
+            d.beginHash();
+            d.putItem("name", i);
+            qDumpInnerValueHelper(d, NS"QObject *", children.at(i));
+            d.endHash();
+        }
+        d.endChildren();
+    }
+    d.disarm();
+}
 
 #if USE_QT_GUI
 static void qDumpQPixmap(QDumper &d)
@@ -2442,89 +2703,6 @@ static void qDumpQTextCodec(QDumper &d)
     d.disarm();
 }
 
-static void qDumpQVariantHelper(const void *data, QString *value,
-    QString *exp, int *numchild)
-{
-    const QVariant &v = *reinterpret_cast<const QVariant *>(data);
-    switch (v.type()) {
-    case QVariant::Invalid:
-        *value = QLatin1String("<invalid>");
-        *numchild = 0;
-        break;
-    case QVariant::String:
-        *value = QLatin1Char('"') + v.toString() + QLatin1Char('"');
-        *numchild = 0;
-        break;
-    #if QT_VERSION >= 0x040500
-    case QVariant::StringList:
-        *exp = QString(QLatin1String("(*('"NS"QStringList'*)%1)"))
-                    .arg((quintptr)data);
-        *numchild = v.toStringList().size();
-        break;
-    #endif
-    case QVariant::Int:
-        *value = QString::number(v.toInt());
-        *numchild= 0;
-        break;
-    case QVariant::Double:
-        *value = QString::number(v.toDouble());
-        *numchild = 0;
-        break;
-    default: {
-        char buf[1000];
-        const char *format = (v.typeName()[0] == 'Q')
-            ?  "'"NS"%s "NS"qVariantValue<"NS"%s >'(*('"NS"QVariant'*)%p)"
-            :  "'%s "NS"qVariantValue<%s >'(*('"NS"QVariant'*)%p)";
-        qsnprintf(buf, sizeof(buf) - 1, format, v.typeName(), v.typeName(), data);
-        *exp = QLatin1String(buf);
-        *numchild = 1;
-        break;
-        }
-    }
-}
-
-static void qDumpQVariant(QDumper &d)
-{
-    const QVariant &v = *reinterpret_cast<const QVariant *>(d.data);
-    QString value;
-    QString exp;
-    int numchild = 0;
-    qDumpQVariantHelper(d.data, &value, &exp, &numchild);
-    bool isInvalid = (v.typeName() == 0);
-    if (isInvalid) {
-        d.putItem("value", "(invalid)");
-    } else if (value.isEmpty()) {
-        d.beginItem("value");
-            d.put("(").put(v.typeName()).put(") ");
-        d.endItem();
-    } else {
-        QByteArray ba;
-        ba += '(';
-        ba += v.typeName();
-        ba += ") ";
-        ba += qPrintable(value);
-        d.putItem("value", ba);
-        d.putItem("valueencoded", "5");
-    }
-    d.putItem("type", NS"QVariant");
-    d.putItem("numchild", (isInvalid ? "0" : "1"));
-    if (d.dumpChildren) {
-        d.beginChildren();
-        d.beginHash();
-        d.putItem("name", "value");
-        if (!exp.isEmpty())
-            d.putItem("exp", qPrintable(exp));
-        if (!value.isEmpty()) {
-            d.putItem("value", value);
-            d.putItem("valueencoded", "4");
-        }
-        d.putItem("type", v.typeName());
-        d.putItem("numchild", numchild);
-        d.endHash();
-        d.endChildren();
-    }
-    d.disarm();
-}
 
 static void qDumpQVector(QDumper &d)
 {
@@ -2547,6 +2725,7 @@ static void qDumpQVector(QDumper &d)
     d.putItemCount("value", n);
     d.putItem("valuedisabled", "true");
     d.putItem("numchild", n);
+    InnerValueResult innerValueResult = InnerValueChildrenSpecified;
     if (d.dumpChildren) {
         QByteArray strippedInnerType = stripPointerType(d.innertype);
         const char *stripped =
@@ -2557,7 +2736,7 @@ static void qDumpQVector(QDumper &d)
         for (int i = 0; i != n; ++i) {
             d.beginHash();
             d.putItem("name", i);
-            qDumpInnerValueOrPointer(d, d.innertype, stripped,
+            innerValueResult = qDumpInnerValueOrPointer(d, d.innertype, stripped,
                 addOffset(v, i * innersize + typeddatasize));
             d.endHash();
         }
@@ -2565,6 +2744,7 @@ static void qDumpQVector(QDumper &d)
             d.putEllipsis();
         d.endChildren();
     }
+    dumpChildNumChildren(d, innerValueResult);
     d.disarm();
 }
 
@@ -2633,7 +2813,8 @@ static void qDumpStdList(QDumper &d)
 #endif
     int nn = 0;
     std::list<int>::const_iterator it = list.begin();
-    for (; nn < 101 && it != list.end(); ++nn, ++it)
+    const std::list<int>::const_iterator cend = list.end();
+    for (; nn < 101 && it != cend; ++nn, ++it)
         qCheckAccess(it.operator->());
 
     if (nn > 100)
@@ -2643,22 +2824,24 @@ static void qDumpStdList(QDumper &d)
     d.putItem("numchild", nn);
 
     d.putItem("valuedisabled", "true");
+    InnerValueResult innerValueResult = InnerValueChildrenSpecified;
     if (d.dumpChildren) {
         QByteArray strippedInnerType = stripPointerType(d.innertype);
         const char *stripped =
             isPointerType(d.innertype) ? strippedInnerType.data() : 0;
         d.beginChildren();
         it = list.begin();
-        for (int i = 0; i < 1000 && it != list.end(); ++i, ++it) {
+        for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
             d.beginHash();
             d.putItem("name", i);
-            qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->());
+            innerValueResult = qDumpInnerValueOrPointer(d, d.innertype, stripped, it.operator->());
             d.endHash();
         }
         if (it != list.end())
             d.putEllipsis();
         d.endChildren();
     }
+    dumpChildNumChildren(d, innerValueResult);
     d.disarm();
 }
 
@@ -2744,7 +2927,8 @@ static void qDumpStdSet(QDumper &d)
     if (nn < 0)
         return;
     DummyType::const_iterator it = set.begin();
-    for (int i = 0; i < nn && i < 10 && it != set.end(); ++i, ++it)
+    const DummyType::const_iterator cend = set.end();
+    for (int i = 0; i < nn && i < 10 && it != cend; ++i, ++it)
         qCheckAccess(it.operator->());
 
     d.putItemCount("value", nn);
@@ -2752,6 +2936,7 @@ static void qDumpStdSet(QDumper &d)
     d.putItem("numchild", nn);
     d.putItem("valueoffset", d.extraInt[0]);
 
+    InnerValueResult innerValueResult = InnerValueChildrenSpecified;
     if (d.dumpChildren) {
         int valueOffset = 0; // d.extraInt[0];
         QByteArray strippedInnerType = stripPointerType(d.innertype);
@@ -2764,17 +2949,18 @@ static void qDumpStdSet(QDumper &d)
 
         d.beginChildren();
         it = set.begin();
-        for (int i = 0; i < 1000 && it != set.end(); ++i, ++it) {
+        for (int i = 0; i < 1000 && it != cend; ++i, ++it) {
             const void *node = it.operator->();
             d.beginHash();
             d.putItem("name", i);
-            qDumpInnerValueOrPointer(d, d.innertype, stripped, node);
+            innerValueResult = qDumpInnerValueOrPointer(d, d.innertype, stripped, node);
             d.endHash();
         }
         if (it != set.end())
             d.putEllipsis();
         d.endChildren();
     }
+    dumpChildNumChildren(d, innerValueResult);
     d.disarm();
 }
 
@@ -2838,6 +3024,7 @@ static void qDumpStdVector(QDumper &d)
     d.putItemCount("value", n);
     d.putItem("valuedisabled", "true");
     d.putItem("numchild", n);
+    InnerValueResult innerValueResult = InnerValueChildrenSpecified;
     if (d.dumpChildren) {
         unsigned innersize = d.extraInt[0];
         QByteArray strippedInnerType = stripPointerType(d.innertype);
@@ -2857,6 +3044,7 @@ static void qDumpStdVector(QDumper &d)
             d.putEllipsis();
         d.endChildren();
     }
+    dumpChildNumChildren(d, innerValueResult);
     d.disarm();
 }
 
@@ -2974,6 +3162,8 @@ static void handleProtocolVersion2and3(QDumper & d)
                 qDumpQObject(d);
             else if (isEqual(type, "QObjectPropertyList"))
                 qDumpQObjectPropertyList(d);
+            else if (isEqual(type, "QObjectProperty"))
+                qDumpQObjectProperty(d);
             else if (isEqual(type, "QObjectMethodList"))
                 qDumpQObjectMethodList(d);
             else if (isEqual(type, "QObjectSignal"))
@@ -2984,6 +3174,8 @@ static void handleProtocolVersion2and3(QDumper & d)
                 qDumpQObjectSlot(d);
             else if (isEqual(type, "QObjectSlotList"))
                 qDumpQObjectSlotList(d);
+            else if (isEqual(type, "QObjectChildList"))
+                qDumpQObjectChildList(d);
             break;
         case 'P':
             #if USE_QT_GUI
@@ -3125,11 +3317,13 @@ void *qDumpObjectData440(
             "\""NS"QModelIndex\","
             "\""NS"QObject\","
             "\""NS"QObjectMethodList\","   // hack to get nested properties display
+            "\""NS"QObjectProperty\","
             "\""NS"QObjectPropertyList\","
             "\""NS"QObjectSignal\","
             "\""NS"QObjectSignalList\","
             "\""NS"QObjectSlot\","
             "\""NS"QObjectSlotList\","
+            "\""NS"QObjectChildList\","
             //"\""NS"QRegion\","
             "\""NS"QSet\","
             "\""NS"QString\","
@@ -3166,7 +3360,7 @@ void *qDumpObjectData440(
             "\"").put(((QT_VERSION >> 16) & 255)).put("\","
             "\"").put(((QT_VERSION >> 8)  & 255)).put("\","
             "\"").put(((QT_VERSION)       & 255)).put("\"]");
-        d.put(",namespace=\""NS"\",");
+        d.put(",dumperversion=\"1.3\",");
 //      Dump out size information
         d.put("sizes={");
         d.put("int=\"").put(sizeof(int)).put("\",")
diff --git a/share/qtcreator/gdbmacros/test/dumpertest.pro b/share/qtcreator/gdbmacros/test/dumpertest.pro
index 7b5fd3e582a..ddac946a12a 100644
--- a/share/qtcreator/gdbmacros/test/dumpertest.pro
+++ b/share/qtcreator/gdbmacros/test/dumpertest.pro
@@ -4,8 +4,6 @@
 #
 #-------------------------------------------------
 
-QT       -= gui
-
 TARGET = dumpertest
 CONFIG   += console
 CONFIG   -= app_bundle
diff --git a/share/qtcreator/gdbmacros/test/main.cpp b/share/qtcreator/gdbmacros/test/main.cpp
index eca00156df3..0ec31578b0e 100644
--- a/share/qtcreator/gdbmacros/test/main.cpp
+++ b/share/qtcreator/gdbmacros/test/main.cpp
@@ -32,6 +32,8 @@
 #include <QtCore/QSharedPointer>
 #include <QtCore/QTimer>
 #include <QtCore/QMap>
+#include <QtCore/QVariant>
+#include <QtGui/QAction>
 
 #include <string>
 #include <list>
@@ -174,6 +176,20 @@ static int dumpQMapIntString()
     return 0;
 }
 
+static int dumpQVariant()
+{
+    QVariant test(QLatin1String("item"));
+    prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", "");
+    qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0);
+    fputs(qDumpOutBuffer, stdout);
+    fputs("\n\n", stdout);
+    test = QVariant(QStringList(QLatin1String("item1")));
+    prepareInBuffer("QVariant", "local.qvariant", "local.qvariant", "");
+    qDumpObjectData440(2, 42, testAddress(&test), 1, 0, 0,0 ,0);
+    fputs(qDumpOutBuffer, stdout);
+    return 0;
+}
+
 // ---------------  std types
 
 static int dumpStdString()
@@ -309,76 +325,127 @@ static int dumpStdMapIntString()
 static int dumpQObject()
 {
     // Requires the childOffset to be know, but that is not critical
-    QTimer t;
+    QAction action(0);
+    QObject x;
+    QAction *a2= new QAction(&action);
+    a2->setObjectName(QLatin1String("a2"));
+    action.setObjectName(QLatin1String("action"));
+    QObject::connect(&action, SIGNAL(triggered()), &x, SLOT(deleteLater()));
     prepareInBuffer("QObject", "local.qobject", "local.qobject", "");
-    qDumpObjectData440(2, 42, testAddress(&t), 1, 0, 0, 0, 0);
+    qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+    fputs(qDumpOutBuffer, stdout);
+    fputs("\n\n", stdout);
+    // Property list
+    prepareInBuffer("QObjectPropertyList", "local.qobjectpropertylist", "local.qobjectpropertylist", "");
+    qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+    fputs(qDumpOutBuffer, stdout);
+    fputs("\n\n", stdout);
+    // Signal list
+    prepareInBuffer("QObjectSignalList", "local.qobjectsignallist", "local.qobjectsignallist", "");
+    qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+    fputs(qDumpOutBuffer, stdout);
+    // Slot list
+    prepareInBuffer("QObjectSlotList", "local.qobjectslotlist", "local.qobjectslotlist", "");
+    qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+    fputs(qDumpOutBuffer, stdout);
+    fputs("\n\n", stdout);
+    // Signal list
+    prepareInBuffer("QObjectChildList", "local.qobjectchildlist", "local.qobjectchildlist", "");
+    qDumpObjectData440(2, 42, testAddress(&action), 1, 0, 0, 0, 0);
+    fputs(qDumpOutBuffer, stdout);
+    return 0;
+}
+
+static int dumpQObjectList()
+{
+    // Requires the childOffset to be know, but that is not critical
+    QObject *root = new QObject;
+    root ->setObjectName("root");
+    QTimer *t1 = new QTimer;
+    t1 ->setObjectName("t1");
+    QTimer *t2 = new QTimer;
+    t2 ->setObjectName("t2");
+    QObjectList test;
+    test << root << t1 << t2;
+    prepareInBuffer("QList", "local.qobjectlist", "local.qobjectlist", "QObject *");
+    qDumpObjectData440(2, 42, testAddress(&test), sizeof(QObject*), 0, 0, 0, 0);
     fputs(qDumpOutBuffer, stdout);
     fputc('\n', stdout);
+    delete root;
     return 0;
 }
 
-static bool dumpType(const char *arg)
+typedef int (*DumpFunction)();
+typedef QMap<QString, DumpFunction> TypeDumpFunctionMap;
+
+static TypeDumpFunctionMap registerTypes()
 {
-    if (!qstrcmp(arg, "QString"))
-        { dumpQString(); return true; }
-    if (!qstrcmp(arg, "QSharedPointer<QString>"))
-        { dumpQSharedPointerQString(); return true; }
-    if (!qstrcmp(arg, "QStringList"))
-        { dumpQStringList(); return true; }
-    if (!qstrcmp(arg, "QList<int>"))
-        { dumpQIntList(); return true; }
-    if (!qstrcmp(arg, "QList<std::string>"))
-        { dumpStdStringQList(); return true; }
-    if (!qstrcmp(arg, "QVector<int>"))
-        { dumpQIntVector(); return true; }
-    if (!qstrcmp(arg, "QMap<int,QString>"))
-        { dumpQMapIntString(); return true; }
-    if (!qstrcmp(arg, "QMap<int,int>"))
-        { dumpQMapIntInt(); return true; }
-    if (!qstrcmp(arg, "string"))
-        { dumpStdString(); return true; }
-    if (!qstrcmp(arg, "wstring"))
-        { dumpStdWString(); return true; }
-    if (!qstrcmp(arg, "list<int>"))
-        { dumpStdIntList(); return true; }
-    if (!qstrcmp(arg, "list<string>"))
-        { dumpStdStringList(); return true; }
-    if (!qstrcmp(arg, "vector<int>"))
-        { dumpStdIntVector(); return true; }
-    if (!qstrcmp(arg, "vector<string>"))
-        { dumpStdStringVector(); return true; }
-    if (!qstrcmp(arg, "vector<wstring>"))
-        { dumpStdWStringVector(); return true; }
-    if (!qstrcmp(arg, "set<int>"))
-        { dumpStdIntSet(); return true; }
-    if (!qstrcmp(arg, "set<string>"))
-        { dumpStdStringSet(); return true; }
-    if (!qstrcmp(arg, "map<int,string>"))
-        { dumpStdMapIntString(); return true; }
-    if (!qstrcmp(arg, "QObject"))
-        { dumpQObject(); return true; }
-    return false;
+    TypeDumpFunctionMap rc;
+    rc.insert("QString", dumpQString);
+    rc.insert("QSharedPointer<QString>", dumpQSharedPointerQString);
+    rc.insert("QStringList", dumpQStringList);
+    rc.insert("QList<int>", dumpQIntList);
+    rc.insert("QList<std::string>", dumpStdStringQList);
+    rc.insert("QVector<int>", dumpQIntVector);
+    rc.insert("QMap<int,QString>", dumpQMapIntString);
+    rc.insert("QMap<int,int>", dumpQMapIntInt);
+    rc.insert("string", dumpStdString);
+    rc.insert("wstring", dumpStdWString);
+    rc.insert("list<int>", dumpStdIntList);
+    rc.insert("list<string>", dumpStdStringList);
+    rc.insert("vector<int>", dumpStdIntVector);
+    rc.insert("vector<string>", dumpStdStringVector);
+    rc.insert("vector<wstring>", dumpStdWStringVector);
+    rc.insert("set<int>", dumpStdIntSet);
+    rc.insert("set<string>", dumpStdStringSet);
+    rc.insert("map<int,string>", dumpStdMapIntString);
+    rc.insert("QObject", dumpQObject);
+    rc.insert("QObjectList", dumpQObjectList);
+    rc.insert("QVariant", dumpQVariant);
+    return rc;
 }
 
 int main(int argc, char *argv[])
 {
+    printf("\nQt Creator Debugging Helper testing tool\n\n");
     printf("Running query protocol\n");
     qDumpObjectData440(1, 42, 0, 1, 0, 0, 0, 0);
     fputs(qDumpOutBuffer, stdout);
     fputc('\n', stdout);
     fputc('\n', stdout);
-    if (argc < 2)
+
+    const TypeDumpFunctionMap tdm = registerTypes();
+    const TypeDumpFunctionMap::const_iterator cend = tdm.constEnd();
+
+    if (argc < 2) {
+        printf("Usage: %s [-a]|<type1> <type2..>\n", argv[0]);
+        printf("Supported types: ");
+        for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) {
+            fputs(qPrintable(it.key()), stdout);
+            fputc(' ', stdout);
+        }
+        fputc('\n', stdout);
         return 0;
-    for (int i = 1; i < argc; i++) {
-        const char *arg = argv[i];
-        if (!strcmp(arg, "-u")) {
-            optTestUninitialized = true;
-            printf("\nTesting uninitialized...\n");
-            continue;
+    }
+
+    int rc = 0;
+    if (argc == 2 && !qstrcmp(argv[1], "-a")) {
+        for (TypeDumpFunctionMap::const_iterator it = tdm.constBegin(); it != cend; ++it) {
+            printf("\nTesting: %s\n", qPrintable(it.key()));
+            rc += (*it.value())();
+        }
+    } else {
+        for (int i = 1; i < argc; i++) {
+            const char *arg = argv[i];
+            printf("\nTesting: %s\n", arg);
+            const TypeDumpFunctionMap::const_iterator it = tdm.constFind(QLatin1String(arg));
+            if (it == cend) {
+                rc = -1;
+                fprintf(stderr, "\nUnhandled type: %s\n", argv[i]);
+            } else {
+                rc = (*it.value())();
+            }
         }
-        printf("\nTesting %s\n", arg);
-        if (!dumpType(arg))
-            printf("\nUnhandled type: %s\n", arg);
     }
-    return 0;
+    return rc;
 }
diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
index bedf02dd41e..b4cd0bff6c7 100644
--- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp
+++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
@@ -561,6 +561,10 @@ CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool
         *errorMessage = msgNotHandled(wd.type);
         return DumpNotHandled;
     }
+    if (wd.addr.isEmpty()) {
+        *errorMessage = QString::fromLatin1("Adress is missing for '%1' (%2).").arg(wd.exp, wd.type);
+        return DumpNotHandled;
+    }
 
     // Ensure types are parsed and known.
     if (!ensureInitialized(errorMessage)) {
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
index 870ba8f262f..f68beb0db3c 100644
--- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
@@ -35,6 +35,7 @@
 #include "watchhandler.h"
 
 #include <QtCore/QDebug>
+#include <QtCore/QCoreApplication>
 
 namespace Debugger {
 namespace Internal {
@@ -164,6 +165,46 @@ bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QSt
     return handled;
 }
 
+// When querying an item, the queried item is sometimes returned in incomplete form.
+// Take over values from source.
+static inline void fixDumperResult(const WatchData &source,
+                                   QList<WatchData> *result,
+                                   bool suppressGrandChildren)
+{
+    const int size = result->size();
+    if (!size)
+        return;
+    WatchData &returned = result->front();
+    if (returned.iname != source.iname)
+        return;
+    if (returned.type.isEmpty())
+        returned.setType(source.type);
+    if (returned.isValueNeeded()) {
+        if (source.isValueKnown()) {
+            returned.setValue(source.value);
+        } else {
+            // Should not happen
+            returned.setValue(QCoreApplication::translate("CdbStackFrameContext", "<Unknown>"));
+        }
+    }
+    if (size == 1)
+        return;
+    // Fix the children: If the address is missing, we cannot query any further.
+    const QList<WatchData>::iterator wend = result->end();
+    QList<WatchData>::iterator it = result->begin();
+    for (++it; it != wend; ++it) {
+        WatchData &wd = *it;
+        if (wd.addr.isEmpty() && wd.isSomethingNeeded()) {
+            wd.setAllUnneeded();
+        } else {
+            // Hack: Suppress endless recursion of the model. To be fixed,
+            // the model should not query non-visible items.
+            if (suppressGrandChildren && (wd.isChildrenNeeded() || wd.isHasChildrenNeeded()))
+                wd.setHasChildren(false);
+        }
+    }
+}
+
 WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
 {
     if (debugCDBWatchHandling)
@@ -180,9 +221,7 @@ WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
         if (debugCDBWatchHandling)
             qDebug() << "dumper triggered";
         // Dumpers omit types for complicated templates
-        if (!m_dumperResult.isEmpty() && m_dumperResult.front().type.isEmpty()
-            && m_dumperResult.front().iname == wd.iname)
-            m_dumperResult.front().setType(wd.type);
+        fixDumperResult(wd, &m_dumperResult, false);
         // Discard the original item and insert the dumper results
         foreach(const WatchData &dwd, m_dumperResult)
             m_wh->insertData(dwd);
@@ -254,12 +293,17 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal,
         QList<WatchData> dumperResult;
         const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, OwnerDumper, &dumperResult, errorMessage);
         if (dr == CdbDumperHelper::DumpOk) {
+            // Hack to stop endless model recursion
+            const bool suppressGrandChildren = !wh->isExpandedIName(incompleteLocal.iname);
+            fixDumperResult(incompleteLocal, &dumperResult, suppressGrandChildren);
             foreach(const WatchData &dwd, dumperResult)
                 wh->insertData(dwd);
         } else {
             const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: '%1' (%2): %3/%4").arg(incompleteLocal.name, incompleteLocal.type).arg(int(dr)).arg(*errorMessage);
             qWarning("%s", qPrintable(msg));
             WatchData wd = incompleteLocal;
+            if (wd.isValueNeeded())
+                wd.setValue(QCoreApplication::translate("CdbStackFrameContext", "<Unknown>"));
             wd.setAllUnneeded();
             wh->insertData(wd);
         }
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index b564a5468a7..597b12ebd19 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -3192,24 +3192,36 @@ void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record, const
     //qDebug() << m_availableSimpleDebuggingHelpers << "DATA DUMPERS AVAILABLE";
 }
 
-void GdbEngine::sendWatchParameters(const QByteArray &params0)
+static inline QString arrayFillCommand(const char *array, const QByteArray &params)
 {
-    QByteArray params = params0;
-    params.append('\0');
     char buf[50];
-    sprintf(buf, "set {char[%d]} &qDumpInBuffer = {", params.size());
+    sprintf(buf, "set {char[%d]} &%s = {", params.size(), array);
     QByteArray encoded;
     encoded.append(buf);
-    for (int i = 0; i != params.size(); ++i) {
+    const int size = params.size();
+    for (int i = 0; i != size; ++i) {
         sprintf(buf, "%d,", int(params[i]));
         encoded.append(buf);
     }
     encoded[encoded.size() - 1] = '}';
+    return _(encoded);
+}
+
+void GdbEngine::sendWatchParameters(const QByteArray &params0)
+{
+    QByteArray params = params0;
+    params.append('\0');
+    const QString inBufferCmd = arrayFillCommand("qDumpInBuffer", params);
 
     params.replace('\0','!');
     emit gdbInputAvailable(LogMisc, QString::fromUtf8(params));
 
-    postCommand(_(encoded));
+    params.clear();
+    params.append('\0');
+    const QString outBufferCmd = arrayFillCommand("qDumpOutBuffer", params);
+
+    postCommand(inBufferCmd);
+    postCommand(outBufferCmd);
 }
 
 void GdbEngine::handleVarAssign(const GdbResultRecord &, const QVariant &)
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 30eb77478b0..a5e188ed3c9 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -209,6 +209,8 @@ QString WatchData::toString() const
     QTextStream str(&res);
     if (!iname.isEmpty())
         str << "iname=\"" << iname << doubleQuoteComma;
+    if (!addr.isEmpty())
+        str << "addr=\"" << addr << doubleQuoteComma;
     if (!exp.isEmpty())
         str << "exp=\"" << exp << doubleQuoteComma;
 
@@ -780,6 +782,7 @@ static int findInsertPosition(const QList<WatchItem *> &list, const WatchItem *i
 
 void WatchModel::insertData(const WatchData &data)
 {
+    // qDebug() << "WMI:" << data.toString();
     QTC_ASSERT(!data.iname.isEmpty(), return);
     WatchItem *parent = findItem(parentName(data.iname), m_root);
     if (!parent) {
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp
index 5ef9523ed45..555b6ac6cd4 100644
--- a/src/plugins/debugger/watchutils.cpp
+++ b/src/plugins/debugger/watchutils.cpp
@@ -470,16 +470,19 @@ QString cppExpressionAt(TextEditor::ITextEditor *editor, int pos,
 QtDumperResult::Child::Child() :
    keyEncoded(0),
    valueEncoded(0),
-   childCount(0),
-   valuedisabled(false)
+   childCount(-1),
+   valuedisabled(false),
+   valueEncountered(false)
 {
 }
 
 QtDumperResult::QtDumperResult() :
+    valueEncountered(false),
     valueEncoded(0),
     valuedisabled(false),
-    childCount(0),
-    internal(false)
+    childCount(-1),
+    internal(false),
+    childChildCount(-1)
 {
 }
 
@@ -488,15 +491,17 @@ void QtDumperResult::clear()
     iname.clear();
     value.clear();
     address.clear();
+    addressInfo.clear();
     type.clear();
     extra.clear();
     displayedType.clear();
     valueEncoded = 0;
-    valuedisabled = false;
-    childCount = 0;
+    valueEncountered = valuedisabled = false;
+    childCount = -1;
     internal = false;
     childType.clear();
     children.clear();
+    childChildCount = -1;
 }
 
 QList<WatchData> QtDumperResult::toWatchData(int source) const
@@ -508,45 +513,70 @@ QList<WatchData> QtDumperResult::toWatchData(int source) const
     const QChar dot = QLatin1Char('.');
     const int lastDotIndex = root.iname.lastIndexOf(dot);
     root.exp = root.name = lastDotIndex == -1 ? iname : iname.mid(lastDotIndex + 1);
-    root.setValue(decodeData(value, valueEncoded));
+    if (valueEncountered) {
+        root.setValue(decodeData(value, valueEncoded));
+        root.valuedisabled = valuedisabled;
+    }
     root.setType(displayedType.isEmpty() ? type : displayedType);
-    root.valuedisabled = valuedisabled;
     root.setAddress(address);
     root.source = source;
-    root.setHasChildren(childCount > 0);
-    // Children
-    if (childCount > 0) {
-        if (children.size() == childCount) {
-            for (int c = 0; c < childCount; c++) {
-                const Child &dchild = children.at(c);
-                rc.push_back(WatchData());
-                WatchData &wchild = rc.back();
-                wchild.source = source;
-                wchild.iname = iname;
-                wchild.iname += dot;
-                wchild.iname += dchild.name;
-                // Use key entry as name (which is used for map nodes)
-                if (dchild.key.isEmpty()) {
-                    wchild.name = dchild.name;
-                } else {
-                    wchild.name = decodeData(dchild.key, dchild.keyEncoded);
-                    if (wchild.name.size() > 13) {
-                        wchild.name.truncate(12);
-                        wchild.name += QLatin1String("...");
-                    }
+    if (childCount >= 0)
+        root.setHasChildren(childCount > 0);
+    // Children. Sanity check after parsing sets childcount to list size
+    // if list is not empty
+    if (children.empty()) {
+        if (childCount > 0)
+            root.setChildrenNeeded();
+    } else {
+        root.setChildrenUnneeded();
+        for (int c = 0; c < childCount; c++) {
+            const Child &dchild = children.at(c);
+            rc.push_back(WatchData());
+            WatchData &wchild = rc.back();
+            wchild.source = source;
+            wchild.iname = iname;
+            wchild.iname += dot;
+            wchild.iname += dchild.name;
+            // Use key entry as name (which is used for map nodes)
+            if (dchild.key.isEmpty()) {
+                wchild.name = dchild.name;
+            } else {
+                wchild.name = decodeData(dchild.key, dchild.keyEncoded);
+                if (wchild.name.size() > 13) {
+                    wchild.name.truncate(12);
+                    wchild.name += QLatin1String("...");
                 }
-                wchild.exp = dchild.exp;
+            }
+            wchild.exp = dchild.exp;
+            if (dchild.valueEncountered) {
                 wchild.valuedisabled = dchild.valuedisabled;
-                wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
-                wchild.setAddress(dchild.address);
                 wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
+            }
+            wchild.setType(dchild.type.isEmpty() ? childType : dchild.type);
+            wchild.setAddress(dchild.address);
+            // Child overrides.
+            const int effectiveChildChildCount = dchild.childCount == -1 ?  childChildCount : dchild.childCount;
+            switch (effectiveChildChildCount) {
+                case -1:
+                wchild.setChildrenNeeded();
+                wchild.setHasChildrenNeeded();
+                break;
+                case 0:
                 wchild.setHasChildren(false);
+                break;
+                default:
+                wchild.setHasChildren(true);
+                break;
             }
-            root.setChildrenUnneeded();
-        } else {
-            root.setChildrenNeeded();
         }
     }
+    if (debug) {
+        QDebug nospace = qDebug().nospace();
+        nospace << "QtDumperResult::toWatchData" << *this << '\n';
+        foreach(const WatchData &wd, rc)
+            nospace << "  " << wd.toString() << '\n';
+    }
+
     return rc;
 }
 
@@ -554,11 +584,20 @@ QDebug operator<<(QDebug in, const QtDumperResult &d)
 {
     QDebug nospace = in.nospace();
     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
+            << " address=" << d.address;
+    if (!d.addressInfo.isEmpty())
+        nospace << " addressInfo=" << d.addressInfo;
+    if (d.valueEncountered) {
+        nospace << " encoded=" << d.valueEncoded
+                << " value="  << d.value
+                << " disabled=" << d.valuedisabled;
+    } else {
+        nospace  << " <no value>";
+    }
+    nospace << " childnumchild=" << d.childChildCount
+            << " internal=" << d.internal
             << " extra='" << d.extra << "'\n";
+
     const int realChildCount = d.children.size();
     if (d.childCount || realChildCount) {
         nospace << "childCount=" << d.childCount << '/' << realChildCount
@@ -571,8 +610,12 @@ QDebug operator<<(QDebug in, const QtDumperResult &d)
                     << " name=" << c.name;
             if (!c.key.isEmpty())
                 nospace << " keyencoded=" << c.keyEncoded << " key=" << c.key;
-            nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value
-                    << "childcount=" << c.childCount << '\n';
+            if (c.valueEncountered) {
+                nospace << " valueencoded=" << c.valueEncoded << " value=" << c.value;
+            } else {
+                nospace  << " <no value>";
+            }
+            nospace  << "childcount=" << c.childCount << '\n';
         }
     }
     return in;
@@ -608,6 +651,7 @@ void QtDumperHelper::clear()
     m_sizeCache.clear();
     qFill(m_specialSizes, m_specialSizes + SpecialSizeCount, 0);
     m_expressionCache.clear();
+    m_dumperVersion.clear();
 }
 
 static inline void formatQtVersion(int v, QTextStream &str)
@@ -622,7 +666,7 @@ QString QtDumperHelper::toString(bool debug) const
         QTextStream str(&rc);
         str << "version=";
         formatQtVersion(m_qtVersion, str);
-        str << " namespace='" << m_qtNamespace << "'," << m_nameTypeMap.size() << " known types <type enum>: ";
+        str << "dumperversion='" << m_dumperVersion <<  "' namespace='" << m_qtNamespace << "'," << m_nameTypeMap.size() << " known types <type enum>: ";
         const NameTypeMap::const_iterator cend = m_nameTypeMap.constEnd();
         for (NameTypeMap::const_iterator it = m_nameTypeMap.constBegin(); it != cend; ++it) {
             str <<",[" << it.key() << ',' << it.value() << ']';
@@ -639,9 +683,9 @@ QString QtDumperHelper::toString(bool debug) const
     }
     const QString nameSpace = m_qtNamespace.isEmpty() ? QCoreApplication::translate("QtDumperHelper", "<none>") : m_qtNamespace;
     return QCoreApplication::translate("QtDumperHelper",
-                                       "%n known types, Qt version: %1, Qt namespace: %2",
+                                       "%n known types, Qt version: %1, Qt namespace: %2 Dumper version: %3",
                                        0, QCoreApplication::CodecForTr,
-                                       m_nameTypeMap.size()).arg(qtVersionString(), nameSpace);
+                                       m_nameTypeMap.size()).arg(qtVersionString(), nameSpace, m_dumperVersion);
 }
 
 QtDumperHelper::Type QtDumperHelper::simpleType(const QString &simpleType) const
@@ -726,10 +770,9 @@ QtDumperHelper::Type QtDumperHelper::specialType(QString s)
 
 QtDumperHelper::ExpressionRequirement QtDumperHelper::expressionRequirements(Type t)
 {
+
     switch (t) {
     case QAbstractItemType:
-    case QObjectSlotType:
-    case QObjectSignalType:
     case QVectorType:
     case StdMapType:
         return NeedsComplexExpression;
@@ -738,6 +781,7 @@ QtDumperHelper::ExpressionRequirement QtDumperHelper::expressionRequirements(Typ
     case QMapNodeType:
         return NeedsCachedExpression;
     default:
+        // QObjectSlotType, QObjectSignalType need the signal number, which is numeric
         break;
     }
     return NeedsNoExpression;
@@ -968,9 +1012,9 @@ public:
     explicit QueryDumperParser(const char *s);
 
     struct Data {
-        Data() : qtVersion(0) {}
         QString qtNameSpace;
         QString qtVersion;
+        QString dumperVersion;
         QStringList types;
         QList<SizeEntry> sizes;
         QMap<QString, QString> expressionCache;
@@ -986,7 +1030,7 @@ protected:
     virtual bool handleValue(const char *k, int size);
 
 private:
-    enum Mode { None, ExpectingDumpers, ExpectingVersion,
+    enum Mode { None, ExpectingDumpers, ExpectingQtVersion, ExpectingDumperVersion,
                 ExpectingNameSpace, ExpectingSizes, ExpectingExpressionCache };
     Mode m_mode;
     Data m_data;
@@ -1017,7 +1061,11 @@ bool QueryDumperParser::handleKeyword(const char *k, int size)
         return true;
     }
     if (!qstrncmp(k, "qtversion", size)) {
-        m_mode = ExpectingVersion;
+        m_mode = ExpectingQtVersion;
+        return true;
+    }
+    if (!qstrncmp(k, "dumperversion", size)) {
+        m_mode = ExpectingDumperVersion;
         return true;
     }
     if (!qstrncmp(k, "namespace", size)) {
@@ -1038,7 +1086,7 @@ bool QueryDumperParser::handleKeyword(const char *k, int size)
 
 bool QueryDumperParser::handleListStart()
 {
-    return m_mode == ExpectingDumpers || m_mode == ExpectingVersion;
+    return m_mode == ExpectingDumpers || m_mode == ExpectingQtVersion;
 }
 
 bool QueryDumperParser::handleListEnd()
@@ -1064,7 +1112,10 @@ bool QueryDumperParser::handleValue(const char *k, int size)
     case ExpectingNameSpace:
         m_data.qtNameSpace = QString::fromLatin1(k, size);
         break;
-    case ExpectingVersion: // ["4","1","5"]
+    case ExpectingDumperVersion:
+        m_data.dumperVersion = QString::fromLatin1(k, size);
+        break;
+    case ExpectingQtVersion: // ["4","1","5"]
         if (!m_data.qtVersion.isEmpty())
             m_data.qtVersion += QLatin1Char('.');
         m_data.qtVersion += QString::fromLatin1(k, size);
@@ -1092,6 +1143,7 @@ bool QtDumperHelper::parseQuery(const char *data, Debugger debugger)
     foreach (const QueryDumperParser::SizeEntry &se, parser.data().sizes)
         addSize(se.first, se.second);
     m_expressionCache = parser.data().expressionCache;
+    m_dumperVersion = parser.data().dumperVersion;
     return true;
 }
 
@@ -1248,17 +1300,6 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
     case QAbstractItemType:
         inner = data.addr.mid(1);
         break;
-    case QObjectType:
-    case QWidgetType:
-        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*)&((");
         extraArgs[1] += data.exp;
@@ -1355,6 +1396,8 @@ void QtDumperHelper::evaluationParameters(const WatchData &data,
         qWarning("Unknown type encountered in %s.\n", Q_FUNC_INFO);
         break;
     case SupportedType:
+    case QObjectType:
+    case QWidgetType:
         break;
     }
 
@@ -1412,6 +1455,7 @@ private:
                 ExpectingType, ExpectingDisplayedType, ExpectingInternal,
                 ExpectingValueDisabled,  ExpectingValueEncoded,
                 ExpectingCommonChildType, ExpectingChildCount,
+                ExpectingChildChildOverrideCount,
                 ExpectingExtra,
                 IgnoreNext,
                 ChildModeStart,
@@ -1488,7 +1532,7 @@ ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword
         if (!qstrncmp(keyword, "displayedtype", size))
             return ExpectingDisplayedType;
         if (!qstrncmp(keyword, "childnumchild", size))
-            return IgnoreNextChildMode;
+            return ExpectingChildChildOverrideCount;
         break;
     }
     return in > ChildModeStart ? IgnoreNextChildMode : IgnoreNext;
@@ -1519,10 +1563,17 @@ bool ValueDumperParser::handleValue(const char *k, int size)
     case ExpectingIName:
         m_result.iname = QString::fromLatin1(valueBA);
         break;
-    case ExpectingAddress:
-        m_result.address = QString::fromLatin1(valueBA);
-        break;
+        case ExpectingAddress: {
+                const QString address = QString::fromLatin1(valueBA);
+                if (address.startsWith(QLatin1String("0x"))) {
+                    m_result.address = address;
+                } else {
+                    m_result.addressInfo = address;
+                }
+            }
+            break;
     case ExpectingValue:
+        m_result.valueEncountered = true;
         m_result.value = valueBA;
         break;
     case ExpectingValueDisabled:
@@ -1549,6 +1600,9 @@ bool ValueDumperParser::handleValue(const char *k, int size)
     case ExpectingChildCount:
         m_result.childCount = QString::fromLatin1(valueBA).toInt();
         break;
+    case ExpectingChildChildOverrideCount:
+        m_result.childChildCount = QString::fromLatin1(valueBA).toInt();
+        break;
     case ExpectingChildren:
     case IgnoreNextChildMode:
     case IgnoreNext:
@@ -1566,6 +1620,7 @@ bool ValueDumperParser::handleValue(const char *k, int size)
         m_result.children.back().key = valueBA;
         break;
     case ExpectingChildValue:
+        m_result.children.back().valueEncountered = true;
         m_result.children.back().value = valueBA;
         break;
     case ExpectingChildExpression:
@@ -1590,12 +1645,13 @@ bool ValueDumperParser::handleValue(const char *k, int size)
 bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r)
 {
     ValueDumperParser parser(data);
+
     if (!parser.run())
         return false;
     *r = parser.result();
     // Sanity
-    if (r->childCount < r->children.size())
-        r->childCount  = r->children.size();
+    if (!r->children.empty() && r->childCount != r->children.size())
+        r->childCount = r->children.size();
     if (debug)
         qDebug() << '\n' << data << '\n' << *r;
     return true;
diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h
index 9d39372aa0e..d1d9b05215f 100644
--- a/src/plugins/debugger/watchutils.h
+++ b/src/plugins/debugger/watchutils.h
@@ -99,6 +99,7 @@ struct QtDumperResult
         QString exp;
         QString type;
         QByteArray key;
+        bool valueEncountered;
         QByteArray value;
     };
 
@@ -108,15 +109,18 @@ struct QtDumperResult
 
     QString iname;
     QString address;
+    QString addressInfo; // "<synthetic>" or such, in the 2nd adress field.
     QString type;
     QString extra;
     QString displayedType;
+    bool valueEncountered;
     QByteArray value;
     int valueEncoded;
     bool valuedisabled;
     int childCount;
     bool internal;
     QString childType;
+    int childChildCount;
     QList <Child> children;
 };
 
@@ -242,6 +246,7 @@ private:
 
     QMap<QString, QString> m_expressionCache;
     int m_qtVersion;
+    QString m_dumperVersion;
     QString m_qtNamespace;
 };
 
-- 
GitLab