diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbext.def b/src/libs/qtcreatorcdbext/qtcreatorcdbext.def
index 0187da13ebb96b69cdc415138b5f5eb3adc89115..2f84541610a3a67142421dedf1ad11c66d18eb80 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbext.def
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbext.def
@@ -5,6 +5,7 @@ DebugExtensionNotify
 pid
 expandlocals
 locals
+dumplocal
 assign
 threads
 registers
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro b/src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro
index 60041522e58bf2a8518cc5075fc32597f3035e6e..1ddfc45a9bed9d2c8cd2312268a5a3e40fc156c1 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbext_build.pro
@@ -53,7 +53,8 @@ SOURCES += qtcreatorcdbextension.cpp \
     stringutils.cpp \
     gdbmihelpers.cpp \
     outputcallback.cpp \
-    base64.cpp
+    base64.cpp \
+    symbolgroupvalue.cpp
 
 HEADERS += extensioncontext.h \
     common.h \
@@ -63,5 +64,5 @@ HEADERS += extensioncontext.h \
     stringutils.h \
     gdbmihelpers.h \
     outputcallback.h \
-    base64.h
-
+    base64.h \
+    symbolgroupvalue.h
diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
index 700c1c9b2e6021666114fc8187ed3118baacfaab..53bef0ab7d909caa44b2176ded655bc5a5c846cd 100644
--- a/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
+++ b/src/libs/qtcreatorcdbext/qtcreatorcdbextension.cpp
@@ -31,6 +31,7 @@
 #include "outputcallback.h"
 #include "eventcallback.h"
 #include "symbolgroup.h"
+#include "symbolgroupvalue.h"
 #include "stringutils.h"
 #include "gdbmihelpers.h"
 
@@ -224,6 +225,59 @@ extern "C" HRESULT CALLBACK locals(CIDebugClient *client, PCSTR args)
     return S_OK;
 }
 
+// Extension command 'dumplocal':
+// Dump a local variable using dumpers (testing command).
+
+const char dumpLocalUsageC[] = "Usage: dumplocal <frame> <iname>";
+
+static std::string dumplocalHelper(ExtensionCommandContext &exc,PCSTR args, int *token, std::string *errorMessage)
+{
+    // Parse the command
+    StringList tokens = commandTokens<StringList>(args, token);
+    // Frame and iname
+    unsigned frame;
+    if (tokens.empty() || sscanf(tokens.front().c_str(), "%u", &frame) != 1) {
+        *errorMessage = dumpLocalUsageC;
+        return std::string();
+    }
+    tokens.pop_front();
+    if (tokens.empty()) {
+        *errorMessage = dumpLocalUsageC;
+        return std::string();
+    }
+    const std::string iname = tokens.front();
+
+    SymbolGroup * const symGroup = ExtensionContext::instance().symbolGroup(exc.symbols(), exc.threadId(), frame, errorMessage);
+    if (!symGroup)
+        return std::string();
+
+    SymbolGroupNode *n = symGroup->find(iname);
+    if (!n) {
+        *errorMessage = "No such iname " + iname;
+        return std::string();
+    }
+    std::wstring value;
+    if (!dumpSimpleType(n, SymbolGroupValueContext(exc.dataSpaces()), &value)) {
+        *errorMessage = "Cannot dump " + iname;
+        return std::string();
+    }
+    return wStringToString(value);
+}
+
+extern "C" HRESULT CALLBACK dumplocal(CIDebugClient *client, PCSTR  argsIn)
+{
+    ExtensionCommandContext exc(client);
+    std::string errorMessage;
+    int token = 0;
+    const std::string value = dumplocalHelper(exc,argsIn, &token, &errorMessage);
+    if (value.empty()) {
+        ExtensionContext::instance().report('N', token, "dumplocal", errorMessage.c_str());
+    } else {
+        ExtensionContext::instance().report('R', token, "dumplocal", value.c_str());
+    }
+    return S_OK;
+}
+
 // Extension command 'assign':
 // Assign locals by iname: 'assign locals.x=5'
 
diff --git a/src/libs/qtcreatorcdbext/stringutils.cpp b/src/libs/qtcreatorcdbext/stringutils.cpp
index ed0c7309fda9a2a0fe935edb784800f60429d2a4..b0f476d1b30edf4145129b88b7e736847532d863 100644
--- a/src/libs/qtcreatorcdbext/stringutils.cpp
+++ b/src/libs/qtcreatorcdbext/stringutils.cpp
@@ -97,6 +97,15 @@ void replace(std::wstring &s, wchar_t before, wchar_t after)
             s[i] = after;
 }
 
+bool endsWith(const std::string &haystack, const char *needle)
+{
+    const size_t needleLen = strlen(needle);
+    const size_t haystackLen = haystack.size();
+    if (needleLen > haystackLen)
+        return false;
+    return haystack.compare(haystackLen - needleLen, needleLen, needle) == 0;
+}
+
 static inline void formatGdbmiChar(std::ostream &str, wchar_t c)
 {
     switch (c) {
@@ -164,6 +173,18 @@ std::string wStringToString(const std::wstring &w)
     return rc;
 }
 
+std::wstring stringToWString(const std::string &w)
+{
+    if (w.empty())
+        return std::wstring();
+    const std::wstring::size_type size = w.size();
+    std::wstring rc;
+    rc.reserve(size);
+    for (std::wstring::size_type i = 0; i < size; i++)
+        rc.push_back(w.at(i));
+    return rc;
+}
+
 // Format a map as a GDBMI hash {key="value",..}
 void formatGdbmiHash(std::ostream &os, const std::map<std::string, std::string> &m)
 {
diff --git a/src/libs/qtcreatorcdbext/stringutils.h b/src/libs/qtcreatorcdbext/stringutils.h
index cb809aeb918dc8b0b8e588aad05aa5d691edef09..e8a7342a2490f70f419a1882f528f60053ce6257 100644
--- a/src/libs/qtcreatorcdbext/stringutils.h
+++ b/src/libs/qtcreatorcdbext/stringutils.h
@@ -63,6 +63,8 @@ std::string toString(const Streamable s)
     return str.str();
 }
 
+bool endsWith(const std::string &haystack, const char *needle);
+
 // Read an integer from a string as '10' or '0xA'
 template <class Integer>
 bool integerFromString(const std::string &s, Integer *v)
@@ -115,6 +117,7 @@ inline std::ostream &operator<<(std::ostream &str, const gdbmiWStringFormat &wsf
 
 std::string wStringToGdbmiString(const std::wstring &w);
 std::string wStringToString(const std::wstring &w);
+std::wstring stringToWString(const std::string &w);
 
 // Format a map as a GDBMI hash {key="value",..}
 void formatGdbmiHash(std::ostream &os, const std::map<std::string, std::string> &);
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.cpp b/src/libs/qtcreatorcdbext/symbolgroup.cpp
index 6c2059787cab31b6603e2714d21f38087c90429b..5c2a1e69b6a6f407a6f19737e9d03009913cfc0a 100644
--- a/src/libs/qtcreatorcdbext/symbolgroup.cpp
+++ b/src/libs/qtcreatorcdbext/symbolgroup.cpp
@@ -457,7 +457,7 @@ static bool isSevenBitClean(const wchar_t *buf, ULONG size)
     return true;
 }
 
-std::string SymbolGroupNode::getType() const
+std::string SymbolGroupNode::type() const
 {
     static char buf[BufSize];
     const HRESULT hr = m_symbolGroup->debugSymbolGroup()->GetSymbolTypeName(m_index, buf, BufSize, NULL);
@@ -509,7 +509,7 @@ std::wstring SymbolGroupNode::rawValue() const
 std::wstring SymbolGroupNode::fixedValue() const
 {
     std::wstring value = rawValue();
-    fixValue(getType(), &value);
+    fixValue(type(), &value);
     return value;
 }
 
@@ -518,6 +518,15 @@ SymbolGroupNode *SymbolGroupNode::childAt(unsigned i) const
     return i < m_children.size() ? m_children.at(i) : static_cast<SymbolGroupNode *>(0);
 }
 
+SymbolGroupNode *SymbolGroupNode::childByIName(const char *n) const
+{
+    const SymbolGroupNodePtrVector::const_iterator childrenEnd = m_children.end();
+    for (SymbolGroupNodePtrVector::const_iterator it = m_children.begin(); it != childrenEnd; ++it)
+        if ( (*it)->iName() == n )
+            return *it;
+    return 0;
+}
+
 static inline void indentStream(std::ostream &str, unsigned depth)
 {
     for (unsigned d = 0; d < depth; d++)
@@ -528,7 +537,7 @@ void SymbolGroupNode::dump(std::ostream &str, unsigned child, unsigned depth,
                            bool humanReadable) const
 {
     const std::string iname = fullIName();
-    const std::string type = getType();
+    const std::string t = type();
 
     if (child) { // Separate list of children
         str << ',';
@@ -539,7 +548,7 @@ void SymbolGroupNode::dump(std::ostream &str, unsigned child, unsigned depth,
     if (humanReadable)
         indentStream(str, depth);
     str << "{iname=\"" << iname << "\",exp=\"" << iname << "\",name=\"" << m_name
-        << "\",type=\"" << type << '"';
+        << "\",type=\"" << t << '"';
 
     if (const ULONG64 addr = address())
         str << ",addr=\"" << std::hex << std::showbase << addr << std::noshowbase << std::dec
@@ -559,7 +568,7 @@ void SymbolGroupNode::dump(std::ostream &str, unsigned child, unsigned depth,
             // ASCII or base64?
             if (isSevenBitClean(wbuf, valueSize)) {
                 std::wstring value = wbuf;
-                fixValue(type, &value);
+                fixValue(t, &value);
                 str << ",valueencoded=\"0\",value=\"" << gdbmiWStringFormat(value) << '"';
             } else {
                 str << ",valueencoded=\"2\",value=\"";
@@ -625,7 +634,7 @@ void SymbolGroupNode::debug(std::ostream &str, unsigned verbosity, unsigned dept
         str << " node-flags=" << m_flags;
     if (verbosity) {
         str << ",name=\"" << m_name << "\", Address=0x" << std::hex << address() << std::dec
-            << " Type=\"" << getType() << '"';
+            << " Type=\"" << type() << '"';
         if (!(m_flags & Uninitialized))
             str << "\" Value=\"" << gdbmiWStringFormat(rawValue()) << '"';
     }
diff --git a/src/libs/qtcreatorcdbext/symbolgroup.h b/src/libs/qtcreatorcdbext/symbolgroup.h
index b5556d891b0db56ed54fde7351d17cb7df2162a6..59d8c47c6347005b5f45f0440125f7245680df67 100644
--- a/src/libs/qtcreatorcdbext/symbolgroup.h
+++ b/src/libs/qtcreatorcdbext/symbolgroup.h
@@ -75,6 +75,8 @@ public:
 
     const SymbolGroupNodePtrVector &children() const { return m_children; }
     SymbolGroupNode *childAt(unsigned) const;
+    SymbolGroupNode *childByIName(const char *) const;
+
     const SymbolGroupNode *parent() const { return m_parent; }
 
     // I/O: Gdbmi dump for Visitors
@@ -86,6 +88,7 @@ public:
 
     std::wstring rawValue() const;
     std::wstring fixedValue() const;
+    std::string type() const;
     ULONG64 address() const;
 
     bool accept(SymbolGroupNodeVisitor &visitor, unsigned child, unsigned depth) const;
@@ -101,7 +104,6 @@ public:
 private:
     // Return allocated wide string array of value
     wchar_t *getValue(ULONG *obtainedSize = 0) const;
-    std::string getType() const;
     bool isArrayElement() const;
     // Notify about expansion of a node, shift indexes
     bool notifyExpanded(ULONG index, ULONG insertedCount);
@@ -174,6 +176,7 @@ public:
     ULONG threadId() const { return m_threadId; }
     SymbolGroupNode *root() { return m_root; }
     const SymbolGroupNode *root() const { return m_root; }
+    SymbolGroupNode *find(const std::string &iname) const;
 
     // Expand a node list "locals.i1,locals.i2", expanding all nested child nodes
     // (think mkdir -p).
@@ -201,7 +204,6 @@ public:
                                     std::string *errorMessage);
 
 private:
-    SymbolGroupNode *find(const std::string &iname) const;
     inline SymbolGroupNode *findI(const std::string &iname) const;
     static bool getSymbolParameters(CIDebugSymbolGroup *m_symbolGroup,
                                     SymbolParameterVector *vec,
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9e279e5dd2eda63aa39ed2fec91a21b3215831fd
--- /dev/null
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.cpp
@@ -0,0 +1,161 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "symbolgroupvalue.h"
+#include "symbolgroup.h"
+#include "stringutils.h"
+
+SymbolGroupValueContext::SymbolGroupValueContext(CIDebugDataSpaces *ds)
+    : dataspaces(ds)
+{
+}
+
+SymbolGroupValueContext::SymbolGroupValueContext() : dataspaces(0)
+{
+}
+
+SymbolGroupValue::SymbolGroupValue(SymbolGroupNode *node,
+                                   const SymbolGroupValueContext &ctx) :
+    m_node(node), m_context(ctx)
+{
+}
+
+SymbolGroupValue::SymbolGroupValue() :
+    m_node(0), m_errorMessage("Invalid")
+{
+}
+
+bool SymbolGroupValue::isValid() const
+{
+    return m_node != 0 && m_context.dataspaces != 0;
+}
+
+SymbolGroupValue SymbolGroupValue::operator[](const char *name) const
+{
+    if (isValid() && m_node->expand(&m_errorMessage))
+        if (SymbolGroupNode *child = m_node->childByIName(name))
+            return SymbolGroupValue(child, m_context);
+    return SymbolGroupValue();
+}
+
+std::string SymbolGroupValue::type() const
+{
+    return isValid() ? m_node->type() : std::string();
+}
+
+std::wstring SymbolGroupValue::value() const
+{
+    return isValid() ? m_node->fixedValue() : std::wstring();
+}
+
+int SymbolGroupValue::intValue(int defaultValue) const
+{
+    if (isValid()) {
+        int rc = 0;
+        if (integerFromString(wStringToString(value()), &rc))
+            return rc;
+    }
+    return defaultValue;
+}
+
+ULONG64 SymbolGroupValue::pointerValue(ULONG64 defaultValue) const
+{
+    if (isValid()) {
+        ULONG64 rc = 0;
+        if (integerFromString(wStringToString(value()), &rc))
+            return rc;
+    }
+    return defaultValue;
+}
+
+// Return allocated array of data
+unsigned char *SymbolGroupValue::pointerData(unsigned length) const
+{
+    if (isValid()) {
+        if (const ULONG64 ptr = pointerValue()) {
+            unsigned char *data = new unsigned char[length];
+            std::fill(data, data + length, 0);
+            const HRESULT hr = m_context.dataspaces->ReadVirtual(ptr, data, length, NULL);
+            if (FAILED(hr)) {
+                delete [] data;
+                return 0;
+            }
+            return data;
+        }
+    }
+    return 0;
+}
+
+std::wstring SymbolGroupValue::wcharPointerData(unsigned charCount, unsigned maxCharCount) const
+{
+    const bool truncated = charCount > maxCharCount;
+    if (truncated)
+        charCount = maxCharCount;
+    if (const unsigned char *ucData = pointerData(charCount * sizeof(wchar_t))) {
+        const wchar_t *utf16Data = reinterpret_cast<const wchar_t *>(ucData);
+        // Be smart about terminating 0-character
+        if (charCount && utf16Data[charCount - 1] == 0)
+            charCount--;
+        std::wstring rc = std::wstring(utf16Data, charCount);
+        if (truncated)
+            rc += L"...";
+        delete [] ucData;
+        return rc;
+    }
+    return std::wstring();
+}
+
+std::string SymbolGroupValue::error() const
+{
+    return m_errorMessage;
+}
+
+// Dump a QString.
+static bool dumpQString(const SymbolGroupValue &v, std::wstring *s)
+{
+    if (endsWith(v.type(), "QString")) {
+        if (SymbolGroupValue d = v["d"]) {
+            if (SymbolGroupValue sizeValue = d["size"]) {
+                const int size = sizeValue.intValue();
+                if (size >= 0) {
+                    *s = d["data"].wcharPointerData(size);
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+// Dump builtin simple types using SymbolGroupValue expressions.
+bool dumpSimpleType(SymbolGroupNode  *n, const SymbolGroupValueContext &ctx, std::wstring *s)
+{
+    const SymbolGroupValue v(n, ctx);
+    return dumpQString(v, s);
+}
diff --git a/src/libs/qtcreatorcdbext/symbolgroupvalue.h b/src/libs/qtcreatorcdbext/symbolgroupvalue.h
new file mode 100644
index 0000000000000000000000000000000000000000..bb18ab223cc19c91cabfd0a1c117d0600e9f5af1
--- /dev/null
+++ b/src/libs/qtcreatorcdbext/symbolgroupvalue.h
@@ -0,0 +1,83 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SYMBOLGROUPVALUE_H
+#define SYMBOLGROUPVALUE_H
+
+#include "common.h"
+
+#include <string>
+
+class SymbolGroupNode;
+
+// Structure to pass all IDebug interfaces used for SymbolGroupValue
+struct SymbolGroupValueContext
+{
+    SymbolGroupValueContext(CIDebugDataSpaces *ds);
+    SymbolGroupValueContext();
+
+    CIDebugDataSpaces *dataspaces;
+};
+
+/* SymbolGroupValue: Flyweight tied to a SymbolGroupNode
+ * providing a convenient operator[] + value getters for notation of dumpers.
+ * Inaccesible members return a SymbolGroupValue in state 'invalid'. */
+
+class SymbolGroupValue
+{
+public:
+    explicit SymbolGroupValue(SymbolGroupNode *node, const SymbolGroupValueContext &c);
+    SymbolGroupValue();
+
+    operator bool() const { return isValid(); }
+    bool isValid() const;
+
+    SymbolGroupValue operator[](const char *name) const;
+
+    std::string type() const;
+    std::wstring value() const;
+    int intValue(int defaultValue = -1) const;
+    ULONG64 pointerValue(ULONG64 defaultValue = 0) const;
+    // Return allocated array of data pointed to
+    unsigned char *pointerData(unsigned length) const;
+    // Return data pointed to as wchar_t/std::wstring (UTF16)
+    std::wstring wcharPointerData(unsigned charCount, unsigned maxCharCount = 512) const;
+
+    std::string error() const;
+
+private:
+    SymbolGroupNode *m_node;
+    SymbolGroupValueContext m_context;
+    mutable std::string m_errorMessage;
+};
+
+// Dump builtin simple types using SymbolGroupValue expressions.
+bool dumpSimpleType(SymbolGroupNode  *n, const SymbolGroupValueContext &ctx, std::wstring *s);
+
+#endif // SYMBOLGROUPVALUE_H