diff --git a/src/plugins/debugger/cdb/breakpoint.cpp b/src/plugins/debugger/cdb/breakpoint.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5ce3edf2d66808098f26f2db2274853797f02a17
--- /dev/null
+++ b/src/plugins/debugger/cdb/breakpoint.cpp
@@ -0,0 +1,493 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "breakpoint.h"
+#include "coreengine.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QTextStream>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QMap>
+
+#include <psapi.h>
+
+enum { debugBP = 0 };
+
+namespace CdbCore {
+
+// The CDB breakpoint expression syntax is:
+//    `foo.cpp:523`[ "condition"]
+//    module!function[ "condition"]
+
+static const char sourceFileQuoteC = '`';
+
+BreakPoint::BreakPoint() :
+    ignoreCount(0),
+    lineNumber(-1),
+    oneShot(false),
+    enabled(true)
+{
+}
+
+int BreakPoint::compare(const BreakPoint& rhs) const
+{
+    if (ignoreCount > rhs.ignoreCount)
+        return 1;
+    if (ignoreCount < rhs.ignoreCount)
+        return -1;
+    if (lineNumber > rhs.lineNumber)
+        return 1;
+    if (lineNumber < rhs.lineNumber)
+        return -1;
+    if (oneShot && !rhs.oneShot)
+        return 1;
+    if (!oneShot && rhs.oneShot)
+        return -1;
+    if (enabled && !rhs.enabled)
+        return 1;
+    if (!enabled && rhs.enabled)
+        return -1;
+    if (const int fileCmp = fileName.compare(rhs.fileName))
+        return fileCmp;
+    if (const int  funcCmp = funcName.compare(rhs.funcName))
+        return funcCmp;
+    if (const int condCmp = condition.compare(rhs.condition))
+        return condCmp;
+    return 0;
+}
+
+void BreakPoint::clear()
+{
+     ignoreCount = 0;
+     oneShot = false;
+     enabled = true;
+     clearExpressionData();
+}
+
+void BreakPoint::clearExpressionData()
+{
+    fileName.clear();
+    condition.clear();
+    funcName.clear();
+    lineNumber = -1;
+}
+
+QDebug operator<<(QDebug dbg, const BreakPoint &bp)
+{
+    QDebug nsp = dbg.nospace();
+    if (!bp.fileName.isEmpty()) {
+        nsp << "fileName='" << bp.fileName << ':' << bp.lineNumber << '\'';
+    } else {
+        nsp << "funcName='" << bp.funcName << '\'';
+    }
+    if (!bp.condition.isEmpty())
+        nsp << " condition='" << bp.condition << '\'';
+    if (bp.ignoreCount)
+        nsp << " ignoreCount=" << bp.ignoreCount;
+    if (bp.enabled)
+        nsp << " enabled";
+    if (bp.oneShot)
+        nsp << " oneShot";
+    return dbg;
+}
+
+QString BreakPoint::expression() const
+{
+    // format the breakpoint expression (file/function and condition)
+    QString rc;
+    QTextStream str(&rc);
+    if (funcName.isEmpty()) {
+        const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC);
+        str << sourceFileQuote << QDir::toNativeSeparators(fileName) << QLatin1Char(':') << lineNumber << sourceFileQuote;
+    } else {
+        str << funcName;
+    }
+    if (!condition.isEmpty()) {
+        const QChar doubleQuote = QLatin1Char('"');
+        str << QLatin1Char(' ') << doubleQuote << condition << doubleQuote;
+    }
+    return rc;
+}
+
+bool BreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
+{
+    const QString expr = expression();
+    if (debugBP)
+        qDebug() << Q_FUNC_INFO << *this << expr;
+    const HRESULT hr = ibp->SetOffsetExpressionWide(reinterpret_cast<PCWSTR>(expr.utf16()));
+    if (FAILED(hr)) {
+        *errorMessage = QString::fromLatin1("Unable to set breakpoint '%1' : %2").
+                        arg(expr, CdbCore::msgComFailed("SetOffsetExpressionWide", hr));
+        return false;
+    }
+    // Pass Count is ignoreCount + 1
+    ibp->SetPassCount(ignoreCount + 1u);
+    ULONG flags = 0;
+    if (enabled)
+        flags |= DEBUG_BREAKPOINT_ENABLED;
+    if (oneShot)
+        flags |= DEBUG_BREAKPOINT_ONE_SHOT;
+    ibp->AddFlags(flags);
+    return true;
+}
+
+static inline QString msgCannotAddBreakPoint(const QString &why)
+{
+    return QString::fromLatin1("Unable to add breakpoint: %1").arg(why);
+}
+
+bool BreakPoint::add(CIDebugControl* debugControl,
+                        QString *errorMessage,
+                        unsigned long *id,
+                        quint64 *address) const
+{
+    IDebugBreakpoint2* ibp = 0;
+    if (address)
+        *address = 0;
+    if (id)
+        *id = 0;
+    HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
+    if (FAILED(hr)) {
+        *errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("AddBreakpoint2", hr));
+        return false;
+    }
+    if (!ibp) {
+        *errorMessage = msgCannotAddBreakPoint(QLatin1String("<Unknown error>"));
+        return false;
+    }
+    if (!apply(ibp, errorMessage))
+        return false;
+    // GetOffset can fail when attaching to remote processes, ignore return
+    if (address) {
+        hr = ibp->GetOffset(address);
+        if (FAILED(hr))
+            *address = 0;
+    }
+    if (id) {
+        hr = ibp->GetId(id);
+        if (FAILED(hr)) {
+            *errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("GetId", hr));
+            return false;
+        }
+    }
+    return true;
+}
+
+// Helper for normalizing file names:
+// Map the device paths in  a file name to back to drive letters
+// "/Device/HarddiskVolume1/file.cpp" -> "C:/file.cpp"
+
+static bool mapDeviceToDriveLetter(QString *s)
+{
+    enum { bufSize = 512 };
+    // Retrieve drive letters and get their device names.
+    // Do not cache as it may change due to removable/network drives.
+    TCHAR driveLetters[bufSize];
+    if (!GetLogicalDriveStrings(bufSize-1, driveLetters))
+        return false;
+
+    TCHAR driveName[MAX_PATH];
+    TCHAR szDrive[3] = TEXT(" :");
+    for (const TCHAR *driveLetter = driveLetters; *driveLetter; driveLetter++) {
+        szDrive[0] = *driveLetter; // Look up each device name
+        if (QueryDosDevice(szDrive, driveName, MAX_PATH)) {
+            const QString deviceName = QString::fromUtf16(driveName);
+            if (s->startsWith(deviceName)) {
+                s->replace(0, deviceName.size(), QString::fromUtf16(szDrive));
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+// Helper for normalizing file names:
+// Determine normalized case of a Windows file name (camelcase.cpp -> CamelCase.cpp)
+// as the debugger reports lower case file names.
+// Restriction: File needs to exists and be non-empty and will be to be opened/mapped.
+// This is the MSDN-recommended way of doing that. The result should be cached.
+
+static inline QString normalizeFileNameCaseHelper(const QString &f)
+{
+    HANDLE hFile = CreateFile(f.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+    if(hFile == INVALID_HANDLE_VALUE)
+        return f;
+    // Get the file size. We need a non-empty file to map it.
+    DWORD dwFileSizeHi = 0;
+    DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
+    if (dwFileSizeLo == 0 && dwFileSizeHi == 0) {
+        CloseHandle(hFile);
+        return f;
+    }
+    // Create a file mapping object.
+    HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 1, NULL);
+    if (!hFileMap)  {
+        CloseHandle(hFile);
+        return f;
+    }
+
+    // Create a file mapping to get the file name.
+    void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
+    if (!pMem) {
+        CloseHandle(hFileMap);
+        CloseHandle(hFile);
+        return f;
+    }
+
+    QString rc;
+    WCHAR pszFilename[MAX_PATH];
+    pszFilename[0] = 0;
+    // Get a file name of the form "/Device/HarddiskVolume1/file.cpp"
+    if (GetMappedFileName (GetCurrentProcess(), pMem, pszFilename, MAX_PATH)) {
+        rc = QString::fromUtf16(pszFilename);
+        if (!mapDeviceToDriveLetter(&rc))
+            rc.clear();
+    }
+
+    UnmapViewOfFile(pMem);
+    CloseHandle(hFileMap);
+    CloseHandle(hFile);
+    return rc.isEmpty() ? f : rc;
+}
+
+// Make sure file can be found in editor manager and text markers
+// Use '/', correct case and capitalize drive letter. Use a cache.
+
+typedef QHash<QString, QString> NormalizedFileCache;
+Q_GLOBAL_STATIC(NormalizedFileCache, normalizedFileNameCache)
+
+QString BreakPoint::normalizeFileName(const QString &f)
+{
+    QTC_ASSERT(!f.isEmpty(), return f)
+    const NormalizedFileCache::const_iterator it = normalizedFileNameCache()->constFind(f);
+    if (it != normalizedFileNameCache()->constEnd())
+        return it.value();
+    QString normalizedName = QDir::fromNativeSeparators(normalizeFileNameCaseHelper(f));
+    // Upcase drive letter for consistency even if case mapping fails.
+    if (normalizedName.size() > 2 && normalizedName.at(1) == QLatin1Char(':'))
+        normalizedName[0] = normalizedName.at(0).toUpper();
+    normalizedFileNameCache()->insert(f, normalizedName);
+    return normalizedName;
+}
+
+void BreakPoint::clearNormalizeFileNameCache()
+{
+    normalizedFileNameCache()->clear();
+}
+
+bool BreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
+{
+    clear();
+    WCHAR wszBuf[MAX_PATH];
+    const HRESULT hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0);
+    if (FAILED(hr)) {
+        *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint: %1").
+                        arg(CdbCore::msgComFailed("GetOffsetExpressionWide", hr));
+        return false;
+    }
+    // Pass Count is ignoreCount + 1
+    ibp->GetPassCount(&ignoreCount);
+    if (ignoreCount)
+        ignoreCount--;
+    ULONG flags = 0;
+    ibp->GetFlags(&flags);
+    oneShot = (flags & DEBUG_BREAKPOINT_ONE_SHOT);
+    enabled = (flags & DEBUG_BREAKPOINT_ENABLED);
+    const QString expr = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
+    if (!parseExpression(expr)) {
+        *errorMessage = QString::fromLatin1("Parsing of '%1' failed.").arg(expr);
+        return false;
+    }
+    return true;
+}
+
+bool BreakPoint::parseExpression(const QString &expr)
+{
+    clearExpressionData();
+    const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC);
+    // Check for file or function
+    int conditionPos = 0;
+    if (expr.startsWith(sourceFileQuote)) { // `c:\foo.cpp:523`[ "condition"]
+        // Do not fall for the drive letter colon here
+        const int colonPos = expr.indexOf(QLatin1Char(':'), 3);
+        if (colonPos == -1)
+            return false;
+        conditionPos = expr.indexOf(sourceFileQuote, colonPos + 1);
+        if (conditionPos == -1)
+            return false;
+        fileName = normalizeFileName(expr.mid(1, colonPos - 1));
+        const QString lineNumberS = expr.mid(colonPos + 1, conditionPos - colonPos - 1);
+        bool lineNumberOk = false;
+        lineNumber = lineNumberS.toInt(&lineNumberOk);
+        if (!lineNumberOk)
+            return false;
+        conditionPos++;
+    } else {
+        // Check function token
+        conditionPos = expr.indexOf(QLatin1Char(' '));
+        if (conditionPos != -1) {
+            funcName = expr.mid(0, conditionPos);
+            conditionPos++;
+        } else {
+            funcName = expr;
+            conditionPos = expr.size();
+        }
+    }
+    // Condition? ".if bla"
+    if (conditionPos >= expr.size())
+        return true;
+    const QChar doubleQuote = QLatin1Char('"');
+    conditionPos = expr.indexOf(doubleQuote, conditionPos);
+    if (conditionPos == -1)
+        return true;
+    conditionPos++;
+    const int condEndPos = expr.lastIndexOf(doubleQuote);
+    if (condEndPos == -1)
+        return false;
+    condition = expr.mid(conditionPos, condEndPos - conditionPos);
+    return true;
+}
+
+bool BreakPoint::getBreakPointCount(CIDebugControl* debugControl, ULONG *count, QString *errorMessage /* = 0*/)
+{
+    const HRESULT hr = debugControl->GetNumberBreakpoints(count);
+    if (FAILED(hr)) {
+        if (errorMessage)
+            *errorMessage = QString::fromLatin1("Cannot determine breakpoint count: %1").
+                            arg(CdbCore::msgComFailed("GetNumberBreakpoints", hr));
+        return false;
+    }
+    return true;
+}
+
+bool BreakPoint::getBreakPoints(CIDebugControl* debugControl, QList<BreakPoint> *bps, QString *errorMessage)
+{
+    ULONG count = 0;
+    bps->clear();
+    if (!getBreakPointCount(debugControl, &count, errorMessage))
+        return false;
+    // retrieve one by one and parse
+    for (ULONG b= 0; b < count; b++) {
+        IDebugBreakpoint2 *ibp = 0;
+        const HRESULT hr = debugControl->GetBreakpointByIndex2(b, &ibp);
+        if (FAILED(hr)) {
+            *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2").
+                            arg(b).arg(CdbCore::msgComFailed("GetBreakpointByIndex2", hr));
+            return false;
+        }
+        BreakPoint bp;
+        if (!bp.retrieve(ibp, errorMessage))
+            return false;
+        bps->push_back(bp);
+    }
+    return true;
+}
+
+// Find a breakpoint by id
+static inline QString msgNoBreakPointWithId(unsigned long id, const QString &why)
+{
+    return QString::fromLatin1("Unable to find breakpoint with id %1: %2").arg(id).arg(why);
+}
+
+IDebugBreakpoint2 *BreakPoint::breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
+{
+    CIDebugBreakpoint *ibp = 0;
+    const HRESULT hr = ctl->GetBreakpointById2(id, &ibp);
+    if (FAILED(hr)) {
+        *errorMessage = msgNoBreakPointWithId(id, CdbCore::msgComFailed("GetBreakpointById2", hr));
+        return 0;
+    }
+    if (!ibp) {
+        *errorMessage = msgNoBreakPointWithId(id, QLatin1String("<not found>"));
+        return 0;
+    }
+    return ibp;
+}
+
+// Remove breakpoint by id
+bool BreakPoint::removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
+{
+    if (debugBP)
+        qDebug() << Q_FUNC_INFO << id;
+    CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
+    if (!ibp)
+        return false;
+    const HRESULT hr = ctl->RemoveBreakpoint2(ibp);
+    if (FAILED(hr)) {
+        *errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").arg(id).arg(CdbCore::msgComFailed("RemoveBreakpointById2", hr));
+        return false;
+    }
+    return true;
+}
+
+// Set enabled by id
+
+// Change enabled state of a breakpoint by id
+static inline QString msgCannotSetBreakPointEnabled(unsigned long id, bool enabled, const QString &why)
+{
+    return QString::fromLatin1("Cannot %1 breakpoint %2: %3").
+            arg(QLatin1String(enabled ? "enable" : "disable")).arg(id).arg(why);
+}
+
+bool BreakPoint::setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage)
+{
+    if (debugBP)
+        qDebug() << Q_FUNC_INFO << id << enabled;
+    CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
+    if (!ibp) {
+        *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, *errorMessage);
+        return false;
+    }
+    // Compare flags
+    ULONG flags;
+    HRESULT hr = ibp->GetFlags(&flags);
+    if (FAILED(hr)) {
+        *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, CdbCore::msgComFailed("GetFlags", hr));
+        return false;
+    }
+    const bool wasEnabled = (flags & DEBUG_BREAKPOINT_ENABLED);
+    if (wasEnabled == enabled)
+        return true;
+    // Set new value
+    if (enabled) {
+        flags |= DEBUG_BREAKPOINT_ENABLED;
+    } else {
+        flags &= ~DEBUG_BREAKPOINT_ENABLED;
+    }
+    hr = ibp->SetFlags(flags);
+    if (FAILED(hr)) {
+        *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, CdbCore::msgComFailed("SetFlags", hr));
+        return false;
+    }
+    return true;
+}
+
+}
diff --git a/src/plugins/debugger/cdb/breakpoint.h b/src/plugins/debugger/cdb/breakpoint.h
new file mode 100644
index 0000000000000000000000000000000000000000..61fb02accd51236d45c08b0dc44282d1acf5b030
--- /dev/null
+++ b/src/plugins/debugger/cdb/breakpoint.h
@@ -0,0 +1,99 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CDBCOREBREAKPOINTS_H
+#define CDBCOREBREAKPOINTS_H
+
+#include "cdbcom.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+QT_END_NAMESPACE
+
+namespace CdbCore {
+
+/* CDB Break point data structure with utilities to
+ * apply to engine and to retrieve them from the engine and comparison. */
+
+struct BreakPoint
+{
+    BreakPoint();
+
+    int compare(const BreakPoint& rhs) const;
+
+    void clear();
+    void clearExpressionData();
+
+    QString expression() const;
+
+    // Apply parameters
+    bool apply(IDebugBreakpoint2 *ibp, QString *errorMessage) const;
+    // Convenience to add to a IDebugControl4
+    bool add(CIDebugControl* debugControl,
+             QString *errorMessage,
+             unsigned long *id = 0,
+             quint64 *address = 0) const;
+
+    // Retrieve/parse breakpoints from the interfaces
+    bool retrieve(IDebugBreakpoint2 *ibp, QString *errorMessage);
+    bool parseExpression(const QString &expr);
+    // Retrieve all breakpoints from the engine
+    static bool getBreakPointCount(CIDebugControl* debugControl, ULONG *count, QString *errorMessage = 0);
+    static bool getBreakPoints(CIDebugControl* debugControl, QList<BreakPoint> *bps, QString *errorMessage);
+    // Control helpers
+    static IDebugBreakpoint2 *breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage);
+    static bool removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage);
+    static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage);
+
+    // Return a 'canonical' file (using '/' and capitalized drive letter)
+    static QString normalizeFileName(const QString &f);
+    static void clearNormalizeFileNameCache();
+
+    QString fileName;       // short name of source file
+    QString condition;      // condition associated with breakpoint
+    unsigned long ignoreCount;    // ignore count associated with breakpoint
+    int lineNumber;     // line in source file
+    QString funcName;       // name of containing function
+    bool oneShot;
+    bool enabled;
+};
+
+QDebug operator<<(QDebug, const BreakPoint &bp);
+
+inline bool operator==(const BreakPoint& b1, const BreakPoint& b2)
+    { return b1.compare(b2) == 0; }
+inline bool operator!=(const BreakPoint& b1, const BreakPoint& b2)
+    { return b1.compare(b2) != 0; }
+
+}
+
+#endif // CDBCOREBREAKPOINTS_H
diff --git a/src/plugins/debugger/cdb/cdb.pri b/src/plugins/debugger/cdb/cdb.pri
index 050083339741180d4df7e8bf7167810346ab61a7..fa0b173331f0ca58de979e578805abbfe8642ad2 100644
--- a/src/plugins/debugger/cdb/cdb.pri
+++ b/src/plugins/debugger/cdb/cdb.pri
@@ -10,7 +10,6 @@ HEADERS += \
     $$PWD/cdbsymbolgroupcontext.h \
     $$PWD/cdbsymbolgroupcontext_tpl.h \
     $$PWD/cdbstacktracecontext.h \
-    $$PWD/cdbstackframecontext.h \
     $$PWD/cdbbreakpoint.h \
     $$PWD/cdbmodules.h \
     $$PWD/cdbassembler.h \
@@ -25,7 +24,6 @@ SOURCES += \
     $$PWD/cdbdebugeventcallback.cpp \
     $$PWD/cdbdebugoutput.cpp \
     $$PWD/cdbsymbolgroupcontext.cpp \
-    $$PWD/cdbstackframecontext.cpp \
     $$PWD/cdbstacktracecontext.cpp \
     $$PWD/cdbbreakpoint.cpp \
     $$PWD/cdbmodules.cpp \
@@ -37,6 +35,4 @@ SOURCES += \
     $$PWD/cdbexceptionutils.cpp
 
 FORMS += $$PWD/cdboptionspagewidget.ui
-
-LIBS+=-lpsapi
 }
diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.cpp b/src/plugins/debugger/cdb/cdbbreakpoint.cpp
index 5c81b371512d02d3f544d5d00b6e0cb5d12cecea..032222a3cb961c90508673d2759e4620654b6dbc 100644
--- a/src/plugins/debugger/cdb/cdbbreakpoint.cpp
+++ b/src/plugins/debugger/cdb/cdbbreakpoint.cpp
@@ -29,482 +29,13 @@
 
 #include "cdbbreakpoint.h"
 #include "cdbmodules.h"
-#include "breakhandler.h"
-#include "cdbdebugengine_p.h"
 
-#include <QtCore/QTextStream>
-#include <QtCore/QDir>
-#include <QtCore/QDebug>
-#include <QtCore/QMap>
-
-#include <psapi.h>
-
-enum { debugBP = 0 };
 
 namespace Debugger {
 namespace Internal {
 
-// The CDB breakpoint expression syntax is:
-//    `foo.cpp:523`[ "condition"]
-//    module!function[ "condition"]
-
-static const char sourceFileQuoteC = '`';
-
-CDBBreakPoint::CDBBreakPoint() :
-    ignoreCount(0),
-    lineNumber(-1),
-    oneShot(false),
-    enabled(true)
-{
-}
-
-CDBBreakPoint::CDBBreakPoint(const BreakpointData &bpd) :
-     fileName(QDir::toNativeSeparators(bpd.fileName)),
-     condition(bpd.condition),
-     ignoreCount(0),
-     funcName(bpd.funcName),
-     lineNumber(-1),
-     oneShot(false),
-     enabled(bpd.enabled)
-{
-    if (!bpd.ignoreCount.isEmpty())
-        ignoreCount = bpd.ignoreCount.toInt();
-    if (!bpd.lineNumber.isEmpty())
-        lineNumber = bpd.lineNumber.toInt();
-}
-
-int CDBBreakPoint::compare(const CDBBreakPoint& rhs) const
-{
-    if (ignoreCount > rhs.ignoreCount)
-        return 1;
-    if (ignoreCount < rhs.ignoreCount)
-        return -1;
-    if (lineNumber > rhs.lineNumber)
-        return 1;
-    if (lineNumber < rhs.lineNumber)
-        return -1;
-    if (oneShot && !rhs.oneShot)
-        return 1;
-    if (!oneShot && rhs.oneShot)
-        return -1;
-    if (enabled && !rhs.enabled)
-        return 1;
-    if (!enabled && rhs.enabled)
-        return -1;
-    if (const int fileCmp = fileName.compare(rhs.fileName))
-        return fileCmp;
-    if (const int  funcCmp = funcName.compare(rhs.funcName))
-        return funcCmp;
-    if (const int condCmp = condition.compare(rhs.condition))
-        return condCmp;
-    return 0;
-}
-
-void CDBBreakPoint::clear()
-{
-     ignoreCount = 0;
-     oneShot = false;
-     enabled = true;
-     clearExpressionData();
-}
-
-void CDBBreakPoint::clearExpressionData()
-{
-    fileName.clear();
-    condition.clear();
-    funcName.clear();
-    lineNumber = -1;
-}
-
-QDebug operator<<(QDebug dbg, const CDBBreakPoint &bp)
-{
-    QDebug nsp = dbg.nospace();
-    if (!bp.fileName.isEmpty()) {
-        nsp << "fileName='" << bp.fileName << ':' << bp.lineNumber << '\'';
-    } else {
-        nsp << "funcName='" << bp.funcName << '\'';
-    }
-    if (!bp.condition.isEmpty())
-        nsp << " condition='" << bp.condition << '\'';
-    if (bp.ignoreCount)
-        nsp << " ignoreCount=" << bp.ignoreCount;
-    if (bp.enabled)
-        nsp << " enabled";
-    if (bp.oneShot)
-        nsp << " oneShot";
-    return dbg;
-}
-
-QString CDBBreakPoint::expression() const
-{
-    // format the breakpoint expression (file/function and condition)
-    QString rc;
-    QTextStream str(&rc);
-    if (funcName.isEmpty()) {
-        const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC);
-        str << sourceFileQuote << QDir::toNativeSeparators(fileName) << QLatin1Char(':') << lineNumber << sourceFileQuote;
-    } else {
-        str << funcName;
-    }
-    if (!condition.isEmpty()) {
-        const QChar doubleQuote = QLatin1Char('"');
-        str << QLatin1Char(' ') << doubleQuote << condition << doubleQuote;
-    }
-    return rc;
-}
-
-bool CDBBreakPoint::apply(CIDebugBreakpoint *ibp, QString *errorMessage) const
-{
-    const QString expr = expression();
-    if (debugCDB)
-        qDebug() << Q_FUNC_INFO << *this << expr;
-    const HRESULT hr = ibp->SetOffsetExpressionWide(reinterpret_cast<PCWSTR>(expr.utf16()));
-    if (FAILED(hr)) {
-        *errorMessage = QString::fromLatin1("Unable to set breakpoint '%1' : %2").
-                        arg(expr, CdbCore::msgComFailed("SetOffsetExpressionWide", hr));
-        return false;
-    }
-    // Pass Count is ignoreCount + 1
-    ibp->SetPassCount(ignoreCount + 1u);
-    ULONG flags = 0;
-    if (enabled)
-        flags |= DEBUG_BREAKPOINT_ENABLED;
-    if (oneShot)
-        flags |= DEBUG_BREAKPOINT_ONE_SHOT;
-    ibp->AddFlags(flags);
-    return true;
-}
-
-static inline QString msgCannotAddBreakPoint(const QString &why)
-{
-    return QString::fromLatin1("Unable to add breakpoint: %1").arg(why);
-}
-
-bool CDBBreakPoint::add(CIDebugControl* debugControl,
-                        QString *errorMessage,
-                        unsigned long *id,
-                        quint64 *address) const
-{
-    IDebugBreakpoint2* ibp = 0;
-    if (address)
-        *address = 0;
-    if (id)
-        *id = 0;
-    HRESULT hr = debugControl->AddBreakpoint2(DEBUG_BREAKPOINT_CODE, DEBUG_ANY_ID, &ibp);
-    if (FAILED(hr)) {
-        *errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("AddBreakpoint2", hr));
-        return false;
-    }
-    if (!ibp) {
-        *errorMessage = msgCannotAddBreakPoint(QLatin1String("<Unknown error>"));
-        return false;
-    }
-    if (!apply(ibp, errorMessage))
-        return false;
-    // GetOffset can fail when attaching to remote processes, ignore return
-    if (address) {
-        hr = ibp->GetOffset(address);
-        if (FAILED(hr))
-            *address = 0;
-    }
-    if (id) {
-        hr = ibp->GetId(id);
-        if (FAILED(hr)) {
-            *errorMessage = msgCannotAddBreakPoint(CdbCore::msgComFailed("GetId", hr));
-            return false;
-        }
-    }
-    return true;
-}
-
-// Helper for normalizing file names:
-// Map the device paths in  a file name to back to drive letters
-// "/Device/HarddiskVolume1/file.cpp" -> "C:/file.cpp"
-
-static bool mapDeviceToDriveLetter(QString *s)
-{
-    enum { bufSize = 512 };
-    // Retrieve drive letters and get their device names.
-    // Do not cache as it may change due to removable/network drives.
-    TCHAR driveLetters[bufSize];
-    if (!GetLogicalDriveStrings(bufSize-1, driveLetters))
-        return false;
-
-    TCHAR driveName[MAX_PATH];
-    TCHAR szDrive[3] = TEXT(" :");
-    for (const TCHAR *driveLetter = driveLetters; *driveLetter; driveLetter++) {
-        szDrive[0] = *driveLetter; // Look up each device name
-        if (QueryDosDevice(szDrive, driveName, MAX_PATH)) {
-            const QString deviceName = QString::fromUtf16(driveName);
-            if (s->startsWith(deviceName)) {
-                s->replace(0, deviceName.size(), QString::fromUtf16(szDrive));
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
-// Helper for normalizing file names:
-// Determine normalized case of a Windows file name (camelcase.cpp -> CamelCase.cpp)
-// as the debugger reports lower case file names.
-// Restriction: File needs to exists and be non-empty and will be to be opened/mapped.
-// This is the MSDN-recommended way of doing that. The result should be cached.
-
-static inline QString normalizeFileNameCaseHelper(const QString &f)
-{
-    HANDLE hFile = CreateFile(f.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
-    if(hFile == INVALID_HANDLE_VALUE)
-        return f;
-    // Get the file size. We need a non-empty file to map it.
-    DWORD dwFileSizeHi = 0;
-    DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
-    if (dwFileSizeLo == 0 && dwFileSizeHi == 0) {
-        CloseHandle(hFile);
-        return f;
-    }
-    // Create a file mapping object.
-    HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 1, NULL);
-    if (!hFileMap)  {
-        CloseHandle(hFile);
-        return f;
-    }
-
-    // Create a file mapping to get the file name.
-    void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
-    if (!pMem) {
-        CloseHandle(hFileMap);
-        CloseHandle(hFile);
-        return f;
-    }
-
-    QString rc;
-    WCHAR pszFilename[MAX_PATH];
-    pszFilename[0] = 0;
-    // Get a file name of the form "/Device/HarddiskVolume1/file.cpp"
-    if (GetMappedFileName (GetCurrentProcess(), pMem, pszFilename, MAX_PATH)) {
-        rc = QString::fromUtf16(pszFilename);
-        if (!mapDeviceToDriveLetter(&rc))
-            rc.clear();
-    }
-
-    UnmapViewOfFile(pMem);
-    CloseHandle(hFileMap);
-    CloseHandle(hFile);
-    return rc.isEmpty() ? f : rc;
-}
-
-// Make sure file can be found in editor manager and text markers
-// Use '/', correct case and capitalize drive letter. Use a cache.
-
-typedef QHash<QString, QString> NormalizedFileCache;
-Q_GLOBAL_STATIC(NormalizedFileCache, normalizedFileNameCache)
-
-QString CDBBreakPoint::normalizeFileName(const QString &f)
-{
-    QTC_ASSERT(!f.isEmpty(), return f)
-    const NormalizedFileCache::const_iterator it = normalizedFileNameCache()->constFind(f);
-    if (it != normalizedFileNameCache()->constEnd())
-        return it.value();
-    QString normalizedName = QDir::fromNativeSeparators(normalizeFileNameCaseHelper(f));
-    // Upcase drive letter for consistency even if case mapping fails.
-    if (normalizedName.size() > 2 && normalizedName.at(1) == QLatin1Char(':'))
-        normalizedName[0] = normalizedName.at(0).toUpper();
-    normalizedFileNameCache()->insert(f, normalizedName);
-    return normalizedName;
-}
-
-void CDBBreakPoint::clearNormalizeFileNameCache()
-{
-    normalizedFileNameCache()->clear();
-}
-
-bool CDBBreakPoint::retrieve(CIDebugBreakpoint *ibp, QString *errorMessage)
-{
-    clear();
-    WCHAR wszBuf[MAX_PATH];
-    const HRESULT hr =ibp->GetOffsetExpressionWide(wszBuf, MAX_PATH, 0);
-    if (FAILED(hr)) {
-        *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint: %1").
-                        arg(CdbCore::msgComFailed("GetOffsetExpressionWide", hr));
-        return false;
-    }
-    // Pass Count is ignoreCount + 1
-    ibp->GetPassCount(&ignoreCount);
-    if (ignoreCount)
-        ignoreCount--;
-    ULONG flags = 0;
-    ibp->GetFlags(&flags);
-    oneShot = (flags & DEBUG_BREAKPOINT_ONE_SHOT);
-    enabled = (flags & DEBUG_BREAKPOINT_ENABLED);
-    const QString expr = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
-    if (!parseExpression(expr)) {
-        *errorMessage = QString::fromLatin1("Parsing of '%1' failed.").arg(expr);
-        return false;
-    }
-    return true;
-}
-
-bool CDBBreakPoint::parseExpression(const QString &expr)
-{
-    clearExpressionData();
-    const QChar sourceFileQuote = QLatin1Char(sourceFileQuoteC);
-    // Check for file or function
-    int conditionPos = 0;
-    if (expr.startsWith(sourceFileQuote)) { // `c:\foo.cpp:523`[ "condition"]
-        // Do not fall for the drive letter colon here
-        const int colonPos = expr.indexOf(QLatin1Char(':'), 3);
-        if (colonPos == -1)
-            return false;
-        conditionPos = expr.indexOf(sourceFileQuote, colonPos + 1);
-        if (conditionPos == -1)
-            return false;
-        fileName = normalizeFileName(expr.mid(1, colonPos - 1));
-        const QString lineNumberS = expr.mid(colonPos + 1, conditionPos - colonPos - 1);
-        bool lineNumberOk = false;
-        lineNumber = lineNumberS.toInt(&lineNumberOk);
-        if (!lineNumberOk)
-            return false;
-        conditionPos++;
-    } else {
-        // Check function token
-        conditionPos = expr.indexOf(QLatin1Char(' '));
-        if (conditionPos != -1) {
-            funcName = expr.mid(0, conditionPos);
-            conditionPos++;
-        } else {
-            funcName = expr;
-            conditionPos = expr.size();
-        }
-    }
-    // Condition? ".if bla"
-    if (conditionPos >= expr.size())
-        return true;
-    const QChar doubleQuote = QLatin1Char('"');
-    conditionPos = expr.indexOf(doubleQuote, conditionPos);
-    if (conditionPos == -1)
-        return true;
-    conditionPos++;
-    const int condEndPos = expr.lastIndexOf(doubleQuote);
-    if (condEndPos == -1)
-        return false;
-    condition = expr.mid(conditionPos, condEndPos - conditionPos);
-    return true;
-}
-
-bool CDBBreakPoint::getBreakPointCount(CIDebugControl* debugControl, ULONG *count, QString *errorMessage /* = 0*/)
-{
-    const HRESULT hr = debugControl->GetNumberBreakpoints(count);
-    if (FAILED(hr)) {
-        if (errorMessage)
-            *errorMessage = QString::fromLatin1("Cannot determine breakpoint count: %1").
-                            arg(CdbCore::msgComFailed("GetNumberBreakpoints", hr));
-        return false;
-    }
-    return true;
-}
-
-bool CDBBreakPoint::getBreakPoints(CIDebugControl* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage)
-{
-    ULONG count = 0;
-    bps->clear();
-    if (!getBreakPointCount(debugControl, &count, errorMessage))
-        return false;
-    // retrieve one by one and parse
-    for (ULONG b= 0; b < count; b++) {
-        IDebugBreakpoint2 *ibp = 0;
-        const HRESULT hr = debugControl->GetBreakpointByIndex2(b, &ibp);
-        if (FAILED(hr)) {
-            *errorMessage = QString::fromLatin1("Cannot retrieve breakpoint %1: %2").
-                            arg(b).arg(CdbCore::msgComFailed("GetBreakpointByIndex2", hr));
-            return false;
-        }
-        CDBBreakPoint bp;
-        if (!bp.retrieve(ibp, errorMessage))
-            return false;
-        bps->push_back(bp);
-    }
-    return true;
-}
-
-// Find a breakpoint by id
-static inline QString msgNoBreakPointWithId(unsigned long id, const QString &why)
-{
-    return QString::fromLatin1("Unable to find breakpoint with id %1: %2").arg(id).arg(why);
-}
-
-static IDebugBreakpoint2 *breakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
-{
-    CIDebugBreakpoint *ibp = 0;
-    const HRESULT hr = ctl->GetBreakpointById2(id, &ibp);
-    if (FAILED(hr)) {
-        *errorMessage = msgNoBreakPointWithId(id, CdbCore::msgComFailed("GetBreakpointById2", hr));
-        return 0;
-    }
-    if (!ibp) {
-        *errorMessage = msgNoBreakPointWithId(id, QLatin1String("<not found>"));
-        return 0;
-    }
-    return ibp;
-}
-
-// Remove breakpoint by id
-static bool removeBreakPointById(CIDebugControl *ctl, unsigned long id, QString *errorMessage)
-{
-    if (debugBP)
-        qDebug() << Q_FUNC_INFO << id;
-    CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
-    if (!ibp)
-        return false;
-    const HRESULT hr = ctl->RemoveBreakpoint2(ibp);
-    if (FAILED(hr)) {
-        *errorMessage = QString::fromLatin1("Cannot remove breakpoint %1: %2").arg(id).arg(CdbCore::msgComFailed("RemoveBreakpointById2", hr));
-        return false;
-    }
-    return true;
-}
-
-// Set enabled by id
-
-// Change enabled state of a breakpoint by id
-static inline QString msgCannotSetBreakPointEnabled(unsigned long id, bool enabled, const QString &why)
-{
-    return QString::fromLatin1("Cannot %1 breakpoint %2: %3").
-            arg(QLatin1String(enabled ? "enable" : "disable")).arg(id).arg(why);
-}
+enum { debugBP = 0 };
 
-static bool setBreakPointEnabledById(CIDebugControl *ctl, unsigned long id, bool enabled, QString *errorMessage)
-{
-    if (debugBP)
-        qDebug() << Q_FUNC_INFO << id << enabled;
-    CIDebugBreakpoint *ibp = breakPointById(ctl, id, errorMessage);
-    if (!ibp) {
-        *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, *errorMessage);
-        return false;
-    }
-    // Compare flags
-    ULONG flags;
-    HRESULT hr = ibp->GetFlags(&flags);
-    if (FAILED(hr)) {
-        *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, CdbCore::msgComFailed("GetFlags", hr));
-        return false;
-    }
-    const bool wasEnabled = (flags & DEBUG_BREAKPOINT_ENABLED);
-    if (wasEnabled == enabled)
-        return true;
-    // Set new value
-    if (enabled) {
-        flags |= DEBUG_BREAKPOINT_ENABLED;
-    } else {
-        flags &= ~DEBUG_BREAKPOINT_ENABLED;
-    }
-    hr = ibp->SetFlags(flags);
-    if (FAILED(hr)) {
-        *errorMessage = msgCannotSetBreakPointEnabled(id, enabled, CdbCore::msgComFailed("SetFlags", hr));
-        return false;
-    }
-    return true;
-}
 
 static inline QString msgCannotSetBreakAtFunction(const QString &func, const QString &why)
 {
@@ -512,17 +43,18 @@ static inline QString msgCannotSetBreakAtFunction(const QString &func, const QSt
 }
 
 // Synchronize (halted) engine breakpoints with those of the BreakHandler.
-bool CDBBreakPoint::synchronizeBreakPoints(CIDebugControl* debugControl,
-                                           CIDebugSymbols *syms,
-                                           BreakHandler *handler,
-                                           QString *errorMessage, QStringList *warnings)
+bool synchronizeBreakPoints(CIDebugControl* debugControl,
+                            CIDebugSymbols *syms,
+                            BreakHandler *handler,
+                            QString *errorMessage,
+                            QStringList *warnings)
 {
     errorMessage->clear();
     warnings->clear();
     // Do an initial check whether we are in a state that allows
     // for modifying  breakPoints
     ULONG engineCount;
-    if (!getBreakPointCount(debugControl, &engineCount, errorMessage)) {
+    if (!CdbCore::BreakPoint::getBreakPointCount(debugControl, &engineCount, errorMessage)) {
         *errorMessage = QString::fromLatin1("Cannot modify breakpoints: %1").arg(*errorMessage);
         return false;
     }
@@ -556,7 +88,7 @@ bool CDBBreakPoint::synchronizeBreakPoints(CIDebugControl* debugControl,
         if (breakPointOk) {
             quint64 address;
             unsigned long id;
-            CDBBreakPoint ncdbbp(*nbd);
+            const CdbCore::BreakPoint ncdbbp = breakPointFromBreakPointData(*nbd);
             breakPointOk = ncdbbp.add(debugControl, &warning, &id, &address);
             if (breakPointOk) {
                 if (debugBP)
@@ -578,24 +110,24 @@ bool CDBBreakPoint::synchronizeBreakPoints(CIDebugControl* debugControl,
             warnings->push_back(warning);    }
     // Delete
     foreach (BreakpointData *rbd, handler->takeRemovedBreakpoints()) {
-        if (!removeBreakPointById(debugControl, rbd->bpNumber.toUInt(), &warning))
+        if (!CdbCore::BreakPoint::removeBreakPointById(debugControl, rbd->bpNumber.toUInt(), &warning))
             warnings->push_back(warning);
         delete rbd;
     }
     // Enable/Disable
     foreach (BreakpointData *ebd, handler->takeEnabledBreakpoints())
-        if (!setBreakPointEnabledById(debugControl, ebd->bpNumber.toUInt(), true, &warning))
+        if (!CdbCore::BreakPoint::setBreakPointEnabledById(debugControl, ebd->bpNumber.toUInt(), true, &warning))
             warnings->push_back(warning);
     foreach (BreakpointData *dbd, handler->takeDisabledBreakpoints())
-        if (!setBreakPointEnabledById(debugControl, dbd->bpNumber.toUInt(), false, &warning))
+        if (!CdbCore::BreakPoint::setBreakPointEnabledById(debugControl, dbd->bpNumber.toUInt(), false, &warning))
             warnings->push_back(warning);
 
     if (updateMarkers)
         handler->updateMarkers();
 
     if (debugBP > 1) {
-        QList<CDBBreakPoint> bps;
-        CDBBreakPoint::getBreakPoints(debugControl, &bps, errorMessage);
+        QList<CdbCore::BreakPoint> bps;
+        CdbCore::BreakPoint::getBreakPoints(debugControl, &bps, errorMessage);
         qDebug().nospace() << "### Breakpoints in engine: " << bps;
     }
     return true;
diff --git a/src/plugins/debugger/cdb/cdbbreakpoint.h b/src/plugins/debugger/cdb/cdbbreakpoint.h
index 3a1e8e09b5f7b787b8788f444fd204e46336f47d..d5df85fd836819186b47b15db59c09d991031217 100644
--- a/src/plugins/debugger/cdb/cdbbreakpoint.h
+++ b/src/plugins/debugger/cdb/cdbbreakpoint.h
@@ -31,73 +31,39 @@
 #define CDBBREAKPOINTS_H
 
 #include "cdbcom.h"
+#include "breakpoint.h"
+#include "breakhandler.h"
 
 #include <QtCore/QString>
 #include <QtCore/QList>
+#include <QtCore/QDir>
 
 QT_BEGIN_NAMESPACE
 class QDebug;
 QT_END_NAMESPACE
 
-namespace Debugger {
-namespace Internal {
-
-class BreakHandler;
-class BreakpointData;
-
-/* CDB Break point data structure with utilities to
- * apply to engine and to retrieve them from the engine and comparison. */
-
-struct CDBBreakPoint
+// Convert breakpoint structs
+inline CdbCore::BreakPoint breakPointFromBreakPointData(const Debugger::Internal::BreakpointData &bpd)
 {
-    CDBBreakPoint();
-    CDBBreakPoint(const BreakpointData &bpd);
-
-    int compare(const CDBBreakPoint& rhs) const;
-
-    void clear();
-    void clearExpressionData();
+    CdbCore::BreakPoint rc;
+    rc.fileName = QDir::toNativeSeparators(bpd.fileName);
+    rc.condition = bpd.condition;
+    rc.funcName = bpd.funcName;
+    rc.ignoreCount = bpd.ignoreCount.isEmpty() ? 0  : bpd.ignoreCount.toInt();
+    rc.lineNumber  = bpd.lineNumber.isEmpty()  ? -1 : bpd.lineNumber.toInt();
+    rc.oneShot = false;
+    rc.enabled = bpd.enabled;
+    return rc;
+}
 
-    QString expression() const;
-
-    // Apply parameters
-    bool apply(IDebugBreakpoint2 *ibp, QString *errorMessage) const;
-    // Convenience to add to a IDebugControl4
-    bool add(CIDebugControl* debugControl,
-             QString *errorMessage,
-             unsigned long *id = 0,
-             quint64 *address = 0) const;
-
-    // Retrieve/parse breakpoints from the interfaces
-    bool retrieve(IDebugBreakpoint2 *ibp, QString *errorMessage);
-    bool parseExpression(const QString &expr);
-    // Retrieve all breakpoints from the engine
-    static bool getBreakPointCount(CIDebugControl* debugControl, ULONG *count, QString *errorMessage = 0);
-    static bool getBreakPoints(CIDebugControl* debugControl, QList<CDBBreakPoint> *bps, QString *errorMessage);
-    // Synchronize (halted) engine with BreakHandler.
-    static bool synchronizeBreakPoints(CIDebugControl* ctl, CIDebugSymbols *syms,
-                                       BreakHandler *bh,
-                                       QString *errorMessage, QStringList *warnings);
-
-    // Return a 'canonical' file (using '/' and capitalized drive letter)
-    static QString normalizeFileName(const QString &f);
-    static void clearNormalizeFileNameCache();
-
-    QString fileName;       // short name of source file
-    QString condition;      // condition associated with breakpoint
-    unsigned long ignoreCount;    // ignore count associated with breakpoint
-    int lineNumber;     // line in source file
-    QString funcName;       // name of containing function
-    bool oneShot;
-    bool enabled;
-};
+namespace Debugger {
+namespace Internal {
 
-QDebug operator<<(QDebug, const CDBBreakPoint &bp);
+// Synchronize (halted) engine with BreakHandler.
+bool synchronizeBreakPoints(CIDebugControl* ctl, CIDebugSymbols *syms,
+                            BreakHandler *bh,
+                            QString *errorMessage, QStringList *warnings);
 
-inline bool operator==(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
-    { return b1.compare(b2) == 0; }
-inline bool operator!=(const CDBBreakPoint& b1, const CDBBreakPoint& b2)
-    { return b1.compare(b2) != 0; }
 } // namespace Internal
 } // namespace Debugger
 
diff --git a/src/plugins/debugger/cdb/cdbcore.pri b/src/plugins/debugger/cdb/cdbcore.pri
index 045b0c6382c7819ce11604272ee71c8d444bc164..7c65cada5ecaddb37186711a168b1afb75ac5d46 100644
--- a/src/plugins/debugger/cdb/cdbcore.pri
+++ b/src/plugins/debugger/cdb/cdbcore.pri
@@ -26,15 +26,24 @@ HEADERS += \
     $$PWD/cdbcom.h \
     $$PWD/coreengine.h \
     $$PWD/debugoutputbase.h \
-    $$PWD/debugeventcallbackbase.h
+    $$PWD/debugeventcallbackbase.h \
+    $$PWD/symbolgroupcontext.h \
+    $$PWD/stacktracecontext.h \
+    $$PWD/breakpoint.h
+
 SOURCES += \
     $$PWD/coreengine.cpp \
     $$PWD/debugoutputbase.cpp \
-    $$PWD/debugeventcallbackbase.cpp
+    $$PWD/debugeventcallbackbase.cpp \
+    $$PWD/symbolgroupcontext.cpp \
+    $$PWD/stacktracecontext.cpp \
+    $$PWD/breakpoint.cpp
 
 INCLUDEPATH*=$$PWD
 DEPENDPATH*=$$PWD
 
+LIBS+=-lpsapi
+
 } else {
    message("Debugging Tools for Windows could not be found in $$CDB_PATH")
    CDB_PATH=""
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index 14b22a6dc519a536e77bdab5dc62d481aeb472c6..81e872d8fec262642d38394ddc59868585f8bef7 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -248,17 +248,21 @@ QString CdbDebugEngine::editorToolTip(const QString &exp, const QString &functio
     QString errorMessage;
     QString rc;
     // Find the frame of the function if there is any
-    CdbStackFrameContext *frame = 0;
+    CdbSymbolGroupContext *frame = 0;
     if (m_d->m_currentStackTrace &&  !function.isEmpty()) {
         const int frameIndex = m_d->m_currentStackTrace->indexOf(function);
+        if (debugToolTips)
+            qDebug() << "CdbDebugEngine::editorToolTip" << exp << function << frameIndex;
         if (frameIndex != -1)
-            frame = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
+            frame = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage);
     }
     if (frame && frame->editorToolTip(QLatin1String("local.") + exp, &rc, &errorMessage))
         return rc;
     // No function/symbol context found, try to evaluate in current context.
     // Do not append type as this will mostly be 'long long' for integers, etc.
     QString type;
+    if (debugToolTips)
+        qDebug() << "Defaulting to expression";
     if (!m_d->evaluateExpression(exp, &rc, &type, &errorMessage))
         return QString();
     return rc;
@@ -341,7 +345,7 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
 {
     if (debugCDBExecution)
         qDebug() << "startDebugger" << *sp;
-    CDBBreakPoint::clearNormalizeFileNameCache();
+    CdbCore::BreakPoint::clearNormalizeFileNameCache();
     setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
     m_d->checkVersion();
     if (m_d->m_hDebuggeeProcess) {
@@ -599,13 +603,13 @@ void CdbDebugEngine::detachDebugger()
     m_d->endDebugging(CdbDebugEnginePrivate::EndDebuggingDetach);
 }
 
-CdbStackFrameContext *CdbDebugEnginePrivate::getStackFrameContext(int frameIndex, QString *errorMessage) const
+CdbSymbolGroupContext *CdbDebugEnginePrivate::getSymbolGroupContext(int frameIndex, QString *errorMessage) const
 {
     if (!m_currentStackTrace) {
         *errorMessage = QLatin1String(msgNoStackTraceC);
         return 0;
     }
-    if (CdbStackFrameContext *sg = m_currentStackTrace->frameContextAt(frameIndex, errorMessage))
+    if (CdbSymbolGroupContext *sg = m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, errorMessage))
         return sg;
     return 0;
 }
@@ -649,7 +653,7 @@ void CdbDebugEngine::updateWatchData(const WatchData &incomplete)
     bool success = false;
     QString errorMessage;
     do {
-        CdbStackFrameContext *sg = m_d->m_currentStackTrace->frameContextAt(frameIndex, &errorMessage);
+        CdbSymbolGroupContext *sg = m_d->m_currentStackTrace->cdbSymbolGroupContextAt(frameIndex, &errorMessage);
         if (!sg)
             break;
         if (!sg->completeData(incomplete, watchHandler, &errorMessage))
@@ -902,7 +906,7 @@ void CdbDebugEngine::runToLineExec(const QString &fileName, int lineNumber)
 {
     manager()->showDebuggerOutput(LogMisc, tr("Running up to %1:%2...").arg(fileName).arg(lineNumber));
     QString errorMessage;
-    CDBBreakPoint tempBreakPoint;
+    CdbCore::BreakPoint tempBreakPoint;
     tempBreakPoint.fileName = fileName;
     tempBreakPoint.lineNumber = lineNumber;
     tempBreakPoint.oneShot = true;
@@ -916,7 +920,7 @@ void CdbDebugEngine::runToFunctionExec(const QString &functionName)
 {
     manager()->showDebuggerOutput(LogMisc, tr("Running up to function '%1()'...").arg(functionName));
     QString errorMessage;
-    CDBBreakPoint tempBreakPoint;
+    CdbCore::BreakPoint tempBreakPoint;
     tempBreakPoint.funcName = functionName;
     tempBreakPoint.oneShot = true;
     const bool ok = tempBreakPoint.add(m_d->interfaces().debugControl, &errorMessage)
@@ -939,7 +943,7 @@ void CdbDebugEngine::assignValueInDebugger(const QString &expr, const QString &v
     bool success = false;
     do {
         QString newValue;
-        CdbStackFrameContext *sg = m_d->getStackFrameContext(frameIndex, &errorMessage);
+        CdbSymbolGroupContext *sg = m_d->getSymbolGroupContext(frameIndex, &errorMessage);
         if (!sg)
             break;
         if (!sg->assignValue(expr, value, &newValue, &errorMessage))
@@ -1004,7 +1008,7 @@ void CdbDebugEngine::activateFrame(int frameIndex)
 
         if (oldIndex != frameIndex || m_d->m_firstActivatedFrame) {
             watchHandler->beginCycle();
-            if (CdbStackFrameContext *sgc = m_d->getStackFrameContext(frameIndex, &errorMessage))
+            if (CdbSymbolGroupContext *sgc = m_d->getSymbolGroupContext(frameIndex, &errorMessage))
                 success = sgc->populateModelInitially(watchHandler, &errorMessage);
             watchHandler->endCycle();
         } else {
@@ -1059,7 +1063,7 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
     // called again from the debug event handler.
 
     ULONG dummy;
-    const bool wasRunning = !CDBBreakPoint::getBreakPointCount(interfaces().debugControl, &dummy);
+    const bool wasRunning = !CdbCore::BreakPoint::getBreakPointCount(interfaces().debugControl, &dummy);
     if (debugCDB)
         qDebug() << Q_FUNC_INFO << "\n  Running=" << wasRunning;
 
@@ -1074,10 +1078,10 @@ bool CdbDebugEnginePrivate::attemptBreakpointSynchronization(QString *errorMessa
     }
 
     QStringList warnings;
-    const bool ok = CDBBreakPoint::synchronizeBreakPoints(interfaces().debugControl,
-                                                 interfaces().debugSymbols,
-                                                 manager()->breakHandler(),
-                                                 errorMessage, &warnings);
+    const bool ok = synchronizeBreakPoints(interfaces().debugControl,
+                                           interfaces().debugSymbols,
+                                           manager()->breakHandler(),
+                                           errorMessage, &warnings);
     if (const int warningsCount = warnings.size())
         for (int w = 0; w < warningsCount; w++)
             m_engine->warning(warnings.at(w));
@@ -1361,7 +1365,7 @@ ULONG CdbDebugEnginePrivate::updateThreadList()
     ULONG currentThreadId;
     QString errorMessage;
     // When interrupting, an artifical thread with a breakpoint is created.
-    if (!CdbStackTraceContext::getThreads(interfaces(), true, &threads, &currentThreadId, &errorMessage))
+    if (!CdbStackTraceContext::getThreads(interfaces(), &threads, &currentThreadId, &errorMessage))
         m_engine->warning(errorMessage);
     manager()->threadsHandler()->setThreads(threads);
     return currentThreadId;
@@ -1378,14 +1382,18 @@ static inline unsigned long dumperThreadId(const QList<StackFrame> &frames,
 {
     if (frames.empty())
         return CdbDumperHelper::InvalidDumperCallThread;
-    if (frames.at(0).function == QLatin1String(CdbStackTraceContext::winFuncDebugBreakPoint))
+    switch (CdbCore::StackTraceContext::specialFunction(frames.at(0).from, frames.at(0).function)) {
+    case CdbCore::StackTraceContext::BreakPointFunction:
+    case CdbCore::StackTraceContext::WaitFunction:
         return CdbDumperHelper::InvalidDumperCallThread;
+    default:
+        break;
+    }
+    // Check remaining frames for wait
     const int waitCheckDepth = qMin(frames.size(), 5);
-    static const QString waitForPrefix = QLatin1String(CdbStackTraceContext::winFuncWaitForPrefix);
-    static const QString msgWaitForPrefix = QLatin1String(CdbStackTraceContext::winFuncMsgWaitForPrefix);
-    for (int f = 0; f < waitCheckDepth; f++) {
-        const QString &function = frames.at(f).function;
-        if (function.startsWith(waitForPrefix) || function.startsWith(msgWaitForPrefix))
+    for (int f = 1; f < waitCheckDepth; f++) {
+        if (CdbCore::StackTraceContext::specialFunction(frames.at(f).from, frames.at(f).function)
+            == CdbCore::StackTraceContext::WaitFunction)
             return CdbDumperHelper::InvalidDumperCallThread;
     }
     return currentThread;
@@ -1404,7 +1412,7 @@ void CdbDebugEnginePrivate::updateStackTrace()
         return;
     }
     m_currentStackTrace =
-            CdbStackTraceContext::create(m_dumper, m_currentThreadId, &errorMessage);
+            CdbStackTraceContext::create(m_dumper, &errorMessage);
     if (!m_currentStackTrace) {
         m_engine->warning(msgFunctionFailed(Q_FUNC_INFO, errorMessage));
         return;
@@ -1413,7 +1421,7 @@ void CdbDebugEnginePrivate::updateStackTrace()
 #if 0
     m_engine->reloadDisassembler(); // requires stack trace
 #endif
-    const QList<StackFrame> stackFrames = m_currentStackTrace->frames();
+    const QList<StackFrame> stackFrames = m_currentStackTrace->stackFrames();
     // find the first usable frame and select it
     int current = -1;
     const int count = stackFrames.count();
diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h
index fe6c2a5b61c0ec3c1aaa9ceb73ff9e651d2fa22f..dabbcf8735094f3e20e500a0a53bbf433bdb0c59 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine_p.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h
@@ -46,8 +46,8 @@ class DebuggerManager;
 namespace Internal {
 
 class WatchHandler;
-class CdbStackFrameContext;
 class CdbStackTraceContext;
+class CdbSymbolGroupContext;
 
 class CdbDebugEnginePrivate : public CdbCore::CoreEngine
 {
@@ -82,7 +82,7 @@ public:
     void cleanStackTrace();
     void clearForRun();
     void handleModuleLoad(const QString &);
-    CdbStackFrameContext *getStackFrameContext(int frameIndex, QString *errorMessage) const;
+    CdbSymbolGroupContext *getSymbolGroupContext(int frameIndex, QString *errorMessage) const;
     void clearDisplay();
 
     bool interruptInterferiorProcess(QString *errorMessage);
@@ -135,6 +135,7 @@ enum { messageTimeOut = 5000 };
 enum { debugCDB = 0 };
 enum { debugCDBExecution = 0 };
 enum { debugCDBWatchHandling = 0 };
+enum { debugToolTips = 0 };
 
 } // namespace Internal
 } // namespace Debugger
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
index 0ffc51ff20eda399951dc68beec59dcc55e86d32..ccc249df31a521a085e5db832f167926dbf76b73 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
@@ -75,7 +75,7 @@ STDMETHODIMP CdbDebugEventCallback::Exception(
     QString msg;
     {
         QTextStream str(&msg);
-        formatException(Exception, m_pEngine->m_d->m_dumper, str);
+        formatException(Exception, &m_pEngine->m_d->interfaces(), str);
     }
     const bool fatal = isFatalException(Exception->ExceptionCode);
     if (debugCDB)
diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.cpp b/src/plugins/debugger/cdb/cdbexceptionutils.cpp
index d0d61663cf8974a3245efa5b05720bcc7a69a779..1679650bb43d4b0349fe724d395cb163b8243480 100644
--- a/src/plugins/debugger/cdb/cdbexceptionutils.cpp
+++ b/src/plugins/debugger/cdb/cdbexceptionutils.cpp
@@ -29,8 +29,7 @@
 
 #include "cdbexceptionutils.h"
 #include "cdbdebugengine_p.h"
-#include "cdbdumperhelper.h"
-#include "cdbstacktracecontext.h"
+#include "stacktracecontext.h"
 
 #include <QtCore/QString>
 #include <QtCore/QTextStream>
@@ -247,15 +246,13 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str)
 
 // Format exception with stacktrace in case of C++ exception
 void formatException(const EXCEPTION_RECORD64 *e,
-                     const QSharedPointer<CdbDumperHelper> &dumper,
+                     const CdbCore::ComInterfaces *cif,
                      QTextStream &str)
 {
     formatException(e, str);
     if (e->ExceptionCode == winExceptionCppException) {
         QString errorMessage;
-        ULONG currentThreadId = 0;
-        dumper->comInterfaces()->debugSystemObjects->GetCurrentThreadId(&currentThreadId);
-        if (CdbStackTraceContext *stc = CdbStackTraceContext::create(dumper, currentThreadId, &errorMessage)) {
+        if (CdbCore::StackTraceContext *stc = CdbCore::StackTraceContext::create(cif, 9999, &errorMessage)) {
             str << "at:\n";
             stc->format(str);
             str <<'\n';
diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.h b/src/plugins/debugger/cdb/cdbexceptionutils.h
index b54447580f34c9e3b0fc592e39fcd85e3681dec4..2a5cc2e7528ffe215ec302767f5780d9519a7ef6 100644
--- a/src/plugins/debugger/cdb/cdbexceptionutils.h
+++ b/src/plugins/debugger/cdb/cdbexceptionutils.h
@@ -39,6 +39,10 @@ QT_BEGIN_NAMESPACE
 class QTextStream;
 QT_END_NAMESPACE
 
+namespace CdbCore {
+    struct ComInterfaces;
+}
+
 namespace Debugger {
 namespace Internal {
 
@@ -94,7 +98,7 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str);
 
 // Format exception with stacktrace in case of C++ exception
 void formatException(const EXCEPTION_RECORD64 *e,
-                     const QSharedPointer<CdbDumperHelper> &dumper,
+                     const CdbCore::ComInterfaces *cif,
                      QTextStream &str);
 
 // Is this a crash/recoverable?
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
index 7aceaae9100e8fa2e50deca1645910b023b953e1..be11b3e600ab51e9c05e0484a821790b91d890b3 100644
--- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
@@ -310,15 +310,14 @@ bool CdbStackFrameContext::populateModelInitially(WatchHandler *wh, QString *err
         qDebug() << "populateModelInitially dumpers=" << m_useDumpers;
     // Recurse down items that are initially expanded in the view, stop processing for
     // dumper items.
-    const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper,
-                                              m_dumper->comInterfaces()->debugDataSpaces);
+    const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper);
     const bool rc = m_useDumpers ?
-        CdbSymbolGroupContext::populateModelInitially(rctx,
+        CdbSymbolGroupContext::populateModelInitiallyHelper(rctx,
                                                       WatchHandleDumperInserter(wh, m_dumper),
                                                       WatchHandlerExpandedPredicate(wh),
                                                       isDumperPredicate,
                                                       errorMessage) :
-        CdbSymbolGroupContext::populateModelInitially(rctx,
+        CdbSymbolGroupContext::populateModelInitiallyHelper(rctx,
                                                       WatchHandlerModelInserter(wh),
                                                       WatchHandlerExpandedPredicate(wh),
                                                       falsePredicate,
@@ -333,11 +332,10 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal,
     if (debugCDBWatchHandling)
         qDebug() << ">completeData src=" << incompleteLocal.source << incompleteLocal.toString();
 
-    const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper,
-                                              m_dumper->comInterfaces()->debugDataSpaces);
+    const CdbSymbolGroupRecursionContext rctx(m_symbolContext, OwnerSymbolGroupDumper);
     // Expand symbol group items, recurse one level from desired item
     if (!m_useDumpers) {
-        return CdbSymbolGroupContext::completeData(rctx, incompleteLocal,
+        return CdbSymbolGroupContext::completeDataHelper(rctx, incompleteLocal,
                                                    WatchHandlerModelInserter(wh),
                                                    MatchINamePredicate(incompleteLocal.iname),
                                                    falsePredicate,
@@ -375,7 +373,7 @@ bool CdbStackFrameContext::completeData(const WatchData &incompleteLocal,
     }
 
     // Expand symbol group items, recurse one level from desired item
-    return CdbSymbolGroupContext::completeData(rctx, incompleteLocal,
+    return CdbSymbolGroupContext::completeDataHelper(rctx, incompleteLocal,
                                                WatchHandleDumperInserter(wh, m_dumper),
                                                MatchINamePredicate(incompleteLocal.iname),
                                                isDumperPredicate,
@@ -398,8 +396,12 @@ bool CdbStackFrameContext::editorToolTip(const QString &iname,
         return false;
     }
     // Check dumpers. Should actually be just one item.
-    const WatchData wd = m_symbolContext->watchDataAt(index);
-    if (m_useDumpers && !wd.error && m_dumper->state() != CdbDumperHelper::Disabled) {
+
+    WatchData wd;
+    const unsigned rc = m_symbolContext->watchDataAt(index, &wd);
+    if (m_useDumpers && !wd.error
+        && (0u == (rc & CdbCore::SymbolGroupContext::InternalDumperMask))
+        && m_dumper->state() != CdbDumperHelper::Disabled) {
         QList<WatchData> result;
         if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, &result, errorMessage))  {
             foreach (const WatchData &dwd, result) {
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.h b/src/plugins/debugger/cdb/cdbstackframecontext.h
deleted file mode 100644
index 99f1464f02f50c2db2dbf56f5fcc2a5612ce9630..0000000000000000000000000000000000000000
--- a/src/plugins/debugger/cdb/cdbstackframecontext.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** Commercial Usage
-**
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
-**
-** GNU Lesser General Public License Usage
-**
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at http://qt.nokia.com/contact.
-**
-**************************************************************************/
-
-#ifndef 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:
-    // Mask bits for the source field of watch data.
-    enum { SourceMask = 0xFF, ChildrenKnownBit = 0x0100 };
-
-    explicit CdbStackFrameContext(const QSharedPointer<CdbDumperHelper> &dumper,
-                                  CdbSymbolGroupContext *symbolContext);
-    ~CdbStackFrameContext();
-
-    bool assignValue(const QString &iname, const QString &value,
-                     QString *newValue /* = 0 */, QString *errorMessage);
-    bool editorToolTip(const QString &iname, QString *value, QString *errorMessage);
-
-    bool populateModelInitially(WatchHandler *wh, QString *errorMessage);
-
-    bool completeData(const WatchData &incompleteLocal,
-                      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 b79b7fe8241a866be32c145cb1d7feda13dd4fff..80a006a53f7314908a6b9f957ea38411ebd56cbe 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
@@ -28,332 +28,110 @@
 **************************************************************************/
 
 #include "cdbstacktracecontext.h"
-#include "coreengine.h"
-#include "cdbstackframecontext.h"
-#include "cdbbreakpoint.h"
 #include "cdbsymbolgroupcontext.h"
-#include "cdbdebugengine_p.h"
 #include "cdbdumperhelper.h"
+#include "cdbdebugengine_p.h"
 #include "debuggeractions.h"
-#include "debuggermanager.h"
+#include "watchutils.h"
 
-#include <QtCore/QDir>
 #include <QtCore/QDebug>
-#include <QtCore/QTextStream>
+
+enum { debug = 1 };
 
 namespace Debugger {
 namespace Internal {
 
-const char *CdbStackTraceContext::winFuncFastSystemCallRet = "ntdll!KiFastSystemCallRet";
-const char *CdbStackTraceContext::winFuncDebugBreakPoint = "ntdll!DbgBreakPoint";
-const char *CdbStackTraceContext::winFuncWaitForPrefix = "kernel32!WaitFor";
-const char *CdbStackTraceContext::winFuncMsgWaitForPrefix = "kernel32!MsgWaitForMultipleObjects";
-
 CdbStackTraceContext::CdbStackTraceContext(const QSharedPointer<CdbDumperHelper> &dumper) :
-        m_dumper(dumper),
-        m_cif(dumper->comInterfaces()),
-        m_instructionOffset(0)
+        CdbCore::StackTraceContext(dumper->comInterfaces()),
+        m_dumper(dumper)
 {
 }
 
 CdbStackTraceContext *CdbStackTraceContext::create(const QSharedPointer<CdbDumperHelper> &dumper,
-                                                   unsigned long threadId,
                                                    QString *errorMessage)
 {
-    if (debugCDB)
-        qDebug() << Q_FUNC_INFO << threadId;
-    // fill the DEBUG_STACK_FRAME array
-    ULONG frameCount;
     CdbStackTraceContext *ctx = new CdbStackTraceContext(dumper);
-    const HRESULT hr = dumper->comInterfaces()->debugControl->GetStackTrace(0, 0, 0, ctx->m_cdbFrames, CdbStackTraceContext::maxFrames, &frameCount);
-    if (FAILED(hr)) {
-        delete ctx;
-         *errorMessage = CdbCore::msgComFailed("GetStackTrace", hr);
-        return 0;
-    }
-    if (!ctx->init(frameCount, errorMessage)) {
+    if (!ctx->init(UINT_MAX, errorMessage)) {
         delete ctx;
         return 0;
-
     }
     return ctx;
 }
 
-CdbStackTraceContext::~CdbStackTraceContext()
-{
-    qDeleteAll(m_frameContexts);
-}
-
-bool CdbStackTraceContext::init(unsigned long frameCount, QString * /*errorMessage*/)
-{
-    if (debugCDB)
-        qDebug() << Q_FUNC_INFO << frameCount;
-
-    const QChar exclamationMark = QLatin1Char('!');
-    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];
-    for (ULONG i=0; i < frameCount; ++i) {
-        StackFrame frame;
-        frame.level = i;
-        const ULONG64 instructionOffset = m_cdbFrames[i].InstructionOffset;
-        if (i == 0)
-            m_instructionOffset = instructionOffset;
-        frame.address = QString::fromLatin1("0x%1").arg(instructionOffset, 0, 16);
-
-        m_cif->debugSymbols->GetNameByOffsetWide(instructionOffset, wszBuf, MAX_PATH, 0, 0);
-        // Determine function and module, if available
-        frame.function = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
-        const int moduleSepPos = frame.function.indexOf(exclamationMark);
-        if (moduleSepPos != -1)
-            frame.from = frame.function.mid(0, moduleSepPos);
-
-        ULONG ulLine;
-        ULONG64 ul64Displacement;
-        const HRESULT hr = m_cif->debugSymbols->GetLineByOffsetWide(instructionOffset, &ulLine, wszBuf, MAX_PATH, 0, &ul64Displacement);
-        if (SUCCEEDED(hr)) {
-            frame.line = ulLine;
-            // Vitally important  to use canonical file that matches editormanager,
-            // else the marker will not show.
-            frame.file = CDBBreakPoint::normalizeFileName(QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf)));
-        }
-        m_frames.push_back(frame);
-    }
-    return true;
-}
-
-int CdbStackTraceContext::indexOf(const QString &function) const
-{
-
-    const QChar exclamationMark = QLatin1Char('!');
-    const int count = m_frames.size();
-    // Module contained ('module!foo'). Exact match
-    if (function.contains(exclamationMark)) {
-
-        for (int i = 0; i < count; i++)
-            if (m_frames.at(i).function == function)
-                return i;
-        return -1;
-    }
-    // No module, fuzzy match
-    QString pattern = exclamationMark + function;
-    for (int i = 0; i < count; i++)
-        if (m_frames.at(i).function.endsWith(pattern))
-            return i;
-    return -1;
-}
-
-static inline QString msgFrameContextFailed(int index, const StackFrame &f, const QString &why)
+CdbCore::SymbolGroupContext
+        *CdbStackTraceContext::createSymbolGroup(const CdbCore::ComInterfaces & /* cif */,
+                                                 int index,
+                                                 const QString &prefix,
+                                                 CIDebugSymbolGroup *comSymbolGroup,
+                                                 QString *errorMessage)
 {
-    return QString::fromLatin1("Unable to create stack frame context #%1, %2:%3 (%4): %5").
-            arg(index).arg(f.function).arg(f.line).arg(f.file, why);
-}
-
-CdbStackFrameContext *CdbStackTraceContext::frameContextAt(int index, QString *errorMessage)
-{
-    // Create a frame on demand
-    if (debugCDB)
-        qDebug() << Q_FUNC_INFO << index;
-
-    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_frameContexts.size());
-        return 0;
-    }
-    if (m_frameContexts.at(index))
-        return m_frameContexts.at(index);
-    CIDebugSymbolGroup *sg  = createSymbolGroup(index, errorMessage);
-    if (!sg) {
-        *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage);
-        return 0;
-    }
     // Exclude uninitialized variables if desired
     QStringList uninitializedVariables;
-    if (theDebuggerAction(UseCodeModel)->isChecked()) {
-        const StackFrame &frame = m_frames.at(index);
-        getUninitializedVariables(DebuggerManager::instance()->cppCodeModelSnapshot(), frame.function, frame.file, frame.line, &uninitializedVariables);
-    }
-    CdbSymbolGroupContext *sc = CdbSymbolGroupContext::create(QLatin1String("local"), sg, uninitializedVariables, errorMessage);
+    const CdbCore::StackFrame &frame = stackFrameAt(index);
+    if (theDebuggerAction(UseCodeModel)->isChecked())
+        getUninitializedVariables(DebuggerManager::instance()->cppCodeModelSnapshot(), frame.function, frame.fileName, frame.line, &uninitializedVariables);
+    if (debug)
+        qDebug() << frame << uninitializedVariables;
+    CdbSymbolGroupContext *sc = CdbSymbolGroupContext::create(prefix,
+                                                              comSymbolGroup,
+                                                              m_dumper,
+                                                              uninitializedVariables,
+                                                              errorMessage);
     if (!sc) {
-        *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage);
+        *errorMessage = msgFrameContextFailed(index, frame, *errorMessage);
         return 0;
     }
-    CdbStackFrameContext *fr = new CdbStackFrameContext(m_dumper, sc);
-    m_frameContexts[index] = fr;
-    return fr;
+    return sc;
 }
 
-CIDebugSymbolGroup *CdbStackTraceContext::createSymbolGroup(int index, QString *errorMessage)
+CdbSymbolGroupContext *CdbStackTraceContext::cdbSymbolGroupContextAt(int index, QString *errorMessage)
 {
-    CIDebugSymbolGroup *sg = 0;
-    HRESULT hr = m_cif->debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &sg);
-    if (FAILED(hr)) {
-        *errorMessage = CdbCore::msgComFailed("GetScopeSymbolGroup", hr);
-        return 0;
-    }
-
-    hr = m_cif->debugSymbols->SetScope(0, m_cdbFrames + index, NULL, 0);
-    if (FAILED(hr)) {
-        *errorMessage = CdbCore::msgComFailed("SetScope", hr);
-        sg->Release();
-        return 0;
-    }
-    // refresh with current frame
-    hr = m_cif->debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, sg, &sg);
-    if (FAILED(hr)) {
-        *errorMessage = CdbCore::msgComFailed("GetScopeSymbolGroup", hr);
-        sg->Release();
-        return 0;
-    }
-    return sg;
-}
-
-QString CdbStackTraceContext::toString() const
-{
-    QString rc;
-    QTextStream str(&rc);
-    format(str);
-    return rc;
+    return static_cast<CdbSymbolGroupContext *>(symbolGroupContextAt(index, errorMessage));
 }
 
-void CdbStackTraceContext::format(QTextStream &str) const
+QList<StackFrame> CdbStackTraceContext::stackFrames() const
 {
-    const int count = m_frames.count();
-    const int defaultFieldWidth = str.fieldWidth();
-    const QTextStream::FieldAlignment defaultAlignment = str.fieldAlignment();
-    for (int f = 0; f < count; f++) {
-        const StackFrame &frame = m_frames.at(f);
-        const bool hasFile = !frame.file.isEmpty();
-        // left-pad level
-        str << qSetFieldWidth(6) << left << f;
-        str.setFieldWidth(defaultFieldWidth);
-        str.setFieldAlignment(defaultAlignment);
-        if (hasFile)
-            str << QDir::toNativeSeparators(frame.file) << ':' << frame.line << " (";
-        str << frame.function;
-        if (hasFile)
-            str << ')';
-        str << '\n';
-    }
-}
-
-// Thread state helper
-
-static inline QString msgGetThreadStateFailed(unsigned long threadId, const QString &why)
-{
-    return QString::fromLatin1("Unable to determine the state of thread %1: %2").arg(threadId).arg(why);
-}
-
-// Determine information about thread. This changes the
-// current thread to thread->id.
-static inline bool getStoppedThreadState(const CdbCore::ComInterfaces &cif,
-                                         ThreadData *t,
-                                         QString *errorMessage)
-{
-    enum { MaxFrames = 2 };
-    ULONG currentThread;
-    HRESULT hr = cif.debugSystemObjects->GetCurrentThreadId(&currentThread);
-    if (FAILED(hr)) {
-        *errorMessage = msgGetThreadStateFailed(t->id, CdbCore::msgComFailed("GetCurrentThreadId", hr));
-        return false;
-    }
-    if (currentThread != t->id) {
-        hr = cif.debugSystemObjects->SetCurrentThreadId(t->id);
-        if (FAILED(hr)) {
-            *errorMessage = msgGetThreadStateFailed(t->id, CdbCore::msgComFailed("SetCurrentThreadId", hr));
-            return false;
-        }
-    }
-    ULONG frameCount;
-    // Ignore the top frame if it is "ntdll!KiFastSystemCallRet", which is
-    // not interesting for display.
-    DEBUG_STACK_FRAME frames[MaxFrames];
-    hr = cif.debugControl->GetStackTrace(0, 0, 0, frames, MaxFrames, &frameCount);
-    if (FAILED(hr)) {
-        *errorMessage = msgGetThreadStateFailed(t->id, CdbCore::msgComFailed("GetStackTrace", hr));
-        return false;
-    }
-    // Ignore the top frame if it is "ntdll!KiFastSystemCallRet", which is
-    // not interesting for display.
-    WCHAR wszBuf[MAX_PATH];
-    for (int frame = 0; frame < MaxFrames; frame++) {
-        cif.debugSymbols->GetNameByOffsetWide(frames[frame].InstructionOffset, wszBuf, MAX_PATH, 0, 0);
-        t->function = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
-        if (frame != 0  || t->function != QLatin1String(CdbStackTraceContext::winFuncFastSystemCallRet)) {
-            t->address = frames[frame].InstructionOffset;
-            cif.debugSymbols->GetNameByOffsetWide(frames[frame].InstructionOffset, wszBuf, MAX_PATH, 0, 0);
-            t->function = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
-            ULONG ulLine;
-            hr = cif.debugSymbols->GetLineByOffsetWide(frames[frame].InstructionOffset, &ulLine, wszBuf, MAX_PATH, 0, 0);
-            if (SUCCEEDED(hr)) {
-                t->line = ulLine;
-                // Just display base name
-                t->file = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
-                if (!t->file.isEmpty()) {
-                    const int slashPos = t->file.lastIndexOf(QLatin1Char('\\'));
-                    if (slashPos != -1)
-                        t->file.remove(0, slashPos + 1);
-                }
-            }
-            break;
-        } // was not "ntdll!KiFastSystemCallRet"
+    // Convert from Core data structures
+    QList<StackFrame> rc;
+    const int count = frameCount();
+    const QString hexPrefix = QLatin1String("0x");
+    for(int i = 0; i < count; i++) {
+        const CdbCore::StackFrame &coreFrame = stackFrameAt(i);
+        StackFrame frame;
+        frame.level = i;
+        frame.file = coreFrame.fileName;
+        frame.line = coreFrame.line;
+        frame.function =coreFrame.function;
+        frame.from = coreFrame.module;
+        frame.address = hexPrefix + QString::number(coreFrame.address, 16);
+        rc.push_back(frame);
     }
-    return true;
-}
-
-static inline QString msgGetThreadsFailed(const QString &why)
-{
-    return QString::fromLatin1("Unable to determine the thread information: %1").arg(why);
+    return rc;
 }
 
 bool CdbStackTraceContext::getThreads(const CdbCore::ComInterfaces &cif,
-                                      bool isStopped,
                                       QList<ThreadData> *threads,
                                       ULONG *currentThreadId,
                                       QString *errorMessage)
 {
+    // Convert from Core data structures
     threads->clear();
-    ULONG threadCount;
-    *currentThreadId = 0;
-    HRESULT hr= cif.debugSystemObjects->GetNumberThreads(&threadCount);
-    if (FAILED(hr)) {
-        *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetNumberThreads", hr));
+    ThreadIdFrameMap threadMap;
+    if (!CdbCore::StackTraceContext::getThreads(cif, &threadMap,
+                                               currentThreadId, errorMessage))
         return false;
-    }
-    // Get ids and index of current
-    if (!threadCount)
-        return true;
-    hr = cif.debugSystemObjects->GetCurrentThreadId(currentThreadId);
-    if (FAILED(hr)) {
-        *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetCurrentThreadId", hr));
-        return false;
-    }
-
-    QVector<ULONG> threadIds(threadCount);
-    hr = cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds.begin()), 0);
-    if (FAILED(hr)) {
-        *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetThreadIdsByIndex", hr));
-        return false;
-    }
-    for (ULONG i = 0; i < threadCount; i++) {
-        ThreadData threadData(threadIds.at(i));
-        if (isStopped) {
-            if (!getStoppedThreadState(cif, &threadData, errorMessage)) {
-                qWarning("%s\n", qPrintable(*errorMessage));
-                errorMessage->clear();
-            }
-        }
-        threads->push_back(threadData);
-    }
-    // Restore thread id
-    if (isStopped && threads->back().id != *currentThreadId) {
-        hr = cif.debugSystemObjects->SetCurrentThreadId(*currentThreadId);
-        if (FAILED(hr)) {
-            *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("SetCurrentThreadId", hr));
-            return false;
-        }
+    const QChar slash = QLatin1Char('/');
+    const ThreadIdFrameMap::const_iterator cend = threadMap.constEnd();
+    for (ThreadIdFrameMap::const_iterator it = threadMap.constBegin(); it != cend; ++it) {
+        ThreadData data(it.key());
+        const CdbCore::StackFrame &coreFrame = it.value();
+        data.address = coreFrame.address;
+        data.function = coreFrame.function;
+        data.line = coreFrame.line;
+        // Basename only for brevity
+        const int slashPos = coreFrame.fileName.lastIndexOf(slash);
+        data.file = slashPos == -1 ? coreFrame.fileName : coreFrame.fileName.mid(slashPos + 1);
+        threads->push_back(data);
     }
     return true;
 }
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h
index 1e3a65a0da0e8f0c358b34d453ca64e870857a01..c2f5199fa4b27e7d96ea5d12a368ce3ef31146d7 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.h
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h
@@ -31,6 +31,7 @@
 #define CDBSTACKTRACECONTEXT_H
 
 #include "stackhandler.h"
+#include "stacktracecontext.h"
 
 #include "cdbcom.h"
 
@@ -54,65 +55,38 @@ class CdbStackFrameContext;
 class CdbDumperHelper;
 struct ThreadData;
 
-/* Context representing a break point stack consisting of several frames.
- * Maintains an on-demand constructed list of CdbStackFrameContext
- * containining the local variables of the stack. */
+/* CdbStackTraceContext: Bridges  CdbCore data structures and
+ * Debugger structures and handles CdbSymbolGroupContext's. */
 
-class CdbStackTraceContext
+class CdbStackTraceContext : public CdbCore::StackTraceContext
 {
     Q_DISABLE_COPY(CdbStackTraceContext)
 
     explicit CdbStackTraceContext(const QSharedPointer<CdbDumperHelper> &dumper);
-public:
-    enum { maxFrames = 100 };
-
-    // Some well known-functions
-    static const char *winFuncFastSystemCallRet;
-    // WaitFor...
-    static const char *winFuncWaitForPrefix;
-    static const char *winFuncMsgWaitForPrefix;
-
-    // Dummy function used for interrupting a debuggee
-    static const char *winFuncDebugBreakPoint;
 
-    ~CdbStackTraceContext();
+public:
     static CdbStackTraceContext *create(const QSharedPointer<CdbDumperHelper> &dumper,
-                                        unsigned long threadid,
                                         QString *errorMessage);
 
-    QList<StackFrame> frames() const { return m_frames; }
-    inline int frameCount() const { return m_frames.size(); }
-    // Search for function. Should ideally contain the module as 'module!foo'.
-    int indexOf(const QString &function) const;
-
-    // Top-Level instruction offset for disassembler
-    ULONG64 instructionOffset() const { return m_instructionOffset; }
+    CdbSymbolGroupContext *cdbSymbolGroupContextAt(int index, QString *errorMessage);
 
-    CdbStackFrameContext *frameContextAt(int index, QString *errorMessage);
+    QList<StackFrame> stackFrames() const;
 
-    // Format for logging
-    void format(QTextStream &str) const;
-    QString toString() const;
-
-    // Retrieve information about threads. When stopped, add
-    // current stack frame.
+    // get threads in stopped state
     static bool getThreads(const CdbCore::ComInterfaces &cif,
-                           bool isStopped,
                            QList<ThreadData> *threads,
                            ULONG *currentThreadId,
                            QString *errorMessage);
 
-private:
-    bool init(unsigned long frameCount, QString *errorMessage);
-    CIDebugSymbolGroup *createSymbolGroup(int index, QString *errorMessage);
+protected:
+    virtual CdbCore::SymbolGroupContext *createSymbolGroup(const CdbCore::ComInterfaces &cif,
+                                                           int index,
+                                                           const QString &prefix,
+                                                           CIDebugSymbolGroup *comSymbolGroup,
+                                                           QString *errorMessage);
 
+private:
     const QSharedPointer<CdbDumperHelper> m_dumper;
-    const CdbCore::ComInterfaces *m_cif;
-
-    DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
-    QVector <CdbStackFrameContext*> m_frameContexts;
-    QList<StackFrame> m_frames;
-    ULONG64 m_instructionOffset;
 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
index e8c25bd90b9830f54008822a66c550d6fc64f66c..b4bc8492c8db3e3e0764592c0cccbcd0fe2f3afc 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.cpp
@@ -29,9 +29,13 @@
 
 #include "cdbsymbolgroupcontext.h"
 #include "cdbdebugengine_p.h"
+#include "cdbdumperhelper.h"
 #include "watchhandler.h"
 #include "watchutils.h"
+#include "debuggeractions.h"
+#include "coreengine.h"
 
+#include <QtCore/QDebug>
 #include <QtCore/QTextStream>
 #include <QtCore/QCoreApplication>
 #include <QtCore/QRegExp>
@@ -39,95 +43,262 @@
 enum { debug = 0 };
 enum { debugInternalDumpers = 0 };
 
-// name separator for shadowed variables
-static const char iNameShadowDelimiter = '#';
-
-static inline QString msgSymbolNotFound(const QString &s)
-{
-    return QString::fromLatin1("The symbol '%1' could not be found.").arg(s);
-}
-
-static inline QString msgOutOfScope()
-{
-    return QCoreApplication::translate("SymbolGroup", "Out of scope");
-}
-
-static inline bool isTopLevelSymbol(const DEBUG_SYMBOL_PARAMETERS &p)
-{
-    return p.ParentSymbol == DEBUG_ANY_ID;
-}
+namespace Debugger {
+namespace Internal {
 
-static inline void debugSymbolFlags(unsigned long f, QTextStream &str)
-{
-    if (f & DEBUG_SYMBOL_EXPANDED)
-        str << "DEBUG_SYMBOL_EXPANDED";
-    if (f & DEBUG_SYMBOL_READ_ONLY)
-        str << "|DEBUG_SYMBOL_READ_ONLY";
-    if (f & DEBUG_SYMBOL_IS_ARRAY)
-        str << "|DEBUG_SYMBOL_IS_ARRAY";
-    if (f & DEBUG_SYMBOL_IS_FLOAT)
-        str << "|DEBUG_SYMBOL_IS_FLOAT";
-    if (f & DEBUG_SYMBOL_IS_ARGUMENT)
-        str << "|DEBUG_SYMBOL_IS_ARGUMENT";
-    if (f & DEBUG_SYMBOL_IS_LOCAL)
-        str << "|DEBUG_SYMBOL_IS_LOCAL";
+enum { OwnerNewItem, OwnerSymbolGroup, OwnerSymbolGroupDumper , OwnerDumper };
+
+typedef QSharedPointer<CdbDumperHelper> SharedPointerCdbDumperHelper;
+typedef QList<WatchData> WatchDataList;
+
+// Predicates for parametrizing the symbol group
+inline bool truePredicate(const WatchData & /* whatever */) { return true; }
+inline bool falsePredicate(const WatchData & /* whatever */) { return false; }
+inline bool isDumperPredicate(const WatchData &wd)
+{ return (wd.source & CdbSymbolGroupContext::SourceMask) == OwnerDumper; }
+
+static inline void debugWatchDataList(const QList<WatchData> &l, const char *why = 0)
+{
+    QDebug nospace = qDebug().nospace();
+    if (why)
+        nospace << why << '\n';
+    foreach(const WatchData &wd, l)
+        nospace << wd.toString() << '\n';
+    nospace << '\n';
+}
+
+// Match an item that is expanded in the watchhandler.
+class WatchHandlerExpandedPredicate {
+public:
+    explicit inline WatchHandlerExpandedPredicate(const WatchHandler *wh) : m_wh(wh) {}
+    inline bool operator()(const WatchData &wd) { return m_wh->isExpandedIName(wd.iname); }
+private:
+    const WatchHandler *m_wh;
+};
+
+// Match an item by iname
+class MatchINamePredicate {
+public:
+    explicit inline MatchINamePredicate(const QString &iname) : m_iname(iname) {}
+    inline bool operator()(const WatchData &wd) { return wd.iname == m_iname; }
+private:
+    const QString &m_iname;
+};
+
+// Put a sequence of  WatchData into the model for the non-dumper case
+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;
+};
+
+// Put a sequence of  WatchData into the model for the dumper case.
+// Sorts 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. Additionally, checks for items pointing to a
+// dumpeable type and inserts a fake dereferenced item and value.
+class WatchHandleDumperInserter {
+public:
+    explicit WatchHandleDumperInserter(WatchHandler *wh,
+                                        const SharedPointerCdbDumperHelper &dumper);
+
+    inline WatchHandleDumperInserter & operator*() { return *this; }
+    inline WatchHandleDumperInserter &operator=(WatchData &wd);
+    inline WatchHandleDumperInserter &operator++() { return *this; }
+
+private:
+    bool expandPointerToDumpable(const WatchData &wd, QString *errorMessage);
+
+    const QRegExp m_hexNullPattern;
+    WatchHandler *m_wh;
+    const SharedPointerCdbDumperHelper m_dumper;
+    QList<WatchData> m_dumperResult;
+};
+
+WatchHandleDumperInserter::WatchHandleDumperInserter(WatchHandler *wh,
+                                                       const SharedPointerCdbDumperHelper &dumper) :
+    m_hexNullPattern(QLatin1String("0x0+")),
+    m_wh(wh),
+    m_dumper(dumper)
+{
+    Q_ASSERT(m_hexNullPattern.isValid());
+}
+
+// Prevent recursion of the model by setting value and type
+static inline bool fixDumperType(WatchData *wd, const WatchData *source = 0)
+{
+    const bool missing = wd->isTypeNeeded() || wd->type.isEmpty();
+    if (missing) {
+        static const QString unknownType = QCoreApplication::translate("CdbSymbolGroupContext", "<Unknown Type>");
+        wd->setType(source ? source->type : unknownType, false);
+    }
+    return missing;
 }
 
-QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS &p)
+static inline bool fixDumperValue(WatchData *wd, const WatchData *source = 0)
 {
-    str << " Type=" << p.TypeId << " parent=";
-    if (isTopLevelSymbol(p)) {
-        str << "<ROOT>";
-    } else {
-        str << p.ParentSymbol;
+    const bool missing = wd->isValueNeeded();
+    if (missing) {
+        if (source && source->isValueKnown()) {
+            wd->setValue(source->value);
+        } else {
+            static const QString unknownValue = QCoreApplication::translate("CdbSymbolGroupContext", "<Unknown Value>");
+            wd->setValue(unknownValue);
+        }
     }
-    str << " Subs=" << p.SubElements << " flags=" << p.Flags << '/';
-    debugSymbolFlags(p.Flags, str);
-    return str;
+    return missing;
+}
+
+// When querying an item, the queried item is sometimes returned in incomplete form.
+// Take over values from source.
+static inline void fixDumperResult(const WatchData &source,
+                                   QList<WatchData> *result,
+                                   bool suppressGrandChildren)
+{
+
+    const int size = result->size();
+    if (!size)
+        return;
+    if (debugCDBWatchHandling)
+        debugWatchDataList(*result, suppressGrandChildren ? ">fixDumperResult suppressGrandChildren" : ">fixDumperResult");
+    WatchData &returned = result->front();
+    if (returned.iname != source.iname)
+        return;
+    fixDumperType(&returned, &source);
+    fixDumperValue(&returned, &source);
+    // Indicate owner and known children
+    returned.source = OwnerDumper;
+    if (returned.isChildrenKnown() && returned.isHasChildrenKnown() && returned.hasChildren)
+        returned.source |= CdbSymbolGroupContext::ChildrenKnownBit;
+    if (size == 1)
+        return;
+    // If the model queries the expanding item by pretending childrenNeeded=1,
+    // refuse the request as the children are already known
+    returned.source |= CdbSymbolGroupContext::ChildrenKnownBit;
+    // Fix the children: If the address is missing, we cannot query any further.
+    const QList<WatchData>::iterator wend = result->end();
+    QList<WatchData>::iterator it = result->begin();
+    for (++it; it != wend; ++it) {
+        WatchData &wd = *it;
+        // Indicate owner and known children
+        it->source = OwnerDumper;
+        if (it->isChildrenKnown() && it->isHasChildrenKnown() && it->hasChildren)
+            it->source |= CdbSymbolGroupContext::ChildrenKnownBit;
+        // Cannot dump items with missing addresses or missing types
+        const bool typeFixed = fixDumperType(&wd); // Order of evaluation!
+        if ((wd.addr.isEmpty() && wd.isSomethingNeeded()) || typeFixed) {
+            wd.setHasChildren(false);
+            wd.setAllUnneeded();
+        } else {
+            // Hack: Suppress endless recursion of the model. To be fixed,
+            // the model should not query non-visible items.
+            if (suppressGrandChildren && (wd.isChildrenNeeded() || wd.isHasChildrenNeeded()))
+                wd.setHasChildren(false);
+        }
+    }
+    if (debugCDBWatchHandling)
+        debugWatchDataList(*result, "<fixDumperResult");
 }
 
-static inline QByteArray hexSymbolOffset(CIDebugSymbolGroup *sg, unsigned long index)
+// Is this a non-null pointer to a dumpeable item with a value
+// "0x4343 class QString *" ? - Insert a fake '*' dereferenced item
+// and run dumpers on it. If that succeeds, insert the fake items owned by dumpers,
+// which will trigger the ignore predicate.
+// Note that the symbol context does not create '*' dereferenced items for
+// classes (see note in its header documentation).
+bool WatchHandleDumperInserter::expandPointerToDumpable(const WatchData &wd, QString *errorMessage)
 {
-    ULONG64 rc = 0;
-    if (FAILED(sg->GetSymbolOffset(index, &rc)))
-        rc = 0;
+    if (debugCDBWatchHandling)
+        qDebug() << ">expandPointerToDumpable" << wd.toString();
 
-    return QByteArray("0x") + QByteArray::number(rc, 16);
+    bool handled = false;
+    do {
+        if (wd.error || !isPointerType(wd.type))
+            break;
+        const int classPos = wd.value.indexOf(" class ");
+        if (classPos == -1)
+            break;
+        const QString hexAddrS = wd.value.mid(0, classPos);
+        if (m_hexNullPattern.exactMatch(hexAddrS))
+            break;
+        const QString type = stripPointerType(wd.value.mid(classPos + 7));
+        WatchData derefedWd;
+        derefedWd.setType(type);
+        derefedWd.setAddress(hexAddrS);
+        derefedWd.name = QString(QLatin1Char('*'));
+        derefedWd.iname = wd.iname + ".*";
+        derefedWd.source = OwnerDumper | CdbSymbolGroupContext::ChildrenKnownBit;
+        const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(derefedWd, true, &m_dumperResult, errorMessage);
+        if (dr != CdbDumperHelper::DumpOk)
+            break;
+        fixDumperResult(derefedWd, &m_dumperResult, false);
+        // Insert the pointer item with 1 additional child + its dumper results
+        // Note: formal arguments might already be expanded in the symbol group.
+        WatchData ptrWd = wd;
+        ptrWd.source = OwnerDumper | CdbSymbolGroupContext::ChildrenKnownBit;
+        ptrWd.setHasChildren(true);
+        ptrWd.setChildrenUnneeded();
+        m_wh->insertData(ptrWd);
+        m_wh->insertBulkData(m_dumperResult);
+        handled = true;
+    } while (false);
+    if (debugCDBWatchHandling)
+        qDebug() << "<expandPointerToDumpable returns " << handled << *errorMessage;
+    return handled;
 }
 
-// A helper function to extract a string value from a member function of
-// IDebugSymbolGroup2 taking the symbol index and a character buffer.
-// Pass in the the member function as '&IDebugSymbolGroup2::GetSymbolNameWide'
-
-typedef HRESULT  (__stdcall IDebugSymbolGroup2::*WideStringRetrievalFunction)(ULONG, PWSTR, ULONG, PULONG);
-
-static inline QString getSymbolString(IDebugSymbolGroup2 *sg,
-                                      WideStringRetrievalFunction wsf,
-                                      unsigned long index)
+WatchHandleDumperInserter &WatchHandleDumperInserter::operator=(WatchData &wd)
 {
-    // Template type names can get quite long....
-    enum { BufSize = 1024 };
-    static WCHAR nameBuffer[BufSize + 1];
-    // Name
-    ULONG nameLength;
-    const HRESULT hr = (sg->*wsf)(index, nameBuffer, BufSize, &nameLength);
-    if (SUCCEEDED(hr)) {
-        nameBuffer[nameLength] = 0;
-        return QString::fromUtf16(reinterpret_cast<const ushort *>(nameBuffer));
+    if (debugCDBWatchHandling)
+        qDebug() << "WatchHandleDumperInserter::operator=" << wd.toString();
+    // Check pointer to dumpeable, dumpeable, insert accordingly.
+    QString errorMessage;
+    if (expandPointerToDumpable(wd, &errorMessage)) {
+        // Nasty side effect: Modify owner for the ignore predicate
+        wd.source = OwnerDumper;
+        return *this;
+    }
+    // Expanded by internal dumper? : ok
+    if ((wd.source & CdbSymbolGroupContext::SourceMask) == OwnerSymbolGroupDumper) {
+        m_wh->insertData(wd);
+        return *this;
     }
-    return QString();
+    // Try library dumpers.
+    switch (m_dumper->dumpType(wd, true, &m_dumperResult, &errorMessage)) {
+    case CdbDumperHelper::DumpOk:
+        if (debugCDBWatchHandling)
+            qDebug() << "dumper triggered";
+        // Dumpers omit types for complicated templates
+        fixDumperResult(wd, &m_dumperResult, false);
+        // Discard the original item and insert the dumper results
+        m_wh->insertBulkData(m_dumperResult);
+        // Nasty side effect: Modify owner for the ignore predicate
+        wd.source = OwnerDumper;
+        break;
+    case CdbDumperHelper::DumpNotHandled:
+    case CdbDumperHelper::DumpError:
+        wd.source = OwnerSymbolGroup;
+        m_wh->insertData(wd);
+        break;
+    }
+    return *this;
 }
 
-namespace Debugger {
-namespace Internal {
-
 
 CdbSymbolGroupRecursionContext::CdbSymbolGroupRecursionContext(CdbSymbolGroupContext *ctx,
-                                                         int ido,
-                                                         CIDebugDataSpaces *ds) :
+                                                         int ido) :
     context(ctx),
-    internalDumperOwner(ido),
-    dataspaces(ds)
+    internalDumperOwner(ido)
 {
 }
 
@@ -142,27 +313,26 @@ static inline CdbSymbolGroupContext::SymbolState getSymbolState(const DEBUG_SYMB
 
 CdbSymbolGroupContext::CdbSymbolGroupContext(const QString &prefix,
                                              CIDebugSymbolGroup *symbolGroup,
+                                             const QSharedPointer<CdbDumperHelper> &dumper,
                                              const QStringList &uninitializedVariables) :
-    m_prefix(prefix),
-    m_nameDelimiter(QLatin1Char('.')),
-    m_uninitializedVariables(uninitializedVariables.toSet()),
-    m_symbolGroup(symbolGroup),
-    m_unnamedSymbolNumber(1)
-{
-
-}
-
-CdbSymbolGroupContext::~CdbSymbolGroupContext()
+    CdbCore::SymbolGroupContext(prefix, symbolGroup,
+                                dumper->comInterfaces()->debugDataSpaces,
+                                uninitializedVariables),
+    m_useDumpers(dumper->isEnabled() && theDebuggerBoolSetting(UseDebuggingHelpers)),
+    m_dumper(dumper)
 {
-    m_symbolGroup->Release();
+    setShadowedNameFormat(WatchData::shadowedNameFormat());
 }
 
 CdbSymbolGroupContext *CdbSymbolGroupContext::create(const QString &prefix,
                                                      CIDebugSymbolGroup *symbolGroup,
+                                                     const QSharedPointer<CdbDumperHelper> &dumper,
                                                      const QStringList &uninitializedVariables,
                                                      QString *errorMessage)
 {
-    CdbSymbolGroupContext *rc = new CdbSymbolGroupContext(prefix, symbolGroup, uninitializedVariables);
+    CdbSymbolGroupContext *rc = new CdbSymbolGroupContext(prefix, symbolGroup,
+                                                          dumper,
+                                                          uninitializedVariables);
     if (!rc->init(errorMessage)) {
         delete rc;
         return 0;
@@ -170,287 +340,6 @@ CdbSymbolGroupContext *CdbSymbolGroupContext::create(const QString &prefix,
     return rc;
 }
 
-bool CdbSymbolGroupContext::init(QString *errorMessage)
-{
-    // retrieve the root symbols
-    ULONG count;
-    HRESULT hr = m_symbolGroup->GetNumberSymbols(&count);
-    if (FAILED(hr)) {
-        *errorMessage = CdbCore::msgComFailed("GetNumberSymbols", hr);
-        return false;
-    }
-
-    if (count) {
-        m_symbolParameters.reserve(3u * count);
-        m_symbolParameters.resize(count);
-
-        hr = m_symbolGroup->GetSymbolParameters(0, count, symbolParameters());
-        if (FAILED(hr)) {
-            *errorMessage = QString::fromLatin1("In %1: %2 (%3 symbols)").arg(QLatin1String(Q_FUNC_INFO),
-                                                                              CdbCore::msgComFailed("GetSymbolParameters", hr)).arg(count);
-            return false;
-        }
-        populateINameIndexMap(m_prefix, DEBUG_ANY_ID, count);
-    }
-    if (debug)
-        qDebug() << Q_FUNC_INFO << '\n'<< toString(true);
-    return true;
-}
-
-/* Make the entries for iname->index mapping. We might encounter
- * already expanded subitems when doing it for top-level ('this'-pointers),
- * recurse in that case, (skip over expanded children).
- * Loop backwards to detect shadowed variables in the order the
-/* debugger expects them:
-\code
-int x;             // Occurrence (1), should be reported as "x <shadowed 1>"
-if (true) {
-   int x = 5; (2)  // Occurrence (2), should be reported as "x"
-}
-\endcode
- * The order in the symbol group is (1),(2). Give them an iname of
- * <root>#<shadowed-nr>, which will be split apart for display. */
-
-void CdbSymbolGroupContext::populateINameIndexMap(const QString &prefix, unsigned long parentId,
-                                                  unsigned long end)
-{
-    const QString symbolPrefix = prefix + m_nameDelimiter;
-    if (debug)
-        qDebug() << Q_FUNC_INFO << '\n'<< symbolPrefix << parentId << end;
-    for (unsigned long i = end - 1; ; i--) {
-        const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i);
-        if (parentId == p.ParentSymbol) {
-            // "__formal" occurs when someone writes "void foo(int /* x */)..."
-            static const QString unnamedFormalParameter = QLatin1String("__formal");
-            QString symbolName = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i);
-            if (symbolName == unnamedFormalParameter) {
-                symbolName = QLatin1String("<unnamed");
-                symbolName += QString::number(m_unnamedSymbolNumber++);
-                symbolName += QLatin1Char('>');
-            }
-            // Find a unique name in case the variable is shadowed by
-            // an existing one
-            const QString namePrefix = symbolPrefix + symbolName;
-            QString name = namePrefix;
-            for (int n = 1; m_inameIndexMap.contains(name); n++) {
-                name.truncate(namePrefix.size());
-                name += QLatin1Char(iNameShadowDelimiter);
-                name += QString::number(n);
-            }
-            m_inameIndexMap.insert(name, i);
-            if (getSymbolState(p) == ExpandedSymbol)
-                populateINameIndexMap(name, i, i + 1 + p.SubElements);
-        }
-        if (i == 0 || i == parentId)
-            break;
-    }
-}
-
-QString CdbSymbolGroupContext::toString(bool verbose) const
-{
-    QString rc;
-    QTextStream str(&rc);
-    const int count = m_symbolParameters.size();
-    for (int i = 0; i < count; i++) {
-        str << i << ' ';
-        const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i);
-        if (!isTopLevelSymbol(p))
-            str << "    ";
-        str << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i);
-        if (p.Flags & DEBUG_SYMBOL_IS_LOCAL)
-            str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, i) << '\'';
-        str << " Address: " << hexSymbolOffset(m_symbolGroup, i);
-        if (verbose)
-            str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, i) << '\'';
-        str << p << '\n';
-    }
-    if (verbose) {
-        str << "NameIndexMap\n";
-        NameIndexMap::const_iterator ncend = m_inameIndexMap.constEnd();
-        for (NameIndexMap::const_iterator it = m_inameIndexMap.constBegin() ; it != ncend; ++it)
-            str << it.key() << ' ' << it.value() << '\n';
-    }
-    return rc;
-}
-
-CdbSymbolGroupContext::SymbolState CdbSymbolGroupContext::symbolState(unsigned long index) const
-{
-    return getSymbolState(m_symbolParameters.at(index));
-}
-
-CdbSymbolGroupContext::SymbolState CdbSymbolGroupContext::symbolState(const QString &prefix) const
-{
-    if (prefix == m_prefix) // root
-        return ExpandedSymbol;
-    unsigned long index;
-    if (!lookupPrefix(prefix, &index)) {
-        qWarning("WARNING %s: %s\n", Q_FUNC_INFO, qPrintable(msgSymbolNotFound(prefix)));
-        return LeafSymbol;
-    }
-    return symbolState(index);
-}
-
-// Find index of a prefix
-bool CdbSymbolGroupContext::lookupPrefix(const QString &prefix, unsigned long *index) const
-{
-    *index = 0;
-    const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(prefix);
-    if (it == m_inameIndexMap.constEnd())
-        return false;
-    *index = it.value();
-    return true;
-}
-
-/* Retrieve children and get the position. */
-bool CdbSymbolGroupContext::getChildSymbolsPosition(const QString &prefix,
-                                                    unsigned long *start,
-                                                    unsigned long *parentId,
-                                                    QString *errorMessage)
-{
-    if (debug)
-        qDebug() << Q_FUNC_INFO << '\n'<< prefix;
-
-    *start = *parentId = 0;
-    // Root item?
-    if (prefix == m_prefix) {
-        *start = 0;
-        *parentId = DEBUG_ANY_ID;
-        if (debug)
-            qDebug() << '<' << prefix << "at" << *start;
-        return true;
-    }
-    // Get parent index, make sure it is expanded
-    NameIndexMap::const_iterator nit = m_inameIndexMap.constFind(prefix);
-    if (nit == m_inameIndexMap.constEnd()) {
-        *errorMessage = QString::fromLatin1("'%1' not found.").arg(prefix);
-        return false;
-    }
-    *parentId = nit.value();
-    *start = nit.value() + 1;
-    if (!expandSymbol(prefix, *parentId, errorMessage))
-        return false;
-    if (debug)
-        qDebug() << '<' << prefix << "at" << *start;
-    return true;
-}
-
-static inline QString msgExpandFailed(const QString &prefix, unsigned long index, const QString &why)
-{
-    return QString::fromLatin1("Unable to expand '%1' %2: %3").arg(prefix).arg(index).arg(why);
-}
-
-// Expand a symbol using the symbol group interface.
-bool CdbSymbolGroupContext::expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage)
-{
-    if (debug)
-        qDebug() << '>' << Q_FUNC_INFO << '\n' << prefix << index;
-
-    switch (symbolState(index)) {
-    case LeafSymbol:
-        *errorMessage = QString::fromLatin1("Attempt to expand leaf node '%1' %2!").arg(prefix).arg(index);
-        return false;
-    case ExpandedSymbol:
-        return true;
-    case CollapsedSymbol:
-        break;
-    }
-
-    HRESULT hr = m_symbolGroup->ExpandSymbol(index, TRUE);
-    if (FAILED(hr)) {
-        *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("ExpandSymbol", hr));
-        return false;
-    }
-    // Hopefully, this will never fail, else data structure will be foobar.
-    const ULONG oldSize = m_symbolParameters.size();
-    ULONG newSize;
-    hr = m_symbolGroup->GetNumberSymbols(&newSize);
-    if (FAILED(hr)) {
-        *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("GetNumberSymbols", hr));
-        return false;
-    }
-
-    // Retrieve the new parameter structs which will be inserted
-    // after the parents, offsetting consecutive indexes.
-    m_symbolParameters.resize(newSize);
-
-    hr = m_symbolGroup->GetSymbolParameters(0, newSize, symbolParameters());
-    if (FAILED(hr)) {
-        *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("GetSymbolParameters", hr));
-        return false;
-    }
-    // The new symbols are inserted after the parent symbol.
-    // We need to correct the following values in the name->index map
-    const unsigned long newSymbolCount = newSize - oldSize;
-    const NameIndexMap::iterator nend = m_inameIndexMap.end();
-    for (NameIndexMap::iterator it = m_inameIndexMap.begin(); it != nend; ++it)
-        if (it.value() > index)
-            it.value() += newSymbolCount;
-    // insert the new symbols
-    populateINameIndexMap(prefix, index, index + 1 + newSymbolCount);
-    if (debug > 1)
-        qDebug() << '<' << Q_FUNC_INFO << '\n' << prefix << index << '\n' << toString();
-    return true;
-}
-
-void CdbSymbolGroupContext::clear()
-{
-    m_symbolParameters.clear();
-    m_inameIndexMap.clear();
-}
-
-QString CdbSymbolGroupContext::symbolINameAt(unsigned long index) const
-{
-    return m_inameIndexMap.key(index);
-}
-
-// Return hexadecimal pointer value from a CDB pointer value
-// which look like "0x000032a" or "0x00000000`0250124a" or
-// "0x1`0250124a" on 64-bit systems.
-static bool inline getUnsignedHexValue(QString stringValue, quint64 *value)
-{
-    *value = 0;
-    if (!stringValue.startsWith(QLatin1String("0x")))
-        return false;
-    stringValue.remove(0, 2);
-    // Remove 64bit separator
-    if (stringValue.size() > 9) {
-        const int sepPos = stringValue.size() - 9;
-        if (stringValue.at(sepPos) == QLatin1Char('`'))
-            stringValue.remove(sepPos, 1);
-    }
-    bool ok;
-    *value = stringValue.toULongLong(&ok, 16);
-    return ok;
-}
-
-// check for "0x000", "0x000 class X" or its 64-bit equivalents.
-static inline bool isNullPointer(const WatchData &wd)
-{
-    if (!isPointerType(wd.type))
-        return false;
-    QString stringValue = wd.value;
-    const int blankPos = stringValue.indexOf(QLatin1Char(' '));
-    if (blankPos != -1)
-        stringValue.truncate(blankPos);
-    quint64 value;
-    return getUnsignedHexValue(stringValue, &value) && value == 0u;
-}
-
-// Fix a symbol group value. It is set to the class type for
-// expandable classes (type="class std::foo<..>[*]",
-// value="std::foo<...>[*]". This is not desired
-// as it widens the value column for complex std::template types.
-// Remove the inner template type.
-
-static inline QString removeInnerTemplateType(QString value)
-{
-    const int firstBracketPos = value.indexOf(QLatin1Char('<'));
-    const int lastBracketPos = firstBracketPos != -1 ? value.lastIndexOf(QLatin1Char('>')) : -1;
-    if (lastBracketPos != -1)
-        value.replace(firstBracketPos + 1, lastBracketPos - firstBracketPos -1, QLatin1String("..."));
-    return value;
-}
-
 // Fix display values: Pass through strings, convert unsigned integers
 // to decimal ('0x5454`fedf'), remove inner templates from
 // "0x4343 class list<>".
@@ -463,267 +352,155 @@ static inline QString fixValue(const QString &value, const QString &type)
     // Unsigned hex numbers
     if (isIntType(type) && (size > 2 && value.at(1) == QLatin1Char('x'))) {
         quint64 intValue;
-        if (getUnsignedHexValue(value, &intValue))
+        if (CdbCore::SymbolGroupContext::getUnsignedHexValue(value, &intValue))
             return QString::number(intValue);
     }
-    return size < 20 ? value : removeInnerTemplateType(value);
+    return size < 20 ? value : CdbCore::SymbolGroupContext::removeInnerTemplateType(value);
 }
 
-WatchData CdbSymbolGroupContext::watchDataAt(unsigned long index) const
+unsigned CdbSymbolGroupContext::watchDataAt(unsigned long index, WatchData *wd)
 {
-    WatchData wd;
-    wd.iname = symbolINameAt(index).toLatin1();
-    wd.exp = wd.iname;
-    // Determine name from iname and format shadowed variables correctly
-    // as "<shadowed X>, see populateINameIndexMap().
-    const int lastDelimiterPos = wd.iname.lastIndexOf(m_nameDelimiter.toLatin1());
-    QString name = lastDelimiterPos == -1 ? wd.iname : wd.iname.mid(lastDelimiterPos + 1);
-    int shadowedNumber = 0;
-    const int shadowedPos = name.lastIndexOf(QLatin1Char(iNameShadowDelimiter));
-    if (shadowedPos != -1) {
-        shadowedNumber = name.mid(shadowedPos + 1).toInt();
-        name.truncate(shadowedPos);
+    ULONG typeId;
+    ULONG64 address;
+    QString iname;
+    QString value;
+    QString type;
+    const unsigned rc = dumpValue(index, &iname, &(wd->name), &address,
+                                  &typeId, &type, &value);
+    wd->exp = wd->iname = iname.toLatin1();
+    // Trigger numeric sorting for arrays "local.[22]" -> "local.22"
+    if (wd->iname.endsWith(']')) {
+        const int openingBracketPos = wd->iname.lastIndexOf('[');
+        if (openingBracketPos != -1) {
+            wd->iname.truncate(wd->iname.size() - 1);
+            wd->iname.remove(openingBracketPos, 1);
+        }
     }
-    // For class hierarchies, we get sometimes complicated std::template types here.
-    // (std::map extends std::tree<>... Remove them for display only.
-    const QString fullShadowedName = WatchData::shadowedName(name, shadowedNumber);
-    wd.name = WatchData::shadowedName(removeInnerTemplateType(name), shadowedNumber);
-    wd.addr = hexSymbolOffset(m_symbolGroup, index);
-    const QString type = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index);
-    wd.setType(type);
-    // Check for uninitialized variables at level 0 only.
-    const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(index);
-    if (p.ParentSymbol == DEBUG_ANY_ID && m_uninitializedVariables.contains(fullShadowedName)) {
-        wd.setError(WatchData::msgNotInScope());
-        return wd;
+    wd->setAddress(QString::fromLatin1("0x") + QString::number(address, 16));
+    wd->setType(type, false);
+    wd->setValue(fixValue(value, type));
+    if (rc & OutOfScope) {
+        wd->setError(WatchData::msgNotInScope());
+    } else {
+        const bool hasChildren = rc & HasChildren;
+        wd->setHasChildren(hasChildren);
+        if (hasChildren)
+            wd->setChildrenNeeded();
     }
-    const QString value = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
-    wd.setValue(fixValue(value, type));
-    wd.setChildrenNeeded(); // compensate side effects of above setters
-    // Figure out children. The SubElement is only a guess unless the symbol,
-    // is expanded, so, we leave this as a guess for later updates.
-    // If the symbol has children (expanded or not), we leave the 'Children' flag
-    // in 'needed' state. Suppress 0-pointers right ("0x000 class X")
-    // here as they only lead to children with memory access errors.
-    const bool hasChildren = p.SubElements && !isNullPointer(wd);
-    wd.setHasChildren(hasChildren);
     if (debug > 1)
-        qDebug() << Q_FUNC_INFO << index << '\n' << wd.toString();
-    return wd;
-}
-
-WatchData CdbSymbolGroupContext::dumpSymbolAt(CIDebugDataSpaces *ds, unsigned long index)
-{
-    WatchData rc = watchDataAt(index);
-    dump(ds, &rc);
+        qDebug() << "watchDataAt" << index << QString::number(rc, 16) << wd->toString();
     return rc;
 }
 
-bool CdbSymbolGroupContext::assignValue(const QString &iname, const QString &value,
-                                        QString *newValue, QString *errorMessage)
-{
-    if (debugCDB)
-        qDebug() << Q_FUNC_INFO << '\n' << iname << value;
-    const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(iname);
-    if (it == m_inameIndexMap.constEnd()) {
-        *errorMessage = msgSymbolNotFound(iname);
-        return false;
-    }
-    const unsigned long  index = it.value();
-    const HRESULT hr = m_symbolGroup->WriteSymbolWide(index, reinterpret_cast<PCWSTR>(value.utf16()));
-    if (FAILED(hr)) {
-        *errorMessage = QString::fromLatin1("Unable to assign '%1' to '%2': %3").
-                        arg(value, iname, CdbCore::msgComFailed("WriteSymbolWide", hr));
-        return false;
-    }
-    if (newValue)
-        *newValue = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
-    return true;
-}
-
-/* The special type dumpers have an integer return code meaning:
- *  0:  ok
- *  1:  Dereferencing or retrieving memory failed, this is out of scope,
- *      do not try to query further.
- * > 1: A structural error was encountered, that is, the implementation
- *      of the class changed (Qt or say, a different STL implementation).
- *      Visibly warn about it.
- * To add further types, have a look at the toString() output of the
- * symbol group. */
-
-static QString msgStructuralError(const QString &name, const QString &type, int code)
-{
-    return QString::fromLatin1("Warning: Internal dumper for '%1' (%2) failed with %3.").arg(name, type).arg(code);
-}
-
-static inline bool isStdStringOrPointer(const QString &type)
-{
-#define STD_WSTRING "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >"
-#define STD_STRING "std::basic_string<char,std::char_traits<char>,std::allocator<char> >"
-    return type.endsWith(QLatin1String(STD_STRING))
-            || type.endsWith(QLatin1String(STD_STRING" *"))
-            || type.endsWith(QLatin1String(STD_WSTRING))
-            || type.endsWith(QLatin1String(STD_WSTRING" *"));
-#undef STD_WSTRING
-#undef STD_STRING
-}
-
-CdbSymbolGroupContext::DumperResult
-        CdbSymbolGroupContext::dump(CIDebugDataSpaces *ds, WatchData *wd)
-{
-    DumperResult rc = DumperNotHandled;
-    do {
-        // Is this a previously detected Null-Pointer?
-        if (wd->isHasChildrenKnown() && !wd->hasChildren)
-            break;
-        // QString
-        if (wd->type.endsWith(QLatin1String("QString")) || wd->type.endsWith(QLatin1String("QString *"))) {
-            const int drc = dumpQString(ds, wd);
-            switch (drc) {
-            case 0:
-                rc = DumperOk;
-                break;
-            case 1:
-                rc = DumperError;
-                break;
-            default:
-                qWarning("%s\n", qPrintable(msgStructuralError(wd->iname, wd->type, drc)));
-                rc = DumperNotHandled;
-                break;
-            }
-        }
-        // StdString
-        if (isStdStringOrPointer(wd->type)) {
-            const int drc = dumpStdString(wd);
-            switch (drc) {
-            case 0:
-                rc = DumperOk;
-                break;
-            case 1:
-                rc = DumperError;
-                break;
-            default:
-                qWarning("%s\n", qPrintable(msgStructuralError(wd->iname, wd->type, drc)));
-                rc = DumperNotHandled;
-                break;
-            }
-
-        }
-    } while (false);
-    if (debugInternalDumpers)
-        qDebug() << "CdbSymbolGroupContext::dump" << rc << wd->toString();
+bool CdbSymbolGroupContext::populateModelInitially(WatchHandler *wh, QString *errorMessage)
+{
+    if (debugCDBWatchHandling)
+        qDebug() << "populateModelInitially dumpers=" << m_useDumpers;
+    // Recurse down items that are initially expanded in the view, stop processing for
+    // dumper items.
+    const CdbSymbolGroupRecursionContext rctx(this, OwnerSymbolGroupDumper);
+    const bool rc = m_useDumpers ?
+        populateModelInitiallyHelper(rctx,
+                                     WatchHandleDumperInserter(wh, m_dumper),
+                                     WatchHandlerExpandedPredicate(wh),
+                                     isDumperPredicate,
+                                     errorMessage) :
+        populateModelInitiallyHelper(rctx,
+                                     WatchHandlerModelInserter(wh),
+                                     WatchHandlerExpandedPredicate(wh),
+                                     falsePredicate,
+                                     errorMessage);
     return rc;
 }
 
-// Get integer value of symbol group
-static inline bool getIntValue(CIDebugSymbolGroup *sg, int index, int *value)
+bool CdbSymbolGroupContext::completeData(const WatchData &incompleteLocal,
+                                         WatchHandler *wh,
+                                         QString *errorMessage)
 {
-    const QString valueS = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
-    bool ok;
-    *value = valueS.toInt(&ok);
-    return ok;
-}
+    if (debugCDBWatchHandling)
+        qDebug() << ">completeData src=" << incompleteLocal.source << incompleteLocal.toString();
 
-// Get pointer value of symbol group ("0xAAB")
-// Note that this is on "00000000`0250124a" on 64bit systems.
-static inline bool getUnsignedHexValue(CIDebugSymbolGroup *sg, int index, quint64 *value)
-{
-    const QString stringValue = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
-    return getUnsignedHexValue(stringValue, value);
-}
-
-enum { maxStringLength = 4096 };
+    const CdbSymbolGroupRecursionContext rctx(this, OwnerSymbolGroupDumper);
+    // Expand symbol group items, recurse one level from desired item
+    if (!m_useDumpers) {
+        return completeDataHelper(rctx, incompleteLocal,
+                                  WatchHandlerModelInserter(wh),
+                                  MatchINamePredicate(incompleteLocal.iname),
+                                  falsePredicate,
+                                  errorMessage);
+    }
 
-int CdbSymbolGroupContext::dumpQString(CIDebugDataSpaces *ds, WatchData *wd)
-{
-    QString errorMessage;
-    unsigned long stringIndex;
-    if (!lookupPrefix(wd->iname, &stringIndex))
-        return 1;
-
-    // Expand string and it's "d" (step over 'static null')
-    if (!expandSymbol(wd->iname, stringIndex, &errorMessage))
-        return 2;
-    const unsigned long dIndex = stringIndex + 4;
-    if (!expandSymbol(wd->iname, dIndex, &errorMessage))
-        return 3;
-    const unsigned long sizeIndex = dIndex + 3;
-    const unsigned long arrayIndex = dIndex + 4;
-    // Get size and pointer
-    int size;
-    if (!getIntValue(m_symbolGroup, sizeIndex, &size))
-        return 4;
-    quint64 array;
-    if (!getUnsignedHexValue(m_symbolGroup, arrayIndex, &array))
-        return 5;
-    // Fetch
-    const bool truncated = size > maxStringLength;
-    if (truncated)
-        size = maxStringLength;
-    const QChar doubleQuote = QLatin1Char('"');
-    QString value;
-    if (size > 0) {
-        value += doubleQuote;
-        // Should this ever be a remote debugger, need to check byte order.
-        unsigned short *buf =  new unsigned short[size + 1];
-        unsigned long bytesRead;
-        const HRESULT hr = ds->ReadVirtual(array, buf, size * sizeof(unsigned short), &bytesRead);
-        if (FAILED(hr)) {
-            delete [] buf;
-            return 1;
+    // Expand artifical dumper items
+    if ((incompleteLocal.source & CdbSymbolGroupContext::SourceMask) == OwnerDumper) {
+        // If the model queries the expanding item by pretending childrenNeeded=1,
+        // refuse the request if the children are already known
+        if (incompleteLocal.state == WatchData::ChildrenNeeded && (incompleteLocal.source & CdbSymbolGroupContext::ChildrenKnownBit)) {
+            WatchData local = incompleteLocal;
+            local.setChildrenUnneeded();
+            wh->insertData(local);
+            return true;
         }
-        buf[bytesRead / sizeof(unsigned short)] = 0;
-        value += QString::fromUtf16(buf);
-        delete [] buf;
-        if (truncated)
-            value += QLatin1String("...");
-        value += doubleQuote;
-    } else if (size == 0) {
-        value = QString(doubleQuote) + doubleQuote;
-    } else {
-        value = "Invalid QString";
+        QList<WatchData> dumperResult;
+        const CdbDumperHelper::DumpResult dr = m_dumper->dumpType(incompleteLocal, true, &dumperResult, errorMessage);
+        if (dr == CdbDumperHelper::DumpOk) {
+            // Hack to stop endless model recursion
+            const bool suppressGrandChildren = !wh->isExpandedIName(incompleteLocal.iname);
+            fixDumperResult(incompleteLocal, &dumperResult, suppressGrandChildren);
+            wh->insertBulkData(dumperResult);
+        } else {
+            const QString msg = QString::fromLatin1("Unable to further expand dumper watch data: '%1' (%2): %3/%4").arg(incompleteLocal.name, incompleteLocal.type).arg(int(dr)).arg(*errorMessage);
+            qWarning("%s", qPrintable(msg));
+            WatchData wd = incompleteLocal;
+            if (wd.isValueNeeded())
+                wd.setValue(QCoreApplication::translate("CdbSymbolGroupContext", "<Unknown>"));
+            wd.setHasChildren(false);
+            wd.setAllUnneeded();
+            wh->insertData(wd);
+        }
+        return true;
     }
 
-    wd->setValue(value);
-    wd->setHasChildren(false);
-    return 0;
+    // Expand symbol group items, recurse one level from desired item
+    return completeDataHelper(rctx, incompleteLocal,
+                              WatchHandleDumperInserter(wh, m_dumper),
+                              MatchINamePredicate(incompleteLocal.iname),
+                              isDumperPredicate,
+                              errorMessage);
 }
 
-int CdbSymbolGroupContext::dumpStdString(WatchData *wd)
+bool CdbSymbolGroupContext::editorToolTip(const QString &iname,
+                                         QString *value,
+                                         QString *errorMessage)
 {
-    QString errorMessage;
-    unsigned long stringIndex;
-    if (!lookupPrefix(wd->iname, &stringIndex))
-        return 1;
-
-    // Expand string ->string_val->_bx.
-    if (!expandSymbol(wd->iname, stringIndex, &errorMessage))
-        return 1;
-    const unsigned long bxIndex = stringIndex + 3;
-    if (!expandSymbol(wd->iname, bxIndex, &errorMessage))
-        return 2;
-    // Check if size is something sane
-    const int sizeIndex = stringIndex + 6;
-    int size;
-    if (!getIntValue(m_symbolGroup, sizeIndex, &size))
-        return 3;
-    if (size < 0)
-        return 1;
-    // Just copy over the value of the buf[]-array, which should be the string
-    const QChar doubleQuote = QLatin1Char('"');
-    const int bufIndex = stringIndex + 4;
-    QString bufValue = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, bufIndex);
-    const int quotePos = bufValue.indexOf(doubleQuote);
-    if (quotePos == -1)
-        return 1;
-    bufValue.remove(0, quotePos);
-    if (bufValue.size() > maxStringLength) {
-        bufValue.truncate(maxStringLength);
-        bufValue += QLatin1String("...\"");
+    if (debugToolTips)
+        qDebug() << iname;
+    value->clear();
+    unsigned long index;
+    if (!lookupPrefix(iname, &index)) {
+        *errorMessage = QString::fromLatin1("%1 not found.").arg(iname);
+        return false;
     }
-    wd->setValue(bufValue);
-    wd->setHasChildren(false);
-    return 0;
+    // Check dumpers. Should actually be just one item.
+
+    WatchData wd;
+    const unsigned rc = watchDataAt(index, &wd);
+    if (m_useDumpers && !wd.error
+        && (0u == (rc & CdbCore::SymbolGroupContext::InternalDumperMask))
+        && m_dumper->state() != CdbDumperHelper::Disabled) {
+        QList<WatchData> result;
+        if (CdbDumperHelper::DumpOk == m_dumper->dumpType(wd, false, &result, errorMessage))  {
+            foreach (const WatchData &dwd, result) {
+                if (!value->isEmpty())
+                    value->append(QLatin1Char('\n'));
+                value->append(dwd.toToolTip());
+            }
+            return true;
+        } // Dumped ok
+    }     // has Dumpers
+    if (debugToolTips)
+        qDebug() << iname << wd.toString();
+    *value = wd.toToolTip();
+    return true;
 }
 
 } // namespace Internal
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
index d3f63b282bdd0f7d8d2e6d412a96b49546597754..c23379df1b7173bc0df61ee9382a18cf0ce270cf 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext.h
@@ -31,12 +31,13 @@
 #define CDBSYMBOLGROUPCONTEXT_H
 
 #include "cdbcom.h"
-#include "watchhandler.h"
+#include "symbolgroupcontext.h"
 
 #include <QtCore/QString>
 #include <QtCore/QVector>
 #include <QtCore/QList>
 #include <QtCore/QStringList>
+#include <QtCore/QSharedPointer>
 #include <QtCore/QPair>
 #include <QtCore/QMap>
 #include <QtCore/QSet>
@@ -47,50 +48,47 @@ namespace Internal {
 class WatchData;
 class WatchHandler;
 struct CdbSymbolGroupRecursionContext;
+class CdbDumperHelper;
 
-/* A thin wrapper around the IDebugSymbolGroup2 interface which represents
- * a flat list of symbols using an index (for example, belonging to a stack
- * frame). It uses the hierarchical naming convention of WatchHandler as in:
- * "local" (invisible root)
- * "local.string" (local class variable)
- * "local.string.data" (class member)
- * and maintains a mapping iname -> index.
- * IDebugSymbolGroup2 can "expand" expandable symbols, inserting them into the
- * flat list after their parent.
- *
- * Note the pecularity of IDebugSymbolGroup2 with regard to pointed to items:
- * 1) A pointer to a POD (say int *) will expand to a pointed-to integer named '*'.
- * 2) A pointer to a class (QString *), will expand to the class members right away,
- *    omitting the '*' derefenced item. That is a problem since the dumpers trigger
- *    only on the derefenced item, so, additional handling is required.
- */
-
-class CdbSymbolGroupContext
+
+/* CdbSymbolGroupContext 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 CdbSymbolGroupContext : public CdbCore::SymbolGroupContext
 {
     Q_DISABLE_COPY(CdbSymbolGroupContext);
      explicit CdbSymbolGroupContext(const QString &prefix,
                                     CIDebugSymbolGroup *symbolGroup,
-                                    const QStringList &uninitializedVariables = QStringList());
+                                    const QSharedPointer<CdbDumperHelper> &dumper,
+                                    const QStringList &uninitializedVariables);
 
 public:
-    ~CdbSymbolGroupContext();
-    static CdbSymbolGroupContext *create(const QString &prefix,
-                                         CIDebugSymbolGroup *symbolGroup,
-                                         const QStringList &uninitializedVariables,
-                                         QString *errorMessage);
+     // Mask bits for the source field of watch data.
+     enum { SourceMask = 0xFF, ChildrenKnownBit = 0x0100 };
+
+     static CdbSymbolGroupContext *create(const QString &prefix,
+                                          CIDebugSymbolGroup *symbolGroup,
+                                          const QSharedPointer<CdbDumperHelper> &dumper,
+                                          const QStringList &uninitializedVariables,
+                                          QString *errorMessage);
 
-    QString prefix() const { return m_prefix; }
+     bool editorToolTip(const QString &iname, QString *value, QString *errorMessage);
 
-    bool assignValue(const QString &iname, const QString &value,
-                     QString *newValue /* = 0 */, QString *errorMessage);
+     bool populateModelInitially(WatchHandler *wh, QString *errorMessage);
 
+     bool completeData(const WatchData &incompleteLocal,
+                       WatchHandler *wh,
+                       QString *errorMessage);     
+
+private:
     // Initially populate the locals model for a new stackframe.
     // Write a sequence of WatchData to it, recurse down if the
     // recursionPredicate agrees. The ignorePredicate can be used
     // to terminate processing after insertion of an item (if the calling
     // routine wants to insert another subtree).
     template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
-    static bool populateModelInitially(const CdbSymbolGroupRecursionContext &ctx,
+    static bool populateModelInitiallyHelper(const CdbSymbolGroupRecursionContext &ctx,
                                        OutputIterator it,
                                        RecursionPredicate recursionPredicate,
                                        IgnorePredicate ignorePredicate,
@@ -102,7 +100,7 @@ public:
     // to terminate processing after insertion of an item (if the calling
     // routine wants to insert another subtree).
     template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
-    static bool completeData (const CdbSymbolGroupRecursionContext &ctx,
+    static bool completeDataHelper (const CdbSymbolGroupRecursionContext &ctx,
                               WatchData incompleteLocal,
                               OutputIterator it,
                               RecursionPredicate recursionPredicate,
@@ -116,67 +114,30 @@ public:
     // Retrieve child symbols of prefix as a sequence of WatchData.
     // Is CIDebugDataSpaces is != 0, try internal dumper and set owner
     template <class OutputIterator>
-            bool getDumpChildSymbols(CIDebugDataSpaces *ds, const QString &prefix,
-                                      int dumpedOwner,
-                                      OutputIterator it, QString *errorMessage);
-
-    WatchData watchDataAt(unsigned long index) const;
-    // Run the internal dumpers on the symbol
-    WatchData dumpSymbolAt(CIDebugDataSpaces *ds, unsigned long index);
+            bool getDumpChildSymbols(const QString &prefix,
+                                     int dumpedOwner,
+                                     OutputIterator it, QString *errorMessage);
 
-    bool lookupPrefix(const QString &prefix, unsigned long *index) const;
-
-    enum SymbolState { LeafSymbol, ExpandedSymbol, CollapsedSymbol };
-    SymbolState symbolState(unsigned long index) const;
-    SymbolState symbolState(const QString &prefix) const;
-
-    inline bool isExpanded(unsigned long index) const   { return symbolState(index) == ExpandedSymbol; }
-    inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; }
+    template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
+    static bool insertSymbolRecursion(WatchData wd,
+                                      const CdbSymbolGroupRecursionContext &ctx,
+                                      OutputIterator it,
+                                      RecursionPredicate recursionPredicate,
+                                      IgnorePredicate ignorePredicate,
+                                      QString *errorMessage);
 
-    // Dump
-    enum DumperResult { DumperOk, DumperError, DumperNotHandled };
-    DumperResult dump(CIDebugDataSpaces *ds, WatchData *wd);
+    unsigned watchDataAt(unsigned long index, WatchData *);
 
-private:
-    typedef QMap<QString, unsigned long>  NameIndexMap;
-
-    static inline bool isSymbolDisplayable(const DEBUG_SYMBOL_PARAMETERS &p);
-
-    bool init(QString *errorMessage);
-    void clear();
-    QString toString(bool verbose = false) const;
-    bool getChildSymbolsPosition(const QString &prefix,
-                                 unsigned long *startPos,
-                                 unsigned long *parentId,
-                                 QString *errorMessage);
-    bool expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage);
-    void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long end);
-    QString symbolINameAt(unsigned long index) const;
-
-    int dumpQString(CIDebugDataSpaces *ds, WatchData *wd);
-    int dumpStdString(WatchData *wd);
-
-    inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); }
-    inline const DEBUG_SYMBOL_PARAMETERS *symbolParameters() const { return &(*m_symbolParameters.constBegin()); }
-
-    const QString m_prefix;
-    const QChar m_nameDelimiter;
-    const QSet<QString> m_uninitializedVariables;
-
-    CIDebugSymbolGroup *m_symbolGroup;
-    NameIndexMap m_inameIndexMap;
-    QVector<DEBUG_SYMBOL_PARAMETERS> m_symbolParameters;
-    int m_unnamedSymbolNumber;
+    const bool m_useDumpers;
+    const QSharedPointer<CdbDumperHelper> m_dumper;
 };
 
-
 // A convenience struct to save parameters for the model recursion.
 struct CdbSymbolGroupRecursionContext {
-    explicit CdbSymbolGroupRecursionContext(CdbSymbolGroupContext *ctx, int internalDumperOwner, CIDebugDataSpaces *ds);
+    explicit CdbSymbolGroupRecursionContext(CdbSymbolGroupContext *ctx, int internalDumperOwner);
 
     CdbSymbolGroupContext *context;
     int internalDumperOwner;
-    CIDebugDataSpaces *dataspaces;
 };
 
 // Helper to a sequence of  WatchData into a list.
diff --git a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h
index 0ae6be3353e64decee8e9101c70772f5b82f8f0a..673a1abccc8979c6eff485318ef00cf8acefece2 100644
--- a/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h
+++ b/src/plugins/debugger/cdb/cdbsymbolgroupcontext_tpl.h
@@ -30,6 +30,8 @@
 #ifndef CDBSYMBOLGROUPCONTEXT_TPL_H
 #define CDBSYMBOLGROUPCONTEXT_TPL_H
 
+#include "watchhandler.h"
+
 #include <QtCore/QDebug>
 
 namespace Debugger {
@@ -37,20 +39,10 @@ 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::getDumpChildSymbols(CIDebugDataSpaces *ds, const QString &prefix,
-                             int dumpedOwner,
-                             OutputIterator it, QString *errorMessage)
+bool CdbSymbolGroupContext::getDumpChildSymbols(const QString &prefix,
+                                                int dumpedOwner,
+                                                OutputIterator it, QString *errorMessage)
 {
     unsigned long start;
     unsigned long parentId;
@@ -58,21 +50,14 @@ bool CdbSymbolGroupContext::getDumpChildSymbols(CIDebugDataSpaces *ds, const QSt
         return false;
     // Skip over expanded children. Internal dumping might expand
     // children, so, re-evaluate size in end condition.
-    for (int s = start; s < m_symbolParameters.size(); ++s) {
-        const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(s);
+    const int count = size();
+    for (int s = start; s < count; ++s) {
+        const DEBUG_SYMBOL_PARAMETERS &p = symbolParameterAt(s);
         if (p.ParentSymbol == parentId && isSymbolDisplayable(p)) {
-            WatchData wd = watchDataAt(s);
-            // Run internal dumper, mark ownership
-            if (ds) {
-                switch (dump(ds, &wd)) {
-                case DumperOk:
-                case DumperError: // Not initialized yet, do not run other dumpers
-                    wd.source = dumpedOwner;
-                    break;
-                case DumperNotHandled:
-                    break;
-                }
-            }
+            WatchData wd;
+            const unsigned rc = watchDataAt(s, &wd);
+            if (rc & InternalDumperMask)
+                wd.source = dumpedOwner;
             *it = wd;
             ++it;
         }
@@ -86,7 +71,7 @@ bool CdbSymbolGroupContext::getDumpChildSymbols(CIDebugDataSpaces *ds, const QSt
 // children but can expand none, which would lead to invalid parent information
 // (expand icon), though (ignore for simplicity).
 template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
-bool insertSymbolRecursion(WatchData wd,
+bool CdbSymbolGroupContext::insertSymbolRecursion(WatchData wd,
                            const CdbSymbolGroupRecursionContext &ctx,
                            OutputIterator it,
                            RecursionPredicate recursionPredicate,
@@ -124,8 +109,7 @@ bool insertSymbolRecursion(WatchData wd,
         return true;
     QList<WatchData> watchList;
     // This implicitly enforces expansion
-    if (!ctx.context->getDumpChildSymbols(ctx.dataspaces,
-                                          wd.iname,
+    if (!ctx.context->getDumpChildSymbols(wd.iname,
                                           ctx.internalDumperOwner,
                                           WatchDataBackInserter(watchList), errorMessage))
         return false;
@@ -145,11 +129,11 @@ bool insertSymbolRecursion(WatchData wd,
 }
 
 template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
-bool CdbSymbolGroupContext::populateModelInitially(const CdbSymbolGroupRecursionContext &ctx,
-                                                   OutputIterator it,
-                                                   RecursionPredicate recursionPredicate,
-                                                   IgnorePredicate ignorePredicate,
-                                                   QString *errorMessage)
+bool CdbSymbolGroupContext::populateModelInitiallyHelper(const CdbSymbolGroupRecursionContext &ctx,
+                                                         OutputIterator it,
+                                                         RecursionPredicate recursionPredicate,
+                                                         IgnorePredicate ignorePredicate,
+                                                         QString *errorMessage)
 {
     if (debugSgRecursion)
         qDebug() << "### CdbSymbolGroupContext::populateModelInitially";
@@ -157,7 +141,7 @@ bool CdbSymbolGroupContext::populateModelInitially(const CdbSymbolGroupRecursion
     // Insert root items
     QList<WatchData> watchList;
     CdbSymbolGroupContext *sg = ctx.context;
-    if (!sg->getDumpChildSymbols(ctx.dataspaces, sg->prefix(),
+    if (!sg->getDumpChildSymbols(sg->prefix(),
                                  ctx.internalDumperOwner,
                                  WatchDataBackInserter(watchList), errorMessage))
         return false;
@@ -169,7 +153,7 @@ bool CdbSymbolGroupContext::populateModelInitially(const CdbSymbolGroupRecursion
 }
 
 template <class OutputIterator, class RecursionPredicate, class IgnorePredicate>
-bool CdbSymbolGroupContext::completeData(const CdbSymbolGroupRecursionContext &ctx,
+bool CdbSymbolGroupContext::completeDataHelper(const CdbSymbolGroupRecursionContext &ctx,
                                          WatchData incompleteLocal,
                                          OutputIterator it,
                                          RecursionPredicate recursionPredicate,
diff --git a/src/plugins/debugger/cdb/stacktracecontext.cpp b/src/plugins/debugger/cdb/stacktracecontext.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f5639010f28626334ff0782f6070608acbc68a5e
--- /dev/null
+++ b/src/plugins/debugger/cdb/stacktracecontext.cpp
@@ -0,0 +1,412 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "stacktracecontext.h"
+#include "symbolgroupcontext.h"
+#include "breakpoint.h"
+#include "coreengine.h"
+
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QTextStream>
+
+enum { debug = 0 };
+
+namespace CdbCore {
+
+StackFrame::StackFrame() :
+    line(0),address(0)
+{
+}
+
+QString StackFrame::toString() const
+{
+    QString rc;
+    QTextStream str(&rc);
+    format(str);
+    return rc;
+}
+
+QDebug operator<<(QDebug d, const StackFrame &f)
+{
+    d.nospace() << f.toString();
+    return d;
+}
+
+void StackFrame::format(QTextStream &str) const
+{
+    // left-pad level
+    if (hasFile())
+        str << QDir::toNativeSeparators(fileName) << ':' << line << " (";
+    if (!module.isEmpty())
+        str << module << '!';
+    str << function;
+    if (hasFile())
+        str << ')';
+    str.setIntegerBase(16);
+    str << " 0x" << address;
+    str.setIntegerBase(10);
+}
+
+// Check for special functions
+StackTraceContext::SpecialFunction StackTraceContext::specialFunction(const QString &module,
+                                                                      const QString &function)
+{
+    if (module == QLatin1String("ntdll")) {
+        if (function == QLatin1String("DbgBreakPoint"))
+            return BreakPointFunction;
+        if (function == QLatin1String("KiFastSystemCallRet"))
+            return KiFastSystemCallRet;
+        if (function.startsWith("ZwWaitFor"))
+            return WaitFunction;
+    }
+    if (module == QLatin1String("kernel32")) {
+        if (function == QLatin1String("MsgWaitForMultipleObjects"))
+            return WaitFunction;
+        if (function.startsWith(QLatin1String("WaitFor")))
+            return WaitFunction;
+    }
+    return None;
+}
+
+StackTraceContext::StackTraceContext(const ComInterfaces *cif) :
+        m_cif(cif),
+        m_instructionOffset(0)
+{
+}
+
+StackTraceContext *StackTraceContext::create(const ComInterfaces *cif,
+                                             unsigned long maxFramesIn,
+                                             QString *errorMessage)
+{    
+    StackTraceContext *ctx = new StackTraceContext(cif);
+    if (!ctx->init(maxFramesIn, errorMessage)) {
+        delete ctx;
+        return 0;
+
+    }
+    return ctx;
+}
+
+StackTraceContext::~StackTraceContext()
+{
+    qDeleteAll(m_frameContexts);
+}
+
+// Convert the DEBUG_STACK_FRAMEs to our StackFrame structure
+StackFrame StackTraceContext::frameFromFRAME(const CdbCore::ComInterfaces &cif,
+                                             const DEBUG_STACK_FRAME &s)
+{
+    static WCHAR wszBuf[MAX_PATH];
+    StackFrame frame;
+    frame.address = s.InstructionOffset;
+    cif.debugSymbols->GetNameByOffsetWide(frame.address, wszBuf, MAX_PATH, 0, 0);
+    // Determine function and module, if available ("Qt4Core!foo").
+    const QString moduleFunction = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
+    const int moduleSepPos = moduleFunction.indexOf(QLatin1Char('!'));
+    if (moduleSepPos == -1) {
+        frame.function = moduleFunction;
+    } else {
+        frame.module = moduleFunction.left(moduleSepPos);
+        frame.function = moduleFunction.mid(moduleSepPos + 1);
+    }
+    ULONG64 ul64Displacement;
+    const HRESULT hr = cif.debugSymbols->GetLineByOffsetWide(frame.address, &frame.line, wszBuf, MAX_PATH, 0, &ul64Displacement);
+    if (SUCCEEDED(hr)) {
+        const QString rawName = QString::fromUtf16(reinterpret_cast<const ushort *>(wszBuf));
+        if (!rawName.isEmpty())
+            frame.fileName = BreakPoint::normalizeFileName(rawName);
+    }
+    return frame;
+}
+
+bool StackTraceContext::init(unsigned long maxFramesIn, QString *errorMessage)
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO << maxFramesIn;
+
+    // fill the DEBUG_STACK_FRAME array
+    ULONG frameCount;
+    const unsigned long effectiveMaxFrames = qMin(maxFramesIn, unsigned long(StackTraceContext::maxFrames));
+    const HRESULT hr = m_cif->debugControl->GetStackTrace(0, 0, 0, m_cdbFrames,
+                                                        effectiveMaxFrames,
+                                                        &frameCount);
+    if (FAILED(hr)) {
+         *errorMessage = CdbCore::msgComFailed("GetStackTrace", hr);
+        return false;
+    }
+
+    // Adapt group cache.
+    m_frameContexts.resize(frameCount);
+    qFill(m_frameContexts, static_cast<SymbolGroupContext*>(0));    
+    // Convert the DEBUG_STACK_FRAMEs to our StackFrame structure and populate the frames
+    for (ULONG i=0; i < frameCount; ++i)
+        m_frames.push_back(frameFromFRAME(*m_cif, m_cdbFrames[i]));
+    m_instructionOffset = m_frames.empty() ? ULONG64(0) : m_frames.front().address;
+    return true;
+}
+
+int StackTraceContext::indexOf(const QString &function,
+                               const QString &module /* = QString() */) const
+{    
+    const bool noModuleMatch = module.isEmpty();
+    const int count = m_frames.size();
+    for (int i = 0; i < count; i++) {
+        if (m_frames.at(i).function == function
+            && (noModuleMatch || module == m_frames.at(i).module))
+            return i;
+    }
+    return -1;
+}
+
+QString StackTraceContext::msgFrameContextFailed(int index, const StackFrame &f, const QString &why)
+{
+    return QString::fromLatin1("Unable to create stack frame context #%1, %2!%3:%4 (%5): %6").
+            arg(index).arg(f.module).arg(f.function).arg(f.line).arg(f.fileName, why);
+}
+
+SymbolGroupContext *StackTraceContext::createSymbolGroup(const ComInterfaces &cif,
+                                                         int /* index */,
+                                                         const QString &prefix,
+                                                         CIDebugSymbolGroup *comSymbolGroup,
+                                                         QString *errorMessage)
+{
+    return SymbolGroupContext::create(prefix, comSymbolGroup, cif.debugDataSpaces,
+                                      QStringList(), errorMessage);
+}
+
+SymbolGroupContext *StackTraceContext::symbolGroupContextAt(int index, QString *errorMessage)
+{
+    // Create a frame on demand
+    if (debug)
+        qDebug() << Q_FUNC_INFO << index;
+
+    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_frameContexts.size());
+        return 0;
+    }
+    if (m_frameContexts.at(index))
+        return m_frameContexts.at(index);
+    CIDebugSymbolGroup *comSymbolGroup  = createCOM_SymbolGroup(index, errorMessage);
+    if (!comSymbolGroup) {
+        *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage);
+        return 0;
+    }
+    SymbolGroupContext *sc = createSymbolGroup(*m_cif, index, QLatin1String("local"),
+                                               comSymbolGroup, errorMessage);
+    if (!sc) {
+        *errorMessage = msgFrameContextFailed(index, m_frames.at(index), *errorMessage);
+        return 0;
+    }
+    m_frameContexts[index] = sc;
+    return sc;
+}
+
+CIDebugSymbolGroup *StackTraceContext::createCOM_SymbolGroup(int index, QString *errorMessage)
+{
+    CIDebugSymbolGroup *sg = 0;
+    HRESULT hr = m_cif->debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, NULL, &sg);
+    if (FAILED(hr)) {
+        *errorMessage = CdbCore::msgComFailed("GetScopeSymbolGroup", hr);
+        return 0;
+    }
+
+    hr = m_cif->debugSymbols->SetScope(0, m_cdbFrames + index, NULL, 0);
+    if (FAILED(hr)) {
+        *errorMessage = CdbCore::msgComFailed("SetScope", hr);
+        sg->Release();
+        return 0;
+    }
+    // refresh with current frame
+    hr = m_cif->debugSymbols->GetScopeSymbolGroup2(DEBUG_SCOPE_GROUP_LOCALS, sg, &sg);
+    if (FAILED(hr)) {
+        *errorMessage = CdbCore::msgComFailed("GetScopeSymbolGroup", hr);
+        sg->Release();
+        return 0;
+    }
+    return sg;
+}
+
+QString StackTraceContext::toString() const
+{
+    QString rc;
+    QTextStream str(&rc);
+    format(str);
+    return rc;
+}
+
+void StackTraceContext::format(QTextStream &str) const
+{
+    const int count = m_frames.count();
+    const int defaultFieldWidth = str.fieldWidth();
+    const QTextStream::FieldAlignment defaultAlignment = str.fieldAlignment();
+    for (int f = 0; f < count; f++) {
+        // left-pad level
+        str << qSetFieldWidth(6) << left << f;
+        str.setFieldWidth(defaultFieldWidth);
+        str.setFieldAlignment(defaultAlignment);
+        m_frames.at(f).format(str);
+        str << '\n';
+    }
+}
+
+// Thread state helper
+static inline QString msgGetThreadStateFailed(unsigned long threadId, const QString &why)
+{
+    return QString::fromLatin1("Unable to determine the state of thread %1: %2").arg(threadId).arg(why);
+}
+
+// Determine information about thread. This changes the
+// current thread to thread->id.
+bool StackTraceContext::getStoppedThreadState(const CdbCore::ComInterfaces &cif,
+                                              unsigned long id,
+                                              StackFrame *topFrame,
+                                              QString *errorMessage)
+{
+    enum { MaxFrames = 2 };
+    ULONG currentThread;
+    HRESULT hr = cif.debugSystemObjects->GetCurrentThreadId(&currentThread);
+    if (FAILED(hr)) {
+        *errorMessage = msgGetThreadStateFailed(id, CdbCore::msgComFailed("GetCurrentThreadId", hr));
+        return false;
+    }
+    if (currentThread != id) {
+        hr = cif.debugSystemObjects->SetCurrentThreadId(id);
+        if (FAILED(hr)) {
+            *errorMessage = msgGetThreadStateFailed(id, CdbCore::msgComFailed("SetCurrentThreadId", hr));
+            return false;
+        }
+    }
+    ULONG frameCount;
+    // Ignore the top frame if it is "ntdll!KiFastSystemCallRet", which is
+    // not interesting for display.
+    DEBUG_STACK_FRAME frames[MaxFrames];
+    hr = cif.debugControl->GetStackTrace(0, 0, 0, frames, MaxFrames, &frameCount);
+    if (FAILED(hr)) {
+        *errorMessage = msgGetThreadStateFailed(id, CdbCore::msgComFailed("GetStackTrace", hr));
+        return false;
+    }
+    // Ignore the top frame if it is "ntdll!KiFastSystemCallRet", which is
+    // not interesting for display.
+    *topFrame = frameFromFRAME(cif, frames[0]);
+    if (frameCount > 1
+        && StackTraceContext::specialFunction(topFrame->module, topFrame->function) == KiFastSystemCallRet)
+            *topFrame = frameFromFRAME(cif, frames[1]);
+    return true;
+}
+
+static inline QString msgGetThreadsFailed(const QString &why)
+{
+    return QString::fromLatin1("Unable to determine the thread information: %1").arg(why);
+}
+
+bool StackTraceContext::getThreadIds(const CdbCore::ComInterfaces &cif,
+                                     QVector<ULONG> *threadIds,
+                                     ULONG *currentThreadId,
+                                     QString *errorMessage)
+{
+    threadIds->clear();
+    ULONG threadCount;
+    *currentThreadId = 0;
+    HRESULT hr= cif.debugSystemObjects->GetNumberThreads(&threadCount);
+    if (FAILED(hr)) {
+        *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetNumberThreads", hr));
+        return false;
+    }
+    // Get ids and index of current
+    if (!threadCount)
+        return true;
+    hr = cif.debugSystemObjects->GetCurrentThreadId(currentThreadId);
+    if (FAILED(hr)) {
+        *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetCurrentThreadId", hr));
+        return false;
+    }
+    threadIds->resize(threadCount);
+    hr = cif.debugSystemObjects->GetThreadIdsByIndex(0, threadCount, &(*threadIds->begin()), 0);
+    if (FAILED(hr)) {
+        *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("GetThreadIdsByIndex", hr));
+        return false;
+    }
+    return true;
+}
+
+bool StackTraceContext::getThreads(const CdbCore::ComInterfaces &cif,
+                                   ThreadIdFrameMap *threads,
+                                   ULONG *currentThreadId,
+                                   QString *errorMessage)
+{
+    threads->clear();
+    QVector<ULONG> threadIds;
+    if (!getThreadIds(cif, &threadIds, currentThreadId, errorMessage))
+        return false;
+    if (threadIds.isEmpty())
+        return true;
+
+    const int threadCount = threadIds.size();
+    for (int i = 0; i < threadCount; i++) {
+        const ULONG id = threadIds.at(i);
+        StackFrame frame;
+        if (!getStoppedThreadState(cif, id, &frame, errorMessage)) {
+            qWarning("%s\n", qPrintable(*errorMessage));
+            errorMessage->clear();
+        }
+        threads->insert(id, frame);
+    }
+    // Restore thread id
+    if (threadIds.back() != *currentThreadId) {
+        const HRESULT hr = cif.debugSystemObjects->SetCurrentThreadId(*currentThreadId);
+        if (FAILED(hr)) {
+            *errorMessage= msgGetThreadsFailed(CdbCore::msgComFailed("SetCurrentThreadId", hr));
+            return false;
+        }
+    }
+    return true;
+}
+
+QString StackTraceContext::formatThreads(const ThreadIdFrameMap &threads)
+{
+    QString rc;
+    QTextStream str(&rc);
+    const ThreadIdFrameMap::const_iterator cend = threads.constEnd();
+    for (ThreadIdFrameMap::const_iterator it = threads.constBegin(); it != cend; ++it) {
+        str << '#' << it.key() << ' ';
+        it.value().format(str);
+        str << '\n';
+    }
+    return rc;
+}
+
+QDebug operator<<(QDebug d, const StackTraceContext &t)
+{
+    d.nospace() << t.toString();
+    return d;
+}
+
+}
diff --git a/src/plugins/debugger/cdb/stacktracecontext.h b/src/plugins/debugger/cdb/stacktracecontext.h
new file mode 100644
index 0000000000000000000000000000000000000000..02277b52270327ac5b9d5eee5b107f487bed2ea6
--- /dev/null
+++ b/src/plugins/debugger/cdb/stacktracecontext.h
@@ -0,0 +1,162 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CORESTACKTRACECONTEXT_H
+#define CORESTACKTRACECONTEXT_H
+
+#include "cdbcom.h"
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtCore/QSharedPointer>
+#include <QtCore/QMap>
+
+QT_BEGIN_NAMESPACE
+class QTextStream;
+class QDebug;
+QT_END_NAMESPACE
+
+namespace CdbCore {
+
+struct ComInterfaces;
+class SymbolGroupContext;
+
+
+struct StackFrame {
+    StackFrame();
+
+    bool hasFile() const { return !fileName.isEmpty(); }
+    void format(QTextStream &) const;
+
+    QString toString() const;
+
+    QString module;
+    QString function;
+    QString fileName;
+    ULONG line;
+    ULONG64 address;
+};
+
+QDebug operator<<(QDebug d, const StackFrame &);
+
+/* Context representing a break point stack consisting of several frames.
+ * Maintains an on-demand constructed list of SymbolGroupContext
+ * containining the local variables of the stack. */
+
+class StackTraceContext
+{
+    Q_DISABLE_COPY(StackTraceContext)
+
+protected:
+    explicit StackTraceContext(const ComInterfaces *cif);
+    bool init(unsigned long maxFramesIn, QString *errorMessage);
+
+public:
+    // Utilities to check for special functions
+    enum SpecialFunction {
+        BreakPointFunction,
+        WaitFunction,
+        KiFastSystemCallRet,
+        None
+    };
+    static SpecialFunction specialFunction(const QString &module, const QString &function);
+
+    // A map of thread id, stack frame
+    typedef QMap<unsigned long, StackFrame> ThreadIdFrameMap;
+
+    enum { maxFrames = 100 };
+
+    ~StackTraceContext();
+    static StackTraceContext *create(const ComInterfaces *cif,
+                                     unsigned long maxFramesIn,
+                                     QString *errorMessage);
+
+    // Search for function. Empty module means "don't match on module"
+    int indexOf(const QString &function, const QString &module = QString()) const;
+
+    // Top-Level instruction offset for disassembler
+    ULONG64 instructionOffset() const { return m_instructionOffset; }
+    int frameCount() const { return m_frames.size(); }
+
+    SymbolGroupContext *symbolGroupContextAt(int index, QString *errorMessage);
+    const StackFrame stackFrameAt(int index) const { return m_frames.at(index); }
+
+    // Format for logging
+    void format(QTextStream &str) const;
+    QString toString() const;
+
+    // Thread helpers: Retrieve a list of thread ids. Also works when running.
+    static inline bool getThreadIds(const CdbCore::ComInterfaces &cif,
+                                    QVector<ULONG> *threadIds,
+                                    ULONG *currentThreadId,
+                                    QString *errorMessage);
+
+    // Retrieve detailed information about a threads in stopped state.
+    // Potentially changes current thread id.
+    static inline bool getStoppedThreadState(const CdbCore::ComInterfaces &cif,
+                                             unsigned long id,
+                                             StackFrame *topFrame,
+                                             QString *errorMessage);
+
+    // Retrieve detailed information about all threads, works in stopped state.
+    static bool getThreads(const CdbCore::ComInterfaces &cif,
+                           ThreadIdFrameMap *threads,
+                           ULONG *currentThreadId,
+                           QString *errorMessage);
+
+    static QString formatThreads(const ThreadIdFrameMap &threads);
+
+protected:
+    virtual SymbolGroupContext *createSymbolGroup(const ComInterfaces &cif,
+                                                  int index,
+                                                  const QString &prefix,
+                                                  CIDebugSymbolGroup *comSymbolGroup,
+                                                  QString *errorMessage);
+
+    static QString msgFrameContextFailed(int index, const StackFrame &f, const QString &why);
+
+private:    
+    CIDebugSymbolGroup *createCOM_SymbolGroup(int index, QString *errorMessage);
+    inline static StackFrame frameFromFRAME(const CdbCore::ComInterfaces &cif,
+                                            const DEBUG_STACK_FRAME &s);
+
+    // const QSharedPointer<CdbDumperHelper> m_dumper;
+    const ComInterfaces *m_cif;
+
+    DEBUG_STACK_FRAME m_cdbFrames[maxFrames];
+    QVector <SymbolGroupContext*> m_frameContexts;
+    QVector<StackFrame> m_frames;
+    ULONG64 m_instructionOffset;
+};
+
+QDebug operator<<(QDebug d, const StackTraceContext &);
+
+} // namespace Internal
+
+#endif // CORESTACKTRACECONTEXT_H
diff --git a/src/plugins/debugger/cdb/symbolgroupcontext.cpp b/src/plugins/debugger/cdb/symbolgroupcontext.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a36d142b379ee48df62718bf309136ab37b80b24
--- /dev/null
+++ b/src/plugins/debugger/cdb/symbolgroupcontext.cpp
@@ -0,0 +1,740 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "symbolgroupcontext.h"
+#include "coreengine.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QRegExp>
+#include <QtCore/QString>
+#include <QtCore/QDebug>
+
+enum { debug = 0 };
+enum { debugInternalDumpers = 0 };
+
+// name separator for shadowed variables
+static const char iNameShadowDelimiter = '#';
+
+static inline QString msgSymbolNotFound(const QString &s)
+{
+    return QString::fromLatin1("The symbol '%1' could not be found.").arg(s);
+}
+
+static inline QString msgOutOfScope()
+{
+    return QCoreApplication::translate("SymbolGroup", "Out of scope");
+}
+
+static inline bool isTopLevelSymbol(const DEBUG_SYMBOL_PARAMETERS &p)
+{
+    return p.ParentSymbol == DEBUG_ANY_ID;
+}
+
+static inline void debugSymbolFlags(unsigned long f, QTextStream &str)
+{
+    if (f & DEBUG_SYMBOL_EXPANDED)
+        str << "DEBUG_SYMBOL_EXPANDED";
+    if (f & DEBUG_SYMBOL_READ_ONLY)
+        str << "|DEBUG_SYMBOL_READ_ONLY";
+    if (f & DEBUG_SYMBOL_IS_ARRAY)
+        str << "|DEBUG_SYMBOL_IS_ARRAY";
+    if (f & DEBUG_SYMBOL_IS_FLOAT)
+        str << "|DEBUG_SYMBOL_IS_FLOAT";
+    if (f & DEBUG_SYMBOL_IS_ARGUMENT)
+        str << "|DEBUG_SYMBOL_IS_ARGUMENT";
+    if (f & DEBUG_SYMBOL_IS_LOCAL)
+        str << "|DEBUG_SYMBOL_IS_LOCAL";
+}
+
+QTextStream &operator<<(QTextStream &str, const DEBUG_SYMBOL_PARAMETERS &p)
+{
+    str << " Type=" << p.TypeId << " parent=";
+    if (isTopLevelSymbol(p)) {
+        str << "<ROOT>";
+    } else {
+        str << p.ParentSymbol;
+    }
+    str << " Subs=" << p.SubElements << " flags=" << p.Flags << '/';
+    debugSymbolFlags(p.Flags, str);
+    return str;
+}
+
+static inline ULONG64 symbolOffset(CIDebugSymbolGroup *sg, unsigned long index)
+{
+    ULONG64 rc = 0;
+    if (FAILED(sg->GetSymbolOffset(index, &rc)))
+        rc = 0;
+    return rc;
+}
+
+// A helper function to extract a string value from a member function of
+// IDebugSymbolGroup2 taking the symbol index and a character buffer.
+// Pass in the the member function as '&IDebugSymbolGroup2::GetSymbolNameWide'
+
+typedef HRESULT  (__stdcall IDebugSymbolGroup2::*WideStringRetrievalFunction)(ULONG, PWSTR, ULONG, PULONG);
+
+static inline QString getSymbolString(IDebugSymbolGroup2 *sg,
+                                      WideStringRetrievalFunction wsf,
+                                      unsigned long index)
+{
+    // Template type names can get quite long....
+    enum { BufSize = 1024 };
+    static WCHAR nameBuffer[BufSize + 1];
+    // Name
+    ULONG nameLength;
+    const HRESULT hr = (sg->*wsf)(index, nameBuffer, BufSize, &nameLength);
+    if (SUCCEEDED(hr)) {
+        nameBuffer[nameLength] = 0;
+        return QString::fromUtf16(reinterpret_cast<const ushort *>(nameBuffer));
+    }
+    return QString();
+}
+
+namespace CdbCore {
+
+static inline SymbolGroupContext::SymbolState getSymbolState(const DEBUG_SYMBOL_PARAMETERS &p)
+{
+    if (p.SubElements == 0u)
+        return SymbolGroupContext::LeafSymbol;
+    return (p.Flags & DEBUG_SYMBOL_EXPANDED) ?
+               SymbolGroupContext::ExpandedSymbol :
+               SymbolGroupContext::CollapsedSymbol;
+}
+
+SymbolGroupContext::SymbolGroupContext(const QString &prefix,
+                                       CIDebugSymbolGroup *symbolGroup,
+                                       CIDebugDataSpaces *dataSpaces,
+                                       const QStringList &uninitializedVariables) :
+    m_prefix(prefix),
+    m_nameDelimiter(QLatin1Char('.')),
+    m_uninitializedVariables(uninitializedVariables.toSet()),
+    m_symbolGroup(symbolGroup),
+    m_dataSpaces(dataSpaces),
+    m_unnamedSymbolNumber(1),
+    m_shadowedNameFormat(QLatin1String("%1#%2"))
+{
+}
+
+SymbolGroupContext::~SymbolGroupContext()
+{
+    m_symbolGroup->Release();
+}
+
+SymbolGroupContext *SymbolGroupContext::create(const QString &prefix,
+                                                     CIDebugSymbolGroup *symbolGroup,
+                                                     CIDebugDataSpaces *dataSpaces,
+                                                     const QStringList &uninitializedVariables,
+                                                     QString *errorMessage)
+{
+    SymbolGroupContext *rc = new SymbolGroupContext(prefix, symbolGroup, dataSpaces, uninitializedVariables);
+    if (!rc->init(errorMessage)) {
+        delete rc;
+        return 0;
+    }
+    return rc;
+}
+
+bool SymbolGroupContext::init(QString *errorMessage)
+{
+    // retrieve the root symbols
+    ULONG count;
+    HRESULT hr = m_symbolGroup->GetNumberSymbols(&count);
+    if (FAILED(hr)) {
+        *errorMessage = CdbCore::msgComFailed("GetNumberSymbols", hr);
+        return false;
+    }
+
+    if (count) {
+        m_symbolParameters.reserve(3u * count);
+        m_symbolParameters.resize(count);
+
+        hr = m_symbolGroup->GetSymbolParameters(0, count, symbolParameters());
+        if (FAILED(hr)) {
+            *errorMessage = QString::fromLatin1("In %1: %2 (%3 symbols)").arg(QLatin1String(Q_FUNC_INFO),
+                                                                              CdbCore::msgComFailed("GetSymbolParameters", hr)).arg(count);
+            return false;
+        }
+        populateINameIndexMap(m_prefix, DEBUG_ANY_ID, count);
+    }
+    if (debug)
+        qDebug() << Q_FUNC_INFO << '\n'<< debugToString();
+    return true;
+}
+
+QString SymbolGroupContext::shadowedNameFormat() const
+{
+    return m_shadowedNameFormat;
+}
+
+void SymbolGroupContext::setShadowedNameFormat(const QString &f)
+{
+    m_shadowedNameFormat = f;
+}
+
+/* Make the entries for iname->index mapping. We might encounter
+ * already expanded subitems when doing it for top-level ('this'-pointers),
+ * recurse in that case, (skip over expanded children).
+ * Loop backwards to detect shadowed variables in the order the
+/* debugger expects them:
+\code
+int x;             // Occurrence (1), should be reported as "x <shadowed 1>"
+if (true) {
+   int x = 5; (2)  // Occurrence (2), should be reported as "x"
+}
+\endcode
+ * The order in the symbol group is (1),(2). Give them an iname of
+ * <root>#<shadowed-nr>, which will be split apart for display. */
+
+void SymbolGroupContext::populateINameIndexMap(const QString &prefix, unsigned long parentId,
+                                                  unsigned long end)
+{
+    const QString symbolPrefix = prefix + m_nameDelimiter;
+    if (debug)
+        qDebug() << Q_FUNC_INFO << '\n'<< symbolPrefix << parentId << end;
+    for (unsigned long i = end - 1; ; i--) {
+        const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i);
+        if (parentId == p.ParentSymbol) {
+            // "__formal" occurs when someone writes "void foo(int /* x */)..."
+            static const QString unnamedFormalParameter = QLatin1String("__formal");
+            QString symbolName = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i);
+            if (symbolName == unnamedFormalParameter) {
+                symbolName = QLatin1String("<unnamed");
+                symbolName += QString::number(m_unnamedSymbolNumber++);
+                symbolName += QLatin1Char('>');
+            }
+            // Find a unique name in case the variable is shadowed by
+            // an existing one
+            const QString namePrefix = symbolPrefix + symbolName;
+            QString name = namePrefix;
+            for (int n = 1; m_inameIndexMap.contains(name); n++) {
+                name.truncate(namePrefix.size());
+                name += QLatin1Char(iNameShadowDelimiter);
+                name += QString::number(n);
+            }
+            m_inameIndexMap.insert(name, i);
+            if (getSymbolState(p) == ExpandedSymbol)
+                populateINameIndexMap(name, i, i + 1 + p.SubElements);
+        }
+        if (i == 0 || i == parentId)
+            break;
+    }
+}
+
+QString SymbolGroupContext::toString()
+{
+    QString rc;
+    QTextStream str(&rc);
+    const unsigned long count = m_symbolParameters.size();
+    QString iname;
+    QString name;
+    ULONG64 addr;
+    ULONG typeId;
+    QString typeName;
+    QString value;
+
+
+    for (unsigned long i = 0; i < count; i++) {
+        const unsigned rc = dumpValue(i, &iname, &name, &addr,
+                                      &typeId, &typeName, &value);
+        str << iname << ' ' << name << ' ' << typeName << " (" << typeId
+                << ") '" << value;
+        str.setIntegerBase(16);
+        str << "' 0x" << addr << " flags: 0x"  <<rc << '\n';
+        str.setIntegerBase(10);
+    } // for
+
+    return rc;
+}
+
+QString SymbolGroupContext::debugToString(bool verbose) const
+{
+    QString rc;
+    QTextStream str(&rc);
+    const int count = m_symbolParameters.size();
+    for (int i = 0; i < count; i++) {
+        str << i << ' ';
+        const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(i);
+        if (!isTopLevelSymbol(p))
+            str << "    ";
+        str << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolNameWide, i);
+        if (p.Flags & DEBUG_SYMBOL_IS_LOCAL)
+            str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, i) << '\'';
+        str << " Address: " << symbolOffset(m_symbolGroup, i);
+        if (verbose)
+            str << " '" << getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, i) << '\'';
+        str << p << '\n';
+    }
+    if (verbose) {
+        str << "NameIndexMap\n";
+        NameIndexMap::const_iterator ncend = m_inameIndexMap.constEnd();
+        for (NameIndexMap::const_iterator it = m_inameIndexMap.constBegin() ; it != ncend; ++it)
+            str << it.key() << ' ' << it.value() << '\n';
+    }
+    return rc;
+}
+
+SymbolGroupContext::SymbolState SymbolGroupContext::symbolState(unsigned long index) const
+{
+    return getSymbolState(m_symbolParameters.at(index));
+}
+
+SymbolGroupContext::SymbolState SymbolGroupContext::symbolState(const QString &prefix) const
+{
+    if (prefix == m_prefix) // root
+        return ExpandedSymbol;
+    unsigned long index;
+    if (!lookupPrefix(prefix, &index)) {
+        qWarning("WARNING %s: %s\n", Q_FUNC_INFO, qPrintable(msgSymbolNotFound(prefix)));
+        return LeafSymbol;
+    }
+    return symbolState(index);
+}
+
+// Find index of a prefix
+bool SymbolGroupContext::lookupPrefix(const QString &prefix, unsigned long *index) const
+{
+    *index = 0;
+    const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(prefix);
+    if (it == m_inameIndexMap.constEnd())
+        return false;
+    *index = it.value();
+    return true;
+}
+
+/* Retrieve children and get the position. */
+bool SymbolGroupContext::getChildSymbolsPosition(const QString &prefix,
+                                                    unsigned long *start,
+                                                    unsigned long *parentId,
+                                                    QString *errorMessage)
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO << '\n'<< prefix;
+
+    *start = *parentId = 0;
+    // Root item?
+    if (prefix == m_prefix) {
+        *start = 0;
+        *parentId = DEBUG_ANY_ID;
+        if (debug)
+            qDebug() << '<' << prefix << "at" << *start;
+        return true;
+    }
+    // Get parent index, make sure it is expanded
+    NameIndexMap::const_iterator nit = m_inameIndexMap.constFind(prefix);
+    if (nit == m_inameIndexMap.constEnd()) {
+        *errorMessage = QString::fromLatin1("'%1' not found.").arg(prefix);
+        return false;
+    }
+    *parentId = nit.value();
+    *start = nit.value() + 1;
+    if (!expandSymbol(prefix, *parentId, errorMessage))
+        return false;
+    if (debug)
+        qDebug() << '<' << prefix << "at" << *start;
+    return true;
+}
+
+static inline QString msgExpandFailed(const QString &prefix, unsigned long index, const QString &why)
+{
+    return QString::fromLatin1("Unable to expand '%1' %2: %3").arg(prefix).arg(index).arg(why);
+}
+
+// Expand a symbol using the symbol group interface.
+bool SymbolGroupContext::expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage)
+{
+    if (debug)
+        qDebug() << '>' << Q_FUNC_INFO << '\n' << prefix << index;
+
+    switch (symbolState(index)) {
+    case LeafSymbol:
+        *errorMessage = QString::fromLatin1("Attempt to expand leaf node '%1' %2!").arg(prefix).arg(index);
+        return false;
+    case ExpandedSymbol:
+        return true;
+    case CollapsedSymbol:
+        break;
+    }
+
+    HRESULT hr = m_symbolGroup->ExpandSymbol(index, TRUE);
+    if (FAILED(hr)) {
+        *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("ExpandSymbol", hr));
+        return false;
+    }
+    // Hopefully, this will never fail, else data structure will be foobar.
+    const ULONG oldSize = m_symbolParameters.size();
+    ULONG newSize;
+    hr = m_symbolGroup->GetNumberSymbols(&newSize);
+    if (FAILED(hr)) {
+        *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("GetNumberSymbols", hr));
+        return false;
+    }
+
+    // Retrieve the new parameter structs which will be inserted
+    // after the parents, offsetting consecutive indexes.
+    m_symbolParameters.resize(newSize);
+
+    hr = m_symbolGroup->GetSymbolParameters(0, newSize, symbolParameters());
+    if (FAILED(hr)) {
+        *errorMessage = msgExpandFailed(prefix, index, CdbCore::msgComFailed("GetSymbolParameters", hr));
+        return false;
+    }
+    // The new symbols are inserted after the parent symbol.
+    // We need to correct the following values in the name->index map
+    const unsigned long newSymbolCount = newSize - oldSize;
+    const NameIndexMap::iterator nend = m_inameIndexMap.end();
+    for (NameIndexMap::iterator it = m_inameIndexMap.begin(); it != nend; ++it)
+        if (it.value() > index)
+            it.value() += newSymbolCount;
+    // insert the new symbols
+    populateINameIndexMap(prefix, index, index + 1 + newSymbolCount);
+    if (debug > 1)
+        qDebug() << '<' << Q_FUNC_INFO << '\n' << prefix << index << '\n' << toString();
+    return true;
+}
+
+void SymbolGroupContext::clear()
+{
+    m_symbolParameters.clear();
+    m_inameIndexMap.clear();
+}
+
+QString SymbolGroupContext::symbolINameAt(unsigned long index) const
+{
+    return m_inameIndexMap.key(index);
+}
+
+// Return hexadecimal pointer value from a CDB pointer value
+// which look like "0x000032a" or "0x00000000`0250124a" or
+// "0x1`0250124a" on 64-bit systems.
+bool SymbolGroupContext::getUnsignedHexValue(QString stringValue, quint64 *value)
+{
+    *value = 0;
+    if (!stringValue.startsWith(QLatin1String("0x")))
+        return false;
+    stringValue.remove(0, 2);
+    // Remove 64bit separator
+    if (stringValue.size() > 9) {
+        const int sepPos = stringValue.size() - 9;
+        if (stringValue.at(sepPos) == QLatin1Char('`'))
+            stringValue.remove(sepPos, 1);
+    }
+    bool ok;
+    *value = stringValue.toULongLong(&ok, 16);
+    return ok;
+}
+
+// check for "0x000", "0x000 class X" or its 64-bit equivalents.
+bool SymbolGroupContext::isNullPointer(const QString &type , QString valueS)
+{
+    if (!type.endsWith(QLatin1String(" *")))
+        return false;
+    const int blankPos = valueS.indexOf(QLatin1Char(' '));
+    if (blankPos != -1)
+        valueS.truncate(blankPos);
+    quint64 value;
+    return SymbolGroupContext::getUnsignedHexValue(valueS, &value) && value == 0u;
+}
+
+// Fix a symbol group value. It is set to the class type for
+// expandable classes (type="class std::foo<..>[*]",
+// value="std::foo<...>[*]". This is not desired
+// as it widens the value column for complex std::template types.
+// Remove the inner template type.
+
+QString SymbolGroupContext::removeInnerTemplateType(QString value)
+{
+    const int firstBracketPos = value.indexOf(QLatin1Char('<'));
+    const int lastBracketPos = firstBracketPos != -1 ? value.lastIndexOf(QLatin1Char('>')) : -1;
+    if (lastBracketPos != -1)
+        value.replace(firstBracketPos + 1, lastBracketPos - firstBracketPos -1, QLatin1String("..."));
+    return value;
+}
+
+QString SymbolGroupContext::formatShadowedName(const QString &name, int n) const
+{
+    return n > 0 ? m_shadowedNameFormat.arg(name).arg(n) : name;
+}
+
+unsigned SymbolGroupContext::dumpValueRaw(unsigned long index,
+                                    QString *inameIn,
+                                    QString *nameIn,
+                                    ULONG64 *addrIn,
+                                    ULONG *typeIdIn,
+                                    QString *typeNameIn,
+                                    QString *valueIn) const
+{
+    unsigned rc = 0;
+    const QString iname = symbolINameAt(index);
+    *inameIn = iname;
+    *addrIn = symbolOffset(m_symbolGroup, index);
+    // Determine name from iname and format shadowed variables correctly
+    // as "<shadowed X>, see populateINameIndexMap() (from "name#1").
+    const int lastDelimiterPos = iname.lastIndexOf(m_nameDelimiter);
+    QString name = lastDelimiterPos == -1 ? iname : iname.mid(lastDelimiterPos + 1);
+    int shadowedNumber = 0;
+    const int shadowedPos = name.lastIndexOf(QLatin1Char(iNameShadowDelimiter));
+    if (shadowedPos != -1) {
+        shadowedNumber = name.mid(shadowedPos + 1).toInt();
+        name.truncate(shadowedPos);
+    }
+    // For class hierarchies, we get sometimes complicated std::template types here.
+    // (std::map extends std::tree<>... Remove them for display only.    
+    *nameIn = formatShadowedName(removeInnerTemplateType(name), shadowedNumber);
+    *typeNameIn = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolTypeNameWide, index);
+    // Check for uninitialized variables at level 0 only.
+    const DEBUG_SYMBOL_PARAMETERS &p = m_symbolParameters.at(index);
+    *typeIdIn = p.TypeId;
+    if (p.ParentSymbol == DEBUG_ANY_ID) {
+        const QString fullShadowedName = formatShadowedName(name, shadowedNumber);
+        if (m_uninitializedVariables.contains(fullShadowedName)) {
+            rc |= OutOfScope;
+            valueIn->clear();
+            return rc;
+        }
+    }
+    // In scope: Figure out value
+    *valueIn = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
+    // Figure out children. The SubElement is only a guess unless the symbol,
+    // is expanded, so, we leave this as a guess for later updates.
+    // If the symbol has children (expanded or not), we leave the 'Children' flag
+    // in 'needed' state. Suppress 0-pointers right ("0x000 class X")
+    // here as they only lead to children with memory access errors.
+    if (p.SubElements && !isNullPointer(*typeNameIn, *valueIn))
+        rc |= HasChildren;
+    return rc;
+}
+
+/* The special type dumpers have an integer return code meaning:
+ *  0:  ok
+ *  1:  Dereferencing or retrieving memory failed, this is out of scope,
+ *      do not try to query further.
+ * > 1: A structural error was encountered, that is, the implementation
+ *      of the class changed (Qt or say, a different STL implementation).
+ *      Visibly warn about it.
+ * To add further types, have a look at the toString() output of the
+ * symbol group. */
+
+static QString msgStructuralError(const QString &name, const QString &type, int code)
+{
+    return QString::fromLatin1("Warning: Internal dumper for '%1' (%2) failed with %3.").arg(name, type).arg(code);
+}
+
+static inline bool isStdStringOrPointer(const QString &type)
+{
+#define STD_WSTRING "std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >"
+#define STD_STRING "std::basic_string<char,std::char_traits<char>,std::allocator<char> >"
+    return type.endsWith(QLatin1String(STD_STRING))
+            || type.endsWith(QLatin1String(STD_STRING" *"))
+            || type.endsWith(QLatin1String(STD_WSTRING))
+            || type.endsWith(QLatin1String(STD_WSTRING" *"));
+#undef STD_WSTRING
+#undef STD_STRING
+}
+
+unsigned SymbolGroupContext::dumpValue(unsigned long index,
+                     QString *inameIn,
+                     QString *nameIn,
+                     ULONG64 *addrIn,
+                     ULONG *typeIdIn,
+                     QString *typeNameIn,
+                     QString *valueIn)
+{    
+    unsigned rc = dumpValueRaw(index, inameIn, nameIn, addrIn, typeIdIn,
+                         typeNameIn, valueIn);
+    do {
+        // Is this a previously detected Null-Pointer or out of scope
+        if ( (rc & (HasChildren|OutOfScope)) )
+            break;
+        // QString
+        if (typeNameIn->endsWith(QLatin1String("QString")) || typeNameIn->endsWith(QLatin1String("QString *"))) {
+            const int drc = dumpQString(index, *inameIn, valueIn);
+            switch (drc) {
+            case 0:
+                rc |= InternalDumperSucceeded;
+                break;
+            case 1:
+                rc |= InternalDumperError;
+                break;
+            default:
+                rc |= InternalDumperFailed;
+                qWarning("%s\n", qPrintable(msgStructuralError(*inameIn, *typeNameIn, drc)));
+                break;
+            }
+        }
+        // StdString
+        if (isStdStringOrPointer(*typeNameIn)) {
+            const int drc = dumpStdString(index, *inameIn, valueIn);
+            switch (drc) {
+            case 0:
+                rc |= InternalDumperSucceeded;
+                break;
+            case 1:
+                rc |= InternalDumperError;
+                break;
+            default:
+                rc |= InternalDumperFailed;
+                qWarning("%s\n", qPrintable(msgStructuralError(*inameIn, *typeNameIn, drc)));
+                break;
+            }
+
+        }
+    } while (false);
+    if (debugInternalDumpers)
+        qDebug() << "SymbolGroupContext::dump" << rc << nameIn << valueIn;
+    return rc;
+}
+
+// Get integer value of symbol group
+bool SymbolGroupContext::getDecimalIntValue(CIDebugSymbolGroup *sg, int index, int *value)
+{
+    const QString valueS = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
+    bool ok;
+    *value = valueS.toInt(&ok);
+    return ok;
+}
+
+// Get pointer value of symbol group ("0xAAB")
+// Note that this is on "00000000`0250124a" on 64bit systems.
+static inline bool getSG_UnsignedHexValue(CIDebugSymbolGroup *sg, int index, quint64 *value)
+{
+    const QString stringValue = getSymbolString(sg, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
+    return SymbolGroupContext::getUnsignedHexValue(stringValue, value);
+}
+
+enum { maxStringLength = 4096 };
+
+int SymbolGroupContext::dumpQString(unsigned long index,
+                                    const QString &iname,
+                                    QString *valueIn)
+{
+    valueIn->clear();
+    QString errorMessage;
+    // Expand string and it's "d" (step over 'static null')
+    if (!expandSymbol(iname, index, &errorMessage))
+        return 2;
+    const unsigned long dIndex = index + 4;
+    if (!expandSymbol(iname, dIndex, &errorMessage))
+        return 3;
+    const unsigned long sizeIndex = dIndex + 3;
+    const unsigned long arrayIndex = dIndex + 4;
+    // Get size and pointer
+    int size;
+    if (!getDecimalIntValue(m_symbolGroup, sizeIndex, &size))
+        return 4;
+    quint64 array;
+    if (!getSG_UnsignedHexValue(m_symbolGroup, arrayIndex, &array))
+        return 5;
+    // Fetch
+    const bool truncated = size > maxStringLength;
+    if (truncated)
+        size = maxStringLength;
+    const QChar doubleQuote = QLatin1Char('"');
+    if (size > 0) {
+        valueIn->append(doubleQuote);
+        // Should this ever be a remote debugger, need to check byte order.
+        unsigned short *buf =  new unsigned short[size + 1];
+        unsigned long bytesRead;
+        const HRESULT hr = m_dataSpaces->ReadVirtual(array, buf, size * sizeof(unsigned short), &bytesRead);
+        if (FAILED(hr)) {
+            delete [] buf;
+            return 1;
+        }
+        buf[bytesRead / sizeof(unsigned short)] = 0;
+        valueIn->append(QString::fromUtf16(buf));
+        delete [] buf;
+        if (truncated)
+            valueIn->append(QLatin1String("..."));
+        valueIn->append(doubleQuote);
+    } else if (size == 0) {
+        *valueIn = QString(doubleQuote) + doubleQuote;
+    } else {
+        *valueIn = QLatin1String("Invalid QString");
+    }
+    return 0;
+}
+
+int SymbolGroupContext::dumpStdString(unsigned long index,
+                                      const QString &inameIn,
+                                      QString *valueIn)
+
+{
+    QString errorMessage;
+
+    // Expand string ->string_val->_bx.
+    if (!expandSymbol(inameIn,  index, &errorMessage))
+        return 1;
+    const unsigned long bxIndex =  index + 3;
+    if (!expandSymbol(inameIn, bxIndex, &errorMessage))
+        return 2;
+    // Check if size is something sane
+    const int sizeIndex =  index + 6;
+    int size;
+    if (!getDecimalIntValue(m_symbolGroup, sizeIndex, &size))
+        return 3;
+    if (size < 0)
+        return 1;
+    // Just copy over the value of the buf[]-array, which should be the string
+    const QChar doubleQuote = QLatin1Char('"');
+    const int bufIndex =  index + 4;
+    *valueIn = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, bufIndex);
+    const int quotePos = valueIn->indexOf(doubleQuote);
+    if (quotePos == -1)
+        return 1;
+    valueIn->remove(0, quotePos);
+    if (valueIn->size() > maxStringLength) {
+        valueIn->truncate(maxStringLength);
+        valueIn->append(QLatin1String("...\""));
+    }
+    return 0;
+}
+
+bool SymbolGroupContext::assignValue(const QString &iname, const QString &value,
+                                        QString *newValue, QString *errorMessage)
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO << '\n' << iname << value;
+    const NameIndexMap::const_iterator it = m_inameIndexMap.constFind(iname);
+    if (it == m_inameIndexMap.constEnd()) {
+        *errorMessage = msgSymbolNotFound(iname);
+        return false;
+    }
+    const unsigned long  index = it.value();
+    const HRESULT hr = m_symbolGroup->WriteSymbolWide(index, reinterpret_cast<PCWSTR>(value.utf16()));
+    if (FAILED(hr)) {
+        *errorMessage = QString::fromLatin1("Unable to assign '%1' to '%2': %3").
+                        arg(value, iname, CdbCore::msgComFailed("WriteSymbolWide", hr));
+        return false;
+    }
+    if (newValue)
+        *newValue = getSymbolString(m_symbolGroup, &IDebugSymbolGroup2::GetSymbolValueTextWide, index);
+    return true;
+}
+
+} // namespace CdbCore
diff --git a/src/plugins/debugger/cdb/symbolgroupcontext.h b/src/plugins/debugger/cdb/symbolgroupcontext.h
new file mode 100644
index 0000000000000000000000000000000000000000..0288943f114f956bdabe9a7fc460bdb1cbf43be3
--- /dev/null
+++ b/src/plugins/debugger/cdb/symbolgroupcontext.h
@@ -0,0 +1,183 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SYMBOLGROUPCONTEXT_H
+#define SYMBOLGROUPCONTEXT_H
+
+#include "cdbcom.h"
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtCore/QList>
+#include <QtCore/QStringList>
+#include <QtCore/QPair>
+#include <QtCore/QMap>
+#include <QtCore/QSet>
+
+namespace CdbCore {
+
+/* A thin wrapper around the IDebugSymbolGroup2 interface which represents
+     * a flat list of symbols using an index (for example, belonging to a stack
+     * frame). It uses the hierarchical naming convention of WatchHandler as in:
+     * "local" (invisible root)
+     * "local.string" (local class variable)
+     * "local.string.data" (class member)
+     * and maintains a mapping iname -> index.
+     * IDebugSymbolGroup2 can "expand" expandable symbols, inserting them into the
+     * flat list after their parent.
+     *
+     * Note the pecularity of IDebugSymbolGroup2 with regard to pointed to items:
+     * 1) A pointer to a POD (say int *) will expand to a pointed-to integer named '*'.
+     * 2) A pointer to a class (QString *), will expand to the class members right away,
+     *    omitting the '*' derefenced item. That is a problem since the dumpers trigger
+     *    only on the derefenced item, so, additional handling is required.
+     */
+
+class SymbolGroupContext
+{
+    Q_DISABLE_COPY(SymbolGroupContext);
+protected:
+    explicit SymbolGroupContext(const QString &prefix,
+                                CIDebugSymbolGroup *symbolGroup,
+                                CIDebugDataSpaces *dataSpaces,
+                                const QStringList &uninitializedVariables = QStringList());
+    bool init(QString *errorMessage);
+
+public:
+    virtual ~SymbolGroupContext();
+    static SymbolGroupContext *create(const QString &prefix,
+                                      CIDebugSymbolGroup *symbolGroup,
+                                      CIDebugDataSpaces *dataSpaces,
+                                      const QStringList &uninitializedVariables,
+                                      QString *errorMessage);
+
+    QString prefix() const { return m_prefix; }
+    int size() const { return m_symbolParameters.size(); }
+
+    // Format a shadowed variable name/iname using a format taking two arguments:
+    // "x <shadowed n"
+    QString shadowedNameFormat() const;
+    void setShadowedNameFormat(const QString &);
+
+    bool assignValue(const QString &iname, const QString &value,
+                     QString *newValue /* = 0 */, QString *errorMessage);
+
+    bool lookupPrefix(const QString &prefix, unsigned long *index) const;
+
+    enum SymbolState { LeafSymbol, ExpandedSymbol, CollapsedSymbol };
+    SymbolState symbolState(unsigned long index) const;
+    SymbolState symbolState(const QString &prefix) const;
+
+    inline bool isExpanded(unsigned long index) const   { return symbolState(index) == ExpandedSymbol; }
+    inline bool isExpanded(const QString &prefix) const { return symbolState(prefix) == ExpandedSymbol; }
+
+    // Dump name/type of an entry running the internal dumpers for known types
+    // May expand symbols.
+
+    enum ValueFlags {
+        HasChildren = 0x1,
+        OutOfScope = 0x2,
+        InternalDumperSucceeded = 0x4,
+        InternalDumperError = 0x8, // Hard error
+        InternalDumperFailed = 0x10,
+        InternalDumperMask = InternalDumperSucceeded|InternalDumperError|InternalDumperFailed
+    };
+
+    unsigned dumpValue(unsigned long index, QString *inameIn, QString *nameIn,                  ULONG64 *addrIn,
+                       ULONG *typeIdIn, QString *typeNameIn, QString *valueIn);
+
+    // For 32bit values (returned as dec)
+    static bool getDecimalIntValue(CIDebugSymbolGroup *sg, int index, int *value);
+    // For pointers and 64bit values (returned as hex)
+    static bool getUnsignedHexValue(QString stringValue, quint64 *value);
+    // Null-check for pointers
+    static bool isNullPointer(const QString &type , QString valueS);
+    // Symbol group values may contain template types which is not desired.
+    static QString removeInnerTemplateType(QString value);
+
+    QString debugToString(bool verbose = false) const;
+    QString toString(); // calls dump/potentially expands
+
+    // Filter out locale variables and arguments
+    inline static bool isSymbolDisplayable(const DEBUG_SYMBOL_PARAMETERS &p);
+
+protected:
+    bool getChildSymbolsPosition(const QString &prefix,
+                                 unsigned long *startPos,
+                                 unsigned long *parentId,
+                                 QString *errorMessage);
+
+    const DEBUG_SYMBOL_PARAMETERS &symbolParameterAt(int i) const { return m_symbolParameters.at(i); }
+
+private:
+    typedef QMap<QString, unsigned long>  NameIndexMap;
+
+    void clear();
+    bool expandSymbol(const QString &prefix, unsigned long index, QString *errorMessage);
+    void populateINameIndexMap(const QString &prefix, unsigned long parentId, unsigned long end);
+    QString symbolINameAt(unsigned long index) const;
+    inline QString formatShadowedName(const QString &name, int n) const;
+
+    // Raw dump of an entry (without dumpers)
+    unsigned dumpValueRaw(unsigned long index, QString *inameIn, QString *nameIn,
+                          ULONG64 *addrIn, ULONG *typeIdIn, QString *typeNameIn,
+                          QString *valueIn) const;
+
+    int dumpQString(unsigned long index, const QString &inameIn, QString *valueIn);
+    int dumpStdString(unsigned long index, const QString &inameIn, QString *valueIn);
+
+    inline DEBUG_SYMBOL_PARAMETERS *symbolParameters() { return &(*m_symbolParameters.begin()); }
+    inline const DEBUG_SYMBOL_PARAMETERS *symbolParameters() const { return &(*m_symbolParameters.constBegin()); }
+
+    const QString m_prefix;
+    const QChar m_nameDelimiter;
+    const QSet<QString> m_uninitializedVariables;    
+
+    CIDebugSymbolGroup *m_symbolGroup;
+    CIDebugDataSpaces *m_dataSpaces;
+    NameIndexMap m_inameIndexMap;
+    QVector<DEBUG_SYMBOL_PARAMETERS> m_symbolParameters;
+    int m_unnamedSymbolNumber;
+    QString m_shadowedNameFormat;
+};
+
+// Filter out locale variables and arguments
+bool SymbolGroupContext::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;
+}
+
+} // namespace CdbCore
+
+#endif // SYMBOLGROUPCONTEXT_H
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index f908e7fbd07500b05b05c3fdb63956348730f53a..f0b4458144024ee628ccf598037e3ab82f95d2a5 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -324,14 +324,19 @@ QString WatchData::msgNotInScope()
     return rc;
 }
 
+const QString &WatchData::shadowedNameFormat()
+{
+    static const QString format = QCoreApplication::translate("Debugger::Internal::WatchData", "%1 <shadowed %2>");
+    return format;
+}
+
 QString WatchData::shadowedName(const QString &name, int seen)
 {
     if (seen <= 0)
         return name;
-    return QCoreApplication::translate("Debugger::Internal::WatchData", "%1 <shadowed %2>").arg(name).arg(seen);
+    return shadowedNameFormat().arg(name, seen);
 }
 
-
 ///////////////////////////////////////////////////////////////////////
 //
 // WatchModel
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index c033965f019f07c116da9051cb9a59b73136254f..15f4a56569bdde40085b6b52a416d45070ff0cc6 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -117,6 +117,7 @@ public:
 
     static QString msgNotInScope();
     static QString shadowedName(const QString &name, int seen);
+    static const QString &shadowedNameFormat();
 
 public:
     QByteArray iname;     // internal name sth like 'local.baz.public.a'
diff --git a/tests/manual/ccdb/cdbapplication.cpp b/tests/manual/ccdb/cdbapplication.cpp
index 8ae44c2c17b8203680b1fc1086e11dd16d3707f3..919e65a8c2e6e0948376a9f684495f52ecec961c 100644
--- a/tests/manual/ccdb/cdbapplication.cpp
+++ b/tests/manual/ccdb/cdbapplication.cpp
@@ -32,6 +32,8 @@
 #include "cdbdebugoutput.h"
 #include "cdbpromptthread.h"
 #include "debugeventcallback.h"
+#include "symbolgroupcontext.h"
+#include "stacktracecontext.h"
 
 #include <QtCore/QStringList>
 #include <QtCore/QTimer>
@@ -149,6 +151,45 @@ void CdbApplication::asyncCommand(int command, const QString &arg)
     }
 }
 
+void CdbApplication::printFrame(const QString &arg)
+{
+    QString errorMessage;
+    do {
+        if (m_stackTrace.isNull()) {
+            errorMessage = QLatin1String("No trace.");
+            break;
+        }
+        bool ok;
+        const int frame = arg.toInt(&ok);
+        if (!ok || frame < 0 || frame >= m_stackTrace->frameCount()) {
+            errorMessage = QLatin1String("Invalid or out of range.");
+            break;
+        }
+        CdbCore::SymbolGroupContext *ctx = m_stackTrace->symbolGroupContextAt(frame, &errorMessage);
+        if (!ctx)
+            break;
+        printf("%s\n", qPrintable(ctx->toString()));
+    } while (false);
+    if (!errorMessage.isEmpty())
+        printf("%s\n", qPrintable(errorMessage));
+}
+
+bool CdbApplication::queueBreakPoint(const QString &arg)
+{
+    // Queue file:line
+    const int cpos = arg.lastIndexOf(QLatin1Char(':'));
+    if (cpos == -1)
+        return false;
+    CdbCore::BreakPoint bp;
+    bp.fileName = arg.left(cpos);
+    bool ok;
+    bp.lineNumber = arg.mid(cpos + 1).toInt(&ok);
+    if (!ok || bp.lineNumber < 1)
+        return false;
+    m_queuedBreakPoints.push_back(bp);
+    return true;
+}
+
 void CdbApplication::syncCommand(int command, const QString &arg)
 {
     QString errorMessage;
@@ -163,6 +204,34 @@ void CdbApplication::syncCommand(int command, const QString &arg)
             }
         }
         break;
+    case Sync_Queue: {
+        const QString targs = arg.trimmed();
+        if (targs.isEmpty()) {
+            std::printf("Queue cleared\n");
+            m_queuedCommands.clear();
+        } else {
+            std::printf("Queueing %s\n", qPrintable(targs));
+            m_queuedCommands.push_back(targs);
+        }
+    }
+        break;
+    case Sync_QueueBreakPoint: {
+        const QString targs = arg.trimmed();
+        if (targs.isEmpty()) {
+            std::printf("Breakpoint queue cleared\n");
+            m_queuedBreakPoints.clear();
+        } else {
+            if (queueBreakPoint(targs)) {
+                std::printf("Queueing breakpoint %s\n", qPrintable(targs));
+            } else {
+                std::printf("BREAKPOINT SYNTAX ERROR: %s\n", qPrintable(targs));
+            }
+        }
+    }
+        break;
+    case Sync_PrintFrame:
+        printFrame(arg);
+        break;
     case Unknown:
         if (!m_engine->executeDebuggerCommand(arg, &errorMessage))
             std::printf("%s\n", qPrintable(errorMessage));
@@ -196,6 +265,7 @@ void CdbApplication::executionCommand(int command, const QString &arg)
     }
     if (ok) {
         m_engine->startWatchTimer();
+        m_stackTrace.reset();
     } else {
         std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
     }
@@ -203,11 +273,50 @@ void CdbApplication::executionCommand(int command, const QString &arg)
 
 void CdbApplication::debugEvent()
 {
+    QString errorMessage;
     std::printf("Debug event\n");
+
+    CdbCore::StackTraceContext::ThreadIdFrameMap threads;
+    ULONG currentThreadId;
+    if (CdbCore::StackTraceContext::getThreads(m_engine->interfaces(), &threads,
+                                               &currentThreadId, &errorMessage)) {
+        printf("%s\n", qPrintable(CdbCore::StackTraceContext::formatThreads(threads)));
+    } else {
+        std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
+    }
+
+    CdbCore::StackTraceContext *trace =
+        CdbCore::StackTraceContext::create(&m_engine->interfaces(),
+                                           0xFFFF, &errorMessage);
+    if (trace) {
+        m_stackTrace.reset(trace);
+        printf("%s\n", qPrintable(m_stackTrace->toString()));
+    } else {
+        std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
+    }
 }
 
 void CdbApplication::processAttached(void *handle)
 {
-    std::printf("pe\n");
+    std::printf("### Process attached\n");
     m_processHandle = handle;
+    QString errorMessage;
+    // Commands
+    foreach(const QString &qc, m_queuedCommands) {
+        if (m_engine->executeDebuggerCommand(qc, &errorMessage)) {
+            std::printf("'%s' [ok]\n", qPrintable(qc));
+        } else {
+            std::printf("%s\n", qPrintable(errorMessage));
+        }
+    }
+    // Breakpoints
+    foreach(const CdbCore::BreakPoint &bp, m_queuedBreakPoints) {
+        if (bp.add(m_engine->interfaces().debugControl, &errorMessage)) {
+            std::printf("'%s' [ok]\n", qPrintable(bp.expression()));
+        } else {
+            std::fprintf(stderr, "%s: %s\n",
+                         qPrintable(bp.expression()),
+                         qPrintable(errorMessage));
+        }
+    }
 }
diff --git a/tests/manual/ccdb/cdbapplication.h b/tests/manual/ccdb/cdbapplication.h
index 5ee35b24c253bb9c8808a8ac4091ed447a8c879d..9a360d43488111d3bcbcb8d7f0a18646020dee05 100644
--- a/tests/manual/ccdb/cdbapplication.h
+++ b/tests/manual/ccdb/cdbapplication.h
@@ -30,11 +30,16 @@
 #ifndef CDBAPPLICATION_H
 #define CDBAPPLICATION_H
 
+#include "breakpoint.h"
+
 #include <QtCore/QCoreApplication>
 #include <QtCore/QSharedPointer>
+#include <QtCore/QScopedPointer>
+#include <QtCore/QStringList>
 
 namespace CdbCore {
     class CoreEngine;
+    class StackTraceContext;
 }
 
 class CdbPromptThread;
@@ -61,10 +66,16 @@ private slots:
 
 private:
     bool parseOptions();
+    void printFrame(const QString &arg);
+    bool queueBreakPoint(const QString &arg);
 
     QString m_engineDll;
     QSharedPointer<CdbCore::CoreEngine> m_engine;
+    QScopedPointer<CdbCore::StackTraceContext> m_stackTrace;
     CdbPromptThread *m_promptThread;
+    QStringList m_queuedCommands;
+    QList<CdbCore::BreakPoint> m_queuedBreakPoints;
+
     void *m_processHandle;
 };
 
diff --git a/tests/manual/ccdb/cdbpromptthread.cpp b/tests/manual/ccdb/cdbpromptthread.cpp
index 07e7bc31a48092d7a82ccebc67203913723756cd..c9359aa5b69b6e4b26d3a56618460f7c077dd978 100644
--- a/tests/manual/ccdb/cdbpromptthread.cpp
+++ b/tests/manual/ccdb/cdbpromptthread.cpp
@@ -40,6 +40,11 @@ static const char help[] =
 "S binary args            Start binary\n"
 "I                        Interrupt\n"
 "G                        Go\n"
+"Q cmd                    Queue command for execution in AttachProcess\n"
+"Q                        Clear command queue\n"
+"B file:line              Queue a breakpoint for adding in AttachProcess\n"
+"B                        Clear breakpoint queue\n"
+"F <n>                    Print stack frame <n>, 0 being top\n"
 "\nThe remaining commands are passed to CDB.\n";
 
 CdbPromptThread::CdbPromptThread(QObject *parent) :
@@ -75,12 +80,18 @@ static Command evaluateCommand(const QString &cmdToken)
         switch(cmdToken.at(0).toAscii()) {
         case 'I':
             return Async_Interrupt;
+        case 'Q':
+            return Sync_Queue;
+        case 'B':
+            return Sync_QueueBreakPoint;
         case 'E':
             return Sync_EvalExpression;
         case 'G':
             return Execution_Go;
         case 'S':
             return Execution_StartBinary;
+        case 'F':
+            return Sync_PrintFrame;
         default:
             break;
         }
diff --git a/tests/manual/ccdb/cdbpromptthread.h b/tests/manual/ccdb/cdbpromptthread.h
index 09df8452a597f334bfaed1b20bb7995858ce7854..48a7679a34249a1156523413f1356cd34a56eefb 100644
--- a/tests/manual/ccdb/cdbpromptthread.h
+++ b/tests/manual/ccdb/cdbpromptthread.h
@@ -47,6 +47,9 @@ enum Command {
     UnknownCommand        = 0,
     Async_Interrupt       = AsyncCommand|1,
     Sync_EvalExpression   = SyncCommand|1,
+    Sync_Queue            = SyncCommand|2,
+    Sync_QueueBreakPoint  = SyncCommand|3,
+    Sync_PrintFrame       = SyncCommand|4,
     Execution_Go          = ExecutionCommand|1,
     Execution_StartBinary = ExecutionCommand|2
 };