diff --git a/src/libs/qtcreatorcdbext/containers.cpp b/src/libs/qtcreatorcdbext/containers.cpp
index 13d7b7b452619c6bd4653c5cfb10ff2afbac3124..e8e25fe50bd992ab51a725facfee745207a491fd 100644
--- a/src/libs/qtcreatorcdbext/containers.cpp
+++ b/src/libs/qtcreatorcdbext/containers.cpp
@@ -35,6 +35,8 @@
 #include <functional>
 
 typedef AbstractSymbolGroupNode::AbstractSymbolGroupNodePtrVector AbstractSymbolGroupNodePtrVector;
+typedef std::vector<SymbolGroupValue> SymbolGroupValueVector;
+typedef std::vector<int>::size_type VectorIndexType;
 
 // Read a pointer array from debuggee memory (ULONG64/32 according pointer size)
 static void *readPointerArray(ULONG64 address, unsigned count, const SymbolGroupValueContext &ctx)
@@ -394,12 +396,152 @@ static inline AbstractSymbolGroupNodePtrVector
                            innerType, count);
 }
 
+// Return the list of buckets of a 'QHash<>' as 'QHashData::Node *' values from
+// the list of addresses passed in
+template<class AddressType>
+SymbolGroupValueVector hashBuckets(SymbolGroup *sg, const std::string hashNodeType,
+                                   const AddressType *pointerArray,
+                                   int numBuckets,
+                                   AddressType ePtr,
+                                   const SymbolGroupValueContext &ctx)
+{
+    SymbolGroupValueVector rc;
+    rc.reserve(numBuckets);
+    const AddressType *end = pointerArray + numBuckets;
+    std::string errorMessage;
+    // Skip 'e' special values as they are used as placeholder for reserve(d)
+    // empty array elements.
+    for (const AddressType *p = pointerArray; p < end; p++) {
+        if (*p != ePtr) {
+            const std::string name = pointedToSymbolName(*p, hashNodeType);
+            if (SymbolGroupNode *child = sg->addSymbol(name, std::string(), &errorMessage)) {
+                rc.push_back(SymbolGroupValue(child, ctx));
+            } else {
+                return std::vector<SymbolGroupValue>();
+                break;
+            }
+        }
+    }
+    return rc;
+}
+
+// Return real node type of a QHash: "class QHash<K,V>" -> [struct] "QHashNode<K,V>";
+static inline std::string qHashNodeType(std::string qHashType)
+{
+    qHashType.erase(0, 6); // Strip "class ";
+    const std::string::size_type pos = qHashType.find('<');
+    if (pos != std::string::npos)
+        qHashType.insert(pos, "Node");
+    return qHashType;
+}
+
+// Return up to count nodes of type "QHashNode<K,V>" of a "class QHash<K,V>".
+SymbolGroupValueVector qHashNodes(const SymbolGroupValue &v,
+                                  VectorIndexType count)
+{
+    if (!count)
+        return SymbolGroupValueVector();
+    const SymbolGroupValue hashData = v["d"];
+    // 'e' is used as a special value to indicate empty hash buckets in the array.
+    const ULONG64 ePtr = v["e"].pointerValue();
+    if (!hashData || !ePtr)
+        return SymbolGroupValueVector();
+    // Retrieve the array of buckets of 'd'
+    const int numBuckets = hashData["numBuckets"].intValue();
+    const ULONG64 bucketArray = hashData["buckets"].pointerValue();
+    if (numBuckets <= 0 || !bucketArray)
+        return SymbolGroupValueVector();
+    void *bucketPointers = readPointerArray(bucketArray, numBuckets, v.context());
+    if (!bucketPointers)
+        return SymbolGroupValueVector();
+    // Get list of buckets (starting elements of 'QHashData::Node')
+    const std::string dummyNodeType = "QHashData::Node";
+    const SymbolGroupValueVector buckets = SymbolGroupValue::pointerSize() == 8 ?
+        hashBuckets(v.node()->symbolGroup(), dummyNodeType,
+                    reinterpret_cast<const ULONG64 *>(bucketPointers), numBuckets,
+                    ePtr, v.context()) :
+        hashBuckets(v.node()->symbolGroup(), dummyNodeType,
+                    reinterpret_cast<const ULONG32 *>(bucketPointers), numBuckets,
+                    ULONG32(ePtr), v.context());
+    delete [] bucketPointers ;
+    // Generate the list 'QHashData::Node *' by iterating over the linked list of
+    // nodes starting at each bucket. Using the 'QHashData::Node *' instead of
+    // the 'QHashNode<K,T>' is much faster. Each list has a trailing, unused
+    // dummy element.
+    SymbolGroupValueVector dummyNodeList;
+    dummyNodeList.reserve(count);
+    bool notEnough = true;
+    const SymbolGroupValueVector::const_iterator ncend = buckets.end();
+    for (SymbolGroupValueVector::const_iterator it = buckets.begin(); notEnough && it != ncend; ++it) {
+        for (SymbolGroupValue l = *it; notEnough && l ; ) {
+            const SymbolGroupValue next = l["next"];
+            if (next && next.pointerValue()) { // Stop at trailing dummy element
+                dummyNodeList.push_back(l);
+                if (dummyNodeList.size() >= count) // Stop at maximum count
+                    notEnough = false;
+            } else {
+                break;
+            }
+        }
+    }
+    // Finally convert them into real nodes 'QHashNode<K,V> (potentially expensive)
+    const std::string nodeType = qHashNodeType(v.type());
+    SymbolGroupValueVector nodeList;
+    nodeList.reserve(count);
+    const SymbolGroupValueVector::const_iterator dcend = dummyNodeList.end();
+    for (SymbolGroupValueVector::const_iterator it = dummyNodeList.begin(); it != dcend; ++it) {
+        if (const SymbolGroupValue n = (*it).typeCast(nodeType.c_str())) {
+            nodeList.push_back(n);
+        }  else {
+            return SymbolGroupValueVector();
+        }
+    }
+    return nodeList;
+}
+
+// QSet<>: Contains a 'QHash<key, QHashDummyValue>' as member 'q_hash'.
+// Just dump the keys as an array.
 static inline AbstractSymbolGroupNodePtrVector
-    qHashChildList(const SymbolGroupValue &, int count)
+    qSetChildList(const SymbolGroupValue &v, VectorIndexType count)
+{
+    const SymbolGroupValue qHash = v["q_hash"];
+    AbstractSymbolGroupNodePtrVector rc;
+    if (!count || !qHash)
+        return rc;
+    const SymbolGroupValueVector nodes = qHashNodes(qHash, count);
+    if (nodes.size() != VectorIndexType(count))
+        return rc;
+    rc.reserve(count);
+    for (int i = 0; i < count; i++) {
+        if (const SymbolGroupValue key = nodes.at(i)["key"]) {
+            rc.push_back(ReferenceSymbolGroupNode::createArrayNode(i, key.node()));
+        } else {
+            return AbstractSymbolGroupNodePtrVector();
+        }
+    }
+    return rc;
+}
+
+// QHash<>: Add with fake map nodes.
+static inline AbstractSymbolGroupNodePtrVector
+    qHashChildList(const SymbolGroupValue &v, VectorIndexType count)
 {
     AbstractSymbolGroupNodePtrVector rc;
     if (!count)
         return rc;
+    const SymbolGroupValueVector nodes = qHashNodes(v, count);
+    if (nodes.size() != count)
+        return rc;
+    rc.reserve(count);
+    for (int i = 0; i < count; i++) {
+        const SymbolGroupValue &mapNode = nodes.at(i);
+        const SymbolGroupValue key = mapNode["key"];
+        const SymbolGroupValue value = mapNode["value"];
+        if (!key || !value)
+            return AbstractSymbolGroupNodePtrVector();
+        rc.push_back(MapNodeSymbolGroupNode::create(i, mapNode.address(),
+                                                    mapNode.type(), key.node(), value.node()));
+    }
     return rc;
 }
 
@@ -429,14 +571,12 @@ AbstractSymbolGroupNodePtrVector containerChildren(SymbolGroupNode *node, int ty
         break;
     case KT_QHash:
         return qHashChildList(SymbolGroupValue(node, ctx), size);
-    case KT_QMultiMap:
+    case KT_QMultiHash:
         if (const SymbolGroupValue hash = SymbolGroupValue(node, ctx)[unsigned(0)])
             return qHashChildList(hash, size);
         break;
     case KT_QSet:
-        if (const SymbolGroupValue qHash = SymbolGroupValue(node, ctx)["q_hash"])
-            return qHashChildList(qHash, size);
-        break;
+        return qSetChildList(SymbolGroupValue(node, ctx), size);
     case KT_QStringList:
         if (const SymbolGroupValue qList = SymbolGroupValue(node, ctx)[unsigned(0)])
             return qListChildList(qList, size);
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.h b/src/libs/qtcreatorcdbext/symbolgroup.h
index ce042ae7f3bf3abaab21b16fed66c3d1c9f14c26..67be5b52e005450740e7422d4e0be7863e137def 100644
--- a/src/libs/qtcreatorcdbext/symbolgroup.h
+++ b/src/libs/qtcreatorcdbext/symbolgroup.h
@@ -33,10 +33,13 @@
 #include "common.h"
 #include "symbolgroupnode.h"
 
-// Thin wrapper around a symbol group storing a tree of expanded symbols rooted on
-// a fake "locals" root element.
-// Provides a find() method based on inames ("locals.this.i1.data") that retrieves
-// that index based on the current expansion state.
+/* A symbol group storing a tree of expanded symbols rooted on
+ * a fake "locals" root element.
+ * Provides a find() method based on inames ("locals.this.i1.data") and
+ * dump() methods used for GDBMI-format dumping and debug helpers.
+ * Qt Creator's WatchModel is fed from this class. It basically represents the
+ * symbol group tree with some additional node types (Reference and Map Node
+ * types. */
 
 class SymbolGroup {
 public:
diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp
index d89fbabd6d94f966b97e888706c2af09eda146b0..64755c50e3ff8950af6f81af820b0afd1038c818 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupnode.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroupnode.cpp
@@ -1023,6 +1023,20 @@ SymbolGroupNode *SymbolGroupNode::addSymbolByName(const std::string &name,
 }
 
 // --------- ReferenceSymbolGroupNode
+
+// Utility returning a pair ('[42]','42') as name/iname pair
+// for a node representing an array index
+typedef std::pair<std::string, std::string> StringStringPair;
+
+static inline StringStringPair arrayIndexNameIname(int index)
+{
+    StringStringPair rc(std::string(), toString(index));
+    rc.first = std::string(1, '[');
+    rc.first += rc.second;
+    rc.first.push_back(']');
+    return rc;
+}
+
 ReferenceSymbolGroupNode::ReferenceSymbolGroupNode(const std::string &name,
                                                    const std::string &iname,
                                                    SymbolGroupNode *referencedNode) :
@@ -1034,11 +1048,8 @@ ReferenceSymbolGroupNode::ReferenceSymbolGroupNode(const std::string &name,
 ReferenceSymbolGroupNode *ReferenceSymbolGroupNode::createArrayNode(int index,
                                                                     SymbolGroupNode *referencedNode)
 {
-    const std::string iname = toString(index);
-    std::string name = std::string(1, '[');
-    name += iname;
-    name.push_back(']');
-    return new ReferenceSymbolGroupNode(name, iname, referencedNode);
+    const StringStringPair nameIname = arrayIndexNameIname(index);
+    return new ReferenceSymbolGroupNode(nameIname.first, nameIname.second, referencedNode);
 }
 
 void ReferenceSymbolGroupNode::dump(std::ostream &str, const std::string &visitingFullIname,
@@ -1056,6 +1067,49 @@ void ReferenceSymbolGroupNode::debug(std::ostream &str, const std::string &visit
     m_referencedNode->debug(str, visitingFullIname, verbosity, depth);
 }
 
+// ---------------- MapNodeSymbolGroupNode
+MapNodeSymbolGroupNode::MapNodeSymbolGroupNode(const std::string &name,
+                                               const std::string &iname,
+                                               ULONG64 address,
+                                               const std::string &type,
+                                               AbstractSymbolGroupNode *key,
+                                               AbstractSymbolGroupNode *value) :
+    BaseSymbolGroupNode(name, iname), m_address(address), m_type(type)
+{
+    addChild(key);
+    addChild(value);
+}
+
+MapNodeSymbolGroupNode
+    *MapNodeSymbolGroupNode::create(int index, ULONG64 address,
+                                    const std::string &type,
+                                    SymbolGroupNode *key, SymbolGroupNode *value)
+{
+    const StringStringPair nameIname = arrayIndexNameIname(index);
+    const std::string keyName = "key";
+    ReferenceSymbolGroupNode *keyRN = new ReferenceSymbolGroupNode(keyName, keyName, key);
+    const std::string valueName = "value";
+    ReferenceSymbolGroupNode *valueRN = new ReferenceSymbolGroupNode(valueName, valueName, value);
+    return new MapNodeSymbolGroupNode(nameIname.first, nameIname.second, address, type, keyRN, valueRN);
+}
+
+void MapNodeSymbolGroupNode::dump(std::ostream &str, const std::string &visitingFullIname,
+                                  const DumpParameters &, const SymbolGroupValueContext &)
+{
+    SymbolGroupNode::dumpBasicData(str, name(), visitingFullIname);
+    if (m_address)
+        str << ",address=\"0x" << std::hex << m_address << '"';
+    str << ",type=\"" << m_type << "\",valueencoded=\"0\",value=\"\",valueenabled=\"false\""
+           ",valueeditable=\"false\",numchild=\"2\"";
+}
+
+void MapNodeSymbolGroupNode::debug(std::ostream &os, const std::string &visitingFullIname,
+                                   unsigned /* verbosity */, unsigned depth) const
+{
+    indentStream(os, 2 * depth);
+    os << "MapNode " << name() << '/' << visitingFullIname << '\n';
+}
+
 // --------- DebugSymbolGroupNodeVisitor
 
 // "local.vi" -> "local"
diff --git a/src/libs/qtcreatorcdbext/symbolgroupnode.h b/src/libs/qtcreatorcdbext/symbolgroupnode.h
index 88350741a2d92070f4d50a97b779ec088518edc2..dcb457c9eadbfed7537b8140ec7ecebdbe69a4e0 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupnode.h
+++ b/src/libs/qtcreatorcdbext/symbolgroupnode.h
@@ -159,7 +159,8 @@ private:
     void removeChildren();
 };
 
-/* SymbolGroupNode: 'Real' node within a symbol group, identified by its index.
+/* SymbolGroupNode: 'Real' node within a symbol group, identified by its index
+ * in IDebugSymbolGroup.
  * Provides accessors for fixed-up symbol group value and a dumping facility
  * consisting of:
  * - 'Simple' dumping done when running the DumpVisitor. This produces one
@@ -265,7 +266,7 @@ private:
 
 // Artificial node referencing another (real) SymbolGroupNode (added symbol or
 // symbol from within a linked list structure. Forwards dumping to referenced node
-// using its own name/iname.
+// using its own name.
 class ReferenceSymbolGroupNode  : public AbstractSymbolGroupNode
 {
 public:
@@ -290,6 +291,32 @@ private:
     SymbolGroupNode * const m_referencedNode;
 };
 
+// Base class for a [fake] map node with a fake array index and key/value entries.
+class MapNodeSymbolGroupNode : public BaseSymbolGroupNode
+{
+private:
+    explicit MapNodeSymbolGroupNode(const std::string &name,
+                                    const std::string &iname,
+                                    ULONG64 address /* = 0 */,
+                                    const std::string &type,
+                                    AbstractSymbolGroupNode *key,
+                                    AbstractSymbolGroupNode *value);
+
+public:
+    static MapNodeSymbolGroupNode *
+        create(int i, ULONG64 address /* = 0 */, const std::string &type,
+               SymbolGroupNode *key, SymbolGroupNode *value);
+
+    virtual void dump(std::ostream &str, const std::string &visitingFullIname,
+                      const DumpParameters &p, const SymbolGroupValueContext &ctx);
+    virtual void debug(std::ostream &os, const std::string &visitingFullIname,
+                       unsigned verbosity, unsigned depth) const;
+
+private:
+    const ULONG64 m_address;
+    const std::string m_type;
+};
+
 /* Visitor that takes care of iterating over the nodes and
  * building the full iname path ('local.foo.bar') that is required for
  * GDBMI dumping. The full name depends on the path on which a node was reached
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
index 58e733637b1a52aea8c2a2c03fbc1b44510c8b62..c2513670a57aebbe9869437c1f072d4842c87f9e 100644
--- a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
@@ -189,15 +189,28 @@ SymbolGroupValue SymbolGroupValue::pointerTypeCast(const char *type) const
 
 SymbolGroupValue SymbolGroupValue::typeCastedValue(ULONG64 address, const char *type) const
 {
-    if (address) {
-        SymbolGroup *sg = m_node->symbolGroup();
-        std::ostringstream str;
-        str << '(' << type << ")(" << std::showbase << std::hex << address << ')';
-        if (SymbolGroupNode *node = sg->addSymbol(str.str(),
-                                                  additionalSymbolIname(sg),
-                                                  &m_errorMessage))
-            return SymbolGroupValue(node, m_context);
-    }
+    if (!address)
+        return SymbolGroupValue();
+    const size_t len = strlen(type);
+    if (!len)
+        return SymbolGroupValue();
+    const bool nonPointer = type[len - 1] != '*';
+    SymbolGroup *sg = m_node->symbolGroup();
+    // A bit of magic: For desired pointer types, we can do
+    //     'Foo *' -> '(Foo *)(address)'.
+    // For non-pointers, we need to de-reference:
+    //      'Foo' -> '*(Foo *)(address)'
+    std::ostringstream str;
+    if (nonPointer)
+        str << '*';
+    str << '(' << type;
+    if (nonPointer)
+        str << " *";
+    str << ")(" << std::showbase << std::hex << address << ')';
+    if (SymbolGroupNode *node = sg->addSymbol(str.str(),
+                                              additionalSymbolIname(sg),
+                                              &m_errorMessage))
+        return SymbolGroupValue(node, m_context);
     return SymbolGroupValue();
 }