diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp
index df6004a735e23d0f5f740f5041b6c42067e03a19..7c766dff31ec64c8d9b1b834ddf26fa5f596fc6e 100644
--- a/share/qtcreator/gdbmacros/gdbmacros.cpp
+++ b/share/qtcreator/gdbmacros/gdbmacros.cpp
@@ -60,6 +60,10 @@ int qtGhVersion = QT_VERSION;
 #   include <QtGui/QImage>
 #endif
 
+#ifdef Q_OS_WIN
+#    include <windows.h>
+#endif
+
 #include <list>
 #include <map>
 #include <string>
@@ -231,11 +235,17 @@ static QByteArray stripPointerType(QByteArray type)
 }
 
 // This is used to abort evaluation of custom data dumpers in a "coordinated"
-// way. Abortion will happen anyway when we try to access a non-initialized
+// way. Abortion will happen at the latest when we try to access a non-initialized
 // non-trivial object, so there is no way to prevent this from occuring at all
-// conceptionally.  Gdb will catch SIGSEGV and return to the calling frame.
-// This is just fine provided we only _read_ memory in the custom handlers
-// below.
+// conceptionally.  Ideally, if there is API to check memory access, it should
+// be used to terminate nicely, especially with CDB.
+// 1) Gdb will catch SIGSEGV and return to the calling frame.
+//    This is just fine provided we only _read_ memory in the custom handlers
+//    below.
+// 2) For MSVC/CDB, exceptions must be handled in the dumper, which is
+//    achieved using __try/__except. The exception will be reported in the
+//    debugger, which will then execute a 'gN' command, passing handling back
+//    to the __except clause.
 
 volatile int qProvokeSegFaultHelper;
 
@@ -269,11 +279,16 @@ static bool startsWith(const char *s, const char *t)
     return qstrncmp(s, t, qstrlen(t)) == 0;
 }
 
-// provoke segfault when address is not readable
-#define qCheckAccess(d) do { qProvokeSegFaultHelper = *(char*)d; } while (0)
-#define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
-// provoke segfault unconditionally
-#define qCheck(b) do { if (!(b)) qProvokeSegFaultHelper = *(char*)0; } while (0)
+// Check memory for read access and provoke segfault if nothing else helps.
+// On Windows, try to be less crash-prone by checking memory using WinAPI
+
+#ifdef Q_OS_WIN
+#    define qCheckAccess(d) if (IsBadReadPtr(d, 1)) return; do { qProvokeSegFaultHelper = *(char*)d; } while (0)
+#    define qCheckPointer(d) if (d && IsBadReadPtr(d, 1)) return; do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
+#else
+#    define qCheckAccess(d) do { qProvokeSegFaultHelper = *(char*)d; } while (0)
+#    define qCheckPointer(d) do { if (d) qProvokeSegFaultHelper = *(char*)d; } while (0)
+#endif
 
 const char *stripNamespace(const char *type)
 {
@@ -692,11 +707,14 @@ void QDumper::putEllipsis()
 #define TT(type, value) \
     "<tr><td>" << type << "</td><td> : </td><td>" << value << "</td></tr>"
 
-static void qDumpUnknown(QDumper &d)
+#define DUMPUNKNOWN_MESSAGE "<internal error>"
+static void qDumpUnknown(QDumper &d, const char *why = 0)
 {
     P(d, "iname", d.iname);
     P(d, "addr", d.data);
-    P(d, "value", "<internal error>");
+    if (!why)
+        why = DUMPUNKNOWN_MESSAGE;
+    P(d, "value", why);
     P(d, "type", d.outertype);
     P(d, "numchild", "0");
     d.disarm();
@@ -1078,7 +1096,7 @@ static void qDumpQHash(QDumper &d)
     int n = h->size;
 
     if (n < 0)
-        qCheck(false);
+        return;
     if (n > 0) {
         qCheckPointer(h->fakeNext);
         qCheckPointer(*h->buckets);
@@ -1181,19 +1199,21 @@ static void qDumpQList(QDumper &d)
 {
     // This uses the knowledge that QList<T> has only a single member
     // of type  union { QListData p; QListData::Data *d; };
+
     const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
     const QListData::Data *pdata =
         *reinterpret_cast<const QListData::Data* const*>(d.data);
+    qCheckAccess(pdata);
     int nn = ldata.size();
     if (nn < 0)
-        qCheck(false);
+        return;
     if (nn > 0) {
         qCheckAccess(ldata.d->array);
         //qCheckAccess(ldata.d->array[0]);
         //qCheckAccess(ldata.d->array[nn - 1]);
 #if QT_VERSION >= 0x040400
         if (ldata.d->ref._q_value <= 0)
-            qCheck(false);
+            return;
 #endif
     }
 
@@ -1262,7 +1282,7 @@ static void qDumpQLinkedList(QDumper &d)
         reinterpret_cast<const QLinkedListData*>(deref(d.data));
     int nn = ldata->size;
     if (nn < 0)
-        qCheck(false);
+        return;
 
     int n = nn;
     P(d, "value", "<" << n << " items>");
@@ -1386,7 +1406,7 @@ static void qDumpQMap(QDumper &d)
     int n = h->size;
 
     if (n < 0)
-        qCheck(false);
+        return;
     if (n > 0) {
         qCheckAccess(h->backward);
         qCheckAccess(h->forward[0]);
@@ -1899,7 +1919,7 @@ static void qDumpQSet(QDumper &d)
 
     int n = hd->size;
     if (n < 0)
-        qCheck(false);
+        return;
     if (n > 0) {
         qCheckAccess(node);
         qCheckPointer(node->next);
@@ -1952,8 +1972,23 @@ static void qDumpQSharedPointer(QDumper &d)
             P(d, "name", "data");
             qDumpInnerValue(d, d.innertype, ptr.data());
         d.endHash();
-        I(d, "strongref", 44);
-        I(d, "weakref", 45);
+        const int v = sizeof(void *);
+        d.beginHash();
+            const void *weak = addOffset(deref(addOffset(d.data, v)), v);
+            P(d, "name", "weakref"); 
+            P(d, "value", *static_cast<const int *>(weak));
+            P(d, "type", "int"); 
+            P(d, "addr",  weak);
+            P(d, "numchild", "0");
+        d.endHash();
+        d.beginHash();
+            const void *strong = addOffset(weak, sizeof(int));
+            P(d, "name", "strongref"); 
+            P(d, "value", *static_cast<const int *>(strong));
+            P(d, "type", "int"); 
+            P(d, "addr",  strong);
+            P(d, "numchild", "0");
+        d.endHash();
         d << "]";
     }
     d.disarm();
@@ -1982,7 +2017,7 @@ static void qDumpQStringList(QDumper &d)
     const QStringList &list = *reinterpret_cast<const QStringList *>(d.data);
     int n = list.size();
     if (n < 0)
-        qCheck(false);
+        return;
     if (n > 0) {
         qCheckAccess(&list.front());
         qCheckAccess(&list.back());
@@ -2117,7 +2152,7 @@ static void qDumpQVector(QDumper &d)
     // from asking for unavailable child details
     int nn = v->size;
     if (nn < 0)
-        qCheck(false);
+        return;
     if (nn > 0) {
         //qCheckAccess(&vec.front());
         //qCheckAccess(&vec.back());
@@ -2209,7 +2244,8 @@ static void qDumpStdMap(QDumper &d)
     p = deref(p);
 
     int nn = map.size();
-    qCheck(nn >= 0);
+    if (nn < 0)
+        return;
     DummyType::const_iterator it = map.begin();
     for (int i = 0; i < nn && i < 10 && it != map.end(); ++i, ++it)
         qCheckAccess(it.operator->());
@@ -2274,7 +2310,8 @@ static void qDumpStdSet(QDumper &d)
     p = deref(p);
 
     int nn = set.size();
-    qCheck(nn >= 0);
+    if (nn < 0)
+        return;
     DummyType::const_iterator it = set.begin();
     for (int i = 0; i < nn && i < 10 && it != set.end(); ++i, ++it)
         qCheckAccess(it.operator->());
@@ -2361,7 +2398,7 @@ static void qDumpStdVector(QDumper &d)
     // from asking for unavailable child details
     int nn = (v->finish - v->start) / d.extraInt[0];
     if (nn < 0)
-        qCheck(false);
+        return;
     if (nn > 0) {
         qCheckAccess(v->start);
         qCheckAccess(v->finish);
@@ -2402,10 +2439,14 @@ static void qDumpStdVectorBool(QDumper &d)
 
 static void handleProtocolVersion2and3(QDumper & d)
 {
+
     if (!d.outertype[0]) {
         qDumpUnknown(d);
         return;
     }
+#ifdef Q_CC_MSVC // Catch exceptions with MSVC/CDB
+    __try {
+#endif
 
     d.setupTemplateParameters();
     P(d, "iname", d.iname);
@@ -2551,6 +2592,12 @@ static void handleProtocolVersion2and3(QDumper & d)
 
     if (!d.success)
         qDumpUnknown(d);
+#ifdef Q_CC_MSVC // Catch exceptions with MSVC/CDB
+    } __except(EXCEPTION_EXECUTE_HANDLER) {
+        qDumpUnknown(d, DUMPUNKNOWN_MESSAGE" <exception>");
+    }
+#endif
+
 }
 
 } // anonymous namespace
diff --git a/src/plugins/coreplugin/outputpane.cpp b/src/plugins/coreplugin/outputpane.cpp
index c1cb59462ccb6948733221504149d5bd3690a2a6..e141473162d12ad1ae0d9b88e2594617e5239ed4 100644
--- a/src/plugins/coreplugin/outputpane.cpp
+++ b/src/plugins/coreplugin/outputpane.cpp
@@ -384,7 +384,7 @@ void OutputPaneManager::ensurePageVisible(int idx)
     }
 }
 
-
+// Slot connected to showPage signal of each page
 void OutputPaneManager::showPage(bool focus)
 {
     int idx = findIndexForPage(qobject_cast<IOutputPane*>(sender()));
diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri
index c5680e705cc88c09879a5119ec6cc3bac225dc24..b602ef639a3619f6c45fde00a9d799aae8bf190b 100644
--- a/src/plugins/debugger/cdb/cdb.pri
+++ b/src/plugins/debugger/cdb/cdb.pri
@@ -34,6 +34,7 @@ HEADERS += \
     $$PWD/cdbdebugoutput.h \
     $$PWD/cdbsymbolgroupcontext.h \
     $$PWD/cdbstacktracecontext.h \
+    $$PWD/cdbstackframecontext.h \
     $$PWD/cdbbreakpoint.h \
     $$PWD/cdbmodules.h \
     $$PWD/cdbassembler.h \
@@ -46,6 +47,7 @@ SOURCES += \
     $$PWD/cdbdebugeventcallback.cpp \
     $$PWD/cdbdebugoutput.cpp \
     $$PWD/cdbsymbolgroupcontext.cpp \
+    $$PWD/cdbstackframecontext.cpp \
     $$PWD/cdbstacktracecontext.cpp \
     $$PWD/cdbbreakpoint.cpp \
     $$PWD/cdbmodules.cpp \
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index a60057071b638cfc9aa6986b9027e8b4bcaa6532..e79d9dfdb5e952b78f74ee83eef32f53e593675e 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -29,8 +29,9 @@
 
 #include "cdbdebugengine.h"
 #include "cdbdebugengine_p.h"
-#include "cdbsymbolgroupcontext.h"
 #include "cdbstacktracecontext.h"
+#include "cdbstackframecontext.h"
+#include "cdbsymbolgroupcontext.h"
 #include "cdbbreakpoint.h"
 #include "cdbmodules.h"
 #include "cdbassembler.h"
@@ -274,7 +275,7 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *parent,
     m_hDebuggeeProcess(0),
     m_hDebuggeeThread(0),
     m_breakEventMode(BreakEventHandle),
-    m_dumper(&m_cif),
+    m_dumper(new CdbDumperHelper(parent, &m_cif)),
     m_watchTimer(-1),
     m_debugEventCallBack(engine),
     m_engine(engine),
@@ -464,7 +465,7 @@ bool CdbDebugEngine::startDebugger()
             dumperEnabled = false;
         }
     }
-    m_d->m_dumper.reset(dumperLibName, dumperEnabled);
+    m_d->m_dumper->reset(dumperLibName, dumperEnabled);
     m_d->m_debuggerManager->showStatusMessage("Starting Debugger", -1);
     QString errorMessage;
     bool rc = false;
@@ -590,19 +591,20 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
     } else {
         m_currentThreadId = 0;
     }
-    // Set initial breakpoints
+    // Clear any saved breakpoints and set initial breakpoints
+    m_engine->executeDebuggerCommand(QLatin1String("bc"));
     if (m_debuggerManagerAccess->breakHandler()->hasPendingBreakpoints())
         m_engine->attemptBreakpointSynchronization();    
     // At any event, we want a temporary breakpoint at main() to load
     // the dumpers.
-    if (m_dumper.state() == CdbDumperHelper::NotLoaded) {
+    if (m_dumper->state() == CdbDumperHelper::NotLoaded) {
         if (!hasBreakPointAtMain(m_debuggerManagerAccess->breakHandler())) {
+            QString errorMessage;
             CDBBreakPoint mainBP;
             // Do not resolve at this point in the rare event someone
             // has main in a module
             mainBP.funcName = QLatin1String("main");            
             mainBP.oneShot = true;
-            QString errorMessage;
             if (!mainBP.add(m_cif.debugControl, &errorMessage))
                 m_debuggerManagerAccess->showQtDumperLibraryWarning(errorMessage);
         }
@@ -675,13 +677,13 @@ void CdbDebugEngine::exitDebugger()
     killWatchTimer();
 }
 
-CdbSymbolGroupContext *CdbDebugEnginePrivate::getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const
+CdbStackFrameContext *CdbDebugEnginePrivate::getStackFrameContext(int frameIndex, QString *errorMessage) const
 {
     if (!m_currentStackTrace) {
         *errorMessage = QLatin1String(msgNoStackTraceC);
         return 0;
     }
-    if (CdbSymbolGroupContext *sg = m_currentStackTrace->symbolGroupContextAt(frameIndex, errorMessage))
+    if (CdbStackFrameContext *sg = m_currentStackTrace->frameContextAt(frameIndex, errorMessage))
         return sg;
     return 0;
 }
@@ -718,8 +720,8 @@ bool CdbDebugEnginePrivate::updateLocals(int frameIndex,
     }
 
     bool success = false;
-    if (CdbSymbolGroupContext *sgc = getStackFrameSymbolGroupContext(frameIndex, errorMessage))
-        success = CdbSymbolGroupContext::populateModelInitially(sgc, wh, errorMessage);
+    if (CdbStackFrameContext *sgc = getStackFrameContext(frameIndex, errorMessage))
+        success = sgc->populateModelInitially(wh, errorMessage);
 
     wh->rebuildModel();
     return success;
@@ -800,8 +802,8 @@ void CdbDebugEngine::updateWatchModel()
         filterEvaluateWatchers(&incomplete, watchHandler);
         // Do locals. We might get called while running when someone enters watchers
         if (!incomplete.empty()) {
-            CdbSymbolGroupContext *sg = m_d->m_currentStackTrace->symbolGroupContextAt(frameIndex, &errorMessage);
-            if (!sg || !CdbSymbolGroupContext::completeModel(sg, incomplete, watchHandler, &errorMessage))
+            CdbStackFrameContext *sg = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
+            if (!sg || !sg->completeModel(incomplete, watchHandler, &errorMessage))
                 break;
         }
         watchHandler->rebuildModel();
@@ -1016,7 +1018,7 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v
     bool success = false;
     do {
         QString newValue;
-        CdbSymbolGroupContext *sg = m_d->getStackFrameSymbolGroupContext(frameIndex, &errorMessage);
+        CdbStackFrameContext *sg = m_d->getStackFrameContext(frameIndex, &errorMessage);
         if (!sg)
             break;
         if (!sg->assignValue(expr, value, &newValue, &errorMessage))
@@ -1061,17 +1063,30 @@ bool CdbDebugEngine::evaluateExpression(const QString &expression,
                                         QString *value,
                                         QString *type,
                                         QString *errorMessage)
+{
+    DEBUG_VALUE debugValue;
+    if (!m_d->evaluateExpression(m_d->m_cif.debugControl, expression, &debugValue, errorMessage))
+        return false;
+    *value = CdbSymbolGroupContext::debugValueToString(debugValue, m_d->m_cif.debugControl, type);
+    return true;
+}
+
+bool CdbDebugEnginePrivate::evaluateExpression(CIDebugControl *ctrl,
+                                               const QString &expression,
+                                               DEBUG_VALUE *debugValue,
+                                               QString *errorMessage)
 {
     if (debugCDB > 1)
         qDebug() << Q_FUNC_INFO << expression;
-    DEBUG_VALUE debugValue;
-    memset(&debugValue, 0, sizeof(DEBUG_VALUE));
+
+    memset(debugValue, 0, sizeof(DEBUG_VALUE));
     // Original syntax must be restored, else setting breakpoints will fail.
-    SyntaxSetter syntaxSetter(m_d->m_cif.debugControl, DEBUG_EXPR_CPLUSPLUS);
+    SyntaxSetter syntaxSetter(ctrl, DEBUG_EXPR_CPLUSPLUS);
     ULONG errorPosition = 0;
-    const HRESULT hr = m_d->m_cif.debugControl->EvaluateWide(expression.utf16(),
-                                                          DEBUG_VALUE_INVALID, &debugValue,
-                                                          &errorPosition);    if (FAILED(hr)) {
+    const HRESULT hr = ctrl->EvaluateWide(expression.utf16(),
+                                          DEBUG_VALUE_INVALID, debugValue,
+                                          &errorPosition);
+    if (FAILED(hr)) {
         if (HRESULT_CODE(hr) == 517) {
             *errorMessage = QString::fromLatin1("Unable to evaluate '%1': Expression out of scope.").
                             arg(expression);
@@ -1081,7 +1096,6 @@ bool CdbDebugEngine::evaluateExpression(const QString &expression,
         }
         return false;
     }
-    *value = CdbSymbolGroupContext::debugValueToString(debugValue, m_d->m_cif.debugControl, type);
     return true;
 }
 
@@ -1355,14 +1369,14 @@ void CdbDebugEnginePrivate::handleDebugEvent()
     case BreakEventHandle:
     case BreakEventMain:
         if (mode == BreakEventMain)
-            m_dumper.load(m_debuggerManager, m_debuggerManagerAccess);
+            m_dumper->load(m_debuggerManager);
         m_debuggerManagerAccess->notifyInferiorStopped();
         updateThreadList();
         updateStackTrace();
         break;
     case BreakEventMainLoadDumpers:
         // Temp stop to load dumpers    
-        m_dumper.load(m_debuggerManager, m_debuggerManagerAccess);
+        m_dumper->load(m_debuggerManager);
         m_engine->startWatchTimer();
         continueInferiorProcess();
         break;
@@ -1436,7 +1450,7 @@ void CdbDebugEnginePrivate::updateStackTrace()
     QString errorMessage;
     m_engine->reloadRegisters();
     m_currentStackTrace =
-            CdbStackTraceContext::create(&m_cif, m_currentThreadId, &errorMessage);
+            CdbStackTraceContext::create(m_dumper, m_currentThreadId, &errorMessage);
     if (!m_currentStackTrace) {
         qWarning("%s: failed to create trace context: %s", Q_FUNC_INFO, qPrintable(errorMessage));
         return;
diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h
index 61c7216a286be487df558a3705d326a7547794b1..04636a72167dc0e92123fac421fd14676014e7ba 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine_p.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h
@@ -46,7 +46,7 @@ namespace Internal {
 class DebuggerManager;
 class IDebuggerManagerAccessForEngines;
 class WatchHandler;
-class CdbSymbolGroupContext;
+class CdbStackFrameContext;
 class CdbStackTraceContext;
 
 // Thin wrapper around the 'DBEng' debugger engine shared library
@@ -125,7 +125,7 @@ struct CdbDebugEnginePrivate
     void cleanStackTrace();
     void clearForRun();
     void handleModuleLoad(const QString &);
-    CdbSymbolGroupContext *getStackFrameSymbolGroupContext(int frameIndex, QString *errorMessage) const;
+    CdbStackFrameContext *getStackFrameContext(int frameIndex, QString *errorMessage) const;
     void clearDisplay();
 
     bool interruptInterferiorProcess(QString *errorMessage);
@@ -136,6 +136,7 @@ struct CdbDebugEnginePrivate
     bool attemptBreakpointSynchronization(QString *errorMessage);
 
     static bool executeDebuggerCommand(CIDebugControl *ctrl, const QString &command, QString *errorMessage);
+    static bool evaluateExpression(CIDebugControl *ctrl, const QString &expression, DEBUG_VALUE *v, QString *errorMessage);
 
     const QSharedPointer<CdbOptions>  m_options;
     HANDLE                  m_hDebuggeeProcess;
@@ -147,7 +148,7 @@ struct CdbDebugEnginePrivate
     CdbComInterfaces        m_cif;
     CdbDebugEventCallback   m_debugEventCallBack;
     CdbDebugOutput          m_debugOutputCallBack;    
-    CdbDumperHelper         m_dumper;
+    QSharedPointer<CdbDumperHelper> m_dumper;
 
     CdbDebugEngine* m_engine;
     DebuggerManager *m_debuggerManager;
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
index 372cda234c7a3bdcdba02a049471b1967dca766d..07eab3215e017a6a253b49cef4167e9b1b4ee6d0 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
@@ -318,14 +318,16 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str)
 }
 
 // Format exception with stacktrace in case of C++ exception
-void formatException(const EXCEPTION_RECORD64 *e, CdbComInterfaces &cif, QTextStream &str)
+void formatException(const EXCEPTION_RECORD64 *e,
+                     const QSharedPointer<CdbDumperHelper> &dumper,
+                     QTextStream &str)
 {
     formatException(e, str);
     if (e->ExceptionCode == cppExceptionCode) {
         QString errorMessage;
         ULONG currentThreadId = 0;
-        cif.debugSystemObjects->GetCurrentThreadId(&currentThreadId);
-        if (CdbStackTraceContext *stc = CdbStackTraceContext::create(&cif, currentThreadId, &errorMessage)) {
+        dumper->comInterfaces()->debugSystemObjects->GetCurrentThreadId(&currentThreadId);
+        if (CdbStackTraceContext *stc = CdbStackTraceContext::create(dumper, currentThreadId, &errorMessage)) {
             str << "at:\n";
             stc->format(str);
             str <<'\n';
@@ -343,7 +345,7 @@ STDMETHODIMP CdbDebugEventCallback::Exception(
     QString msg;
     {
         QTextStream str(&msg);
-        formatException(Exception, m_pEngine->m_d->m_cif, str);        
+        formatException(Exception, m_pEngine->m_d->m_dumper, str);
     }
     if (debugCDB)
         qDebug() << Q_FUNC_INFO << '\n' << msg;
@@ -469,6 +471,37 @@ STDMETHODIMP CdbDebugEventCallback::SystemError(
     return S_OK;
 }
 
+// -----------ExceptionLoggerEventCallback
+CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(const QString &logPrefix,
+                                                           IDebuggerManagerAccessForEngines *access) :
+    m_logPrefix(logPrefix),
+    m_access(access)
+{
+}
+
+STDMETHODIMP CdbExceptionLoggerEventCallback::GetInterestMask(THIS_ __out PULONG mask)
+{
+    *mask = DEBUG_EVENT_EXCEPTION;
+    return S_OK;
+}
+
+STDMETHODIMP CdbExceptionLoggerEventCallback::Exception(
+    THIS_
+    __in PEXCEPTION_RECORD64 Exception,
+    __in ULONG /* FirstChance */
+    )
+{
+    m_exceptionMessages.push_back(QString());
+    {
+        QTextStream str(&m_exceptionMessages.back());
+        formatException(Exception, str);
+    }
+    if (debugCDB)
+        qDebug() << Q_FUNC_INFO << '\n' << m_exceptionMessages.back();
+    m_access->showDebuggerOutput(m_logPrefix, m_exceptionMessages.back());
+    return S_OK;
+}
+
 // -----------IgnoreDebugEventCallback
 IgnoreDebugEventCallback::IgnoreDebugEventCallback()
 {
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.h b/src/plugins/debugger/cdb/cdbdebugeventcallback.h
index d7fa7f8829f456e22df1c346253dfca9cef8bfc5..2ea3993c130ffe78f809c9f7f1c9f51a908ba0a6 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.h
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.h
@@ -32,12 +32,13 @@
 
 #include "cdbcom.h"
 
-#include <QtCore/QtGlobal>
+#include <QtCore/QStringList>
 
 namespace Debugger {
 namespace Internal {
 
 class CdbDebugEngine;
+class IDebuggerManagerAccessForEngines;
 
 // Base class for event callbacks that takes care
 // Active X magic. Provides base implementations with
@@ -235,6 +236,34 @@ private:
     CdbDebugEngine *m_pEngine;
 };
 
+// Event handler logs exceptions to the debugger window
+// and ignores the rest. To be used for running dumper calls.
+class CdbExceptionLoggerEventCallback : public CdbDebugEventCallbackBase
+{
+public:
+    explicit CdbExceptionLoggerEventCallback(const QString &logPrefix,
+                                             IDebuggerManagerAccessForEngines *access);
+
+    STDMETHOD(GetInterestMask)(
+        THIS_
+        __out PULONG mask
+        );
+
+    STDMETHOD(Exception)(
+        THIS_
+        __in PEXCEPTION_RECORD64 Exception,
+        __in ULONG FirstChance
+        );
+
+    int exceptionCount() const { return m_exceptionMessages.size(); }
+    QStringList exceptionMessages() const { return m_exceptionMessages; }
+
+private:
+    const QString m_logPrefix;
+    IDebuggerManagerAccessForEngines *m_access;
+    QStringList m_exceptionMessages;
+};
+
 // Event handler that ignores everything
 class IgnoreDebugEventCallback : public CdbDebugEventCallbackBase
 {
diff --git a/src/plugins/debugger/cdb/cdbdebugoutput.cpp b/src/plugins/debugger/cdb/cdbdebugoutput.cpp
index bb89a2f7eca0881ed392f10126fbe478ecd5a5d2..020812b7e0b851c390eaf20314d7dee9f9b1ea73 100644
--- a/src/plugins/debugger/cdb/cdbdebugoutput.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugoutput.cpp
@@ -80,7 +80,8 @@ STDMETHODIMP CdbDebugOutputBase::Output(
     IN PCWSTR text
     )
 {
-    output(mask, QString::fromUtf16(text));
+    const QString msg = QString::fromUtf16(text);
+    output(mask, msg.trimmed());
     return S_OK;
 }
 
diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
index a0aa5142d15740bd3d7ee5c9e6aed14c69bb48fb..1357eb99d6f6abeba672e0ac3780f243b3932779 100644
--- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp
+++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
@@ -32,7 +32,8 @@
 #include "cdbdebugengine_p.h"
 #include "cdbdebugoutput.h"
 #include "cdbdebugeventcallback.h"
-#include "watchutils.h"
+#include "cdbsymbolgroupcontext.h"
+#include "watchhandler.h"
 
 #include <QtCore/QRegExp>
 #include <QtCore/QCoreApplication>
@@ -43,21 +44,20 @@ enum { loadDebug = 0 };
 static const char *dumperModuleNameC = "gdbmacros";
 static const char *qtCoreModuleNameC = "QtCore";
 static const ULONG waitTimeOutMS = 30000;
-
+static const char *dumperPrefixC  = "dumper:";
 namespace Debugger {
 namespace Internal {
 
 // Alloc memory in debuggee using the ".dvalloc" command as
 // there seems to be no API for it.
-static bool allocDebuggeeMemory(CIDebugControl *ctl,
-                                CIDebugClient *client,
+static bool allocDebuggeeMemory(CdbComInterfaces *cif,
                                 int size, ULONG64 *address, QString *errorMessage)
 {
     *address = 0;
     const QString allocCmd = QLatin1String(".dvalloc ") + QString::number(size);
     StringOutputHandler stringHandler;
-    OutputRedirector redir(client, &stringHandler);
-    if (!CdbDebugEnginePrivate::executeDebuggerCommand(ctl, allocCmd, errorMessage))
+    OutputRedirector redir(cif->debugClient, &stringHandler);
+    if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, allocCmd, errorMessage))
         return false;
    // "Allocated 1000 bytes starting at 003a0000" .. hopefully never localized    
     bool ok = false;
@@ -68,7 +68,7 @@ static bool allocDebuggeeMemory(CIDebugControl *ctl,
         if (ok)
             *address = addri;
     }
-     if (loadDebug)
+     if (loadDebug > 1)
         qDebug() << Q_FUNC_INFO << '\n' << output << *address << ok;
     if (!ok) {
         *errorMessage = QString::fromLatin1("Failed to parse output '%1'").arg(output);
@@ -78,18 +78,16 @@ static bool allocDebuggeeMemory(CIDebugControl *ctl,
 }
 
 // Alloc an AscII string in debuggee
-static bool createDebuggeeAscIIString(CIDebugControl *ctl,
-                                CIDebugClient *client,
-                                CIDebugDataSpaces *data,
-                                const QString &s,
-                                ULONG64 *address,
-                                QString *errorMessage)
+static bool createDebuggeeAscIIString(CdbComInterfaces *cif,
+                                      const QString &s,
+                                      ULONG64 *address,
+                                      QString *errorMessage)
 {
     QByteArray sAsciiData = s.toLocal8Bit();
     sAsciiData += '\0';
-    if (!allocDebuggeeMemory(ctl, client, sAsciiData.size(), address, errorMessage))
+    if (!allocDebuggeeMemory(cif, sAsciiData.size(), address, errorMessage))
         return false;
-    const HRESULT hr = data->WriteVirtual(*address, sAsciiData.data(), sAsciiData.size(), 0);
+    const HRESULT hr = cif->debugDataSpaces->WriteVirtual(*address, sAsciiData.data(), sAsciiData.size(), 0);
     if (FAILED(hr)) {
         *errorMessage= msgComFailed("WriteVirtual", hr);
         return false;
@@ -101,21 +99,20 @@ static bool createDebuggeeAscIIString(CIDebugControl *ctl,
 // the QtCored4.pdb file to be present as we need "qstrdup"
 // as dummy symbol. This is ok ATM since dumpers only
 // make sense for Qt apps.
-static bool debuggeeLoadLibrary(CIDebugControl *ctl,
-                         CIDebugClient *client,
-                         CIDebugSymbols *syms,
-                         CIDebugDataSpaces *data,
-                         const QString &moduleName, QString *errorMessage)
+static bool debuggeeLoadLibrary(IDebuggerManagerAccessForEngines *access,
+                                CdbComInterfaces *cif,
+                                const QString &moduleName,
+                                QString *errorMessage)
 {
-    if (loadDebug)
+    if (loadDebug > 1)
         qDebug() << Q_FUNC_INFO << moduleName;
     // Try to ignore the breakpoints
-    IgnoreDebugEventCallback devNull;
-    EventCallbackRedirector eventRedir(client, &devNull);
+    CdbExceptionLoggerEventCallback exLogger(QLatin1String(dumperPrefixC), access);
+    EventCallbackRedirector eventRedir(cif->debugClient, &exLogger);
     // Make a call to LoadLibraryA. First, reserve memory in debugger
     // and copy name over.
     ULONG64 nameAddress;
-    if (!createDebuggeeAscIIString(ctl, client, data, moduleName, &nameAddress, errorMessage))
+    if (!createDebuggeeAscIIString(cif, moduleName, &nameAddress, errorMessage))
         return false;
     // We want to call "HMODULE LoadLibraryA(LPCTSTR lpFileName)"
     // (void* LoadLibraryA(char*)). However, despite providing a symbol
@@ -125,21 +122,21 @@ static bool debuggeeLoadLibrary(CIDebugControl *ctl,
     // Prepare call: Locate 'qstrdup' in the (potentially namespaced) corelib. For some
     // reason, the symbol is present in QtGui as well without type information.
     QString dummyFunc = QLatin1String("*qstrdup");
-    if (resolveSymbol(syms, QLatin1String("QtCore[d]*4!"), &dummyFunc, errorMessage) != ResolveSymbolOk)
+    if (resolveSymbol(cif->debugSymbols, QLatin1String("QtCore[d]*4!"), &dummyFunc, errorMessage) != ResolveSymbolOk)
         return false;
     QString callCmd = QLatin1String(".call ");
     callCmd += dummyFunc;
     callCmd += QLatin1String("(0x");
     callCmd += QString::number(nameAddress, 16);
     callCmd += QLatin1Char(')');
-    if (!CdbDebugEnginePrivate::executeDebuggerCommand(ctl, callCmd, errorMessage))
+    if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, callCmd, errorMessage))
         return false;
-    if (!CdbDebugEnginePrivate::executeDebuggerCommand(ctl, QLatin1String("r eip=Kernel32!LoadLibraryA"), errorMessage))
+    if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, QLatin1String("r eip=Kernel32!LoadLibraryA"), errorMessage))
         return false;
     // This will hit a breakpoint.
-    if (!CdbDebugEnginePrivate::executeDebuggerCommand(ctl, QString(QLatin1Char('g')), errorMessage))
+    if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, QString(QLatin1Char('g')), errorMessage))
         return false;    
-    const HRESULT hr = ctl->WaitForEvent(0, waitTimeOutMS);
+    const HRESULT hr = cif->debugControl->WaitForEvent(0, waitTimeOutMS);
     if (FAILED(hr)) {
         *errorMessage = msgComFailed("WaitForEvent", hr);
         return false;
@@ -147,66 +144,13 @@ static bool debuggeeLoadLibrary(CIDebugControl *ctl,
     return true;
 }
 
-// ------------------- CdbDumperHelper::DumperInputParameters
-struct CdbDumperHelper::DumperInputParameters {
-    DumperInputParameters(int protocolVersion_ = 1,
-                          int token_ = 1,
-                          quint64 Address_ = 0,
-                          bool dumpChildren_ = false,
-                          int extraInt0_ = 0,
-                          int extraInt1_ = 0,
-                          int extraInt2_ = 0,
-                          int extraInt3_ = 0);
-
-    QString command(const QString &dumpFunction) const;
-
-    int protocolVersion;
-    int token;
-    quint64 address;
-    bool dumpChildren;
-    int extraInt0;
-    int extraInt1;
-    int extraInt2;
-    int extraInt3;
-};
-
-CdbDumperHelper::DumperInputParameters::DumperInputParameters(int protocolVersion_,
-                                                              int token_,
-                                                              quint64 address_,
-                                                              bool dumpChildren_,
-                                                              int extraInt0_,
-                                                              int extraInt1_,
-                                                              int extraInt2_,
-                                                              int extraInt3_) :
-    protocolVersion(protocolVersion_),
-    token(token_),
-    address(address_),
-    dumpChildren(dumpChildren_),
-    extraInt0(extraInt0_),
-    extraInt1(extraInt1_),
-    extraInt2(extraInt2_),
-    extraInt3(extraInt3_)
-{
-}
-
-QString CdbDumperHelper::DumperInputParameters::command(const QString &dumpFunction) const
-{
-    QString rc;
-    QTextStream str(&rc);
-    str.setIntegerBase(16);
-    str << ".call " << dumpFunction << '(' << protocolVersion << ',' << token << ',';
-    str.setIntegerBase(16);
-    str << "0x" << address;
-    str.setIntegerBase(10);
-    str << ',' << (dumpChildren ? 1 : 0) << ',' << extraInt0 << ',' << extraInt1
-            << ',' << extraInt2 << ',' << extraInt3 << ')';
-    return rc;
-}
-
 // ------------------- CdbDumperHelper
 
-CdbDumperHelper::CdbDumperHelper(CdbComInterfaces *cif) :    
+CdbDumperHelper::CdbDumperHelper(IDebuggerManagerAccessForEngines *access,
+                                 CdbComInterfaces *cif) :
+    m_messagePrefix(QLatin1String(dumperPrefixC)),
     m_state(NotLoaded),
+    m_access(access),
     m_cif(cif),
     m_inBufferAddress(0),
     m_inBufferSize(0),
@@ -234,24 +178,23 @@ void CdbDumperHelper::reset(const QString &library, bool enabled)
     m_library = library;
     m_state = enabled ? NotLoaded : Disabled;
     m_dumpObjectSymbol = QLatin1String("qDumpObjectData440");
-    m_knownTypes.clear();
-    m_qtVersion.clear();
-    m_qtNamespace.clear();
+    m_helper.clear();
     m_inBufferAddress = m_outBufferAddress = 0;
     m_inBufferSize = m_outBufferSize = 0;
+    m_typeSizeCache.clear();
+    m_failedTypes.clear();
     clearBuffer();
 }
 
 // Attempt to load and initialize dumpers, give feedback
 // to user.
-void CdbDumperHelper::load(DebuggerManager *manager, IDebuggerManagerAccessForEngines *access)
+void CdbDumperHelper::load(DebuggerManager *manager)
 {
     enum Result { Failed, Succeeded, NoQtApp };
 
     if (m_state != NotLoaded)
         return;
     manager->showStatusMessage(QCoreApplication::translate("CdbDumperHelper", "Loading dumpers..."), 10000);
-    const QString messagePrefix = QLatin1String("dumper:");
     QString message;
     Result result = Failed;
     do {
@@ -266,12 +209,11 @@ void CdbDumperHelper::load(DebuggerManager *manager, IDebuggerManagerAccessForEn
         // Make sure the dumper lib is loaded.
         if (modules.filter(QLatin1String(dumperModuleNameC), Qt::CaseInsensitive).isEmpty()) {
             // Try to load
-            if (!debuggeeLoadLibrary(m_cif->debugControl, m_cif->debugClient, m_cif->debugSymbols, m_cif->debugDataSpaces,
-                                     m_library, &message)) {
+            if (!debuggeeLoadLibrary(m_access, m_cif, m_library, &message)) {
                 break;
             }
         } else {
-            access->showDebuggerOutput(messagePrefix, QCoreApplication::translate("CdbDumperHelper", "The dumper module appears to be already loaded."));
+            m_access->showDebuggerOutput(m_messagePrefix, QCoreApplication::translate("CdbDumperHelper", "The dumper module appears to be already loaded."));
         }
         // Resolve symbols and do call to get types
         if (!resolveSymbols(&message))
@@ -285,17 +227,17 @@ void CdbDumperHelper::load(DebuggerManager *manager, IDebuggerManagerAccessForEn
     switch (result) {
     case Failed:
         message = QCoreApplication::translate("CdbDumperHelper", "The dumper library '%1' could not be loaded:\n%2").arg(m_library, message);
-        access->showDebuggerOutput(messagePrefix, message);
-        access->showQtDumperLibraryWarning(message);
+        m_access->showDebuggerOutput(m_messagePrefix, message);
+        m_access->showQtDumperLibraryWarning(message);
         m_state = Disabled;
         break;
     case Succeeded:
-        access->showDebuggerOutput(messagePrefix, message);
-        access->showDebuggerOutput(messagePrefix, statusMessage());
+        m_access->showDebuggerOutput(m_messagePrefix, message);
+        m_access->showDebuggerOutput(m_messagePrefix, m_helper.toString());
         m_state = Loaded;
         break;
     case NoQtApp:
-        access->showDebuggerOutput(messagePrefix, message);
+        m_access->showDebuggerOutput(m_messagePrefix, message);
         m_state = Disabled;
         break;
     }    
@@ -303,15 +245,6 @@ void CdbDumperHelper::load(DebuggerManager *manager, IDebuggerManagerAccessForEn
         qDebug() << Q_FUNC_INFO << "\n<" << result << '>' << m_state << message;
 }
 
-QString CdbDumperHelper::statusMessage() const
-{
-    const QString nameSpace = m_qtNamespace.isEmpty() ? QCoreApplication::translate("CdbDumperHelper", "<none>") : m_qtNamespace;
-    return QCoreApplication::translate("CdbDumperHelper",
-                                       "%n known types, Qt version: %1, Qt namespace: %2",
-                                       0, QCoreApplication::CodecForTr,
-                                       m_knownTypes.size()).arg(m_qtVersion, nameSpace);
-}
-
 // Retrieve address and optionally size of a symbol.
 static inline bool getSymbolAddress(CIDebugSymbols *sg,
                                     const QString &name,
@@ -373,41 +306,82 @@ bool CdbDumperHelper::resolveSymbols(QString *errorMessage)
 bool CdbDumperHelper::getKnownTypes(QString *errorMessage)
 {
     QByteArray output;
-    if (!callDumper(DumperInputParameters(1), &output, errorMessage)) {
+    QString callCmd;
+    QTextStream(&callCmd) << ".call " << m_dumpObjectSymbol << "(1,0,0,0,0,0,0,0)";
+    const char *outData;
+    if (!callDumper(callCmd, QByteArray(), &outData, errorMessage)) {
         return false;
     }
-    if (!parseQueryDumperOutput(output, &m_knownTypes, &m_qtVersion, &m_qtNamespace)) {
+    if (!m_helper.parseQuery(outData, QtDumperHelper::CdbDebugger)) {
      *errorMessage = QString::fromLatin1("Unable to parse the dumper output: '%1'").arg(QString::fromAscii(output));
     }
     if (loadDebug)
-        qDebug() << Q_FUNC_INFO << m_knownTypes << m_qtVersion  << m_qtNamespace;
+        qDebug() << Q_FUNC_INFO << m_helper.toString(true);
     return true;
 }
 
-bool CdbDumperHelper::callDumper(const DumperInputParameters &p, QByteArray *output, QString *errorMessage)
+// Write to debuggee memory in chunks
+bool CdbDumperHelper::writeToDebuggee(CIDebugDataSpaces *ds, const QByteArray &buffer, quint64 address, QString *errorMessage)
 {
-    IgnoreDebugEventCallback devNull;
-    EventCallbackRedirector eventRedir(m_cif->debugClient, &devNull);
-    const QString callCmd = p.command(m_dumpObjectSymbol);
-    // Set up call and a temporary breakpoint after it.
+    char *ptr = const_cast<char*>(buffer.data());
+    ULONG bytesToWrite = buffer.size();
+    while (bytesToWrite > 0) {
+        ULONG bytesWritten = 0;
+        const HRESULT hr = ds->WriteVirtual(address, ptr, bytesToWrite, &bytesWritten);
+        if (FAILED(hr)) {
+            *errorMessage = msgComFailed("WriteVirtual", hr);
+            return false;
+        }
+        bytesToWrite -= bytesWritten;
+        ptr += bytesWritten;
+    }
+    return true;
+}
+
+bool CdbDumperHelper::callDumper(const QString &callCmd, const QByteArray &inBuffer, const char **outDataPtr, QString *errorMessage)
+{
+    *outDataPtr = 0;
+    CdbExceptionLoggerEventCallback exLogger(m_messagePrefix, m_access);
+    EventCallbackRedirector eventRedir(m_cif->debugClient, &exLogger);
+    // write input buffer
+    if (!inBuffer.isEmpty()) {
+        if (!writeToDebuggee(m_cif->debugDataSpaces, inBuffer, m_inBufferAddress, errorMessage))
+            return false;
+    }
     if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, callCmd, errorMessage))
-        return false;    
-    // Go and filter away break event
-    if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, QString(QLatin1Char('g')), errorMessage))
         return false;
-    HRESULT hr = m_cif->debugControl->WaitForEvent(0, waitTimeOutMS);
-    if (FAILED(hr)) {
-        *errorMessage = msgComFailed("WaitForEvent", hr);
+    // Set up call and a temporary breakpoint after it.
+    // Try to skip debuggee crash exceptions and dumper exceptions
+    // by using 'gh' (go handled)
+    for (int i = 0; i < 10; i++) {
+        const int oldExceptionCount = exLogger.exceptionCount();
+        // Go. If an exception occurs in loop 2, let the dumper handle it.
+        const QString goCmd = i ? QString(QLatin1String("gN")) : QString(QLatin1Char('g'));
+        if (!CdbDebugEnginePrivate::executeDebuggerCommand(m_cif->debugControl, goCmd, errorMessage))
+            return false;
+        HRESULT hr = m_cif->debugControl->WaitForEvent(0, waitTimeOutMS);
+        if (FAILED(hr)) {
+            *errorMessage = msgComFailed("WaitForEvent", hr);
+            return false;
+        }
+        const int newExceptionCount = exLogger.exceptionCount();
+        // no new exceptions? -> break
+        if (oldExceptionCount == newExceptionCount)
+            break;
+    }
+    if (exLogger.exceptionCount()) {
+        const QString exMsgs = exLogger.exceptionMessages().join(QString(QLatin1Char(',')));
+        *errorMessage = QString::fromLatin1("Exceptions occurred during the dumper call: %1").arg(exMsgs);
         return false;
     }
     // Read output
-    hr = m_cif->debugDataSpaces->ReadVirtual(m_outBufferAddress, m_buffer, m_outBufferSize, 0);
+    const HRESULT hr = m_cif->debugDataSpaces->ReadVirtual(m_outBufferAddress, m_buffer, m_outBufferSize, 0);
     if (FAILED(hr)) {
         *errorMessage = msgComFailed("ReadVirtual", hr);
         return false;
     }
     // see QDumper implementation
-    const char result = m_buffer[0];
+    const char result = m_buffer[0];    
     switch (result) {
     case 't':
         break;
@@ -421,7 +395,144 @@ bool CdbDumperHelper::callDumper(const DumperInputParameters &p, QByteArray *out
         *errorMessage = QString::fromLatin1("Dumper call '%1' failed ('%2').").arg(callCmd).arg(QLatin1Char(result));
         return false;
     }
-    *output = QByteArray(m_buffer + 1);
+    *outDataPtr = m_buffer + 1;
+    return true;
+}
+
+CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren, int source,
+                                                      QList<WatchData> *result, QString *errorMessage)
+{
+    // Check failure cache and supported types
+    if (m_failedTypes.contains(wd.type))
+        return DumpNotHandled;
+    const QtDumperHelper::TypeData td = m_helper.typeData(wd.type);
+    if (td.type == QtDumperHelper::UnknownType)
+        return DumpNotHandled;
+
+    // Now evaluate
+    const QString message = QCoreApplication::translate("CdbDumperHelper",
+                                                        "Querying dumpers for '%1'/'%2' (%3)").
+                                                        arg(wd.name, wd.exp, wd.type);
+    m_access->showDebuggerOutput(m_messagePrefix, message);
+    const DumpExecuteResult der = executeDump(wd, td, dumpChildren, source, result, errorMessage);
+    if (der == DumpExecuteOk)
+        return DumpOk;
+    // Cache types that fail due to complicated template size expressions.
+    // Exceptions OTOH might occur when accessing variables that are not
+    // yet initialized in a particular breakpoint. That should be ignored
+    if (der == DumpExecuteSizeFailed)
+        m_failedTypes.push_back(wd.type);    
+    // log error
+    *errorMessage = QString::fromLatin1("Unable to dump '%1' (%2): %3").arg(wd.name, wd.type, *errorMessage);
+    m_access->showDebuggerOutput(m_messagePrefix, *errorMessage);
+    return DumpError;
+}
+
+CdbDumperHelper::DumpExecuteResult
+    CdbDumperHelper::executeDump(const WatchData &wd,
+                                const QtDumperHelper::TypeData& td, bool dumpChildren, int source,
+                                QList<WatchData> *result, QString *errorMessage)
+{
+    QByteArray inBuffer;
+    QStringList extraParameters;    
+    // Build parameter list.
+    m_helper.evaluationParameters(wd, td, QtDumperHelper::CdbDebugger, &inBuffer, &extraParameters);
+    // If the parameter list contains sizeof-expressions, execute them separately
+    // and replace them by the resulting numbers
+    const QString sizeOfExpr = QLatin1String("sizeof");
+    const QStringList::iterator eend = extraParameters.end();
+    for (QStringList::iterator it = extraParameters.begin() ; it != eend; ++it) {
+        // Strip 'sizeof(X)' to 'X' and query size
+        QString &ep = *it;
+        if (ep.startsWith(sizeOfExpr)) {
+            int size;
+            ep.truncate(ep.lastIndexOf(QLatin1Char(')')));
+            ep.remove(0, ep.indexOf(QLatin1Char('(')) + 1);
+            if (!getTypeSize(ep, &size, errorMessage))
+                return DumpExecuteSizeFailed;
+            if (loadDebug)
+                qDebug() << "Size" << size << ep;
+            ep = QString::number(size);
+        }
+    }
+    // Execute call
+    QString callCmd;
+    QTextStream(&callCmd) << ".call " << m_dumpObjectSymbol
+            << "(2,0," << wd.addr << ','
+            << (dumpChildren ? 1 : 0) << ',' << extraParameters.join(QString(QLatin1Char(','))) << ')';
+    if (loadDebug)
+        qDebug() << "Query: " << wd.toString() << "\nwith: " << callCmd;
+    const char *outputData;
+    if (!callDumper(callCmd, inBuffer, &outputData, errorMessage))
+        return DumpExecuteCallFailed;
+    QtDumperResult dumpResult;
+    if (!QtDumperHelper::parseValue(outputData, &dumpResult)) {
+        *errorMessage = QLatin1String("Parsing of value query output failed.");
+        return DumpExecuteCallFailed;
+    }
+    *result = dumpResult.toWatchData(source);
+    return DumpExecuteOk;
+}
+
+// Simplify some types for sizeof expressions
+static inline void simplifySizeExpression(QString *typeName)
+{
+    typeName->replace(QLatin1String("std::basic_string<char,std::char_traits<char>,std::allocator<char>>"),
+                      QLatin1String("std::string"));
+}
+
+bool CdbDumperHelper::getTypeSize(const QString &typeNameIn, int *size, QString *errorMessage)
+{
+    if (loadDebug > 1)
+        qDebug() << Q_FUNC_INFO << typeNameIn;
+    // Look up cache
+    const TypeSizeCache::const_iterator it = m_typeSizeCache.constFind(typeNameIn);
+    if (it != m_typeSizeCache.constEnd()) {
+        *size = it.value();     
+        return true;
+    }
+    QString typeName = typeNameIn;
+    simplifySizeExpression(&typeName);
+    // "std::" types sometimes only work without namespace.
+    // If it fails, try again with stripped namespace
+    *size = 0;
+    bool success = false;
+    do {
+        if (runTypeSizeQuery(typeName, size, errorMessage)) {
+            success = true;
+            break;
+        }
+        const QString stdNameSpace = QLatin1String("std::");
+        if (!typeName.contains(stdNameSpace))
+            break;
+        typeName.remove(stdNameSpace);
+        errorMessage->clear();
+        if (!runTypeSizeQuery(typeName, size, errorMessage))
+            break;
+        success = true;
+    } while (false);
+    if (success)
+        m_typeSizeCache.insert(typeName, *size);
+    return success;
+}
+
+bool CdbDumperHelper::runTypeSizeQuery(const QString &typeName, int *size, QString *errorMessage)
+{
+    // Retrieve by C++ expression. If we knew the module, we could make use
+    // of the TypeId query mechanism provided by the IDebugSymbolGroup.
+    DEBUG_VALUE sizeValue;
+    QString expression = QLatin1String("sizeof(");
+    expression += typeName;
+    expression += QLatin1Char(')');
+    if (!CdbDebugEnginePrivate::evaluateExpression(m_cif->debugControl,
+                                                  expression, &sizeValue, errorMessage))
+        return false;
+    qint64 size64;
+    if (!CdbSymbolGroupContext::debugValueToInteger(sizeValue, &size64)) {
+        *errorMessage = QLatin1String("Expression result is not an integer");
+        return false;
+    }
+    *size = static_cast<int>(size64);
     return true;
 }
 
diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.h b/src/plugins/debugger/cdb/cdbdumperhelper.h
index c5be52e22f45eef7dee26d24e78371984279eed9..2f576b196ef978ce5447b81db71e71c0db162bd8 100644
--- a/src/plugins/debugger/cdb/cdbdumperhelper.h
+++ b/src/plugins/debugger/cdb/cdbdumperhelper.h
@@ -30,7 +30,10 @@
 #ifndef CDBDUMPERHELPER_H
 #define CDBDUMPERHELPER_H
 
+#include "watchutils.h"
+#include "cdbcom.h"
 #include <QtCore/QStringList>
+#include <QtCore/QMap>
 
 namespace Debugger {
 namespace Internal {
@@ -66,7 +69,8 @@ public:
         Failed
     };
 
-    explicit CdbDumperHelper(CdbComInterfaces *cif);
+    explicit CdbDumperHelper(IDebuggerManagerAccessForEngines *access,
+                             CdbComInterfaces *cif);
     ~CdbDumperHelper();
 
     State state() const { return m_state; }
@@ -76,31 +80,50 @@ public:
     void reset(const QString &library, bool enabled);
 
     // Call in a temporary breakpoint state to actually load.
-    void load(DebuggerManager *manager, IDebuggerManagerAccessForEngines *access);
+    void load(DebuggerManager *manager);
 
-private:
-    struct DumperInputParameters;
+    enum DumpResult { DumpNotHandled, DumpOk, DumpError };
+    DumpResult dumpType(const WatchData &d, bool dumpChildren, int source,
+                        QList<WatchData> *result, QString *errorMessage);
+
+    // bool handlesType(const QString &typeName) const;
 
+    inline CdbComInterfaces *comInterfaces() const { return m_cif; }
+
+private:
     void clearBuffer();
     bool resolveSymbols(QString *errorMessage);
     bool getKnownTypes(QString *errorMessage);
-    bool callDumper(const DumperInputParameters &p, QByteArray *output, QString *errorMessage);
-    inline QString statusMessage() const;
+    bool getTypeSize(const QString &typeName, int *size, QString *errorMessage);
+    bool runTypeSizeQuery(const QString &typeName, int *size, QString *errorMessage);
+    bool callDumper(const QString &call, const QByteArray &inBuffer, const char **outputPtr, QString *errorMessage);
 
+    enum DumpExecuteResult { DumpExecuteOk, DumpExecuteSizeFailed, DumpExecuteCallFailed };
+    DumpExecuteResult executeDump(const WatchData &wd,
+                                  const QtDumperHelper::TypeData& td, bool dumpChildren, int source,
+                                  QList<WatchData> *result, QString *errorMessage);
+
+    static bool writeToDebuggee(CIDebugDataSpaces *ds, const QByteArray &buffer, quint64 address, QString *errorMessage);
+
+    const QString m_messagePrefix;
     State m_state;
+    IDebuggerManagerAccessForEngines *m_access;
     CdbComInterfaces *m_cif;
 
     QString m_library;
     QString m_dumpObjectSymbol;
-    QStringList m_knownTypes;
-    QString m_qtVersion;
-    QString m_qtNamespace;
 
     quint64 m_inBufferAddress;
     unsigned long m_inBufferSize;
     quint64 m_outBufferAddress;
     unsigned long m_outBufferSize;
     char *m_buffer;
+
+    typedef QMap<QString, int> TypeSizeCache;
+    TypeSizeCache m_typeSizeCache;
+    QStringList m_failedTypes;
+
+    QtDumperHelper m_helper;
 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..be04856ccc08eae66127acfbb3d1b54d318c2606
--- /dev/null
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
@@ -0,0 +1,189 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (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 qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "cdbstackframecontext.h"
+#include "cdbsymbolgroupcontext.h"
+#include "cdbdumperhelper.h"
+#include "debuggeractions.h"
+#include "watchhandler.h"
+
+#include <QtCore/QDebug>
+
+enum { debug = 0 };
+
+namespace Debugger {
+namespace Internal {
+
+enum { OwnerNewItem, OwnerSymbolGroup, OwnerDumper };
+
+typedef QSharedPointer<CdbDumperHelper> SharedPointerCdbDumperHelper;
+typedef QList<WatchData> WatchDataList;
+
+// Put a sequence of  WatchData into the model
+class WatchHandlerModelInserter {
+public:
+    explicit WatchHandlerModelInserter(WatchHandler *wh) : m_wh(wh) {}
+
+    inline WatchHandlerModelInserter & operator*() { return *this; }
+    inline WatchHandlerModelInserter &operator=(const WatchData &wd)  {
+        m_wh->insertData(wd);
+        return *this;
+    }
+    inline WatchHandlerModelInserter &operator++() { return *this; }
+
+private:
+    WatchHandler *m_wh;
+};
+
+// Helper to sort apart a sequence of  WatchData using the Dumpers.
+// Puts the stuff for which there is no dumper in the model
+// as is and sets ownership to symbol group. The rest goes
+// to the dumpers.
+class WatchHandlerSorterInserter {
+public:
+    explicit WatchHandlerSorterInserter(WatchHandler *wh,
+                                        const SharedPointerCdbDumperHelper &dumper);
+
+    inline WatchHandlerSorterInserter & operator*() { return *this; }
+    inline WatchHandlerSorterInserter &operator=(WatchData wd);
+    inline WatchHandlerSorterInserter &operator++() { return *this; }
+
+private:
+    WatchHandler *m_wh;
+    const SharedPointerCdbDumperHelper m_dumper;
+    QList<WatchData> m_dumperResult;
+    QStringList m_dumperINames;
+};
+
+WatchHandlerSorterInserter::WatchHandlerSorterInserter(WatchHandler *wh,
+                                                       const SharedPointerCdbDumperHelper &dumper) :
+    m_wh(wh),
+    m_dumper(dumper)
+{
+}
+
+WatchHandlerSorterInserter &WatchHandlerSorterInserter::operator=(WatchData wd)
+{
+    // Is this a child belonging to some item handled by dumpers,
+    // such as d-elements of QStrings -> just ignore it.
+    if (const int dumperINamesCount = m_dumperINames.size()) {
+        for (int i = 0; i < dumperINamesCount; i++)
+            if (wd.iname.startsWith(m_dumperINames.at(i)))
+                return *this;
+    }
+    QString errorMessage;
+    switch (m_dumper->dumpType(wd, true, OwnerDumper, &m_dumperResult, &errorMessage)) {
+    case CdbDumperHelper::DumpOk:
+        // Discard the original item and insert the dumper results
+        m_dumperINames.push_back(wd.iname + QLatin1Char('.'));
+        foreach(const WatchData &dwd, m_dumperResult)
+            m_wh->insertData(dwd);
+        break;
+    case CdbDumperHelper::DumpNotHandled:
+    case CdbDumperHelper::DumpError:
+        wd.source = OwnerSymbolGroup;
+        m_wh->insertData(wd);
+        break;
+    }
+    return *this;
+}
+
+// -----------CdbStackFrameContext
+CdbStackFrameContext::CdbStackFrameContext(const QSharedPointer<CdbDumperHelper> &dumper,
+                                           CdbSymbolGroupContext *symbolContext) :
+        m_useDumpers(dumper->state() == CdbDumperHelper::Loaded
+                     && theDebuggerBoolSetting(UseDebuggingHelpers)),
+        m_dumper(dumper),
+        m_symbolContext(symbolContext)
+{
+}
+
+bool CdbStackFrameContext::assignValue(const QString &iname, const QString &value,
+                                       QString *newValue /* = 0 */, QString *errorMessage)
+{
+    return m_symbolContext->assignValue(iname, value, newValue, errorMessage);
+}
+
+bool CdbStackFrameContext::populateModelInitially(WatchHandler *wh, QString *errorMessage)
+{
+    if (debug)
+        qDebug() << "populateModelInitially";
+    const bool rc = m_useDumpers ?
+        CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
+                                                      WatchHandlerSorterInserter(wh, m_dumper),
+                                                      errorMessage) :
+        CdbSymbolGroupContext::populateModelInitially(m_symbolContext,
+                                                      WatchHandlerModelInserter(wh),
+                                                      errorMessage);
+    return rc;
+}
+
+bool CdbStackFrameContext::completeModel(const QList<WatchData> &incompleteLocals,
+                                         WatchHandler *wh,
+                                         QString *errorMessage)
+{
+    if (debug) {
+        QDebug nsp = qDebug().nospace();
+        nsp << ">completeModel ";
+        foreach (const WatchData &wd, incompleteLocals)
+            nsp << wd.iname << ' ';
+        nsp << '\n';
+    }
+
+    if (!m_useDumpers) {
+        return CdbSymbolGroupContext::completeModel(m_symbolContext, incompleteLocals,
+                                                    WatchHandlerModelInserter(wh),
+                                                    errorMessage);
+    }
+
+    // Expand dumper items
+    int handledDumpers = 0;
+    foreach (const WatchData &cwd, incompleteLocals) {
+        if (cwd.source == OwnerDumper) { // You already know that.
+            WatchData wd = cwd;
+            wd.setAllUnneeded();
+            wh->insertData(wd);
+            handledDumpers++;
+        }
+    }
+    if (handledDumpers == incompleteLocals.size())
+        return true;
+    // Expand symbol group items
+    return CdbSymbolGroupContext::completeModel(m_symbolContext, incompleteLocals,
+                                                WatchHandlerSorterInserter(wh, m_dumper),
+                                                errorMessage);
+}
+
+CdbStackFrameContext::~CdbStackFrameContext()
+{
+    delete m_symbolContext;
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.h b/src/plugins/debugger/cdb/cdbstackframecontext.h
new file mode 100644
index 0000000000000000000000000000000000000000..caf84dde97bfc5e5e8ce06ceab20ac2323bb89c8
--- /dev/null
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.h
@@ -0,0 +1,74 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (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 qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef CDBSTACKFRAMECONTEXT_H
+#define CDBSTACKFRAMECONTEXT_H
+
+#include <QtCore/QList>
+#include <QtCore/QSharedPointer>
+
+namespace Debugger {
+namespace Internal {
+
+class WatchData;
+class WatchHandler;
+class CdbSymbolGroupContext;
+class CdbDumperHelper;
+
+/* CdbStackFrameContext manages a symbol group context and
+ * a dumper context. It dispatches calls between the local items
+ * that are handled by the symbol group and those that are handled by the dumpers. */
+
+class CdbStackFrameContext
+{
+    Q_DISABLE_COPY(CdbStackFrameContext)
+public:
+    explicit CdbStackFrameContext(const QSharedPointer<CdbDumperHelper> &dumper,
+                                  CdbSymbolGroupContext *symbolContext);
+    ~CdbStackFrameContext();
+
+    bool assignValue(const QString &iname, const QString &value,
+                     QString *newValue /* = 0 */, QString *errorMessage);
+
+    bool populateModelInitially(WatchHandler *wh, QString *errorMessage);
+
+    bool completeModel(const QList<WatchData> &incompleteLocals,
+                       WatchHandler *wh,
+                       QString *errorMessage);
+
+private:
+    const bool m_useDumpers;
+    const QSharedPointer<CdbDumperHelper> m_dumper;
+    CdbSymbolGroupContext *m_symbolContext;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // CDBSTACKFRAMECONTEXT_H
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
index d769817c7e5bf111e148a7a6af7a017be53fa372..3b3997635581d409848c25e57b67bd76859462c7 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
@@ -28,9 +28,11 @@
 **************************************************************************/
 
 #include "cdbstacktracecontext.h"
+#include "cdbstackframecontext.h"
 #include "cdbbreakpoint.h"
 #include "cdbsymbolgroupcontext.h"
 #include "cdbdebugengine_p.h"
+#include "cdbdumperhelper.h"
 
 #include <QtCore/QDir>
 #include <QtCore/QTextStream>
@@ -38,18 +40,20 @@
 namespace Debugger {
 namespace Internal {
 
-CdbStackTraceContext::CdbStackTraceContext(CdbComInterfaces *cif) :
-        m_cif(cif),
+CdbStackTraceContext::CdbStackTraceContext(const QSharedPointer<CdbDumperHelper> &dumper) :
+        m_dumper(dumper),
+        m_cif(dumper->comInterfaces()),
         m_instructionOffset(0)
 {
 }
 
-CdbStackTraceContext *CdbStackTraceContext::create(CdbComInterfaces *cif,
+CdbStackTraceContext *CdbStackTraceContext::create(const QSharedPointer<CdbDumperHelper> &dumper,
                                                    unsigned long threadId,
                                                    QString *errorMessage)
 {    
     if (debugCDB)
         qDebug() << Q_FUNC_INFO << threadId;
+    CdbComInterfaces *cif = dumper->comInterfaces();
     HRESULT hr = cif->debugSystemObjects->SetCurrentThreadId(threadId);
     if (FAILED(hr)) {
         *errorMessage = QString::fromLatin1("%1: SetCurrentThreadId %2 failed: %3").
@@ -60,7 +64,7 @@ CdbStackTraceContext *CdbStackTraceContext::create(CdbComInterfaces *cif,
     }
     // fill the DEBUG_STACK_FRAME array
     ULONG frameCount;
-    CdbStackTraceContext *ctx = new CdbStackTraceContext(cif);
+    CdbStackTraceContext *ctx = new CdbStackTraceContext(dumper);
     hr = cif->debugControl->GetStackTrace(0, 0, 0, ctx->m_cdbFrames, CdbStackTraceContext::maxFrames, &frameCount);
     if (FAILED(hr)) {
         delete ctx;
@@ -77,7 +81,7 @@ CdbStackTraceContext *CdbStackTraceContext::create(CdbComInterfaces *cif,
 
 CdbStackTraceContext::~CdbStackTraceContext()
 {
-    qDeleteAll(m_symbolContexts);
+    qDeleteAll(m_frameContexts);
 }
 
 bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessage*/)
@@ -85,8 +89,8 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa
     if (debugCDB)
         qDebug() << Q_FUNC_INFO << frameCount;
 
-    m_symbolContexts.resize(frameCount);
-    qFill(m_symbolContexts, static_cast<CdbSymbolGroupContext*>(0));
+    m_frameContexts.resize(frameCount);
+    qFill(m_frameContexts, static_cast<CdbStackFrameContext*>(0));
 
     // Convert the DEBUG_STACK_FRAMEs to our StackFrame structure and populate the frames
     WCHAR wszBuf[MAX_PATH];
@@ -114,28 +118,28 @@ bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessa
     return true;
 }
 
-CdbSymbolGroupContext *CdbStackTraceContext::symbolGroupContextAt(int index, QString *errorMessage)
+CdbStackFrameContext *CdbStackTraceContext::frameContextAt(int index, QString *errorMessage)
 {
-    // Create a symbol group on demand
+    // Create a frame on demand
     if (debugCDB)
         qDebug() << Q_FUNC_INFO << index;
 
-    if (index < 0 || index >= m_symbolContexts.size()) {
+    if (index < 0 || index >= m_frameContexts.size()) {
         *errorMessage = QString::fromLatin1("%1: Index %2 out of range %3.").
-                        arg(QLatin1String(Q_FUNC_INFO)).arg(index).arg(m_symbolContexts.size());
+                        arg(QLatin1String(Q_FUNC_INFO)).arg(index).arg(m_frameContexts.size());
         return 0;
     }
-
-    if (m_symbolContexts.at(index))
-        return m_symbolContexts.at(index);
+    if (m_frameContexts.at(index))
+        return m_frameContexts.at(index);
     CIDebugSymbolGroup *sg  = createSymbolGroup(index, errorMessage);
     if (!sg)
         return 0;
     CdbSymbolGroupContext *sc = CdbSymbolGroupContext::create(QLatin1String("local"), sg, errorMessage);
     if (!sc)
-        return 0;                                \
-    m_symbolContexts[index] = sc;
-    return sc;
+        return 0;
+    CdbStackFrameContext *fr = new CdbStackFrameContext(m_dumper, sc);
+    m_frameContexts[index] = fr;
+    return fr;
 }
 
 CIDebugSymbolGroup *CdbStackTraceContext::createSymbolGroup(int index, QString *errorMessage)
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h
index 56389481c62f43865f8dd9a267609864c66354a6..98e509ad982e99c500342f7ee9332b8add8936ac 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.h
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h
@@ -36,6 +36,7 @@
 
 #include <QtCore/QString>
 #include <QtCore/QVector>
+#include <QtCore/QSharedPointer>
 
 QT_BEGIN_NAMESPACE
 class QTextStream;
@@ -46,21 +47,23 @@ namespace Internal {
 
 struct CdbComInterfaces;
 class CdbSymbolGroupContext;
+class CdbStackFrameContext;
+class CdbDumperHelper;
 
 /* Context representing a break point stack consisting of several frames.
- * Maintains an on-demand constructed list of CdbSymbolGroupContext
+ * Maintains an on-demand constructed list of CdbStackFrameContext
  * containining the local variables of the stack. */
 
 class CdbStackTraceContext        
 {
     Q_DISABLE_COPY(CdbStackTraceContext)
 
-    explicit CdbStackTraceContext(CdbComInterfaces *cif);
+    explicit CdbStackTraceContext(const QSharedPointer<CdbDumperHelper> &dumper);
 public:
     enum { maxFrames = 100 };
 
     ~CdbStackTraceContext();
-    static CdbStackTraceContext *create(CdbComInterfaces *cif,
+    static CdbStackTraceContext *create(const QSharedPointer<CdbDumperHelper> &dumper,
                                         unsigned long threadid,
                                         QString *errorMessage);
 
@@ -70,7 +73,7 @@ public:
     // Top-Level instruction offset for disassembler
     ULONG64 instructionOffset() const { return m_instructionOffset; }
 
-    CdbSymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage);
+    CdbStackFrameContext*frameContextAt(int index, QString *errorMessage);
 
     // Format for logging
     void format(QTextStream &str) const;
@@ -80,10 +83,11 @@ private:
     bool init(unsigned long frameCount, QString *errorMessage);
     CIDebugSymbolGroup *createSymbolGroup(int index, QString *errorMessage);
 
+    const QSharedPointer<CdbDumperHelper> m_dumper;
     CdbComInterfaces *m_cif;
 
     DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
-    QVector <CdbSymbolGroupContext*> m_symbolContexts;
+    QVector <CdbStackFrameContext*> m_frameContexts;
     QList<StackFrame> m_frames;
     ULONG64 m_instructionOffset;
 };
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
index 857a80912f14bfbaa9762ca1ea21c36ce8b3bc54..7daba56a587ca91624b298569e391fb6ba727360 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
@@ -200,16 +200,6 @@ QString CdbSymbolGroupContext::toString(bool verbose) const
     return rc;
 }
 
-bool CdbSymbolGroupContext::isSymbolDisplayable(const DEBUG_SYMBOL_PARAMETERS &p)
-{
-    if (p.Flags & (DEBUG_SYMBOL_IS_LOCAL|DEBUG_SYMBOL_IS_ARGUMENT))
-        return true;
-    // Do not display static members.
-    if (p.Flags & DEBUG_SYMBOL_READ_ONLY)
-        return false;
-    return true;
-}
-
 CdbSymbolGroupContext::SymbolState CdbSymbolGroupContext::symbolState(unsigned long index) const
 {
     return getSymbolState(m_symbolParameters.at(index));
@@ -499,144 +489,26 @@ QString CdbSymbolGroupContext::debugValueToString(const DEBUG_VALUE &dv, CIDebug
     return formatArrayHelper(dv.RawBytes, 24, integerBase);
 }
 
-// - Watch model functions
-class WatchDataBackInserter {
-public:
-    explicit WatchDataBackInserter(QList<WatchData> &wh) : m_wh(wh) {}
-
-    WatchDataBackInserter & operator*() { return *this; }
-    WatchDataBackInserter &operator=(const WatchData &wd) {
-        m_wh.push_back(wd);
-        return *this;
-    }
-    WatchDataBackInserter &operator++() { return *this; }
-
-private:
-    QList<WatchData> &m_wh;
-};
-
-static bool insertChildrenRecursion(const QString &iname,
-                                    CdbSymbolGroupContext *sg,
-                                    WatchHandler *watchHandler,
-                                    int maxRecursionLevel,
-                                    int level,
-                                    QString *errorMessage,
-                                    int *childCount = 0);
-
-// Insert a symbol (and its first level children depending on forceRecursion)
-static bool insertSymbolRecursion(WatchData wd,
-                                  CdbSymbolGroupContext *sg,
-                                  WatchHandler *watchHandler,
-                                  int maxRecursionLevel,
-                                  int level,
-                                  QString *errorMessage)
-{    
-    // Find out whether to recurse (has children or at least knows it has children)
-    // Open next level if specified by recursion depth or child is already expanded
-    // (Sometimes, some root children are already expanded after creating the context).
-    const bool hasChildren = wd.childCount > 0 || wd.isChildrenNeeded();
-    const bool recurse = hasChildren && (level < maxRecursionLevel || sg->isExpanded(wd.iname));
-    if (debug)
-        qDebug() << Q_FUNC_INFO << '\n' << wd.iname << "level=" << level <<  "recurse=" << recurse;
-    bool rc = true;
-    if (recurse) { // Determine number of children and indicate in model
-        int childCount;
-        rc = insertChildrenRecursion(wd.iname, sg, watchHandler, maxRecursionLevel, level, errorMessage, &childCount);
-        if (rc) {
-            wd.setChildCount(childCount);
-            wd.setChildrenUnneeded();
-        }
-    } else {
-        // No further recursion at this level, pretend entry is complete
-        if (wd.isChildrenNeeded()) {
-            wd.setChildCount(1);
-            wd.setChildrenUnneeded();
-        }
-    }
-    if (debug)
-        qDebug() << " INSERTING: at " << level << wd.toString();
-    watchHandler->insertData(wd);
-    return rc;
-}
-
-// Insert the children of prefix.
-static bool insertChildrenRecursion(const QString &iname,
-                                    CdbSymbolGroupContext *sg,
-                                    WatchHandler *watchHandler,
-                                    int maxRecursionLevel,
-                                    int level,
-                                    QString *errorMessage,
-                                    int *childCountPtr)
+bool CdbSymbolGroupContext::debugValueToInteger(const DEBUG_VALUE &dv, qint64 *value)
 {
-    if (debug > 1)
-        qDebug() << Q_FUNC_INFO << '\n' << iname << level;
-
-    QList<WatchData> watchList;
-    // This implicitly enforces expansion
-    if (!sg->getChildSymbols(iname, WatchDataBackInserter(watchList), errorMessage))
-        return false;
-
-    const int childCount = watchList.size();
-    if (childCountPtr)
-        *childCountPtr = childCount;
-    int succeededChildCount = 0;
-    for (int c = 0; c < childCount; c++) {
-        const WatchData &wd = watchList.at(c);
-        if (wd.isValid()) { // We sometimes get empty names for deeply nested data
-            if (!insertSymbolRecursion(wd, sg, watchHandler, maxRecursionLevel, level + 1, errorMessage))
-                return false;
-            succeededChildCount++;
-        }  else {
-            const QString msg = QString::fromLatin1("WARNING: Skipping invalid child symbol #%2 (type %3) of '%4'.").
-                                arg(QLatin1String(Q_FUNC_INFO)).arg(c).arg(wd.type, iname);
-            qWarning("%s\n", qPrintable(msg));
-        }
-    }
-    if (childCountPtr)
-        *childCountPtr = succeededChildCount;
-    return true;
-}
-
-bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg,
-                                                   WatchHandler *watchHandler,
-                                                   QString *errorMessage)
-{
-    if (debugCDB)
-        qDebug() << "###" << Q_FUNC_INFO;
-
-    // Insert root items
-    QList<WatchData> watchList;
-    if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage))
-        return false;
-
-    foreach(const WatchData &wd, watchList)
-        if (!insertSymbolRecursion(wd, sg, watchHandler, 0, 0, errorMessage))
-            return false;
-    return true;
-}
-
-bool CdbSymbolGroupContext::completeModel(CdbSymbolGroupContext *sg,
-                                          const QList<WatchData> &incompleteLocals,
-                                          WatchHandler *watchHandler,
-                                          QString *errorMessage)
-{
-    if (debugCDB)
-        qDebug().nospace() << "###>" << Q_FUNC_INFO << ' ' << incompleteLocals.size() << '\n';
-    // The view reinserts any node being expanded with flag 'ChildrenNeeded'.
-    // Recurse down one level in context unless this is already the case.
-    foreach(WatchData wd, incompleteLocals) {
-        const bool contextExpanded = sg->isExpanded(wd.iname);
-        if (debug)
-            qDebug() << "  " << wd.iname << "CE=" << contextExpanded;
-        if (contextExpanded) { // You know that already.
-            wd.setChildrenUnneeded();
-            watchHandler->insertData(wd);
-        } else {
-            if (!insertSymbolRecursion(wd, sg, watchHandler, 1, 0, errorMessage))
-                return false;
-        }
+    *value = 0;
+    switch (dv.Type) {
+    case DEBUG_VALUE_INT8:
+        *value = dv.I8;
+        return true;
+    case DEBUG_VALUE_INT16:
+        *value = static_cast<short>(dv.I16);
+        return true;
+    case DEBUG_VALUE_INT32:
+        *value = static_cast<long>(dv.I32);
+        return true;
+    case DEBUG_VALUE_INT64:
+        *value = static_cast<long long>(dv.I64);
+        return true;
+    default:
+        break;
     }
-    return true;
+    return false;
 }
 
 } // namespace Internal
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
index 31beb1d8d71fb31a4900c804df500de40a3cea78..033252e387c989ac561d01073c95a1a38575d26c 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
@@ -31,6 +31,7 @@
 #define CDBSYMBOLGROUPCONTEXT_H
 
 #include "cdbcom.h"
+#include "watchhandler.h"
 
 #include <QtCore/QString>
 #include <QtCore/QVector>
@@ -72,11 +73,13 @@ public:
     bool assignValue(const QString &iname, const QString &value,
                      QString *newValue /* = 0 */, QString *errorMessage);
 
-    static bool populateModelInitially(CdbSymbolGroupContext *sg, WatchHandler *wh, QString *errorMessage);
+    template <class OutputIterator>
+    static bool populateModelInitially(CdbSymbolGroupContext *sg, OutputIterator it, QString *errorMessage);
 
+    template <class OutputIterator>
     static bool completeModel(CdbSymbolGroupContext *sg,
                               const QList<WatchData> &incompleteLocals,
-                              WatchHandler *wh,
+                              OutputIterator it,
                               QString *errorMessage);
 
     // Retrieve child symbols of prefix as a sequence of WatchData.
@@ -92,6 +95,7 @@ public:
 
     // Helper to convert a DEBUG_VALUE structure to a string representation
     static QString debugValueToString(const DEBUG_VALUE &dv, CIDebugControl *ctl, QString *type = 0, int integerBase = 10);
+    static bool debugValueToInteger(const DEBUG_VALUE &dv, qint64 *value);
 
     // format an array of unsigned longs as "0x323, 0x2322, ..."
     static QString hexFormatArray(const unsigned short *array, int size);
@@ -125,26 +129,25 @@ private:
     QVector<DEBUG_SYMBOL_PARAMETERS> m_symbolParameters;
 };
 
-template <class OutputIterator>
-bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage)
-{
-    unsigned long start;
-    unsigned long parentId;
-    if (!getChildSymbolsPosition(prefix, &start, &parentId, errorMessage))
-        return false;    
-    // Skip over expanded children
-    const unsigned long end = m_symbolParameters.size();
-    for (unsigned long s = start; s < end; ++s) {
-        const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(s);
-        if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) {
-            *it = symbolAt(s);
-            ++it;
-        }
+// Helper to a sequence of  WatchData into a list.
+class WatchDataBackInserter {
+public:
+    explicit WatchDataBackInserter(QList<WatchData> &wh) : m_wh(wh) {}
+
+    inline WatchDataBackInserter & operator*() { return *this; }
+    inline WatchDataBackInserter &operator=(const WatchData &wd) {
+        m_wh.push_back(wd);
+        return *this;
     }
-    return true;
-}
+    inline WatchDataBackInserter &operator++() { return *this; }
+
+private:
+    QList<WatchData> &m_wh;
+};
 
 } // namespace Internal
 } // namespace Debugger
 
+#include "cdbsymbolgroupcontext_tpl.h"
+
 #endif // CDBSYMBOLGROUPCONTEXT_H
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h
new file mode 100644
index 0000000000000000000000000000000000000000..9a2f992bf47b46ba5a7695d560126ffac88db04f
--- /dev/null
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h
@@ -0,0 +1,203 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (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 qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef CDBSYMBOLGROUPCONTEXT_TPL_H
+#define CDBSYMBOLGROUPCONTEXT_TPL_H
+
+#include <QtCore/QDebug>
+
+namespace Debugger {
+namespace Internal {
+
+enum { debugSgRecursion = 0 };
+
+/* inline static */ bool CdbSymbolGroupContext::isSymbolDisplayable(const DEBUG_SYMBOL_PARAMETERS &p)
+{
+    if (p.Flags & (DEBUG_SYMBOL_IS_LOCAL|DEBUG_SYMBOL_IS_ARGUMENT))
+        return true;
+    // Do not display static members.
+    if (p.Flags & DEBUG_SYMBOL_READ_ONLY)
+        return false;
+    return true;
+}
+
+template <class OutputIterator>
+bool CdbSymbolGroupContext::getChildSymbols(const QString &prefix, OutputIterator it, QString *errorMessage)
+{
+    unsigned long start;
+    unsigned long parentId;
+    if (!getChildSymbolsPosition(prefix, &start, &parentId, errorMessage))
+        return false;
+    // Skip over expanded children
+    const unsigned long end = m_symbolParameters.size();
+    for (unsigned long s = start; s < end; ++s) {
+        const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(s);
+        if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) {
+            *it = symbolAt(s);
+            ++it;
+        }
+    }
+    return true;
+}
+
+template <class OutputIterator>
+        bool insertChildrenRecursion(const QString &iname,
+                                     CdbSymbolGroupContext *sg,
+                                     OutputIterator it,
+                                     int maxRecursionLevel,
+                                     int level,
+                                     QString *errorMessage,
+                                     int *childCount = 0);
+
+// Insert a symbol (and its first level children depending on forceRecursion)
+template <class OutputIterator>
+bool insertSymbolRecursion(WatchData wd,
+                                  CdbSymbolGroupContext *sg,
+                                  OutputIterator it,
+                                  int maxRecursionLevel,
+                                  int level,
+                                  QString *errorMessage)
+{
+    // Find out whether to recurse (has children or at least knows it has children)
+    // Open next level if specified by recursion depth or child is already expanded
+    // (Sometimes, some root children are already expanded after creating the context).
+    const bool hasChildren = wd.childCount > 0 || wd.isChildrenNeeded();
+    const bool recurse = hasChildren && (level < maxRecursionLevel || sg->isExpanded(wd.iname));
+    if (debugSgRecursion)
+        qDebug() << Q_FUNC_INFO << '\n' << wd.iname << "level=" << level <<  "recurse=" << recurse;
+    bool rc = true;
+    if (recurse) { // Determine number of children and indicate in model
+        int childCount;
+        rc = insertChildrenRecursion(wd.iname, sg, it, maxRecursionLevel, level, errorMessage, &childCount);
+        if (rc) {
+            wd.setChildCount(childCount);
+            wd.setChildrenUnneeded();
+        }
+    } else {
+        // No further recursion at this level, pretend entry is complete
+        if (wd.isChildrenNeeded()) {
+            wd.setChildCount(1);
+            wd.setChildrenUnneeded();
+        }
+    }
+    if (debugSgRecursion)
+        qDebug() << " INSERTING: at " << level << wd.toString();
+    *it = wd;
+    ++it;
+    return rc;
+}
+
+// Insert the children of prefix.
+template <class OutputIterator>
+        bool insertChildrenRecursion(const QString &iname,
+                                     CdbSymbolGroupContext *sg,
+                                     OutputIterator it,
+                                     int maxRecursionLevel,
+                                     int level,
+                                     QString *errorMessage,
+                                     int *childCountPtr)
+{
+    if (debugSgRecursion > 1)
+        qDebug() << Q_FUNC_INFO << '\n' << iname << level;
+
+    QList<WatchData> watchList;
+    // This implicitly enforces expansion
+    if (!sg->getChildSymbols(iname, WatchDataBackInserter(watchList), errorMessage))
+        return false;
+
+    const int childCount = watchList.size();
+    if (childCountPtr)
+        *childCountPtr = childCount;
+    int succeededChildCount = 0;
+    for (int c = 0; c < childCount; c++) {
+        const WatchData &wd = watchList.at(c);
+        if (wd.isValid()) { // We sometimes get empty names for deeply nested data
+            if (!insertSymbolRecursion(wd, sg, it, maxRecursionLevel, level + 1, errorMessage))
+                return false;
+            succeededChildCount++;
+        }  else {
+            const QString msg = QString::fromLatin1("WARNING: Skipping invalid child symbol #%2 (type %3) of '%4'.").
+                                arg(QLatin1String(Q_FUNC_INFO)).arg(c).arg(wd.type, iname);
+            qWarning("%s\n", qPrintable(msg));
+        }
+    }
+    if (childCountPtr)
+        *childCountPtr = succeededChildCount;
+    return true;
+}
+
+template <class OutputIterator>
+bool CdbSymbolGroupContext::populateModelInitially(CdbSymbolGroupContext *sg,
+                                                   OutputIterator it,
+                                                   QString *errorMessage)
+{
+    if (debugSgRecursion)
+        qDebug() << "###" << Q_FUNC_INFO;
+
+    // Insert root items
+    QList<WatchData> watchList;
+    if (!sg->getChildSymbols(sg->prefix(), WatchDataBackInserter(watchList), errorMessage))
+        return false;
+
+    foreach(const WatchData &wd, watchList)
+        if (!insertSymbolRecursion(wd, sg, it, 0, 0, errorMessage))
+            return false;
+    return true;
+}
+
+template <class OutputIterator>
+bool CdbSymbolGroupContext::completeModel(CdbSymbolGroupContext *sg,
+                                          const QList<WatchData> &incompleteLocals,
+                                          OutputIterator it,
+                                          QString *errorMessage)
+{
+    if (debugSgRecursion)
+        qDebug().nospace() << "###>" << Q_FUNC_INFO << ' ' << incompleteLocals.size() << '\n';
+    // The view reinserts any node being expanded with flag 'ChildrenNeeded'.
+    // Recurse down one level in context unless this is already the case.
+    foreach(WatchData wd, incompleteLocals) {
+        const bool contextExpanded = sg->isExpanded(wd.iname);
+        if (debugSgRecursion)
+            qDebug() << "  " << wd.iname << "CE=" << contextExpanded;
+        if (contextExpanded) { // You know that already.
+            wd.setChildrenUnneeded();            
+            *it = wd;
+            ++it;
+        } else {
+            if (!insertSymbolRecursion(wd, sg, it, 1, 0, errorMessage))
+                return false;
+        }
+    }
+    return true;
+}
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // CDBSYMBOLGROUPCONTEXT_TPL_H
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 6ef682829d7a61ac73a5ad282a5b17f5e2a25f39..67b3e988372f8a17d05d7afac56bebaf7cbdc07c 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -146,6 +146,7 @@ private:
     friend class ScriptEngine;
     friend struct CdbDebugEnginePrivate;
     friend class CdbDumperHelper;
+    friend class CdbExceptionLoggerEventCallback;
 
     // called from the engines after successful startup
     virtual void notifyInferiorStopRequested() = 0;
diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp
index e163b99802f24ef73f9d681cb9072fe0fa0f85ae..da1fead265e2435cbd72cd65d9e1d2be6c436fc0 100644
--- a/src/plugins/debugger/gdbengine.cpp
+++ b/src/plugins/debugger/gdbengine.cpp
@@ -55,6 +55,7 @@
 #include <QtCore/QFileInfo>
 #include <QtCore/QTime>
 #include <QtCore/QTimer>
+#include <QtCore/QTextStream>
 
 #include <QtGui/QAction>
 #include <QtGui/QApplication>
@@ -2913,44 +2914,6 @@ void GdbEngine::setToolTipExpression(const QPoint &pos, const QString &exp0)
 
 static const QString strNotInScope = QLatin1String("<not in scope>");
 
-static QString quoteUnprintableLatin1(const QByteArray &ba)
-{
-    QString res;
-    char buf[10];
-    for (int i = 0, n = ba.size(); i != n; ++i) {
-        unsigned char c = ba.at(i);
-        if (isprint(c)) {
-            res += c;
-        } else {
-            qsnprintf(buf, sizeof(buf) - 1, "\\%x", int(c));
-            res += buf;
-        }
-    }
-    return res;
-}
-
-static QString decodeData(QByteArray ba, int encoding)
-{
-    switch (encoding) {
-        case 0: // unencoded 8 bit data
-            return quoteUnprintableLatin1(ba);
-        case 1: //  base64 encoded 8 bit data, used for QByteArray
-            ba = QByteArray::fromBase64(ba);
-            return '"' + quoteUnprintableLatin1(ba) + '"';
-        case 2: //  base64 encoded 16 bit data, used for QString
-            ba = QByteArray::fromBase64(ba);
-            return '"' + QString::fromUtf16((ushort *)ba.data(), ba.size() / 2) + '"';
-        case 3: //  base64 encoded 32 bit data
-            ba = QByteArray::fromBase64(ba);
-            return '"' + QString::fromUcs4((uint *)ba.data(), ba.size() / 4) + '"';
-            break;
-        case 4: //  base64 encoded 16 bit data, without quotes (see 2)
-            ba = QByteArray::fromBase64(ba);
-            return QString::fromUtf16((ushort *)ba.data(), ba.size() / 2);
-    }
-    return "<Encoding error>";
-}
-
 static void setWatchDataValue(WatchData &data, const GdbMi &mi,
     int encoding = 0)
 {
@@ -3041,15 +3004,7 @@ bool GdbEngine::hasDebuggingHelperForType(const QString &type) const
         return false;
 
     // simple types
-    if (m_availableSimpleDebuggingHelpers.contains(type))
-        return true;
-
-    // templates
-    QString tmplate;
-    QString inner;
-    if (!extractTemplate(type, &tmplate, &inner))
-        return false;
-    return m_availableSimpleDebuggingHelpers.contains(tmplate);
+    return m_dumperHelper.type(type) != QtDumperHelper::UnknownType;
 }
 
 void GdbEngine::runDirectDebuggingHelper(const WatchData &data, bool dumpChildren)
@@ -3080,145 +3035,33 @@ void GdbEngine::runDebuggingHelper(const WatchData &data0, bool dumpChildren)
     }
     WatchData data = data0;
     QTC_ASSERT(!data.exp.isEmpty(), return);
-    QString tmplate;
-    QString inner;
-    bool isTemplate = extractTemplate(data.type, &tmplate, &inner);
-    QStringList inners = inner.split('@');
-    if (inners.at(0).isEmpty())
-        inners.clear();
-    for (int i = 0; i != inners.size(); ++i)
-        inners[i] = inners[i].simplified();
-
-    QString outertype = isTemplate ? tmplate : data.type;
-    // adjust the data extract
-    if (outertype == m_namespace + "QWidget")
-        outertype = m_namespace + "QObject";
-
-    QString extraArgs[4];
-    extraArgs[0] = "0";
-    extraArgs[1] = "0";
-    extraArgs[2] = "0";
-    extraArgs[3] = "0";
-
-    int extraArgCount = 0;
-
-    // "generic" template dumpers: passing sizeof(argument)
-    // gives already most information the dumpers need
-    foreach (const QString &arg, inners)
-        extraArgs[extraArgCount++] = sizeofTypeExpression(arg);
-
-    // in rare cases we need more or less:
-    if (outertype == m_namespace + "QObject") {
-        extraArgs[0] = "(char*)&((('"
-            + m_namespace + "QObjectPrivate'*)&"
-            + data.exp + ")->children)-(char*)&" + data.exp;
-    } else if (outertype == m_namespace + "QVector") {
-        extraArgs[1] = "(char*)&(("
-            + data.exp + ").d->array)-(char*)" + data.exp + ".d";
-    } else if (outertype == m_namespace + "QObjectSlot"
-            || outertype == m_namespace + "QObjectSignal") {
-        // we need the number out of something like
-        // iname="local.ob.slots.2" // ".deleteLater()"?
-        int pos = data.iname.lastIndexOf('.');
-        QString slotNumber = data.iname.mid(pos + 1);
-        QTC_ASSERT(slotNumber.toInt() != -1, /**/);
-        extraArgs[0] = slotNumber;
-    } else if (outertype == m_namespace + "QMap" || outertype == m_namespace + "QMultiMap") {
-        QString nodetype;
-        if (m_qtVersion >= (4 << 16) + (5 << 8) + 0) {
-            nodetype  = m_namespace + "QMapNode";
-            nodetype += data.type.mid(outertype.size());
-        } else {
-            // FIXME: doesn't work for QMultiMap
-            nodetype  = data.type + "::Node";
-        }
-        //qDebug() << "OUTERTYPE: " << outertype << " NODETYPE: " << nodetype
-        //    << "QT VERSION" << m_qtVersion << ((4 << 16) + (5 << 8) + 0);
-        extraArgs[2] = sizeofTypeExpression(nodetype);
-        extraArgs[3] = "(size_t)&(('" + nodetype + "'*)0)->value";
-    } else if (outertype == m_namespace + "QMapNode") {
-        extraArgs[2] = sizeofTypeExpression(data.type);
-        extraArgs[3] = "(size_t)&(('" + data.type + "'*)0)->value";
-    } else if (outertype == "std::vector" || outertype == "vector") {
-        //qDebug() << "EXTRACT TEMPLATE: " << outertype << inners;
-        if (inners.at(0) == "bool") {
-            outertype = "std::vector::bool";
-        } else {
-            //extraArgs[extraArgCount++] = sizeofTypeExpression(data.type);
-            //extraArgs[extraArgCount++] = "(size_t)&(('" + data.type + "'*)0)->value";
-        }
-    } else if (outertype == "std::deque" || outertype == "deque") {
-        // remove 'std::allocator<...>':
-        extraArgs[1] = "0";
-    } else if (outertype == "std::stack" || outertype == "stack") {
-        // remove 'std::allocator<...>':
-        extraArgs[1] = "0";
-    } else if (outertype == "std::set" || outertype == "set") {
-        // remove 'std::less<...>':
-        extraArgs[1] = "0";
-        // remove 'std::allocator<...>':
-        extraArgs[2] = "0";
-    } else if (outertype == "std::map" || outertype == "map") {
-        // We don't want the comparator and the allocator confuse gdb.
-        // But we need the offset of the second item in the value pair.
-        // We read the type of the pair from the allocator argument because
-        // that gets the constness "right" (in the sense that gdb can
-        // read it back;
-        QString pairType = inners.at(3);
-        // remove 'std::allocator<...>':
-        pairType = pairType.mid(15, pairType.size() - 15 - 2);
-        extraArgs[2] = "(size_t)&(('" + pairType + "'*)0)->second";
-        extraArgs[3] = "0";
-    } else if (outertype == "std::basic_string" || outertype == "basic_string") {
-        //qDebug() << "EXTRACT TEMPLATE: " << outertype << inners;
-        if (inners.at(0) == "char") {
-            outertype = "std::string";
-        } else if (inners.at(0) == "wchar_t") {
-            outertype = "std::wstring";
-        }
-        extraArgs[0] = "0";
-        extraArgs[1] = "0";
-        extraArgs[2] = "0";
-        extraArgs[3] = "0";
-    }
+
+    QByteArray params;
+    QStringList extraArgs;
+    const QtDumperHelper::TypeData td = m_dumperHelper.typeData(data0.type);
+    m_dumperHelper.evaluationParameters(data, td, QtDumperHelper::GdbDebugger, &params, &extraArgs);
 
     //int protocol = (data.iname.startsWith("watch") && data.type == "QImage") ? 3 : 2;
     //int protocol = data.iname.startsWith("watch") ? 3 : 2;
-    int protocol = 2;
+    const int protocol = 2;
     //int protocol = isDisplayedIName(data.iname) ? 3 : 2;
 
     QString addr;
-    if (data.addr.startsWith("0x"))
-        addr = "(void*)" + data.addr;
-    else
-        addr = "&(" + data.exp + ")";
-
-    QByteArray params;
-    params.append(outertype.toUtf8());
-    params.append('\0');
-    params.append(data.iname.toUtf8());
-    params.append('\0');
-    params.append(data.exp.toUtf8());
-    params.append('\0');
-    params.append(inner.toUtf8());
-    params.append('\0');
-    params.append(data.iname.toUtf8());
-    params.append('\0');
+    if (data.addr.startsWith(QLatin1String("0x"))) {
+        addr = QLatin1String("(void*)") + data.addr;
+    } else {
+        addr = QLatin1String("&(") + data.exp + QLatin1Char(')');
+    }
 
     sendWatchParameters(params);
 
-    QString cmd ="call "
-            + QString("(void*)qDumpObjectData440(")
-            + QString::number(protocol)
-            + ',' + "%1+1"                // placeholder for token
-            + ',' + addr
-            + ',' + (dumpChildren ? "1" : "0")
-            + ',' + extraArgs[0]
-            + ',' + extraArgs[1]
-            + ',' + extraArgs[2]
-            + ',' + extraArgs[3] + ')';
+    QString cmd;
+    QTextStream(&cmd) << "call " << "(void*)qDumpObjectData440(" <<
+            protocol << ',' << "%1+1"                // placeholder for token
+            <<',' <<  addr << ',' << (dumpChildren ? "1" : "0")
+            << ',' << extraArgs.join(QString(QLatin1Char(','))) <<  ')';
 
-    //qDebug() << "CMD: " << cmd;
+    qDebug() << "CMD: " << cmd;
 
     QVariant var;
     var.setValue(data);
@@ -3451,6 +3294,7 @@ void GdbEngine::updateWatchModel2()
 
 void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record)
 {
+    m_dumperHelper.clear();
     //qDebug() << "DATA DUMPER TRIAL:" << record.toString();
     GdbMi output = record.data.findChild("consolestreamoutput");
     QByteArray out = output.data();
@@ -3464,23 +3308,27 @@ void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record)
     GdbMi contents;
     contents.fromString(out);
     GdbMi simple = contents.findChild("dumpers");
-    m_namespace = contents.findChild("namespace").data();
+
+    m_dumperHelper.setQtNamespace(contents.findChild("namespace").data());
     GdbMi qtversion = contents.findChild("qtversion");
+    int qtv = 0;
     if (qtversion.children().size() == 3) {
-        m_qtVersion = (qtversion.childAt(0).data().toInt() << 16)
+        qtv = (qtversion.childAt(0).data().toInt() << 16)
                     + (qtversion.childAt(1).data().toInt() << 8)
                     + qtversion.childAt(2).data().toInt();
         //qDebug() << "FOUND QT VERSION: " << qtversion.toString() << m_qtVersion;
-    } else {
-        m_qtVersion = 0;
     }
+    m_dumperHelper.setQtVersion(qtv);
 
     //qDebug() << "CONTENTS: " << contents.toString();
     //qDebug() << "SIMPLE DUMPERS: " << simple.toString();
-    m_availableSimpleDebuggingHelpers.clear();
+
+    QStringList availableSimpleDebuggingHelpers;
     foreach (const GdbMi &item, simple.children())
-        m_availableSimpleDebuggingHelpers.append(item.data());
-    if (m_availableSimpleDebuggingHelpers.isEmpty()) {
+        availableSimpleDebuggingHelpers.append(item.data());
+    m_dumperHelper.parseQueryTypes(availableSimpleDebuggingHelpers, QtDumperHelper::GdbDebugger);
+
+    if (availableSimpleDebuggingHelpers.isEmpty()) {
         m_debuggingHelperState = DebuggingHelperUnavailable;
         q->showStatusMessage(tr("Debugging helpers not found."));
         //QMessageBox::warning(q->mainWindow(),
@@ -3494,8 +3342,9 @@ void GdbEngine::handleQueryDebuggingHelper(const GdbResultRecord &record)
     } else {
         m_debuggingHelperState = DebuggingHelperAvailable;
         q->showStatusMessage(tr("%1 custom dumpers found.")
-            .arg(m_availableSimpleDebuggingHelpers.size()));
+            .arg(m_dumperHelper.typeCount()));
     }
+    qDebug() << m_dumperHelper.toString(true);
     //qDebug() << "DATA DUMPERS AVAILABLE" << m_availableSimpleDebuggingHelpers;
 }
 
diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h
index 67a7c9a24249154bb8824811cd0467bb764a33c5..5b12c8a7392d932ca8135d99222bf45391ade67d 100644
--- a/src/plugins/debugger/gdbengine.h
+++ b/src/plugins/debugger/gdbengine.h
@@ -33,6 +33,7 @@
 #include "idebuggerengine.h"
 #include "gdbmi.h"
 #include "outputcollector.h"
+#include "watchutils.h"
 
 #include <consoleprocess.h>
 
@@ -342,9 +343,7 @@ private:
     QString m_editedData;
     int m_pendingRequests;
 
-    QStringList m_availableSimpleDebuggingHelpers;
-    QString m_namespace; // namespace used in "namespaced Qt";
-    int m_qtVersion; // Qt version used in the debugged program
+    QtDumperHelper m_dumperHelper;
     
     DebuggingHelperState m_debuggingHelperState;
     QList<GdbMi> m_currentFunctionArgs;
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 105f8384faec5e07b74c956091f9a37ddaa23f11..144f85f4f8dd9af3e40aed65a8ffb2845f8c7dcc 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -78,6 +78,7 @@ static int watcherCounter = 0;
 WatchData::WatchData() :
     childCount(-1),
     valuedisabled(false),
+    source(0),
     state(InitialState),
     parentIndex(-1),
     row(-1),
@@ -807,6 +808,8 @@ void WatchHandler::cleanup()
     m_completeSet = initialSet();
     m_displaySet = m_completeSet;
 
+    rebuildModel(); // to get the dummy entries back
+
 #if 0
     for (EditWindows::ConstIterator it = m_editWindows.begin();
             it != m_editWindows.end(); ++it) {
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index 13f37dabf49c2a1cb1d6a206bdb708c78a1fa3dd..ed565044b29f847507bdf5305dd822b08727020c 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -124,6 +124,7 @@ public:
 private:
 
 public:
+    int source;  // Used by some debuggers (CDB) to tell where it originates from (dumper or symbol evaluation)
     int state;
 
     // Model
diff --git a/src/plugins/debugger/watchutils.cpp b/src/plugins/debugger/watchutils.cpp
index cc1a9784870a3ee57ecdad660e03d6708a0295ca..c1150c2ad8f15598a3180500263bf8307d0b1066 100644
--- a/src/plugins/debugger/watchutils.cpp
+++ b/src/plugins/debugger/watchutils.cpp
@@ -28,10 +28,19 @@
 **************************************************************************/
 
 #include "watchutils.h"
+#include "watchhandler.h"
+#include <utils/qtcassert.h>
 
 #include <QtCore/QDebug>
 #include <QtCore/QTime>
 #include <QtCore/QStringList>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTextStream>
+
+#include <string.h>
+#include <ctype.h>
+
+enum { debug = 0 };
 
 namespace Debugger {
 namespace Internal {
@@ -299,58 +308,957 @@ QString sizeofTypeExpression(const QString &type)
     return QLatin1String("sizeof(") + gdbQuoteTypes(type) + QLatin1Char(')');
 }
 
+// Utilities to decode string data returned by the dumper helpers.
+
+static QString quoteUnprintableLatin1(const QByteArray &ba)
+{
+    QString res;
+    char buf[10];
+    for (int i = 0, n = ba.size(); i != n; ++i) {
+        const unsigned char c = ba.at(i);
+        if (isprint(c)) {
+            res += c;
+        } else {
+            qsnprintf(buf, sizeof(buf) - 1, "\\%x", int(c));
+            res += buf;
+        }
+    }
+    return res;
+}
+
+QString decodeData(const QByteArray &baIn, int encoding)
+{
+    switch (encoding) {
+        case 0: // unencoded 8 bit data
+            return quoteUnprintableLatin1(baIn);
+        case 1: { //  base64 encoded 8 bit data, used for QByteArray
+            const QChar doubleQuote(QLatin1Char('"'));
+            QString rc = doubleQuote;
+            rc += quoteUnprintableLatin1(QByteArray::fromBase64(baIn));
+            rc += doubleQuote;
+            return rc;
+        }
+        case 2: { //  base64 encoded 16 bit data, used for QString
+            const QChar doubleQuote(QLatin1Char('"'));
+            const QByteArray ba = QByteArray::fromBase64(baIn);
+            QString rc = doubleQuote;
+            rc += QString::fromUtf16(reinterpret_cast<const ushort *>(ba.data()), ba.size() / 2);
+            rc += doubleQuote;
+            return rc;
+        }
+        case 3: { //  base64 encoded 32 bit data
+            const QByteArray ba = QByteArray::fromBase64(baIn);
+            const QChar doubleQuote(QLatin1Char('"'));
+            QString rc = doubleQuote;
+            rc += QString::fromUcs4(reinterpret_cast<const uint *>(ba.data()), ba.size() / 4);
+            rc += doubleQuote;
+            return rc;
+        }
+        case 4: { //  base64 encoded 16 bit data, without quotes (see 2)
+            const QByteArray ba = QByteArray::fromBase64(baIn);
+            return QString::fromUtf16(reinterpret_cast<const ushort *>(ba.data()), ba.size() / 2);
+        }
+    }
+    return QCoreApplication::translate("Debugger", "<Encoding error>");
+}
+
+// --------------- QtDumperResult
+
+QtDumperResult::Child::Child() :
+   valueEncoded(0)
+{
+}
+
+QtDumperResult::QtDumperResult() :
+    valueEncoded(0),
+    valuedisabled(false),
+    childCount(0),
+    internal(false)
+
+{
+}
+
+void QtDumperResult::clear()
+{
+    iname.clear();
+    value.clear();
+    address.clear();
+    type.clear();
+    valueEncoded = 0;
+    valuedisabled = false;
+    childCount = 0;
+    internal = false;
+    childType.clear();
+    children.clear();
+}
+
+QList<WatchData> QtDumperResult::toWatchData(int source) const
+{
+    QList<WatchData> rc;
+    rc.push_back(WatchData());
+    WatchData &root = rc.front();
+    root.iname = iname;
+    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));
+    root.setType(type);
+    root.valuedisabled = valuedisabled;
+    root.setAddress(address);
+    root.source = source;
+    root.setChildCount(childCount);
+    // 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;                
+                wchild.exp = wchild.name = dchild.name;
+                wchild.setType(childType);
+                wchild.setAddress(dchild.address);
+                wchild.setValue(decodeData(dchild.value, dchild.valueEncoded));
+                wchild.setChildCount(0);
+            }
+            root.setChildrenUnneeded();
+        } else {
+            root.setChildrenNeeded();
+        }
+    }
+    return rc;
+}
+
+QDebug operator<<(QDebug in, const QtDumperResult &d)
+{
+    QDebug nospace = in.nospace();
+    nospace << " iname=" << d.iname << " type=" << d.type << " address=" << d.address
+            << " value="  << d.value
+            << " disabled=" << d.valuedisabled
+            << " encoded=" << d.valueEncoded << " internal=" << d.internal;
+    if (d.childCount) {
+        nospace << " childCount=" << d.childCount
+                << " childType=" << d.childType << '\n';
+        const int childCount = d.children.size();
+        for (int i = 0; i < childCount; i++) {
+            const QtDumperResult::Child &c = d.children.at(i);
+            nospace << "   #" << i << " addr=" << c.address
+                    << " name=" << c.name << " encoded=" << c.valueEncoded
+                    << " value=" << c.value << '\n';
+        }
+    }
+    return in;
+}
+
+// ----------------- QtDumperHelper::TypeData
+QtDumperHelper::TypeData::TypeData() :
+    type(UnknownType),
+    isTemplate(false)
+{
+}
+
+void QtDumperHelper::TypeData::clear()
+{
+    isTemplate = false;
+    type = UnknownType;
+    tmplate.clear();
+    inner.clear();
+}
+
+// ----------------- QtDumperHelper
+QtDumperHelper::QtDumperHelper() :
+    m_qtVersion(0)
+{
+}
+
+void QtDumperHelper::clear()
+{
+    m_nameTypeMap.clear();
+    m_qtVersion = 0;
+    m_qtNamespace.clear();
+}
+
+static inline void formatQtVersion(int v, QTextStream &str)
+{
+    str  << ((v >> 16) & 0xFF) << '.' << ((v >> 8) & 0xFF) << '.' << (v & 0xFF);
+}
+
+QString QtDumperHelper::toString(bool debug) const
+{
+    if (debug)  {
+        QString rc;
+        QTextStream str(&rc);
+        str << "version=";
+        formatQtVersion(m_qtVersion, str);
+        str << " namespace='" << m_qtNamespace << "'," << m_nameTypeMap.size() << " known types: ";
+        const NameTypeMap::const_iterator cend = m_nameTypeMap.constEnd();
+        for (NameTypeMap::const_iterator it = m_nameTypeMap.constBegin(); it != cend; ++it) {
+            str <<",[" << it.key() << ',' << it.value() << ']';
+        }
+        return rc;
+    }
+    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",
+                                       0, QCoreApplication::CodecForTr,
+                                       m_nameTypeMap.size()).arg(qtVersionString(), nameSpace);
+}
+
+QtDumperHelper::Type QtDumperHelper::simpleType(const QString &simpleType) const
+{
+    return m_nameTypeMap.value(simpleType, UnknownType);
+}
+
+int QtDumperHelper::qtVersion() const
+{
+    return m_qtVersion;
+}
+
+QString QtDumperHelper::qtNamespace() const
+{
+    return m_qtNamespace;
+}
+
+void QtDumperHelper::setQtNamespace(const QString &qtNamespace)
+{
+    m_qtNamespace = qtNamespace;
+}
+
+int QtDumperHelper::typeCount() const
+{
+    return m_nameTypeMap.size();
+}
+
+// Look up unnamespaced 'std' types.
+static inline QtDumperHelper::Type stdType(const QString &s)
+{
+    if (s == QLatin1String("vector"))
+        return QtDumperHelper::StdVectorType;
+    if (s == QLatin1String("deque"))
+        return QtDumperHelper::StdDequeType;
+    if (s == QLatin1String("set"))
+        return QtDumperHelper::StdSetType;
+    if (s == QLatin1String("stack"))
+        return QtDumperHelper::StdStackType;
+    if (s == QLatin1String("map"))
+        return QtDumperHelper::StdMapType;
+    if (s == QLatin1String("basic_string"))
+        return QtDumperHelper::StdStringType;
+    return QtDumperHelper::UnknownType;
+}
+
+QtDumperHelper::Type QtDumperHelper::specialType(QString s)
+{
+    // Std classes.
+    if (s.startsWith(QLatin1String("std::")))
+        return stdType(s.mid(5));
+    // Strip namespace
+    const int namespaceIndex = s.lastIndexOf(QLatin1String("::"));
+    if (namespaceIndex == -1) {
+        // None ... check for std..
+        const Type sType = stdType(s);
+        if (sType != UnknownType)
+            return sType;
+    } else {
+        s.remove(namespaceIndex + 2);
+    }
+    if (s == QLatin1String("QObject"))
+        return QObjectType;
+    if (s == QLatin1String("QWidget"))
+        return QWidgetType;
+    if (s == QLatin1String("QObjectSlot"))
+        return QObjectSlotType;
+    if (s == QLatin1String("QObjectSignal"))
+        return QObjectSignalType;
+    if (s == QLatin1String("QVector"))
+        return QVectorType;
+    if (s == QLatin1String("QMap"))
+        return QMapType;
+    if (s == QLatin1String("QMultiMap"))
+        return QMultiMapType;
+    if (s == QLatin1String("QMapNode"))
+        return QMapNodeType;
+    return UnknownType;
+}
+
+
+bool QtDumperHelper::needsExpressionSyntax(Type t)
+{
+    switch (t) {
+        case QObjectType:
+        case QWidgetType:
+        case QObjectSlotType:
+        case QObjectSignalType:
+        case QMapType:
+        case QVectorType:
+        case QMultiMapType:
+        case QMapNodeType:
+        case StdMapType:
+            return true;
+        default:
+            break;
+        }
+    return false;
+}
+
+QString QtDumperHelper::qtVersionString() const
+{
+    QString rc;
+    QTextStream str(&rc);
+    formatQtVersion(m_qtVersion, str);
+    return rc;
+}
+
+void QtDumperHelper::setQtVersion(int v)
+{
+    m_qtVersion = v;
+}
+
+void QtDumperHelper::setQtVersion(const QString &v)
+{
+    m_qtVersion = 0;
+    const QStringList vl = v.split(QLatin1Char('.'));
+    if (vl.size() == 3) {
+        const int major = vl.at(0).toInt();
+        const int minor = vl.at(1).toInt();
+        const int patch = vl.at(2).toInt();
+        m_qtVersion = (major << 16) | (minor << 8) | patch;
+    }
+}
+
+// Parse a list of types.
+void QtDumperHelper::parseQueryTypes(const QStringList &l, Debugger debugger)
+{
+    m_nameTypeMap.clear();
+    const int count = l.count();
+    for (int i = 0; i < count; i++) {
+        const Type t = specialType(l.at(i));
+        if (t != UnknownType) {
+            // Exclude types that require expression syntax for CDB
+            if (debugger == GdbDebugger || !needsExpressionSyntax(t)) {
+                m_nameTypeMap.insert(l.at(i), t);
+            }
+        } else {
+            m_nameTypeMap.insert(l.at(i), SupportedType);
+        }
+    }
+}
+
+/*  A parse for dumper output:
+ * "iname="local.sl",addr="0x0012BA84",value="<3 items>",valuedisabled="true",
+ * numchild="3",childtype="QString",childnumchild="0",children=[{name="0",value="<binhex>",
+ * valueencoded="2"},{name="1",value="dAB3AG8A",valueencoded="2"},{name="2",
+ * value="dABoAHIAZQBlAA==",valueencoded="2"}]"
+ * Default implementation can be used for debugging purposes. */
+
+class DumperParser {
+public:
+    explicit DumperParser(const char *s) : m_s(s) {}
+    bool run();
+
+protected:
+    // handle 'key="value"'
+    virtual bool handleKeyword(const char *k, int size);
+    virtual bool handleListStart();
+    virtual bool handleListEnd();
+    virtual bool handleHashStart();
+    virtual bool handleHashEnd();
+    virtual bool handleValue(const char *k, int size);
+
+private:
+    bool parseHash(int level, const char *&pos);
+    bool parseValue(int level, const char *&pos);
+    bool parseStringValue(const char *&ptr, int &size, const char *&pos) const;
+
+    const char *m_s;
+};
+
+// get a string value with pos at the opening double quote
+bool DumperParser::parseStringValue(const char *&ptr, int &size, const char *&pos) const
+{
+    pos++;
+    const char *endValuePtr = strchr(pos, '"');
+    if (!endValuePtr)
+        return false;
+    size = endValuePtr - pos;
+    ptr = pos;
+    pos = endValuePtr + 1;
+    return true;
+}
+
+bool DumperParser::run()
+{
+    const char *ptr = m_s;
+    const bool rc = parseHash(0, ptr);
+    if (debug)
+        qDebug() << Q_FUNC_INFO << '\n' << m_s << rc;
+    return rc;
+}
+
+// Parse a non-empty hash with pos at the first keyword.
+// Curly braces are present at level 0 only.
+// '{a="X", b="X"}'
+bool DumperParser::parseHash(int level, const char *&pos)
+{
+    while (true) {
+        switch (*pos) {
+        case '\0': // EOS is acceptable at level 0 only
+            return level == 0;
+        case '}':
+            pos++;
+            return true;
+        default:
+            break;
+        }
+        const char *equalsPtr = strchr(pos, '=');
+        if (!equalsPtr)
+            return false;
+        const int keywordLen = equalsPtr - pos;
+        if (!handleKeyword(pos, keywordLen))
+            return false;
+        pos = equalsPtr + 1;
+        if (!*pos)
+            return false;        
+        if (!parseValue(level + 1, pos))
+            return false;    
+        if (*pos == ',')
+            pos++;
+    }
+    return false;
+}
+
+bool DumperParser::parseValue(int level, const char *&pos)
+{
+    // Simple string literal
+    switch (*pos) {
+    case '"': {
+            const char *valuePtr;
+            int valueSize;
+            return parseStringValue(valuePtr, valueSize, pos) && handleValue(valuePtr, valueSize);
+        }
+        // A List. Note that it has a trailing comma '["a",]'
+    case '[': {
+            if (!handleListStart())
+                return false;
+            pos++;
+            while (true) {
+                switch (*pos) {
+                case ']':
+                    pos++;
+                    return handleListEnd();
+                case '\0':
+                    return false;
+                default:
+                    break;
+                }
+                if (!parseValue(level + 1, pos))
+                    return false;
+                if (*pos == ',')
+                    pos++;
+            }
+        }        
+        return false;
+        // A hash '{a="b",b="c"}'
+    case '{': {
+            if (!handleHashStart())
+                return false;
+            pos++;
+            if (!parseHash(level + 1, pos))
+                return false;            
+            return handleHashEnd();
+        }
+        return false;
+    }
+    return false;
+}
+
+bool DumperParser::handleKeyword(const char *k, int size)
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO << '\n' << QByteArray(k, size);
+    return true;
+}
+
+bool DumperParser::handleListStart()
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO;
+    return true;
+}
+
+bool DumperParser::handleListEnd()
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO;
+    return true;
+}
+
+bool DumperParser::handleHashStart()
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO;
+    return true;
+}
+
+bool DumperParser::handleHashEnd()
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO;
+
+    return true;
+}
+
+bool DumperParser::handleValue(const char *k, int size)
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO << '\n' << QByteArray(k, size);
+    return true;
+}
+
 /* Parse 'query' (1) protocol response of the custom dumpers:
  * "'dumpers=["QByteArray","QDateTime",..."std::basic_string",],
  * qtversion=["4","5","1"],namespace="""' */
 
-bool parseQueryDumperOutput(const QByteArray &a, QStringList *types, QString *qtVersion, QString *qtNamespace)
-{
-    types->clear();
-    qtVersion->clear();
-    qtNamespace->clear();
-    const QChar equals = QLatin1Char('=');
-    const QChar doubleQuote = QLatin1Char('"');
-    const QChar openingBracket = QLatin1Char('[');
-    const QChar closingBracket = QLatin1Char(']');
-    const QString dumperKey = QLatin1String("dumpers");
-    const QString versionKey = QLatin1String("qtversion");
-    const QString namespaceKey = QLatin1String("namespace");
-
-    const QString s = QString::fromLatin1(a);
-    const int size = a.size();
-    for (int pos = 0; pos < size; ) {
-        // split into keyword / value pairs
-        const int equalsPos = s.indexOf(equals, pos);
-        if (equalsPos == -1)
-            break;
-        const QStringRef keyword = s.midRef(pos, equalsPos - pos);
-        // Array or flat value. Cut out value without delimiters
-        int valuePos = equalsPos + 1;
-        const QChar endChar = s.at(valuePos) == doubleQuote ? doubleQuote : closingBracket;
-        valuePos++;
-        int endValuePos = s.indexOf(endChar, valuePos);
-        if (endValuePos == -1)
-            return false;
-        QString value = s.mid(valuePos, endValuePos - valuePos);
-        pos = endValuePos;
-        // Evaluate
-        if (keyword == namespaceKey) {
-            *qtNamespace = value;
-        } else {
-            if (keyword == versionKey) {
-                *qtVersion = value.remove(doubleQuote).replace(QLatin1Char(','), QLatin1Char('.'));
+class QueryDumperParser : public DumperParser {
+public:
+    explicit QueryDumperParser(const char *s);
+
+    struct Data {
+        Data() : qtVersion(0) {}
+        QString qtNameSpace;
+        QString qtVersion;
+        QStringList types;
+    };
+
+    inline Data data() const { return m_data; }
+
+protected:
+    virtual bool handleKeyword(const char *k, int size);
+    virtual bool handleListStart();
+    virtual bool handleListEnd();
+    virtual bool handleValue(const char *k, int size);
+
+private:
+    enum Mode { None, ExpectingDumpers, ExpectingVersion, ExpectingNameSpace };
+    Mode m_mode;
+    Data m_data;
+};
+
+QueryDumperParser::QueryDumperParser(const char *s) :
+    DumperParser(s),
+    m_mode(None)
+{
+}
+
+bool QueryDumperParser::handleKeyword(const char *k, int size)        
+{
+    if (!qstrncmp(k, "dumpers", size)) {
+        m_mode = ExpectingDumpers;
+        return true;
+    }
+    if (!qstrncmp(k, "qtversion", size)) {
+        m_mode = ExpectingVersion;
+        return true;
+    }
+    if (!qstrncmp(k, "namespace", size)) {
+        m_mode = ExpectingNameSpace;
+        return true;
+    }
+    qWarning("%s Unexpected keyword %s.\n", Q_FUNC_INFO, QByteArray(k, size).constData());
+    return false;
+}
+
+bool QueryDumperParser::handleListStart()
+{
+    return m_mode == ExpectingDumpers || m_mode == ExpectingVersion;
+}
+
+bool QueryDumperParser::handleListEnd()
+{
+    m_mode = None;
+    return true;
+}
+
+bool QueryDumperParser::handleValue(const char *k, int size)
+{
+    switch (m_mode) {
+        case None:
+        return false;
+        case ExpectingDumpers:
+        m_data.types.push_back(QString::fromLatin1(k, size));
+        break;
+        case ExpectingNameSpace:
+        m_data.qtNameSpace = QString::fromLatin1(k, size);
+        break;
+    case ExpectingVersion: // ["4","1","5"]
+        if (!m_data.qtVersion.isEmpty())
+            m_data.qtVersion += QLatin1Char('.');
+        m_data.qtVersion += QString::fromLatin1(k, size);
+        break;
+    }
+    return true;
+}
+
+// parse a query
+bool QtDumperHelper::parseQuery(const char *data, Debugger debugger)
+{
+
+    QueryDumperParser parser(data);
+    if (!parser.run())
+        return false;
+    clear();
+    m_qtNamespace = parser.data().qtNameSpace;
+    setQtVersion(parser.data().qtVersion);
+    parseQueryTypes(parser.data().types, debugger);
+    return true;
+}
+
+QtDumperHelper::Type QtDumperHelper::type(const QString &typeName) const
+{
+    const QtDumperHelper::TypeData td = typeData(typeName);
+    return td.type;
+}
+
+QtDumperHelper::TypeData QtDumperHelper::typeData(const QString &typeName) const
+{
+    TypeData td;
+    td.type = UnknownType;
+    const Type st = simpleType(typeName);
+    if (st != UnknownType) {
+        td.isTemplate = false;
+        td.type =st;
+        return td;
+    }
+    // Try template
+    td.isTemplate = extractTemplate(typeName, &td.tmplate, &td.inner);
+    if (!td.isTemplate)
+        return td;
+    // Check the template type QMap<X,Y> -> 'QMap'
+    td.type = simpleType(td.tmplate);
+    return td;
+}
+
+void QtDumperHelper::evaluationParameters(const WatchData &data,
+                                          const TypeData &td,
+                                          Debugger /* debugger */,
+                                          QByteArray *inBuffer,
+                                          QStringList *extraArgsIn) const
+{
+    enum { maxExtraArgCount = 4 };
+
+    QStringList &extraArgs = *extraArgsIn;
+
+    // See extractTemplate for parameters
+    QStringList inners = td.inner.split(QLatin1Char('@'));
+    if (inners.at(0).isEmpty())
+        inners.clear();
+    for (int i = 0; i != inners.size(); ++i)
+        inners[i] = inners[i].simplified();
+
+    QString outertype = td.isTemplate ? td.tmplate : data.type;
+    // adjust the data extract
+    if (outertype == m_qtNamespace + QLatin1String("QWidget"))
+        outertype = m_qtNamespace + QLatin1String("QObject");
+
+    extraArgs.clear();
+
+    if (!inners.empty()) {
+        // "generic" template dumpers: passing sizeof(argument)
+        // gives already most information the dumpers need
+        const int count = qMin(int(maxExtraArgCount), inners.size());
+        for (int i = 0; i < count; i++)
+            extraArgs.push_back(sizeofTypeExpression(inners.at(i)));
+    }
+    int extraArgCount = extraArgs.size();
+    // Pad with zeros
+    const QString zero = QString(QLatin1Char('0'));
+    const int extraPad = maxExtraArgCount - extraArgCount;
+    for (int i = 0; i < extraPad; i++)
+        extraArgs.push_back(zero);
+
+    // in rare cases we need more or less:
+    switch (td.type) {
+    case QObjectType:
+    case QWidgetType:
+        extraArgs[0] = QLatin1String("(char*)&((('");
+        extraArgs[0] += m_qtNamespace;
+        extraArgs[0] += QLatin1String("QObjectPrivate'*)&");
+        extraArgs[0] += data.exp;
+        extraArgs[0] += QLatin1String(")->children)-(char*)&");
+        extraArgs[0] += data.exp;
+        break;
+    case QVectorType:
+        extraArgs[1] = QLatin1String("(char*)&((");
+        extraArgs[1] += data.exp;
+        extraArgs[1] += QLatin1String(").d->array)-(char*)");
+        extraArgs[1] += data.exp;
+        extraArgs[1] +=  QLatin1String(".d");
+        break;
+    case QObjectSlotType:
+    case QObjectSignalType: {
+            // we need the number out of something like
+            // iname="local.ob.slots.2" // ".deleteLater()"?
+            const int pos = data.iname.lastIndexOf('.');
+            const QString slotNumber = data.iname.mid(pos + 1);
+            QTC_ASSERT(slotNumber.toInt() != -1, /**/);
+            extraArgs[0] = slotNumber;
+        }
+        break;
+    case QMapType:
+    case QMultiMapType: {
+            QString nodetype;
+            if (m_qtVersion >= (4 << 16) + (5 << 8) + 0) {
+                nodetype = m_qtNamespace + QLatin1String("QMapNode");
+                nodetype += data.type.mid(outertype.size());
             } else {
-                if (keyword == dumperKey) {
-                    *types = value.remove(doubleQuote).split(QLatin1Char(','));
-                }
+                // FIXME: doesn't work for QMultiMap
+                nodetype  = data.type + QLatin1String("::Node");
             }
+            //qDebug() << "OUTERTYPE: " << outertype << " NODETYPE: " << nodetype
+            //    << "QT VERSION" << m_qtVersion << ((4 << 16) + (5 << 8) + 0);
+            extraArgs[2] = sizeofTypeExpression(nodetype);
+            extraArgs[3] = QLatin1String("(size_t)&(('");
+            extraArgs[3] += nodetype;
+            extraArgs[3] += QLatin1String("'*)0)->value");
         }
-        // find next keyword
-        while (pos < size && !s.at(pos).isLetterOrNumber())
-            pos++;
+        break;
+            case QMapNodeType:
+        extraArgs[2] = sizeofTypeExpression(data.type);
+        extraArgs[3] = QLatin1String("(size_t)&(('");
+        extraArgs[3] += data.type;
+        extraArgs[3] += QLatin1String("'*)0)->value");
+        break;
+    case StdVectorType:
+        //qDebug() << "EXTRACT TEMPLATE: " << outertype << inners;
+        if (inners.at(0) == QLatin1String("bool")) {
+            outertype = QLatin1String("std::vector::bool");
+        } else {
+            //extraArgs[extraArgCount++] = sizeofTypeExpression(data.type);
+            //extraArgs[extraArgCount++] = "(size_t)&(('" + data.type + "'*)0)->value";
+        }
+        break;
+    case StdDequeType:
+        extraArgs[1] = zero;
+    case StdStackType:
+        // remove 'std::allocator<...>':
+        extraArgs[1] = zero;
+        break;
+    case StdSetType:
+        // remove 'std::less<...>':
+        extraArgs[1] = zero;
+        // remove 'std::allocator<...>':
+        extraArgs[2] = zero;
+        break;
+    case StdMapType: {
+            // We don't want the comparator and the allocator confuse gdb.
+            // But we need the offset of the second item in the value pair.
+            // We read the type of the pair from the allocator argument because
+            // that gets the constness "right" (in the sense that gdb can
+            // read it back;
+            QString pairType = inners.at(3);
+            // remove 'std::allocator<...>':
+            pairType = pairType.mid(15, pairType.size() - 15 - 2);
+            extraArgs[2] = QLatin1String("(size_t)&(('");
+            extraArgs[2] += pairType;
+            extraArgs[2] += QLatin1String("'*)0)->second");
+            extraArgs[3] = zero;
+        }
+        break;
+    case StdStringType:
+        //qDebug() << "EXTRACT TEMPLATE: " << outertype << inners;
+        if (inners.at(0) == QLatin1String("char")) {
+            outertype = QLatin1String("std::string");
+        } else if (inners.at(0) == QLatin1String("wchar_t")) {
+            outertype = QLatin1String("std::wstring");
+        }
+        qFill(extraArgs, zero);
+        break;
+    case UnknownType:
+        qWarning("Unknown type encountered in %s.\n", Q_FUNC_INFO);
+        break;
+    case SupportedType:
+        break;
+    }
+
+    inBuffer->clear();
+    inBuffer->append(outertype.toUtf8());
+    inBuffer->append('\0');
+    inBuffer->append(data.iname.toUtf8());
+    inBuffer->append('\0');
+    inBuffer->append(data.exp.toUtf8());
+    inBuffer->append('\0');
+    inBuffer->append(td.inner.toUtf8());
+    inBuffer->append('\0');
+    inBuffer->append(data.iname.toUtf8());
+    inBuffer->append('\0');
+
+    if (debug)
+        qDebug() << '\n' << Q_FUNC_INFO << '\n' << data.toString() << "\n-->" << outertype << td.type << extraArgs;
+}
+
+/* Parse value:
+ * "iname="local.sl",addr="0x0012BA84",value="<3 items>",valuedisabled="true",
+ * numchild="3",childtype="QString",childnumchild="0",children=[{name="0",value="<binhex>",
+ * valueencoded="2"},{name="1",value="dAB3AG8A",valueencoded="2"},{name="2",
+ * value="dABoAHIAZQBlAA==",valueencoded="2"}]" */
+
+class ValueDumperParser : public DumperParser {
+public:
+    explicit ValueDumperParser(const char *s);
+
+    inline QtDumperResult result() const { return m_result; }
+
+protected:
+    virtual bool handleKeyword(const char *k, int size);
+    virtual bool handleHashStart();
+    virtual bool handleValue(const char *k, int size);
+
+private:
+    enum Mode { None, ExpectingIName, ExpectingAddress, ExpectingValue,
+                ExpectingType, ExpectingInternal,
+                ExpectingValueDisabled,  ExpectingValueEncoded,
+                ExpectingChildType, ExpectingChildCount,
+                IgnoreNext,
+                ChildModeStart,
+                ExpectingChildren,ExpectingChildName, ExpectingChildAddress,
+                ExpectingChildValue, ExpectingChildValueEncoded  };
+
+    static inline Mode nextMode(Mode in, const char *keyword, int size);
+
+    Mode m_mode;
+    QtDumperResult m_result;
+};
+
+ValueDumperParser::ValueDumperParser(const char *s) :
+   DumperParser(s),
+   m_mode(None)
+{
+}
+
+// Check key words
+ValueDumperParser::Mode ValueDumperParser::nextMode(Mode in, const char *keyword, int size)
+{
+    // Careful with same prefix
+    switch (size) {
+    case 4:
+        if (!qstrncmp(keyword, "addr", size))
+            return in > ChildModeStart ? ExpectingChildAddress : ExpectingAddress;
+        if (!qstrncmp(keyword, "type", size))
+            return ExpectingType;
+        if (!qstrncmp(keyword, "name", size))
+            return ExpectingChildName;
+        break;
+    case 5:
+        if (!qstrncmp(keyword, "iname", size))
+            return ExpectingIName;
+        if (!qstrncmp(keyword, "value", size))
+            return in > ChildModeStart ? ExpectingChildValue : ExpectingValue;
+        break;
+    case 8:
+        if (!qstrncmp(keyword, "children", size))
+            return ExpectingChildren;
+        if (!qstrncmp(keyword, "numchild", size))
+            return ExpectingChildCount;
+        if (!qstrncmp(keyword, "internal", size))
+            return ExpectingInternal;
+        break;
+    case 9:
+        if (!qstrncmp(keyword, "childtype", size))
+            return ExpectingChildType;
+        break;    
+    case 12:
+        if (!qstrncmp(keyword, "valueencoded", size))
+            return in > ChildModeStart ? ExpectingChildValueEncoded : ExpectingValueEncoded;
+        break;
+    case 13:
+        if (!qstrncmp(keyword, "valuedisabled", size))
+            return ExpectingValueDisabled;
+        if (!qstrncmp(keyword, "childnumchild", size))
+            return IgnoreNext;
+        break;
+    }
+    return IgnoreNext;
+}
+
+bool ValueDumperParser::handleKeyword(const char *k, int size)
+{
+    const Mode newMode = nextMode(m_mode, k, size);
+    if (debug && newMode == IgnoreNext)
+        qWarning("%s Unexpected keyword %s.\n", Q_FUNC_INFO, QByteArray(k, size).constData());
+    m_mode = newMode;
+    return true;
+}
+
+bool ValueDumperParser::handleHashStart()
+{
+    m_result.children.push_back(QtDumperResult::Child());
+    return true;
+}
+
+bool ValueDumperParser::handleValue(const char *k, int size)
+{
+    const QByteArray valueBA(k, size);
+    switch (m_mode) {
+    case None:
+    case ChildModeStart:
+        return false;
+    case ExpectingIName:
+        m_result.iname = QString::fromLatin1(valueBA);
+        break;
+    case ExpectingAddress:
+        m_result.address = QString::fromLatin1(valueBA);
+        break;
+    case ExpectingValue:
+        m_result.value = valueBA;
+        break;
+    case ExpectingValueDisabled:
+        m_result.valuedisabled = valueBA == "true";
+        break;
+    case ExpectingValueEncoded:
+        m_result.valueEncoded = QString::fromLatin1(valueBA).toInt();
+        break;
+    case ExpectingType:
+        m_result.type = QString::fromLatin1(valueBA);
+        break;
+    case ExpectingInternal:
+        m_result.internal = valueBA == "true";
+        break;
+    case ExpectingChildType:
+        m_result.childType = QString::fromLatin1(valueBA);
+        break;
+    case ExpectingChildCount:
+        m_result.childCount = QString::fromLatin1(valueBA).toInt();
+        break;
+    case ExpectingChildren:
+    case IgnoreNext:
+        break;
+    case ExpectingChildName:
+        m_result.children.back().name = QString::fromLatin1(valueBA);
+        break;
+    case ExpectingChildAddress:
+        m_result.children.back().address = QString::fromLatin1(valueBA);
+        break;
+    case ExpectingChildValue:
+        m_result.children.back().value = valueBA;
+        break;
+    case ExpectingChildValueEncoded:
+        m_result.children.back().valueEncoded = QString::fromLatin1(valueBA).toInt();
+        break;
     }
     return true;
 }
 
+bool QtDumperHelper::parseValue(const char *data, QtDumperResult *r)
+{    
+    ValueDumperParser parser(data);
+    if (!parser.run())
+        return false;
+    *r = parser.result();
+    return true;
+}
+
 }
 }
diff --git a/src/plugins/debugger/watchutils.h b/src/plugins/debugger/watchutils.h
index 392f0e0c3fdb89880c7f98ec1d7e4166f3f7f883..2fd9a802465d7f26349f450cce223e66200da23f 100644
--- a/src/plugins/debugger/watchutils.h
+++ b/src/plugins/debugger/watchutils.h
@@ -31,15 +31,17 @@
 #define WATCHUTILS_H
 
 #include <QtCore/QString>
+#include <QtCore/QMap>
 
 QT_BEGIN_NAMESPACE
-class QString;
-class QByteArray;
+class QDebug;
 QT_END_NAMESPACE
 
 namespace Debugger {
 namespace Internal {
 
+class WatchData;
+
 QString dotEscape(QString str);
 QString currentTime();
 bool isSkippableFunction(const QString &funcName, const QString &fileName);
@@ -64,8 +66,131 @@ QString extractTypeFromPTypeOutput(const QString &str);
 bool isIntOrFloatType(const QString &type);
 QString sizeofTypeExpression(const QString &type);
 
-// Parse 'query' (1) protocol response of the custom dumpers
-bool parseQueryDumperOutput(const QByteArray &a, QStringList *types, QString *qtVersion, QString *qtNamespace);
+// Decode string data as returned by the dumper helpers.
+QString decodeData(const QByteArray &baIn, int encoding);
+
+// Result of a dumper call.
+struct QtDumperResult
+{
+    struct Child {
+        Child();
+
+        int valueEncoded;
+        QString name;
+        QString address;
+        QByteArray value;
+    };
+
+    QtDumperResult();
+    void clear();
+    QList<WatchData> toWatchData(int source = 0) const;
+
+    QString iname;
+    QString address;
+    QString type;
+    QByteArray value;
+    int valueEncoded;
+    bool valuedisabled;
+    int childCount;
+    bool internal;
+    QString childType;
+    QList <Child> children;
+};
+
+QDebug operator<<(QDebug in, const QtDumperResult &d);
+
+/* Attempt to put common code of the dumper handling into a helper
+ * class.
+ * "Custom dumper" is a library compiled against the current
+ * Qt containing functions to evaluate values of Qt classes
+ * (such as QString, taking pointers to their addresses).
+ * The library must be loaded into the debuggee.
+ * It provides a function that takes input from an input buffer
+ * and some parameters and writes output into an output buffer.
+ * Parameter 1 is the protocol:
+ * 1) Query. Fills output buffer with known types, Qt version and namespace.
+ *    This information is parsed and stored by this class (special type
+ *    enumeration).
+ * 2) Evaluate symbol, taking address and some additional parameters
+ *    depending on type. */
+
+class QtDumperHelper {
+public:
+    enum Debugger {
+        GdbDebugger,  // Can evalulate expressions in function calls
+        CdbDebugger   // Can only handle scalar, simple types in function calls
+    };
+
+    enum Type {
+        UnknownType,
+        SupportedType, // A type that requires no special handling by the dumper
+        // Below types require special handling
+        QObjectType, QWidgetType, QObjectSlotType, QObjectSignalType,
+        QVectorType, QMapType, QMultiMapType, QMapNodeType,
+        StdVectorType, StdDequeType, StdSetType,StdMapType, StdStackType,
+        StdStringType
+    };
+
+    // Type/Parameter struct required for building a value query
+    struct TypeData {
+        TypeData();
+        void clear();
+
+        Type type;
+        bool isTemplate;
+        QString tmplate;
+        QString inner;
+    };
+
+    QtDumperHelper();
+    void clear();
+
+    int typeCount() const;
+    // Look up a simple, non-template  type
+    Type simpleType(const QString &simpleType) const;
+    // Look up a (potentially) template type and fill parameter struct
+    TypeData typeData(const QString &typeName) const;
+    Type type(const QString &typeName) const;
+
+    int qtVersion() const;
+    QString qtVersionString() const;
+    void setQtVersion(int v);
+    void setQtVersion(const QString &v);
+
+    QString qtNamespace() const;
+    void setQtNamespace(const QString &qtNamespace);
+
+    // Complete parse of "query" (protocol 1) response from debuggee buffer.
+    // 'data' excludes the leading indicator character.
+    bool parseQuery(const char *data, Debugger debugger);
+    // Set up from pre-parsed type list
+    void parseQueryTypes(const QStringList &l, Debugger debugger);
+
+    // Determine the parameters required for an "evaluate" (protocol 2) call
+    void evaluationParameters(const WatchData &data,
+                              const TypeData &td,
+                              Debugger debugger,
+                              QByteArray *inBuffer,
+                              QStringList *extraParameters) const;
+
+    // Parse the value response (protocol 2) from debuggee buffer.
+    // 'data' excludes the leading indicator character.
+    static bool parseValue(const char *data, QtDumperResult *r);
+
+    static bool needsExpressionSyntax(Type t);
+
+    QString toString(bool debug = false) const;
+
+private:    
+    typedef QMap<QString, Type> NameTypeMap;
+
+    // Look up a simple (namespace) type
+    static Type specialType(QString s);
+
+    NameTypeMap m_nameTypeMap;
+    int m_qtVersion;
+    QString m_qtNamespace;
+};
 
 } // namespace Internal
 } // namespace Debugger
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
index 71ac3bb1e6ca47b297da0b22fe59c1ec1ec08d02..7484b29e34543e03c5b91b66958aa5f23a904927 100644
--- a/src/plugins/debugger/watchwindow.cpp
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -122,6 +122,9 @@ WatchWindow::WatchWindow(Type type, QWidget *parent)
     setIndentation(indentation() * 9/10);
     setUniformRowHeights(true);
     setItemDelegate(new WatchDelegate(this));
+    setDragEnabled(true);
+    setAcceptDrops(true);
+    setDropIndicatorShown(true);
 
     connect(this, SIGNAL(expanded(QModelIndex)),
         this, SLOT(expandNode(QModelIndex)));
@@ -161,6 +164,35 @@ void WatchWindow::keyPressEvent(QKeyEvent *ev)
     QTreeView::keyPressEvent(ev);
 }
 
+void WatchWindow::dragEnterEvent(QDragEnterEvent *ev)
+{
+    //QTreeView::dragEnterEvent(ev);
+    if (ev->mimeData()->hasFormat("text/plain")) {
+        ev->setDropAction(Qt::CopyAction);
+        ev->accept();
+    }
+}
+
+void WatchWindow::dragMoveEvent(QDragMoveEvent *ev)
+{
+    //QTreeView::dragMoveEvent(ev);
+    if (ev->mimeData()->hasFormat("text/plain")) {
+        ev->setDropAction(Qt::CopyAction);
+        ev->accept();
+    }
+}
+
+void WatchWindow::dropEvent(QDropEvent *ev)
+{
+    if (ev->mimeData()->hasFormat("text/plain")) {
+        theDebuggerAction(WatchExpression)->trigger(ev->mimeData()->text());
+        //ev->acceptProposedAction();
+        ev->setDropAction(Qt::CopyAction);
+        ev->accept();
+    }
+    //QTreeView::dropEvent(ev);
+}
+
 void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
 {
     QMenu menu;
diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h
index 715507f8b16df9cef441cebd960581a11e02d9e4..adf4e06347e99268b29355a8822c527a2bd2f9e3 100644
--- a/src/plugins/debugger/watchwindow.h
+++ b/src/plugins/debugger/watchwindow.h
@@ -64,6 +64,10 @@ private:
 
     void keyPressEvent(QKeyEvent *ev);
     void contextMenuEvent(QContextMenuEvent *ev);
+    void dragEnterEvent(QDragEnterEvent *ev);
+    void dropEvent(QDropEvent *ev);
+    void dragMoveEvent(QDragMoveEvent *ev);
+
     void editItem(const QModelIndex &idx);
     void reset(); /* reimpl */
 
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index 2550f88eb80aac33d001987f37d4ac60c3c5b7ac..035fdb6792846d9cbbec5558aae1836fbde3e6a5 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -877,10 +877,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
         finishMovement();
     } else if (m_submode == DeleteSubMode && key == 'd') { // tested
         moveToStartOfLine();
+        setTargetColumn(); 
         setAnchor();
         moveDown(count());
         m_moveType = MoveLineWise;
-        finishMovement("d");
+        setDotCommand("%1dd", count());
+        finishMovement();
     } else if (m_submode == YankSubMode && key == 'y') {
         moveToStartOfLine();
         setAnchor();
diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp
index 56c294a2e06204ad5695935b07c8b62199a20a5f..493e6c492dcf6d66b4b44ca418dfb35f23c7f87b 100644
--- a/src/plugins/projectexplorer/compileoutputwindow.cpp
+++ b/src/plugins/projectexplorer/compileoutputwindow.cpp
@@ -36,6 +36,7 @@
 #include <QtGui/QKeyEvent>
 #include <QtGui/QIcon>
 #include <QtGui/QTextEdit>
+#include <QtGui/QScrollBar>
 
 using namespace ProjectExplorer;
 using namespace ProjectExplorer::Internal;
@@ -82,9 +83,10 @@ void CompileOutputWindow::clearContents()
     m_textEdit->clear();
 }
 
-void CompileOutputWindow::visibilityChanged(bool /* b */)
+void CompileOutputWindow::visibilityChanged(bool b)
 {
-
+    if (b)
+        m_textEdit->verticalScrollBar()->setValue(m_textEdit->verticalScrollBar()->maximum());
 }
 
 int CompileOutputWindow::priorityInStatusBar() const
diff --git a/src/plugins/qt4projectmanager/projectloadwizard.cpp b/src/plugins/qt4projectmanager/projectloadwizard.cpp
index 3887e4f9487e2702562accdf0c0296ce210f9d8e..ab27fb981ced6976102c0116e40138c46bcc415f 100644
--- a/src/plugins/qt4projectmanager/projectloadwizard.cpp
+++ b/src/plugins/qt4projectmanager/projectloadwizard.cpp
@@ -190,7 +190,7 @@ void ProjectLoadWizard::setupImportPage(QtVersion *version, QtVersion::QmakeBuil
     QVBoxLayout *importLayout = new QVBoxLayout(importPage);
     importLabel = new QLabel(importPage);
 
-    QString versionString = version->name() + " (" + version->path() + ")";
+    QString versionString = version->name() + " (" + QDir::toNativeSeparators(version->path()) + ")";
     QString buildConfigString = (buildConfig & QtVersion::BuildAll) ? QLatin1String("debug_and_release ") : QLatin1String("");
     buildConfigString.append((buildConfig & QtVersion::DebugBuild) ? QLatin1String("debug") : QLatin1String("release"));
     importLabel->setTextFormat(Qt::RichText);
@@ -211,7 +211,7 @@ void ProjectLoadWizard::setupImportPage(QtVersion *version, QtVersion::QmakeBuil
     import2Label->setTextFormat(Qt::RichText);
     if (m_temporaryVersion)
         import2Label->setText(tr("<b>Note:</b> Importing the settings will automatically add the Qt Version from:<br><b>%1</b> to the list of qt versions.")
-                              .arg(m_importVersion->path()));
+                              .arg(QDir::toNativeSeparators(m_importVersion->path())));
     importLayout->addWidget(import2Label);
     addPage(importPage);
 }
diff --git a/tests/auto/fakevim/main.cpp b/tests/auto/fakevim/main.cpp
index fd5b06f0931b6c168e60a07cff90df3796e260f8..9e931526f92acfaa31d1cd33277d84d8dcc05a75 100644
--- a/tests/auto/fakevim/main.cpp
+++ b/tests/auto/fakevim/main.cpp
@@ -265,6 +265,10 @@ void tst_FakeVim::command_dd()
     check("dd",  l[0] + "\n@" + lmid(2));
     check(".",   l[0] + "\n@" + lmid(3));
     check("3dd", l[0] + "\n@" + lmid(6));
+    check("8l",  l[0] + "\n    QApp@lication app(argc, argv);\n" + lmid(7));
+    check("dd",  l[0] + "\n@" + lmid(7));
+    check(".",   l[0] + "\n@" + lmid(8));
+    check("dd",  l[0] + "\n@" + lmid(9));
 }
 
 void tst_FakeVim::command_dollar()