diff --git a/share/qtcreator/gdbmacros/gdbmacros.cpp b/share/qtcreator/gdbmacros/gdbmacros.cpp
index 3407b3645c17d103e49a54339d3644afff3c5022..f68a1cf6cc9e5922990e0f45a0f72e8065862c95 100644
--- a/share/qtcreator/gdbmacros/gdbmacros.cpp
+++ b/share/qtcreator/gdbmacros/gdbmacros.cpp
@@ -1618,9 +1618,11 @@ static void qDumpQList(QDumper &d)
     const QListData &ldata = *reinterpret_cast<const QListData*>(d.data);
     const QListData::Data *pdata =
         *reinterpret_cast<const QListData::Data* const*>(d.data);
-    int nn = ldata.size();
+    const int nn = ldata.size();
     if (nn < 0)
         return;
+    const bool innerTypeIsPointer = isPointerType(d.innerType);
+    const int n = qMin(nn, 1000);
     if (nn > 0) {
         if (ldata.d->begin < 0)
             return;
@@ -1631,18 +1633,19 @@ static void qDumpQList(QDumper &d)
             return;
 #endif
         qCheckAccess(ldata.d->array);
-        //qCheckAccess(ldata.d->array[0]);
-        //qCheckAccess(ldata.d->array[nn - 1]);
+        // Additional checks on pointer arrays
+        if (innerTypeIsPointer)
+            for (int i = 0; i != n; ++i)
+                if (const void *p = ldata.d->array + i + pdata->begin)
+                    qCheckAccess(deref(p));
     }
     qCheckAccess(pdata);
 
-    int n = nn;
     d.putItemCount("value", n);
     d.putItem("valueeditable", "false");
     d.putItem("numchild", n);
     if (d.dumpChildren) {
-        unsigned innerSize = d.extraInt[0];
-        bool innerTypeIsPointer = isPointerType(d.innerType);
+        const unsigned innerSize = d.extraInt[0];
         QByteArray strippedInnerType = stripPointerType(d.innerType);
 
         // The exact condition here is:
@@ -1653,8 +1656,6 @@ static void qDumpQList(QDumper &d)
         bool isInternal = innerSize <= int(sizeof(void*))
             && isMovableType(d.innerType);
         d.putItem("internal", (int)isInternal);
-        if (n > 1000)
-            n = 1000;
         d.beginChildren(n ? d.innerType : 0);
         for (int i = 0; i != n; ++i) {
             d.beginHash();
@@ -2917,23 +2918,21 @@ static void qDumpQVector(QDumper &d)
     int nn = v->size;
     if (nn < 0)
         return;
-    if (nn > 0) {
-        //qCheckAccess(&vec.front());
-        //qCheckAccess(&vec.back());
-    }
-
+    const bool innerIsPointerType = isPointerType(d.innerType);
     const unsigned innersize = d.extraInt[0];
+    const int n = qMin(nn, 1000);
+    // Check pointers
+    if (innerIsPointerType && nn > 0)
+        for (int i = 0; i != n; ++i)
+            if (const void *p = addOffset(v, i * innersize + typeddatasize))
+                qCheckAccess(deref(p));
 
-    int n = nn;
     d.putItemCount("value", n);
     d.putItem("valueeditable", "false");
     d.putItem("numchild", n);
     if (d.dumpChildren) {
         QByteArray strippedInnerType = stripPointerType(d.innerType);
-        const char *stripped =
-            isPointerType(d.innerType) ? strippedInnerType.data() : 0;
-        if (n > 1000)
-            n = 1000;
+        const char *stripped = innerIsPointerType ? strippedInnerType.data() : 0;
         d.beginChildren(d.innerType);
         for (int i = 0; i != n; ++i) {
             d.beginHash();
diff --git a/src/plugins/cpptools/cppfindreferences.cpp b/src/plugins/cpptools/cppfindreferences.cpp
index 06bc4affa87468dbd6d028b7025fc0423085cc56..3c11479a02523583e73f1179bbe0f11346a4225f 100644
--- a/src/plugins/cpptools/cppfindreferences.cpp
+++ b/src/plugins/cpptools/cppfindreferences.cpp
@@ -166,12 +166,32 @@ protected:
         return false;
     }
 
+    bool checkScope(Symbol *symbol, Symbol *otherSymbol) const
+    {
+        if (! (symbol && otherSymbol))
+            return false;
+
+        else if (symbol->scope() == otherSymbol->scope())
+            return true;
+
+        else if (symbol->name() && otherSymbol->name()) {
+
+            if (! symbol->name()->isEqualTo(otherSymbol->name()))
+                return false;
+
+        } else if (symbol->name() != otherSymbol->name()) {
+            return false;
+        }
+
+        return checkScope(symbol->enclosingSymbol(), otherSymbol->enclosingSymbol());
+    }
+
     bool isDeclSymbol(Symbol *symbol) const
     {
-        if (! symbol)
+        if (! symbol) {
             return false;
 
-        else if (symbol == _declSymbol) {
+        } else if (symbol == _declSymbol) {
             return true;
 
         } else if (symbol->line() == _declSymbol->line() && symbol->column() == _declSymbol->column()) {
@@ -180,11 +200,11 @@ protected:
 
         } else if (symbol->isForwardClassDeclaration() && (_declSymbol->isClass() ||
                                                            _declSymbol->isForwardClassDeclaration())) {
-            return true;
+            return checkScope(symbol, _declSymbol);
 
         } else if (_declSymbol->isForwardClassDeclaration() && (symbol->isClass() ||
                                                                 symbol->isForwardClassDeclaration())) {
-            return true;
+            return checkScope(symbol, _declSymbol);
         }
 
         return false;
@@ -349,6 +369,20 @@ protected:
         return false;
     }
 
+    virtual bool visit(EnumeratorAST *ast)
+    {
+        Identifier *id = identifier(ast->identifier_token);
+        if (id == _id) {
+            LookupContext context = currentContext(ast);
+            const QList<Symbol *> candidates = context.resolve(control()->nameId(id));
+            reportResult(ast->identifier_token, candidates);
+        }
+
+        accept(ast->expression);
+
+        return false;
+    }
+
     virtual bool visit(SimpleNameAST *ast)
     {
         Identifier *id = identifier(ast->identifier_token);
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
index f0373e89bf8f1ea216eed2cbaeb7c0d1d9b4c68c..1d8869205667a2048f8e73c25abd1d7b69342487 100644
--- a/src/plugins/cpptools/cppmodelmanager.cpp
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -727,7 +727,7 @@ QByteArray CppModelManager::internalDefinedMacros() const
     return macros;
 }
 
-void CppModelManager::setIncludesInPaths(const QMap<QString, QStringList> includesInPaths)
+void CppModelManager::setIncludesInPaths(const QMap<QString, QStringList> &includesInPaths)
 {
     QMutexLocker locker(&mutex);
     QMapIterator<QString, QStringList> i(includesInPaths);
@@ -1182,7 +1182,7 @@ void CppModelManager::updateIncludesInPaths(QFutureInterface<void> &future,
             future.waitForResume();
 
         if (future.isCanceled())
-            break;
+            return;
 
         const QString path = paths.takeFirst();
 
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
index 0e7b0271ce156363e02e56d3bef52534c1f08232..4222ccab6be790d6ba5010db6de501511ac7c645 100644
--- a/src/plugins/cpptools/cppmodelmanager.h
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -163,7 +163,7 @@ private:
     QStringList internalFrameworkPaths() const;
     QByteArray internalDefinedMacros() const;
 
-    void setIncludesInPaths(const QMap<QString, QStringList> includesInPaths);
+    void setIncludesInPaths(const QMap<QString, QStringList> &includesInPaths);
 
     static void updateIncludesInPaths(QFutureInterface<void> &future,
                                       CppModelManager *manager,
diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index 1086adf8e559a1112f1dd686fe1fe85bb264db43..181ed4e06039bb141c28916546002ff3eb62a06c 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -37,6 +37,7 @@
 #include "cdbassembler.h"
 #include "cdboptionspage.h"
 #include "cdboptions.h"
+#include "cdbexceptionutils.h"
 #include "debuggeragents.h"
 
 #include "debuggeractions.h"
@@ -305,12 +306,14 @@ CdbDebugEnginePrivate::CdbDebugEnginePrivate(DebuggerManager *manager,
     m_dumper(new CdbDumperHelper(manager, &m_cif)),
     m_currentThreadId(-1),
     m_eventThreadId(-1),
-    m_interrupted(false),
+    m_interruptArticifialThreadId(-1),
+    m_interrupted(false),    
     m_watchTimer(-1),
     m_debugEventCallBack(engine),
     m_engine(engine),
     m_currentStackTrace(0),
     m_firstActivatedFrame(true),
+    m_inferiorStartupComplete(false),
     m_mode(AttachCore)
 {
 }
@@ -447,7 +450,7 @@ void CdbDebugEnginePrivate::clearForRun()
         qDebug() << Q_FUNC_INFO;
 
     m_breakEventMode = BreakEventHandle;
-    m_eventThreadId = -1;
+    m_eventThreadId = m_interruptArticifialThreadId = -1;
     m_interrupted = false;
     cleanStackTrace();
 }
@@ -619,6 +622,8 @@ void CdbDebugEnginePrivate::checkVersion()
 
 void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters> &sp)
 {
+    if (debugCDBExecution)
+        qDebug() << "startDebugger" << *sp;
     setState(AdapterStarting, Q_FUNC_INFO, __LINE__);
     m_d->checkVersion();
     if (m_d->m_hDebuggeeProcess) {
@@ -627,6 +632,7 @@ void CdbDebugEngine::startDebugger(const QSharedPointer<DebuggerStartParameters>
         emit startFailed();
     }
     m_d->clearDisplay();
+    m_d->m_inferiorStartupComplete = false;
     setState(AdapterStarted, Q_FUNC_INFO, __LINE__);
 
     setState(InferiorPreparing, Q_FUNC_INFO, __LINE__);
@@ -699,10 +705,11 @@ bool CdbDebugEngine::startAttachDebugger(qint64 pid, DebuggerStartMode sm, QStri
 {
     // Need to attrach invasively, otherwise, no notification signals
     // for for CreateProcess/ExitProcess occur.
-    const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS;
+    // As of version 6.11, the initial breakpoint suppression has no effect (see notifyException).
+    const ULONG flags = DEBUG_ATTACH_INVASIVE_RESUME_PROCESS|DEBUG_ATTACH_INVASIVE_NO_INITIAL_BREAK;
     const HRESULT hr = m_d->m_cif.debugClient->AttachProcess(NULL, pid, flags);
     if (debugCDB)
-        qDebug() << "Attaching to " << pid << " returns " << hr << executionStatusString(m_d->m_cif.debugControl);
+        qDebug() << "Attaching to " << pid << " using flags" << flags << " returns " << hr << executionStatusString(m_d->m_cif.debugControl);
     if (FAILED(hr)) {
         *errorMessage = tr("Attaching to a process failed for process id %1: %2").arg(pid).arg(msgDebugEngineComResult(hr));
         return false;
@@ -771,7 +778,7 @@ bool CdbDebugEngine::startDebuggerWithExecutable(DebuggerStartMode sm, QString *
 }
 
 void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG64 initialThreadHandle)
-{
+{   
     m_engine->setState(InferiorRunningRequested, Q_FUNC_INFO, __LINE__);
     setDebuggeeHandles(reinterpret_cast<HANDLE>(processHandle), reinterpret_cast<HANDLE>(initialThreadHandle));
     ULONG currentThreadId;
@@ -782,8 +789,11 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
     }
     // Clear any saved breakpoints and set initial breakpoints
     m_engine->executeDebuggerCommand(QLatin1String("bc"));
-    if (manager()->breakHandler()->hasPendingBreakpoints())
+    if (manager()->breakHandler()->hasPendingBreakpoints()) {
+        if (debugCDBExecution)
+            qDebug() << "processCreatedAttached: Syncing breakpoints";
         m_engine->attemptBreakpointSynchronization();
+    }
     // Attaching to crashed: This handshake (signalling an event) is required for
     // the exception to be delivered to the debugger
     if (m_mode == AttachCrashedExternal) {
@@ -796,8 +806,8 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
         }
     }
     m_engine->setState(InferiorRunning, Q_FUNC_INFO, __LINE__);
-    if (debugCDB)
-        qDebug() << Q_FUNC_INFO << '\n' << executionStatusString(m_cif.debugControl);
+    if (debugCDBExecution)
+        qDebug() << "<processCreatedAttached" << executionStatusString(m_cif.debugControl);
 }
 
 void CdbDebugEngine::processTerminated(unsigned long exitCode)
@@ -1018,8 +1028,8 @@ static inline QString msgStepFailed(unsigned long executionStatus, int threadId,
 // its reverse equivalents in the case of single threads.
 bool CdbDebugEngine::step(unsigned long executionStatus)
 {
-    if (debugCDB)
-        qDebug() << Q_FUNC_INFO << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId;
+    if (debugCDBExecution)
+        qDebug() << ">step" << executionStatus << "curr " << m_d->m_currentThreadId << " evt " << m_d->m_eventThreadId;
 
     // State of reverse stepping as of 10/2009 (Debugging tools 6.11@404):
     // The constants exist, but invoking the calls leads to E_NOINTERFACE.
@@ -1029,6 +1039,12 @@ bool CdbDebugEngine::step(unsigned long executionStatus)
         return false;
     }
 
+    // Do not step the artifical thread created to interrupt the debuggee.
+    if (m_d->m_interrupted && m_d->m_currentThreadId == m_d->m_interruptArticifialThreadId) {
+        warning(tr("Thread %1 cannot be stepped.").arg(m_d->m_currentThreadId));
+        return false;
+    }
+
     // SetExecutionStatus() continues the thread that triggered the
     // stop event (~# p). This can be confusing if the user is looking
     // at the stack trace of another thread and wants to step that one. If that
@@ -1067,6 +1083,8 @@ bool CdbDebugEngine::step(unsigned long executionStatus)
     } else {
         setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
     }
+    if (debugCDBExecution)
+        qDebug() << "<step samethread" << sameThread << "succeeded" << success;
     return success;
 }
 
@@ -1092,8 +1110,8 @@ void CdbDebugEngine::nextIExec()
 
 void CdbDebugEngine::stepOutExec()
 {
-   if (debugCDB)
-       qDebug() << Q_FUNC_INFO;
+    if (debugCDBExecution)
+        qDebug() << "stepOutExec";
    // emulate gdb 'exec-finish' (exec until return of current function)
    // by running up to address of the above stack frame (mostly works).
    const StackHandler* sh = manager()->stackHandler();
@@ -1142,8 +1160,8 @@ void CdbDebugEngine::continueInferior()
 // Continue process without notifications
 bool CdbDebugEnginePrivate::continueInferiorProcess(QString *errorMessagePtr /* = 0 */)
 {
-    if (debugCDB)
-        qDebug() << Q_FUNC_INFO;
+    if (debugCDBExecution)
+        qDebug() << "continueInferiorProcess";
     const HRESULT hr = m_cif.debugControl->SetExecutionStatus(DEBUG_STATUS_GO);
     if (FAILED(hr)) {
         const QString errorMessage = msgComFailed("SetExecutionStatus", hr);
@@ -1198,11 +1216,12 @@ bool CdbDebugEnginePrivate::continueInferior(QString *errorMessage)
 
 bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
 {
+
     // Interrupt the interferior process without notifications
-    if (debugCDB) {
+    if (debugCDBExecution) {
         ULONG executionStatus;
         getExecutionStatus(m_cif.debugControl, &executionStatus, errorMessage);
-        qDebug() << Q_FUNC_INFO << "\n    ex=" << executionStatus;
+        qDebug() << "interruptInterferiorProcess  ex=" << executionStatus;
     }
 
     if (DebugBreakProcess(m_hDebuggeeProcess)) {
@@ -1218,6 +1237,7 @@ bool CdbDebugEnginePrivate::interruptInterferiorProcess(QString *errorMessage)
                         arg(getInterruptTimeOutSecs(m_cif.debugControl)).arg(msgComFailed("SetInterrupt", hr));
         return false;
     }
+    m_interrupted = true;
 #endif
     return true;
 }
@@ -1646,10 +1666,27 @@ void CdbDebugEngine::warning(const QString &w)
     qWarning("%s\n", qPrintable(w));
 }
 
-void CdbDebugEnginePrivate::notifyCrashed()
+void CdbDebugEnginePrivate::notifyException(long code, bool fatal)
 {
+    if (debugCDBExecution)
+        qDebug() << "notifyException code" << code << " fatal=" << fatal;
+    // Suppress the initial breakpoint that occurs when
+    // attaching (If a breakpoint is encountered before startup
+    // is complete).
+    switch (code) {
+    case winExceptionStartupCompleteTrap:
+        m_inferiorStartupComplete = true;
+        break;
+    case EXCEPTION_BREAKPOINT:
+        if (!m_inferiorStartupComplete && m_breakEventMode == BreakEventHandle) {
+            manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Ignoring initial breakpoint..."));
+            m_breakEventMode = BreakEventIgnoreOnce;
+        }
+        break;
+    }
     // Cannot go over crash point to execute calls.
-    m_dumper->disable();
+    if (fatal)
+        m_dumper->disable();
 }
 
 static int threadIndexById(const ThreadsHandler *threadsHandler, int id)
@@ -1664,10 +1701,10 @@ static int threadIndexById(const ThreadsHandler *threadsHandler, int id)
 
 void CdbDebugEnginePrivate::handleDebugEvent()
 {
-    if (debugCDB)
-        qDebug() << Q_FUNC_INFO << '\n'  << m_hDebuggeeProcess << m_breakEventMode
-                << executionStatusString(m_cif.debugControl);
-
+    if (debugCDBExecution)
+        qDebug() << "handleDebugEvent mode " << m_breakEventMode
+                << executionStatusString(m_cif.debugControl) << " interrupt" << m_interrupted
+                << " startupcomplete" << m_inferiorStartupComplete;
     // restore mode and do special handling
     const HandleBreakEventMode mode = m_breakEventMode;
     m_breakEventMode = BreakEventHandle;
@@ -1679,9 +1716,27 @@ void CdbDebugEnginePrivate::handleDebugEvent()
         if (m_engine->state() != InferiorStopping)
             m_engine->setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
         m_engine->setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
-        m_eventThreadId = m_currentThreadId = updateThreadList();
-        manager()->showDebuggerOutput(LogMisc, CdbDebugEngine::tr("Stopped, current thread: %1").arg(m_currentThreadId));
+        m_eventThreadId = updateThreadList();
+        m_interruptArticifialThreadId = m_interrupted ? m_eventThreadId : -1;
+        // Get thread to stop and its index. If avoidable, do not use
+        // the artifical thread that is created when interrupting,
+        // use the oldest thread 0 instead.
         ThreadsHandler *threadsHandler = manager()->threadsHandler();
+        m_currentThreadId = m_interrupted ? 0 : m_eventThreadId;
+        int currentThreadIndex = -1;
+        m_currentThreadId = -1;
+        if (m_interrupted) {
+            m_currentThreadId = 0;
+            currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId);
+        }
+        if (!m_interrupted || currentThreadIndex == -1) {
+            m_currentThreadId = m_eventThreadId;
+            currentThreadIndex = threadIndexById(threadsHandler, m_currentThreadId);
+        }
+        const QString msg = m_interrupted ?
+                            CdbDebugEngine::tr("Interrupted in thread %1, current thread: %2").arg(m_interruptArticifialThreadId).arg(m_currentThreadId) :
+                            CdbDebugEngine::tr("Stopped, current thread: %1").arg(m_currentThreadId);
+        manager()->showDebuggerOutput(LogMisc, msg);
         const int threadIndex = threadIndexById(threadsHandler, m_currentThreadId);
         if (threadIndex != -1)
             threadsHandler->setCurrentThread(threadIndex);
@@ -1690,8 +1745,10 @@ void CdbDebugEnginePrivate::handleDebugEvent()
         break;
     case BreakEventIgnoreOnce:
         m_engine->startWatchTimer();
+        m_interrupted = false;
         break;
     case BreakEventSyncBreakPoints: {
+            m_interrupted = false;
             // Temp stop to sync breakpoints
             QString errorMessage;
             attemptBreakpointSynchronization(&errorMessage);
@@ -1764,9 +1821,12 @@ static inline unsigned long dumperThreadId(const QList<StackFrame> &frames,
         return CdbDumperHelper::InvalidDumperCallThread;
     const int waitCheckDepth = qMin(frames.size(), 5);
     static const QString waitForPrefix = QLatin1String(CdbStackTraceContext::winFuncWaitForPrefix);
-    for (int f = 0; f < waitCheckDepth; f++)
-        if (frames.at(f).function.startsWith(waitForPrefix))
+    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))
             return CdbDumperHelper::InvalidDumperCallThread;
+    }
     return currentThread;
 }
 
@@ -1812,7 +1872,7 @@ void CdbDebugEnginePrivate::updateStackTrace()
     }
     // Set up dumper with a thread (or invalid)
     const unsigned long dumperThread = dumperThreadId(stackFrames, m_currentThreadId);
-    if (debugCDB)
+    if (debugCDBExecution)
         qDebug() << "updateStackTrace() current: " << m_currentThreadId << " dumper=" << dumperThread;
     m_dumper->setDumperCallThread(dumperThread);
     // Display frames
@@ -1824,6 +1884,10 @@ void CdbDebugEnginePrivate::updateStackTrace()
         if (m_dumper->isEnabled() && m_dumper->state() != CdbDumperHelper::Initialized)
             QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
         m_engine->activateFrame(current);
+    } else {
+        // Clean out variables
+        manager()->watchHandler()->beginCycle();
+        manager()->watchHandler()->endCycle();
     }
     manager()->watchHandler()->updateWatchers();
 }
diff --git a/src/plugins/debugger/cdb/cdbdebugengine_p.h b/src/plugins/debugger/cdb/cdbdebugengine_p.h
index b0a01d378961428133fded48999b46a1b5d024f2..e52ddadef5c78ff11844e2486bc26915928386fd 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine_p.h
+++ b/src/plugins/debugger/cdb/cdbdebugengine_p.h
@@ -135,7 +135,7 @@ struct CdbDebugEnginePrivate
     bool executeContinueCommand(const QString &command);
 
     bool attemptBreakpointSynchronization(QString *errorMessage);
-    void notifyCrashed();
+    void notifyException(long code, bool fatal);
 
     enum EndInferiorAction { DetachInferior, TerminateInferior };
     bool endInferior(EndInferiorAction a, QString *errorMessage);
@@ -157,9 +157,10 @@ struct CdbDebugEnginePrivate
     const QSharedPointer<CdbOptions>  m_options;
     HANDLE                  m_hDebuggeeProcess;
     HANDLE                  m_hDebuggeeThread;
-    bool                    m_interrupted;
+    bool                    m_interrupted;    
     int                     m_currentThreadId;
     int                     m_eventThreadId;
+    int                     m_interruptArticifialThreadId;
     HandleBreakEventMode    m_breakEventMode;
 
     int                     m_watchTimer;
@@ -175,6 +176,7 @@ struct CdbDebugEnginePrivate
     EditorToolTipCache m_editorToolTipCache;
 
     bool m_firstActivatedFrame;
+    bool m_inferiorStartupComplete;
 
     DebuggerStartMode m_mode;
     Utils::ConsoleProcess m_consoleStubProc;
@@ -192,6 +194,7 @@ QString msgDebugEngineComResult(HRESULT hr);
 QString msgComFailed(const char *func, HRESULT hr);
 
 enum { debugCDB = 0 };
+enum { debugCDBExecution = 0 };
 enum { debugCDBWatchHandling = 0 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
index 21f867ede22f7678add22ed44b961ebb8113f867..26c24b2058ba22fc3afd99809c46f5d35670d46a 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.cpp
@@ -35,6 +35,7 @@
 
 #include <QtCore/QDebug>
 #include <QtCore/QTextStream>
+#include <QtCore/QCoreApplication>
 
 namespace Debugger {
 namespace Internal {
@@ -249,8 +250,7 @@ STDMETHODIMP CdbDebugEventCallback::Exception(
         qDebug() << Q_FUNC_INFO << "\nex=" << Exception->ExceptionCode << " fatal=" << fatal << msg;
     m_pEngine->manager()->showApplicationOutput(msg);
     m_pEngine->manager()->showDebuggerOutput(LogMisc, msg);
-    if (fatal)
-        m_pEngine->m_d->notifyCrashed();
+    m_pEngine->m_d->notifyException(Exception->ExceptionCode, fatal);
     return S_OK;
 }
 
@@ -373,8 +373,11 @@ STDMETHODIMP CdbDebugEventCallback::SystemError(
 }
 
 // -----------ExceptionLoggerEventCallback
-CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(int logChannel, DebuggerManager *manager) :
+CdbExceptionLoggerEventCallback::CdbExceptionLoggerEventCallback(int logChannel,
+                                                                 bool skipNonFatalExceptions,
+                                                                 DebuggerManager *manager) :
     m_logChannel(logChannel),
+    m_skipNonFatalExceptions(skipNonFatalExceptions),
     m_manager(manager)
 {
 }
@@ -391,15 +394,18 @@ STDMETHODIMP CdbExceptionLoggerEventCallback::Exception(
     __in ULONG /* FirstChance */
     )
 {
-    m_exceptionCodes.push_back(Exception->ExceptionCode);
-    m_exceptionMessages.push_back(QString());
-    {
-        QTextStream str(&m_exceptionMessages.back());
-        formatException(Exception, str);
+    const bool recordException = !m_skipNonFatalExceptions || isFatalException(Exception->ExceptionCode);
+    QString message;
+    formatException(Exception, QTextStream(&message));
+    if (recordException) {
+        m_exceptionCodes.push_back(Exception->ExceptionCode);
+        m_exceptionMessages.push_back(message);
     }
     if (debugCDB)
-        qDebug() << Q_FUNC_INFO << '\n' << m_exceptionMessages.back();
-    m_manager->showDebuggerOutput(m_logChannel, m_exceptionMessages.back());
+        qDebug() << Q_FUNC_INFO << '\n' << message;
+    m_manager->showDebuggerOutput(m_logChannel, message);
+    if (recordException)
+        QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
     return S_OK;
 }
 
diff --git a/src/plugins/debugger/cdb/cdbdebugeventcallback.h b/src/plugins/debugger/cdb/cdbdebugeventcallback.h
index b9de88e1745650a667a22c2ba794aae4f1f69937..4250cd5b24c03d106c0284542552522fb9c0bb28 100644
--- a/src/plugins/debugger/cdb/cdbdebugeventcallback.h
+++ b/src/plugins/debugger/cdb/cdbdebugeventcallback.h
@@ -242,7 +242,9 @@ private:
 class CdbExceptionLoggerEventCallback : public CdbDebugEventCallbackBase
 {
 public:
-    CdbExceptionLoggerEventCallback(int logChannel, DebuggerManager *access);
+    CdbExceptionLoggerEventCallback(int logChannel,
+                                    bool skipNonFatalExceptions,
+                                    DebuggerManager *access);
 
     STDMETHOD(GetInterestMask)(
         THIS_
@@ -261,6 +263,7 @@ public:
 
 private:
     const int m_logChannel;
+    const bool m_skipNonFatalExceptions;
     DebuggerManager *m_manager;
     QList<ULONG> m_exceptionCodes;
     QStringList m_exceptionMessages;
diff --git a/src/plugins/debugger/cdb/cdbdumperhelper.cpp b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
index a188d2c1f2b82a6428a1fe767ab54cba2a5c06a3..753c54be845d7b7d3cc42f89e07f709b74c23280 100644
--- a/src/plugins/debugger/cdb/cdbdumperhelper.cpp
+++ b/src/plugins/debugger/cdb/cdbdumperhelper.cpp
@@ -144,13 +144,14 @@ static bool createDebuggeeAscIIString(CdbComInterfaces *cif,
 // make sense for Qt apps.
 static bool debuggeeLoadLibrary(DebuggerManager *manager,
                                 CdbComInterfaces *cif,
+                                unsigned long threadId,
                                 const QString &moduleName,
                                 QString *errorMessage)
 {
     if (loadDebug > 1)
         qDebug() << Q_FUNC_INFO << moduleName;
-    // Try to ignore the breakpoints
-    CdbExceptionLoggerEventCallback exLogger(LogWarning, manager);
+    // Try to ignore the breakpoints, skip stray startup-complete trap exceptions
+    CdbExceptionLoggerEventCallback exLogger(LogWarning, true, manager);
     EventCallbackRedirector eventRedir(cif->debugClient, &exLogger);
     // Make a call to LoadLibraryA. First, reserve memory in debugger
     // and copy name over.
@@ -178,7 +179,9 @@ static bool debuggeeLoadLibrary(DebuggerManager *manager,
     if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, callCmd, errorMessage))
         return false;
     // Execute current thread. This will hit a breakpoint.
-    if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, QLatin1String("~. g"), errorMessage))
+    QString goCmd;
+    QTextStream(&goCmd) << '~' << threadId << " g";
+    if (!CdbDebugEnginePrivate::executeDebuggerCommand(cif->debugControl, goCmd, errorMessage))
         return false;
     const HRESULT hr = cif->debugControl->WaitForEvent(0, waitTimeOutMS);
     if (FAILED(hr)) {
@@ -329,7 +332,7 @@ CdbDumperHelper::CallLoadResult CdbDumperHelper::initCallLoad(QString *errorMess
     if (modules.filter(QLatin1String(qtCoreModuleNameC), Qt::CaseInsensitive).isEmpty())
         return CallLoadNoQtApp;
     // Try to load
-    if (!debuggeeLoadLibrary(m_manager, m_cif, m_library, errorMessage))
+    if (!debuggeeLoadLibrary(m_manager, m_cif, m_dumperCallThread, m_library, errorMessage))
         return CallLoadError;
     return CallLoadOk;
 }
@@ -495,7 +498,8 @@ CdbDumperHelper::CallResult
                                 bool ignoreAccessViolation, QString *errorMessage)
 {
     *outDataPtr = 0;
-    CdbExceptionLoggerEventCallback exLogger(LogWarning, m_manager);
+    // Skip stray startup-complete trap exceptions.
+    CdbExceptionLoggerEventCallback exLogger(LogWarning, true, m_manager);
     EventCallbackRedirector eventRedir(m_cif->debugClient, &exLogger);
     // write input buffer
     if (!inBuffer.isEmpty()) {
@@ -576,7 +580,7 @@ static inline QString msgNotHandled(const QString &type)
 CdbDumperHelper::DumpResult CdbDumperHelper::dumpType(const WatchData &wd, bool dumpChildren,
                                                       QList<WatchData> *result, QString *errorMessage)
 {
-    if (dumpDebug)
+    if (dumpDebug || debugCDBExecution)
         qDebug() << ">dumpType() thread: " << m_dumperCallThread << " state: " << m_state << wd.type << QTime::currentTime().toString();
     const CdbDumperHelper::DumpResult rc = dumpTypeI(wd, dumpChildren, result, errorMessage);
     if (dumpDebug)
diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.cpp b/src/plugins/debugger/cdb/cdbexceptionutils.cpp
index 4975b697243adfcf0dc2424d33a80408be7298f0..2c9b49d413e1a2e3bdf409a2763efc0b5837a4c5 100644
--- a/src/plugins/debugger/cdb/cdbexceptionutils.cpp
+++ b/src/plugins/debugger/cdb/cdbexceptionutils.cpp
@@ -38,15 +38,6 @@
 
 enum { debugExc = 0 };
 
-// Special exception codes.
-enum { cppExceptionCode = 0xe06d7363, startupCompleteTrap = 0x406d1388,
-       rpcServerUnavailableExceptionCode = 0x6ba,
-       dllNotFoundExceptionCode = 0xc0000135,
-       dllInitFailed = 0xc0000142,
-       missingSystemFile = 0xc0000143,
-       appInitFailed = 0xc0000143
-   };
-
 namespace Debugger {
 namespace Internal {
 
@@ -167,19 +158,19 @@ void formatException(const EXCEPTION_RECORD64 *e, QTextStream &str)
     str << "\nException at 0x"  << e->ExceptionAddress
             <<  ", code: 0x" << e->ExceptionCode << ": ";
     switch (e->ExceptionCode) {
-    case cppExceptionCode:
+    case winExceptionCppException:
         str << "C++ exception";
         break;
-    case startupCompleteTrap:
+    case winExceptionStartupCompleteTrap:
         str << "Startup complete";
         break;
-    case dllNotFoundExceptionCode:
+    case winExceptionDllNotFound:
         str << "DLL not found";
         break;
-    case dllInitFailed:
+    case winExceptionDllInitFailed:
         str << "DLL failed to initialize";
         break;
-    case missingSystemFile:
+    case winExceptionMissingSystemFile:
         str << "System file is missing";
         break;
     case EXCEPTION_ACCESS_VIOLATION: {
@@ -260,7 +251,7 @@ void formatException(const EXCEPTION_RECORD64 *e,
                      QTextStream &str)
 {
     formatException(e, str);
-    if (e->ExceptionCode == cppExceptionCode) {
+    if (e->ExceptionCode == winExceptionCppException) {
         QString errorMessage;
         ULONG currentThreadId = 0;
         dumper->comInterfaces()->debugSystemObjects->GetCurrentThreadId(&currentThreadId);
@@ -278,10 +269,10 @@ bool isFatalException(LONG code)
     switch (code) {
     case EXCEPTION_BREAKPOINT:
     case EXCEPTION_SINGLE_STEP:
-    case startupCompleteTrap: // Mysterious exception at start of application
-    case rpcServerUnavailableExceptionCode:
-    case dllNotFoundExceptionCode:
-    case cppExceptionCode:
+    case winExceptionStartupCompleteTrap: // Mysterious exception at start of application
+    case winExceptionRpcServerUnavailable:
+    case winExceptionDllNotFound:
+    case winExceptionCppException:
         return false;
     default:
         break;
diff --git a/src/plugins/debugger/cdb/cdbexceptionutils.h b/src/plugins/debugger/cdb/cdbexceptionutils.h
index 98af74706fa9411177cfe36ee707fd94d61e85a6..b54447580f34c9e3b0fc592e39fcd85e3681dec4 100644
--- a/src/plugins/debugger/cdb/cdbexceptionutils.h
+++ b/src/plugins/debugger/cdb/cdbexceptionutils.h
@@ -42,6 +42,17 @@ QT_END_NAMESPACE
 namespace Debugger {
 namespace Internal {
 
+// Special exception codes.
+enum { winExceptionCppException = 0xe06d7363,
+       winExceptionStartupCompleteTrap = 0x406d1388,
+       winExceptionRpcServerUnavailable = 0x6ba,
+       winExceptionDllNotFound = 0xc0000135,
+       winExceptionDllInitFailed = 0xc0000142,
+       winExceptionMissingSystemFile = 0xc0000143,
+       winExceptionAppInitFailed = 0xc0000143
+};
+
+
 class CdbDumperHelper;
 
 // Utility class that blocks out exception handling (breaking)
diff --git a/src/plugins/debugger/cdb/cdbstackframecontext.cpp b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
index 93ab11d75efb31956cad1e7bbaa844aaa51090f5..d97a968768c2cf2c6fa29285256e1780339244e8 100644
--- a/src/plugins/debugger/cdb/cdbstackframecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstackframecontext.cpp
@@ -134,7 +134,7 @@ 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("CdbStackFrameContext", "<Unknown Type>");
-        wd->setType(source ? source->type : unknownType);
+        wd->setType(source ? source->type : unknownType, false);
     }
     return missing;
 }
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
index 605eeb61dbfd4c05d6519b39305ca49ffbf77a62..0a338f9fdcc79a0bf46de4e2b53ec4cfc016aa1b 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.cpp
@@ -43,6 +43,7 @@ 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),
diff --git a/src/plugins/debugger/cdb/cdbstacktracecontext.h b/src/plugins/debugger/cdb/cdbstacktracecontext.h
index 3b0e2061fc89c31310ecd38fae2952464c6e0bff..ac9cb030b06b3f6f3ad9659708e462a2a617066b 100644
--- a/src/plugins/debugger/cdb/cdbstacktracecontext.h
+++ b/src/plugins/debugger/cdb/cdbstacktracecontext.h
@@ -67,6 +67,8 @@ public:
     static const char *winFuncFastSystemCallRet;
     // WaitFor...
     static const char *winFuncWaitForPrefix;
+    static const char *winFuncMsgWaitForPrefix;
+
     // Dummy function used for interrupting a debuggee
     static const char *winFuncDebugBreakPoint;
 
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index ea3924ddd26853b982c1fbd41d966cd7e2473036..166902112eb370d3905fa8db2c784a112847f8be 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -1406,10 +1406,14 @@ void DebuggerManager::modulesDockToggled(bool on)
 
 void DebuggerManager::showDebuggerOutput(int channel, const QString &msg)
 {
-    if (d->m_outputWindow)
+    if (d->m_outputWindow) {
         emit emitShowOutput(channel, msg);
-    else 
+        if (channel == LogError)
+            ensureLogVisible();
+    } else  {
         qDebug() << "OUTPUT: " << channel << msg;
+
+    }
 }
 
 void DebuggerManager::showDebuggerInput(int channel, const QString &msg)
@@ -1761,6 +1765,13 @@ bool DebuggerManager::checkDebugConfiguration(int toolChain,
     return success;
 }
 
+void DebuggerManager::ensureLogVisible()
+{
+    QAction *action = d->m_outputDock->toggleViewAction();
+    if (!action->isChecked())
+        action->trigger();
+}
+
 QDebug operator<<(QDebug d, DebuggerState state)
 {
     return d << stateName(state) << '(' << int(state) << ')';
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index ddd692b43167fa6156764d4a07a69c840c2855f1..2d84c9383cc1ae9a7b730d0d83ff91487cc016ce 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -234,6 +234,8 @@ public slots:
 public slots: // FIXME
     void showDebuggerOutput(const QString &msg)
         { showDebuggerOutput(LogDebug, msg); }
+   void ensureLogVisible();
+
 //private slots:  // FIXME
     void showDebuggerOutput(int channel, const QString &msg);
     void showDebuggerInput(int channel, const QString &msg);
diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp
index 04e3bee8f739c9bcb52f06a261d2970c12b5a680..1cf41e932350e5576a1d5d0e524f540eb64bf2ad 100644
--- a/src/plugins/debugger/watchhandler.cpp
+++ b/src/plugins/debugger/watchhandler.cpp
@@ -177,7 +177,7 @@ void WatchData::setValueToolTip(const QString &tooltip)
     valuetooltip = tooltip;
 }
 
-void WatchData::setType(const QString &str)
+void WatchData::setType(const QString &str, bool guessChildrenFromType)
 {
     type = str.trimmed();
     bool changed = true;
@@ -202,7 +202,8 @@ void WatchData::setType(const QString &str)
             changed = false;
     }
     setTypeUnneeded();
-    switch (guessChildren(type)) {
+    if (guessChildrenFromType) {
+        switch (guessChildren(type)) {
         case HasChildren:
             setHasChildren(true);
             break;
@@ -212,6 +213,7 @@ void WatchData::setType(const QString &str)
         case HasPossiblyChildren:
             setHasChildren(true); // FIXME: bold assumption
             break;
+        }
     }
 }
 
@@ -1091,7 +1093,10 @@ void WatchHandler::cleanup()
 void WatchHandler::insertData(const WatchData &data)
 {
     MODEL_DEBUG("INSERTDATA: " << data.toString());
-    QTC_ASSERT(data.isValid(), return);
+    if (!data.isValid()) {
+        qWarning("%s:%d: Attempt to insert invalid watch item: %s", __FILE__, __LINE__, qPrintable(data.toString()));
+        return;
+    }
     if (data.isSomethingNeeded()) {
         m_manager->updateWatchData(data);
     } else {
@@ -1117,7 +1122,11 @@ void WatchHandler::insertBulkData(const QList<WatchData> &list)
     foreach (const WatchData &data, list) {
         // we insert everything, including incomplete stuff
         // to reduce the number of row add operations in the model.
-        hash[parentName(data.iname)].append(data);
+        if (data.isValid()) {
+            hash[parentName(data.iname)].append(data);
+        } else {
+            qWarning("%s:%d: Attempt to bulk-insert invalid watch item: %s", __FILE__, __LINE__, qPrintable(data.toString()));
+        }
     }
     foreach (const QString &parentIName, hash.keys()) {
         WatchModel *model = modelForIName(parentIName);
diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h
index eb2797f3e0ee130c376277712e18d28af8378024..dc426f4e22de74d5f28256a0cbfc1c55b74f6b79 100644
--- a/src/plugins/debugger/watchhandler.h
+++ b/src/plugins/debugger/watchhandler.h
@@ -78,7 +78,7 @@ public:
     };
 
     void setValue(const QString &);
-    void setType(const QString &);
+    void setType(const QString &, bool guessChildrenFromType = true);
     void setValueToolTip(const QString &);
     void setError(const QString &);
     void setAddress(const QString &address);
diff --git a/src/shared/cplusplus/Symbol.cpp b/src/shared/cplusplus/Symbol.cpp
index 3d3f3c78744b1d1e030de4463581e68830e39778..dc80add92b2c92c9a7295ab19e74ee3bbe210b54 100644
--- a/src/shared/cplusplus/Symbol.cpp
+++ b/src/shared/cplusplus/Symbol.cpp
@@ -314,6 +314,14 @@ void Symbol::setScope(Scope *scope)
     _scope = scope;
 }
 
+Symbol *Symbol::enclosingSymbol() const
+{
+    if (! _scope)
+        return 0;
+
+    return _scope->owner();
+}
+
 Scope *Symbol::enclosingNamespaceScope() const
 {
     if (! _scope)
diff --git a/src/shared/cplusplus/Symbol.h b/src/shared/cplusplus/Symbol.h
index 511e14c9f21def5bc3aa94af5869c6b19a70440b..0857673d3f4df62b9a9e14d3841f69375ed899dc 100644
--- a/src/shared/cplusplus/Symbol.h
+++ b/src/shared/cplusplus/Symbol.h
@@ -281,6 +281,8 @@ public:
 
     bool isGenerated() const;
 
+    Symbol *enclosingSymbol() const;
+
     /// Returns the eclosing namespace scope.
     Scope *enclosingNamespaceScope() const;
 
diff --git a/tests/auto/debugger/debugger.pro b/tests/auto/debugger/debugger.pro
index c4cadd3715fe7d7a30cc98d3436ac24c7d5c17fa..ef1547f9ce69a765f4a06ada22cc07c862031abf 100644
--- a/tests/auto/debugger/debugger.pro
+++ b/tests/auto/debugger/debugger.pro
@@ -1,5 +1,5 @@
 
 TEMPLATE = subdirs
 
-SUBDIRS = dumpers.pro plugin.pro
+SUBDIRS = dumpers.pro plugin.pro gdb.pro
 
diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp
index b4ca3723c848381b633d8f212941c73e638c7ab2..3a3fbef043f2b434cd49db2f6a47adccafc00f72 100644
--- a/tests/auto/debugger/tst_dumpers.cpp
+++ b/tests/auto/debugger/tst_dumpers.cpp
@@ -1195,7 +1195,7 @@ template <typename T>
     const QString &sizeStr = N(size);
     const QByteArray elemTypeStr = typeToString<T>();
     QByteArray expected = QByteArray("value='<").append(sizeStr).
-        append(" items>',valuedisabled='true',numchild='").append(sizeStr).
+        append(" items>',valueeditable='false',numchild='").append(sizeStr).
         append("',childtype='").append(elemTypeStr).append("',childnumchild='").
         append(typeToNumchild<T>()).append("',children=[");
     typename QLinkedList<T>::const_iterator iter = l.constBegin();
@@ -1277,13 +1277,13 @@ void tst_Debugger::dumpQLinkedList()
         QLinkedList<int> l;
 
         // Case 1.1: Empty list.
-        testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+        testDumper("value='<0 items>',valueeditable='false',numchild='0',"
             "childtype='int',childnumchild='0',children=[]",
             &l, NS"QLinkedList", true, "int");
 
         // Case 1.2: One element.
         l.append(2);
-        testDumper("value='<1 items>',valuedisabled='true',numchild='1',"
+        testDumper("value='<1 items>',valueeditable='false',numchild='1',"
             "childtype='int',childnumchild='0',children=[{addr='%',value='2'}]"
                 << ptrToBa(l.constBegin().operator->()),
             &l, NS"QLinkedList", true, "int");
@@ -1292,7 +1292,7 @@ void tst_Debugger::dumpQLinkedList()
         l.append(3);
         QByteArray it0 = ptrToBa(l.constBegin().operator->());
         QByteArray it1 = ptrToBa(l.constBegin().operator++().operator->());
-        testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+        testDumper("value='<2 items>',valueeditable='false',numchild='2',"
             "childtype='int',childnumchild='0',children=[{addr='%',value='2'},"
             "{addr='%',value='3'}]" << it0 << it1,
             &l, NS"QLinkedList", true, "int");
@@ -1302,7 +1302,7 @@ void tst_Debugger::dumpQLinkedList()
         QLinkedList<QString>::const_iterator iter;
 
         // Case 2.1: Empty list.
-        testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+        testDumper("value='<0 items>',valueeditable='false',numchild='0',"
             "childtype='"NS"QString',childnumchild='0',children=[]",
             &l2, NS"QLinkedList", true, NS"QString");
 
@@ -1310,13 +1310,13 @@ void tst_Debugger::dumpQLinkedList()
         l2.append("Teststring 1");
         iter = l2.constBegin();
         qDebug() << *iter;
-        testDumper("value='<1 items>',valuedisabled='true',numchild='1',"
+        testDumper("value='<1 items>',valueeditable='false',numchild='1',"
             "childtype='"NS"QString',childnumchild='0',children=[{addr='%',value='%',}]"
                 << ptrToBa(iter.operator->()) << utfToBase64(*iter),
             &l2, NS"QLinkedList", true, NS"QString");
 
         // Case 2.3: Two elements.
-        QByteArray expected = "value='<2 items>',valuedisabled='true',numchild='2',"
+        QByteArray expected = "value='<2 items>',valueeditable='false',numchild='2',"
             "childtype='int',childnumchild='0',children=[";
         iter = l2.constBegin();
         expected.append("{addr='%',%},"
@@ -1331,7 +1331,7 @@ void tst_Debugger::dumpQLinkedList()
         for (int i = 3; i <= 1002; ++i)
             l2.append("Test " + N(i));
 
-        expected = "value='<1002 items>',valuedisabled='true',"
+        expected = "value='<1002 items>',valueeditable='false',"
             "numchild='1002',childtype='"NS"QString',childnumchild='0',children=['";
         iter = l2.constBegin();
         for (int i = 0; i < 1002; ++i, ++iter)
@@ -1354,12 +1354,12 @@ void tst_Debugger::dumpQLinkedList()
 void tst_Debugger::dumpQList_int()
 {
     QList<int> ilist;
-    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+    testDumper("value='<0 items>',valueeditable='false',numchild='0',"
         "internal='1',children=[]",
         &ilist, NS"QList", true, "int");
     ilist.append(1);
     ilist.append(2);
-    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+    testDumper("value='<2 items>',valueeditable='false',numchild='2',"
         "internal='1',childtype='int',childnumchild='0',children=["
         "{addr='" + str(&ilist.at(0)) + "',value='1'},"
         "{addr='" + str(&ilist.at(1)) + "',value='2'}]",
@@ -1369,12 +1369,12 @@ void tst_Debugger::dumpQList_int()
 void tst_Debugger::dumpQList_char()
 {
     QList<char> clist;
-    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+    testDumper("value='<0 items>',valueeditable='false',numchild='0',"
         "internal='1',children=[]",
         &clist, NS"QList", true, "char");
     clist.append('a');
     clist.append('b');
-    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+    testDumper("value='<2 items>',valueeditable='false',numchild='2',"
         "internal='1',childtype='char',childnumchild='0',children=["
         "{addr='" + str(&clist.at(0)) + "',value=''a', ascii=97'},"
         "{addr='" + str(&clist.at(1)) + "',value=''b', ascii=98'}]",
@@ -1384,12 +1384,12 @@ void tst_Debugger::dumpQList_char()
 void tst_Debugger::dumpQList_QString()
 {
     QList<QString> slist;
-    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+    testDumper("value='<0 items>',valueeditable='false',numchild='0',"
         "internal='1',children=[]",
         &slist, NS"QList", true, NS"QString");
     slist.append("a");
     slist.append("b");
-    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+    testDumper("value='<2 items>',valueeditable='false',numchild='2',"
         "internal='1',childtype='"NS"QString',childnumchild='0',children=["
         "{addr='" + str(&slist.at(0)) + "',value='YQA=',valueencoded='2'},"
         "{addr='" + str(&slist.at(1)) + "',value='YgA=',valueencoded='2'}]",
@@ -1399,12 +1399,12 @@ void tst_Debugger::dumpQList_QString()
 void tst_Debugger::dumpQList_Int3()
 {
     QList<Int3> i3list;
-    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+    testDumper("value='<0 items>',valueeditable='false',numchild='0',"
         "internal='0',children=[]",
         &i3list, NS"QList", true, "Int3");
     i3list.append(Int3());
     i3list.append(Int3());
-    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+    testDumper("value='<2 items>',valueeditable='false',numchild='2',"
         "internal='0',childtype='Int3',children=["
         "{addr='" + str(&i3list.at(0)) + "'},"
         "{addr='" + str(&i3list.at(1)) + "'}]",
@@ -1414,12 +1414,12 @@ void tst_Debugger::dumpQList_Int3()
 void tst_Debugger::dumpQList_QString3()
 {
     QList<QString3> s3list;
-    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+    testDumper("value='<0 items>',valueeditable='false',numchild='0',"
         "internal='0',children=[]",
         &s3list, NS"QList", true, "QString3");
     s3list.append(QString3());
     s3list.append(QString3());
-    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+    testDumper("value='<2 items>',valueeditable='false',numchild='2',"
         "internal='0',childtype='QString3',children=["
         "{addr='" + str(&s3list.at(0)) + "'},"
         "{addr='" + str(&s3list.at(1)) + "'}]",
@@ -1819,6 +1819,7 @@ void tst_Debugger::dumpQObjectSignalHelper(QObject &o, int sigNum)
         connLists != 0 && connLists->size() > sigNum ?
         connLists->at(sigNum) : QObjectPrivate::ConnectionList();
     int i = 0;
+    // FIXME: 4.6 only
     for (QObjectPrivate::Connection *conn = connList.first; conn != 0;
          ++i, conn = conn->nextConnectionList) {
         const QString iStr = N(i);
@@ -2137,7 +2138,7 @@ void tst_Debugger::dumpQSharedPointerHelper(QSharedPointer<T> &ptr)
         weakAddr = strongAddr = 0;
         weakValue = strongValue = 0;
     }
-    expected.append(val2).append("',valuedisabled='true',numchild='1',children=[").
+    expected.append(val2).append("',valueeditable='false',numchild='1',children=[").
         append("{name='data',addr='").append(ptrToBa(ptr.data())).
         append("',type='").append(typeToString<T>()).append("',value='").append(val1).
         append("'},{name='weakref',value='").append(N(weakValue)).
@@ -2236,18 +2237,18 @@ void tst_Debugger::dumpStdVector()
     std::vector<std::list<int> *> vector;
     QByteArray inner = "std::list<int> *";
     QByteArray innerp = "std::list<int>";
-    testDumper("value='<0 items>',valuedisabled='true',numchild='0'",
+    testDumper("value='<0 items>',valueeditable='false',numchild='0'",
         &vector, "std::vector", false, inner, "", sizeof(std::list<int> *));
     std::list<int> list;
     vector.push_back(new std::list<int>(list));
-    testDumper("value='<1 items>',valuedisabled='true',numchild='1',"
+    testDumper("value='<1 items>',valueeditable='false',numchild='1',"
         "childtype='" + inner + "',childnumchild='1',"
         "children=[{addr='" + str(deref(&vector[0])) + "',"
             "saddr='" + str(deref(&vector[0])) + "',type='" + innerp + "'}]",
         &vector, "std::vector", true, inner, "", sizeof(std::list<int> *));
     vector.push_back(0);
     list.push_back(45);
-    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+    testDumper("value='<2 items>',valueeditable='false',numchild='2',"
         "childtype='" + inner + "',childnumchild='1',"
         "children=[{addr='" + str(deref(&vector[0])) + "',"
             "saddr='" + str(deref(&vector[0])) + "',type='" + innerp + "'},"
@@ -2297,7 +2298,7 @@ void tst_Debugger::dumpQWeakPointerHelper(QWeakPointer<T> &ptr)
     QByteArray expected("value='");
     if (isSimpleType<T>())
         expected.append(dataStr);
-    expected.append("',valuedisabled='true',numchild='1',children=[{name='data',addr='").
+    expected.append("',valueeditable='false',numchild='1',children=[{name='data',addr='").
         append(ptrToBa(data)).append("',type='").append(typeToString<T>()).
         append("',value='").append(dataStr).append("'},{name='weakref',value='").
         append(valToString(*weakRefPtr)).append("',type='int',addr='").
@@ -2316,7 +2317,7 @@ void tst_Debugger::dumpQWeakPointer()
     // Case 1.1: Null pointer.
     QSharedPointer<int> spNull;
     QWeakPointer<int> wp = spNull.toWeakRef();
-    testDumper("value='<null>',valuedisabled='true',numchild='0'",
+    testDumper("value='<null>',valueeditable='false',numchild='0'",
         &wp, NS"QWeakPointer", true, "int");
 
     // Case 1.2: Weak pointer is unique.
diff --git a/tests/auto/debugger/tst_gdb.cpp b/tests/auto/debugger/tst_gdb.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9310016b4b570a4f088ba8bc8d62426be6556631
--- /dev/null
+++ b/tests/auto/debugger/tst_gdb.cpp
@@ -0,0 +1,2324 @@
+
+#include <QtCore/QThread>
+#include <QtCore/QMutex>
+#include <QtCore/QWaitCondition>
+
+#include <QtCore/private/qobject_p.h>
+
+#include <QtGui/QStandardItemModel>
+#include <QtGui/QStringListModel>
+
+#include <QtTest/QtTest>
+
+#include "gdb/gdbmi.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+
+#undef NS
+#ifdef QT_NAMESPACE
+#   define STRINGIFY0(s) #s
+#   define STRINGIFY1(s) STRINGIFY0(s)
+#   define NS STRINGIFY1(QT_NAMESPACE) "::"
+#   define NSX "'" STRINGIFY1(QT_NAMESPACE) "::"
+#   define NSY "'"
+#else
+#   define NS ""
+#   define NSX ""
+#   define NSY ""
+#endif
+
+#define gettid()  QString("0x%1").arg((qulonglong)(void *)currentThread(), 0, 16)
+
+using namespace Debugger;
+using namespace Debugger::Internal;
+
+typedef QList<QByteArray> QByteArrayList;
+
+static QByteArray operator<<(QByteArray ba, const QByteArray &replacement)
+{
+    int pos = ba.indexOf('%');
+    Q_ASSERT(pos != -1);
+    return ba.replace(pos, 1, replacement);
+}
+
+static QByteArray &operator<<=(QByteArray &ba, const QByteArray &replacement)
+{
+    int pos = ba.indexOf('%');
+    Q_ASSERT(pos != -1);
+    return ba.replace(pos, 1, replacement);
+}
+
+
+template <typename T> 
+inline QByteArray N(T t) { return QByteArray::number(t); }
+
+
+
+struct Int3 {
+    Int3() { i1 = 42; i2 = 43; i3 = 44; }
+    int i1, i2, i3;
+};
+
+struct QString3 {
+    QString3() { s1 = "a"; s2 = "b"; s3 = "c"; }
+    QString s1, s2, s3;
+};
+
+class tst_Gdb;
+
+class Thread : public QThread
+{
+    Q_OBJECT
+
+public:
+    Thread(tst_Gdb *test);
+    void run();
+
+public slots:
+    void readStandardOutput();
+    void readStandardError();
+    void handleGdbStarted();
+    void handleGdbError(QProcess::ProcessError);
+    void handleGdbFinished(int, QProcess::ExitStatus);
+    void writeToGdbRequested(const QByteArray &ba)
+    {
+        //qDebug() << "THREAD GDB IN: " << ba;
+        m_proc->write(ba);
+        m_proc->write("\n");
+    }
+
+
+public:
+    QByteArray m_output;
+    QByteArray m_error;
+    QProcess *m_proc; // owned
+    tst_Gdb *m_test; // not owned
+};
+
+class tst_Gdb : public QObject
+{
+    Q_OBJECT
+
+public:
+    tst_Gdb() : m_thread(this) {}
+
+public slots:
+    void dumperCompatibility();
+    void dumpQAbstractItemAndModelIndex();
+    void dumpQAbstractItemModel();
+    void dumpQByteArray();
+    void dumpQChar();
+    void dumpQDateTime();
+    void dumpQDir();
+    void dumpQFile();
+    void dumpQFileInfo();
+    void dumpQHash();
+    void dumpQHashNode();
+    void dumpQImage();
+    void dumpQImageData();
+    void dumpQLinkedList();
+    void dumpQList_int();
+    void dumpQList_char();
+    void dumpQList_QString();
+    void dumpQList_QString3();
+    void dumpQList_Int3();
+    void dumpQLocale();
+    void dumpQMap();
+    void dumpQMapNode();
+    void dumpQObject();
+    void dumpQObjectChildList();
+    void dumpQObjectMethodList();
+    void dumpQObjectPropertyList();
+    void dumpQObjectSignal();
+    void dumpQObjectSignalList();
+    void dumpQObjectSlot();
+    void dumpQObjectSlotList();
+    void dumpQPixmap();
+    void dumpQSharedPointer();
+    void dumpQTextCodec();
+    void dumpQVariant_invalid();
+    void dumpQVariant_QString();
+    void dumpQVariant_QStringList();
+    void dumpStdVector();
+    void dumpQWeakPointer();
+    void initTestCase();
+    void cleanupTestCase();
+    void runTestCase(const QByteArray &name,
+        const QByteArray &type,
+        const QByteArrayList &expexted);
+
+signals:
+    void writeToGdb(const QByteArray &ba);
+
+private slots:
+    void dumpQString();
+    void dumpQStringList();
+
+private:
+    void dumpQAbstractItemHelper(QModelIndex &index);
+    void dumpQAbstractItemModelHelper(QAbstractItemModel &m);
+    void dumpQDateTimeHelper(const QDateTime &d);
+    void dumpQFileHelper(const QString &name, bool exists);
+    template <typename K, typename V> void dumpQHashNodeHelper(QHash<K, V> &hash);
+    void dumpQImageHelper(const QImage &img);
+    void dumpQImageDataHelper(QImage &img);
+    template <typename T> void dumpQLinkedListHelper(QLinkedList<T> &l);
+    void dumpQLocaleHelper(QLocale &loc);
+    template <typename K, typename V> void dumpQMapHelper(QMap<K, V> &m);
+    template <typename K, typename V> void dumpQMapNodeHelper(QMap<K, V> &m);
+    void dumpQObjectChildListHelper(QObject &o);
+    void dumpQObjectSignalHelper(QObject &o, int sigNum);
+#if QT_VERSION >= 0x040500
+    template <typename T>
+    void dumpQSharedPointerHelper(QSharedPointer<T> &ptr);
+    template <typename T>
+    void dumpQWeakPointerHelper(QWeakPointer<T> &ptr);
+#endif
+    void dumpQTextCodecHelper(QTextCodec *codec);
+
+private:
+    Thread m_thread;
+};
+
+QMutex m_mutex;
+QWaitCondition m_waitCondition;
+
+//
+// Dumpers
+//
+
+static void testDumper(QByteArray expected, const void *data, QByteArray outertype,
+    bool dumpChildren, QByteArray actual____ = QByteArray(), 
+    QByteArray = QByteArray(), int = 0, int = 0, int = 0, int = 0)
+{
+    Q_UNUSED(dumpChildren);
+    expected = "locals={iname='local',name='Locals',value=' ',type=' ',"
+        "children=[" + expected + "],arg=''}";
+    char buf[100];
+    sprintf(buf, "%p", data);
+    //if ((!expected.startsWith('t') && !expected.startsWith('f'))
+    //        || expected.startsWith("type"))
+    //    expected = "tiname='$I',addr='$A'," + expected;
+    expected.replace("$I", "iname");
+    expected.replace("$T", QByteArray(outertype));
+    expected.replace("$A", QByteArray(buf));
+    if (actual____ != expected) {
+        QByteArrayList l1 = actual____.split(',');
+        QByteArrayList l2 = expected.split(',');
+        for (int i = 0; i < l1.size() && i < l2.size(); ++i) {
+            if (l1.at(i) == l2.at(i))
+                qWarning() << "== " << l1.at(i);
+            else 
+                //qWarning() << "!= " << l1.at(i).right(30) << l2.at(i).right(30);
+                qWarning() << "!= " << l1.at(i) << l2.at(i);
+        }
+        if (l1.size() != l2.size())
+            qWarning() << "!= size: " << l1.size() << l2.size();
+    }
+    QCOMPARE(actual____, expected);
+}
+
+QByteArray str(const void *p)
+{
+    char buf[100];
+    sprintf(buf, "%p", p);
+    return buf;
+}
+
+static const void *deref(const void *p)
+{
+    return *reinterpret_cast<const char* const*>(p);
+}
+
+void tst_Gdb::dumperCompatibility()
+{
+    // Ensure that no arbitrary padding is introduced by QVectorTypedData.
+    const size_t qVectorDataSize = 16;
+    QCOMPARE(sizeof(QVectorData), qVectorDataSize);
+    QVectorTypedData<int> *v = 0;
+    QCOMPARE(size_t(&v->array), qVectorDataSize);
+}
+
+static const QByteArray utfToBase64(const QString &string)
+{
+    return QByteArray(reinterpret_cast<const char *>(string.utf16()), 2 * string.size()).toBase64();
+}
+
+static const char *boolToVal(bool b)
+{
+    return b ? "'true'" : "'false'";
+}
+
+static const QByteArray ptrToBa(const void *p, bool symbolicNull = true)
+{
+    return QByteArray().append(p == 0 && symbolicNull ?
+        "<null>" :
+        QByteArray("0x") + QByteArray::number((quintptr) p, 16));
+}
+
+static const QByteArray generateQStringSpec(const QString &str)
+{
+    return QByteArray("value='%',type='"NS"QString',numchild='0',valueencoded='2'")
+        << utfToBase64(str);
+}
+
+static const QByteArray generateQCharSpec(const QChar& ch)
+{
+    return QByteArray("value='%',valueencoded='2',type='"NS"QChar',numchild='0'")
+        << utfToBase64(QString(QLatin1String("'%1' (%2, 0x%3)")).
+                   arg(ch).arg(ch.unicode()).arg(ch.unicode(), 0, 16));
+}
+
+static const QByteArray generateBoolSpec(bool b)
+{
+    return QByteArray("value=%,type='bool',numchild='0'")
+        << boolToVal(b);
+}
+
+static const QByteArray generateLongSpec(long n)
+{
+    return QByteArray("value='%',type='long',numchild='0'")
+        << N(qlonglong(n));
+}
+
+static const QByteArray generateIntSpec(int n)
+{
+    return QByteArray("value='%',type='int',numchild='0'")
+        << N(n);
+}
+
+const QByteArray createExp(const void *ptr,
+    const QByteArray &type, const QByteArray &method)
+{
+    return QByteArray("exp='(("NSX"%"NSY"*)%)->%'")
+        << type << ptrToBa(ptr) << method;
+}
+
+// Helper functions.
+
+#ifdef Q_CC_MSVC
+#  define MAP_NODE_TYPE_END ">"
+#else
+#  define MAP_NODE_TYPE_END " >"
+#endif
+
+template <typename T> static const char *typeToString()
+{
+    return "<unknown type>";
+}
+template <typename T> const QByteArray valToString(const T &)
+{
+    return "<unknown value>";
+}
+template <> const QByteArray valToString(const int &n)
+{
+    return QByteArray().append(N(n));
+}
+template <> const QByteArray valToString(const QString &s)
+{
+    return QByteArray(utfToBase64(s)).append("',valueencoded='2");
+}
+template <> const QByteArray valToString(int * const &p)
+{
+    return ptrToBa(p);
+}
+template <typename T> const QByteArray derefValToString(const T &v)
+{
+    return valToString(v);
+}
+template <> const QByteArray derefValToString(int * const &ptr)
+{
+    return valToString(*ptr);
+}
+const QString stripPtrType(const QString &ptrTypeStr)
+{
+    return ptrTypeStr.mid(0, ptrTypeStr.size() - 2);
+}
+template <> const char *typeToString<int>()
+{
+    return "int";
+}
+template <> const char *typeToString<QString>()
+{
+    return NS"QString";
+}
+template <> const char *typeToString<int *>()
+{
+    return "int *";
+}
+template <typename T> bool isSimpleType()
+{
+    return false;
+}
+template <> bool isSimpleType<int>()
+{
+    return true;
+}
+template <typename T> bool isPointer()
+{
+    return false;
+}
+template <> bool isPointer<int *>()
+{
+    return true;
+}
+
+template <typename T> static const char *typeToNumchild()
+{
+    return "1";
+}
+template <> const char *typeToNumchild<int>()
+{
+    return "0";
+}
+template <> const char *typeToNumchild<QString>()
+{
+    return "0";
+}
+template <typename K, typename V>
+QByteArray getMapType()
+{
+    return QByteArray(typeToString<K>()) + "@" + QByteArray(typeToString<V>());
+}
+template <typename K, typename V>
+void getMapNodeParams(size_t &nodeSize, size_t &valOffset)
+{
+#if QT_VERSION >= 0x040500
+    typedef QMapNode<K, V> NodeType;
+    NodeType *node = 0;
+    nodeSize = sizeof(NodeType);
+    valOffset = size_t(&node->value);
+#else
+    nodeSize = sizeof(K) + sizeof(V) + 2*sizeof(void *);
+    valOffset = sizeof(K);
+#endif
+}
+
+void tst_Gdb::dumpQAbstractItemHelper(QModelIndex &index)
+{
+    const QAbstractItemModel *model = index.model();
+    const QString &rowStr = N(index.row());
+    const QString &colStr = N(index.column());
+    const QByteArray &internalPtrStrSymbolic = ptrToBa(index.internalPointer());
+    const QByteArray &internalPtrStrValue = ptrToBa(index.internalPointer(), false);
+    const QByteArray &modelPtrStr = ptrToBa(model);
+    QByteArray indexSpecSymbolic = QByteArray().append(rowStr + "," + colStr + ",").
+        append(internalPtrStrSymbolic + "," + modelPtrStr);
+    QByteArray indexSpecValue = QByteArray().append(rowStr + "," + colStr + ",").
+        append(internalPtrStrValue + "," + modelPtrStr);
+    QByteArray expected = QByteArray("tiname='iname',addr='").append(ptrToBa(&index)).
+        append("',type='"NS"QAbstractItem',addr='$").append(indexSpecSymbolic).
+        append("',value='").append(valToString(model->data(index).toString())).
+        append("',numchild='1',children=[");
+    int rowCount = model->rowCount(index);
+    int columnCount = model->columnCount(index);
+    for (int row = 0; row < rowCount; ++row) {
+        for (int col = 0; col < columnCount; ++col) {
+            const QModelIndex &childIndex = model->index(row, col, index);
+            expected.append("{name='[").append(valToString(row)).append(",").
+                append(N(col)).append("]',numchild='1',addr='$").
+                append(N(childIndex.row())).append(",").
+                append(N(childIndex.column())).append(",").
+                append(ptrToBa(childIndex.internalPointer())).append(",").
+                append(modelPtrStr).append("',type='"NS"QAbstractItem',value='").
+                append(valToString(model->data(childIndex).toString())).append("'}");
+            if (col < columnCount - 1 || row < rowCount - 1)
+                expected.append(",");
+        }
+    }
+    expected.append("]");
+    testDumper(expected, &index, NS"QAbstractItem", true, indexSpecValue);
+}
+
+void tst_Gdb::dumpQAbstractItemAndModelIndex()
+{
+    class PseudoTreeItemModel : public QAbstractItemModel
+    {
+    public:
+        PseudoTreeItemModel() : QAbstractItemModel(), parent1(0),
+            parent1Child(1), parent2(10), parent2Child1(11), parent2Child2(12)
+        {}
+
+        int columnCount(const QModelIndex &parent = QModelIndex()) const
+        {
+            Q_UNUSED(parent);
+            return 1;
+        }
+
+        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+        {
+            return !index.isValid() || role != Qt::DisplayRole ?
+                    QVariant() : *static_cast<int *>(index.internalPointer());
+        }
+
+        QModelIndex index(int row, int column,
+                          const QModelIndex & parent = QModelIndex()) const
+        {
+            QModelIndex index;
+            if (column == 0) {
+                if (!parent.isValid()) {
+                    if (row == 0)
+                        index = createIndex(row, column, &parent1);
+                    else if (row == 1)
+                        index = createIndex(row, column, &parent2);
+                } else if (parent.internalPointer() == &parent1 && row == 0) {
+                    index = createIndex(row, column, &parent1Child);
+                } else if (parent.internalPointer() == &parent2) {
+                    index = createIndex(row, column,
+                                row == 0 ? &parent2Child1 : &parent2Child2);
+                }
+            }
+            return index;
+        }
+
+        QModelIndex parent(const QModelIndex & index) const
+        {
+            QModelIndex parent;
+            if (index.isValid()) {
+                if (index.internalPointer() == &parent1Child)
+                    parent = createIndex(0, 0, &parent1);
+                else if (index.internalPointer() == &parent2Child1 ||
+                         index.internalPointer() == &parent2Child2)
+                    parent = createIndex(1, 0, &parent2);
+            }
+            return parent;
+        }
+
+        int rowCount(const QModelIndex &parent = QModelIndex()) const
+        {
+            int rowCount;
+            if (!parent.isValid() || parent.internalPointer() == &parent2)
+                rowCount = 2;
+            else if (parent.internalPointer() == &parent1)
+                rowCount = 1;
+            else
+                rowCount = 0;
+            return rowCount;
+        }
+
+    private:
+        mutable int parent1;
+        mutable int parent1Child;
+        mutable int parent2;
+        mutable int parent2Child1;
+        mutable int parent2Child2;
+    };
+
+    PseudoTreeItemModel m2;
+
+    // Case 1: ModelIndex with no children.
+    QStringListModel m(QStringList() << "item1" << "item2" << "item3");
+    QModelIndex index = m.index(2, 0);
+
+    testDumper(QByteArray("type='$T',value='(2, 0)',numchild='5',children=["
+        "{name='row',value='2',type='int',numchild='0'},"
+        "{name='column',value='0',type='int',numchild='0'},"
+        "{name='parent',value='<invalid>',exp='(('$T'*)$A)->parent()',"
+            "type='$T',numchild='1'},"
+        "{name='internalId',%},"
+        "{name='model',value='%',type='"NS"QAbstractItemModel*',"
+            "numchild='1'}]")
+         << generateQStringSpec(N(index.internalId()))
+         << ptrToBa(&m),
+        &index, NS"QModelIndex", true);
+
+    // Case 2: ModelIndex with one child.
+    QModelIndex index2 = m2.index(0, 0);
+    dumpQAbstractItemHelper(index2);
+
+    qDebug() << "FIXME: invalid indices should not have children";
+    testDumper(QByteArray("type='$T',value='(0, 0)',numchild='5',children=["
+        "{name='row',value='0',type='int',numchild='0'},"
+        "{name='column',value='0',type='int',numchild='0'},"
+        "{name='parent',value='<invalid>',exp='(('$T'*)$A)->parent()',"
+            "type='$T',numchild='1'},"
+        "{name='internalId',%},"
+        "{name='model',value='%',type='"NS"QAbstractItemModel*',"
+            "numchild='1'}]")
+         << generateQStringSpec(N(index2.internalId()))
+         << ptrToBa(&m2),
+        &index2, NS"QModelIndex", true);
+
+
+    // Case 3: ModelIndex with two children.
+    QModelIndex index3 = m2.index(1, 0);
+    dumpQAbstractItemHelper(index3);
+
+    testDumper(QByteArray("type='$T',value='(1, 0)',numchild='5',children=["
+        "{name='row',value='1',type='int',numchild='0'},"
+        "{name='column',value='0',type='int',numchild='0'},"
+        "{name='parent',value='<invalid>',exp='(('$T'*)$A)->parent()',"
+            "type='$T',numchild='1'},"
+        "{name='internalId',%},"
+        "{name='model',value='%',type='"NS"QAbstractItemModel*',"
+            "numchild='1'}]")
+         << generateQStringSpec(N(index3.internalId()))
+         << ptrToBa(&m2),
+        &index3, NS"QModelIndex", true);
+
+
+    // Case 4: ModelIndex with a parent.
+    index = m2.index(0, 0, index3);
+    testDumper(QByteArray("type='$T',value='(0, 0)',numchild='5',children=["
+        "{name='row',value='0',type='int',numchild='0'},"
+        "{name='column',value='0',type='int',numchild='0'},"
+        "{name='parent',value='(1, 0)',exp='(('$T'*)$A)->parent()',"
+            "type='$T',numchild='1'},"
+        "{name='internalId',%},"
+        "{name='model',value='%',type='"NS"QAbstractItemModel*',"
+            "numchild='1'}]")
+         << generateQStringSpec(N(index.internalId()))
+         << ptrToBa(&m2),
+        &index, NS"QModelIndex", true);
+
+
+    // Case 5: Empty ModelIndex
+    QModelIndex index4;
+    testDumper("type='$T',value='<invalid>',numchild='0'",
+        &index4, NS"QModelIndex", true);
+}
+
+void tst_Gdb::dumpQAbstractItemModelHelper(QAbstractItemModel &m)
+{
+    QByteArray address = ptrToBa(&m);
+    QByteArray expected = QByteArray("tiname='iname',addr='%',"
+        "type='"NS"QAbstractItemModel',value='(%,%)',numchild='1',children=["
+        "{numchild='1',name='"NS"QObject',addr='%',value='%',"
+        "valueencoded='2',type='"NS"QObject',displayedtype='%'}")
+            << address
+            << N(m.rowCount())
+            << N(m.columnCount())
+            << address
+            << utfToBase64(m.objectName())
+            << m.metaObject()->className();
+
+    for (int row = 0; row < m.rowCount(); ++row) {
+        for (int column = 0; column < m.columnCount(); ++column) {
+            QModelIndex mi = m.index(row, column);
+            expected.append(QByteArray(",{name='[%,%]',value='%',"
+                "valueencoded='2',numchild='1',addr='$%,%,%,%',"
+                "type='"NS"QAbstractItem'}")
+                << N(row)
+                << N(column)
+                << utfToBase64(m.data(mi).toString())
+                << N(mi.row())
+                << N(mi.column())
+                << ptrToBa(mi.internalPointer())
+                << ptrToBa(mi.model()));
+        }
+    }
+    expected.append("]");
+    testDumper(expected, &m, NS"QAbstractItemModel", true);
+}
+
+void tst_Gdb::dumpQAbstractItemModel()
+{
+    // Case 1: No rows, one column.
+    QStringList strList;
+    QStringListModel model(strList);
+    dumpQAbstractItemModelHelper(model);
+
+    // Case 2: One row, one column.
+    strList << "String 1";
+    model.setStringList(strList);
+    dumpQAbstractItemModelHelper(model);
+
+    // Case 3: Two rows, one column.
+    strList << "String 2";
+    model.setStringList(strList);
+    dumpQAbstractItemModelHelper(model);
+
+    // Case 4: No rows, two columns.
+    QStandardItemModel model2(0, 2);
+    dumpQAbstractItemModelHelper(model2);
+
+    // Case 5: One row, two columns.
+    QStandardItem item1("Item (0,0)");
+    QStandardItem item2("(Item (0,1)");
+    model2.appendRow(QList<QStandardItem *>() << &item1 << &item2);
+    dumpQAbstractItemModelHelper(model2);
+
+    // Case 6: Two rows, two columns
+    QStandardItem item3("Item (1,0");
+    QStandardItem item4("Item (1,1)");
+    model2.appendRow(QList<QStandardItem *>() << &item3 << &item4);
+    dumpQAbstractItemModelHelper(model);
+}
+
+void tst_Gdb::dumpQByteArray()
+{
+    // Case 1: Empty object.
+    QByteArray ba;
+    testDumper("value='',valueencoded='1',type='"NS"QByteArray',numchild='0',"
+            "childtype='char',childnumchild='0',children=[]",
+        &ba, NS"QByteArray", true);
+
+    // Case 2: One element.
+    ba.append('a');
+    testDumper("value='YQ==',valueencoded='1',type='"NS"QByteArray',numchild='1',"
+            "childtype='char',childnumchild='0',children=[{value='61  (97 'a')'}]",
+        &ba, NS"QByteArray", true);
+
+    // Case 3: Two elements.
+    ba.append('b');
+    testDumper("value='YWI=',valueencoded='1',type='"NS"QByteArray',numchild='2',"
+            "childtype='char',childnumchild='0',children=["
+            "{value='61  (97 'a')'},{value='62  (98 'b')'}]",
+        &ba, NS"QByteArray", true);
+
+    // Case 4: > 100 elements.
+    ba = QByteArray(101, 'a');
+    QByteArray children;
+    for (int i = 0; i < 101; i++)
+        children.append("{value='61  (97 'a')'},");
+    children.chop(1);
+    testDumper(QByteArray("value='YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh"
+            "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh"
+            "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYQ== <size: 101, cut...>',"
+            "valueencoded='1',type='"NS"QByteArray',numchild='101',"
+            "childtype='char',childnumchild='0',children=[%]") << children,
+        &ba, NS"QByteArray", true);
+
+    // Case 5: Regular and special characters and the replacement character.
+    ba = QByteArray("abc\a\n\r\e\'\"?");
+    testDumper("value='YWJjBwoNGyciPw==',valueencoded='1',type='"NS"QByteArray',"
+            "numchild='10',childtype='char',childnumchild='0',children=["
+            "{value='61  (97 'a')'},{value='62  (98 'b')'},"
+            "{value='63  (99 'c')'},{value='07  (7 '?')'},"
+            "{value='0a  (10 '?')'},{value='0d  (13 '?')'},"
+            "{value='1b  (27 '?')'},{value='27  (39 '?')'},"
+            "{value='22  (34 '?')'},{value='3f  (63 '?')'}]",
+        &ba, NS"QByteArray", true);
+}
+
+void tst_Gdb::dumpQChar()
+{
+    // Case 1: Printable ASCII character.
+    QChar c('X');
+    testDumper("value=''X', ucs=88',numchild='0'",
+        &c, NS"QChar", false);
+
+    // Case 2: Printable non-ASCII character.
+    c = QChar(0x600);
+    testDumper("value=''?', ucs=1536',numchild='0'",
+        &c, NS"QChar", false);
+
+    // Case 3: Non-printable ASCII character.
+    c = QChar::fromAscii('\a');
+    testDumper("value=''?', ucs=7',numchild='0'",
+        &c, NS"QChar", false);
+
+    // Case 4: Non-printable non-ASCII character.
+    c = QChar(0x9f);
+    testDumper("value=''?', ucs=159',numchild='0'",
+        &c, NS"QChar", false);
+
+    // Case 5: Printable ASCII Character that looks like the replacement character.
+    c = QChar::fromAscii('?');
+    testDumper("value=''?', ucs=63',numchild='0'",
+        &c, NS"QChar", false);
+}
+
+void tst_Gdb::dumpQDateTimeHelper(const QDateTime &d)
+{
+    QByteArray value;
+    if (d.isNull())
+        value = "value='(null)'";
+    else 
+        value = QByteArray("value='%',valueencoded='2'")
+            << utfToBase64(d.toString());
+
+    QByteArray expected = QByteArray("%,type='$T',numchild='3',children=["
+        "{name='isNull',%},"
+        "{name='toTime_t',%},"
+        "{name='toString',%},"
+        "{name='toString_(ISO)',%},"
+        "{name='toString_(SystemLocale)',%},"
+        "{name='toString_(Locale)',%}]")
+            << value
+            << generateBoolSpec(d.isNull())
+            << generateLongSpec((d.toTime_t()))
+            << generateQStringSpec(d.toString())
+            << generateQStringSpec(d.toString(Qt::ISODate))
+            << generateQStringSpec(d.toString(Qt::SystemLocaleDate))
+            << generateQStringSpec(d.toString(Qt::LocaleDate));
+    testDumper(expected, &d, NS"QDateTime", true);
+}
+
+void tst_Gdb::dumpQDateTime()
+{
+    // Case 1: Null object.
+    QDateTime d;
+    dumpQDateTimeHelper(d);
+
+    // Case 2: Non-null object.
+    d = QDateTime::currentDateTime();
+    dumpQDateTimeHelper(d);
+}
+
+void tst_Gdb::dumpQDir()
+{
+    // Case 1: Current working directory.
+    QDir dir = QDir::current();
+    testDumper(QByteArray("value='%',valueencoded='2',type='"NS"QDir',numchild='3',"
+        "children=[{name='absolutePath',%},{name='canonicalPath',%}]")
+            << utfToBase64(dir.absolutePath())
+            << generateQStringSpec(dir.absolutePath())
+            << generateQStringSpec(dir.canonicalPath()),
+        &dir, NS"QDir", true);
+
+    // Case 2: Root directory.
+    dir = QDir::root();
+    testDumper(QByteArray("value='%',valueencoded='2',type='"NS"QDir',numchild='3',"
+        "children=[{name='absolutePath',%},{name='canonicalPath',%}]")
+            << utfToBase64(dir.absolutePath())
+            << generateQStringSpec(dir.absolutePath())
+            << generateQStringSpec(dir.canonicalPath()),
+        &dir, NS"QDir", true);
+}
+
+void tst_Gdb::dumpQFileHelper(const QString &name, bool exists)
+{
+    QFile file(name);
+    QByteArray filenameAsBase64 = utfToBase64(name);
+    testDumper(QByteArray("value='%',valueencoded='2',type='$T',numchild='2',"
+        "children=[{name='fileName',value='%',type='"NS"QString',"
+        "numchild='0',valueencoded='2'},"
+        "{name='exists',value=%,type='bool',numchild='0'}]")
+            << filenameAsBase64 << filenameAsBase64 << boolToVal(exists),
+        &file, NS"QFile", true);
+}
+
+void tst_Gdb::dumpQFile()
+{
+    // Case 1: Empty file name => Does not exist.
+    dumpQFileHelper("", false);
+
+    // Case 2: File that is known to exist.
+    QTemporaryFile file;
+    file.open();
+    dumpQFileHelper(file.fileName(), true);
+
+    // Case 3: File with a name that most likely does not exist.
+    dumpQFileHelper("jfjfdskjdflsdfjfdls", false);
+}
+
+void tst_Gdb::dumpQFileInfo()
+{
+    QFileInfo fi(".");
+    QByteArray expected("value='%',valueencoded='2',type='$T',numchild='3',"
+        "children=["
+        "{name='absolutePath',%},"
+        "{name='absoluteFilePath',%},"
+        "{name='canonicalPath',%},"
+        "{name='canonicalFilePath',%},"
+        "{name='completeBaseName',%},"
+        "{name='completeSuffix',%},"
+        "{name='baseName',%},"
+#ifdef QX
+        "{name='isBundle',%},"
+        "{name='bundleName',%},"
+#endif
+        "{name='fileName',%},"
+        "{name='filePath',%},"
+        "{name='group',%},"
+        "{name='owner',%},"
+        "{name='path',%},"
+        "{name='groupid',%},"
+        "{name='ownerid',%},"
+        "{name='permissions',%},"
+        "{name='caching',%},"
+        "{name='exists',%},"
+        "{name='isAbsolute',%},"
+        "{name='isDir',%},"
+        "{name='isExecutable',%},"
+        "{name='isFile',%},"
+        "{name='isHidden',%},"
+        "{name='isReadable',%},"
+        "{name='isRelative',%},"
+        "{name='isRoot',%},"
+        "{name='isSymLink',%},"
+        "{name='isWritable',%},"
+        "{name='created',value='%',valueencoded='2',%,"
+            "type='"NS"QDateTime',numchild='1'},"
+        "{name='lastModified',value='%',valueencoded='2',%,"
+            "type='"NS"QDateTime',numchild='1'},"
+        "{name='lastRead',value='%',valueencoded='2',%,"
+            "type='"NS"QDateTime',numchild='1'}]");
+
+    expected <<= utfToBase64(fi.filePath());
+    expected <<= generateQStringSpec(fi.absolutePath());
+    expected <<= generateQStringSpec(fi.absoluteFilePath());
+    expected <<= generateQStringSpec(fi.canonicalPath());
+    expected <<= generateQStringSpec(fi.canonicalFilePath());
+    expected <<= generateQStringSpec(fi.completeBaseName());
+    expected <<= generateQStringSpec(fi.completeSuffix());
+    expected <<= generateQStringSpec(fi.baseName());
+#ifdef Q_OS_MACX
+    expected <<= generateBoolSpec(fi.isBundle());
+    expected <<= generateQStringSpec(fi.bundleName());
+#endif
+    expected <<= generateQStringSpec(fi.fileName());
+    expected <<= generateQStringSpec(fi.filePath());
+    expected <<= generateQStringSpec(fi.group());
+    expected <<= generateQStringSpec(fi.owner());
+    expected <<= generateQStringSpec(fi.path());
+    expected <<= generateLongSpec(fi.groupId());
+    expected <<= generateLongSpec(fi.ownerId());
+    expected <<= generateLongSpec(fi.permissions());
+    expected <<= generateBoolSpec(fi.caching());
+    expected <<= generateBoolSpec(fi.exists());
+    expected <<= generateBoolSpec(fi.isAbsolute());
+    expected <<= generateBoolSpec(fi.isDir());
+    expected <<= generateBoolSpec(fi.isExecutable());
+    expected <<= generateBoolSpec(fi.isFile());
+    expected <<= generateBoolSpec(fi.isHidden());
+    expected <<= generateBoolSpec(fi.isReadable());
+    expected <<= generateBoolSpec(fi.isRelative());
+    expected <<= generateBoolSpec(fi.isRoot());
+    expected <<= generateBoolSpec(fi.isSymLink());
+    expected <<= generateBoolSpec(fi.isWritable());
+    expected <<= utfToBase64(fi.created().toString());
+    expected <<= createExp(&fi, "QFileInfo", "created()");
+    expected <<= utfToBase64(fi.lastModified().toString());
+    expected <<= createExp(&fi, "QFileInfo", "lastModified()");
+    expected <<= utfToBase64(fi.lastRead().toString());
+    expected <<= createExp(&fi, "QFileInfo", "lastRead()");
+
+    testDumper(expected, &fi, NS"QFileInfo", true);
+}
+
+void tst_Gdb::dumpQHash()
+{
+    QHash<QString, QList<int> > hash;
+    hash.insert("Hallo", QList<int>());
+    hash.insert("Welt", QList<int>() << 1);
+    hash.insert("!", QList<int>() << 1 << 2);
+    hash.insert("!", QList<int>() << 1 << 2);
+}
+
+template <typename K, typename V>
+void tst_Gdb::dumpQHashNodeHelper(QHash<K, V> &hash)
+{
+    typename QHash<K, V>::iterator it = hash.begin();
+    typedef QHashNode<K, V> HashNode;
+    HashNode *dummy = 0;
+    HashNode *node =
+        reinterpret_cast<HashNode *>(reinterpret_cast<char *>(const_cast<K *>(&it.key())) -
+            size_t(&dummy->key));
+    const K &key = it.key();
+    const V &val = it.value();
+    QByteArray expected("value='");
+    if (isSimpleType<V>())
+        expected.append(valToString(val));
+    expected.append("',numchild='2',children=[{name='key',type='").
+        append(typeToString<K>()).append("',addr='").append(ptrToBa(&key)).
+        append("'},{name='value',type='").append(typeToString<V>()).
+        append("',addr='").append(ptrToBa(&val)).append("'}]");
+    testDumper(expected, node, NS"QHashNode", true,
+        getMapType<K, V>(), "", sizeof(it.key()), sizeof(it.value()));
+}
+
+void tst_Gdb::dumpQHashNode()
+{
+    // Case 1: simple type -> simple type.
+    QHash<int, int> hash1;
+    hash1[2] = 3;
+    dumpQHashNodeHelper(hash1);
+
+    // Case 2: simple type -> composite type.
+    QHash<int, QString> hash2;
+    hash2[5] = "String 7";
+    dumpQHashNodeHelper(hash2);
+
+    // Case 3: composite type -> simple type
+    QHash<QString, int> hash3;
+    hash3["String 11"] = 13;
+    dumpQHashNodeHelper(hash3);
+
+    // Case 4: composite type -> composite type
+    QHash<QString, QString> hash4;
+    hash4["String 17"] = "String 19";
+    dumpQHashNodeHelper(hash4);
+}
+
+void tst_Gdb::dumpQImageHelper(const QImage &img)
+{
+    QByteArray expected = "value='(%x%)',type='"NS"QImage',numchild='1',"
+        "children=[{name='data',type='"NS"QImageData',addr='%'}]"
+            << N(img.width())
+            << N(img.height())
+            << ptrToBa(&img);
+    testDumper(expected, &img, NS"QImage", true);
+}
+
+void tst_Gdb::dumpQImage()
+{
+    // Case 1: Null image.
+    QImage img;
+    dumpQImageHelper(img);
+
+    // Case 2: Normal image.
+    img = QImage(3, 700, QImage::Format_RGB555);
+    dumpQImageHelper(img);
+
+    // Case 3: Invalid image.
+    img = QImage(100, 0, QImage::Format_Invalid);
+    dumpQImageHelper(img);
+}
+
+void tst_Gdb::dumpQImageDataHelper(QImage &img)
+{
+    const QByteArray ba(QByteArray::fromRawData((const char*) img.bits(), img.numBytes()));
+    QByteArray expected = QByteArray("tiname='$I',addr='$A',type='"NS"QImageData',").
+        append("numchild='0',value='<hover here>',valuetooltipencoded='1',").
+        append("valuetooltipsize='").append(N(ba.size())).append("',").
+        append("valuetooltip='").append(ba.toBase64()).append("'");
+    testDumper(expected, &img, NS"QImageData", false);
+}
+
+void tst_Gdb::dumpQImageData()
+{
+    // Case 1: Null image.
+    QImage img;
+    dumpQImageDataHelper(img);
+
+    // Case 2: Normal image.
+    img = QImage(3, 700, QImage::Format_RGB555);
+    dumpQImageDataHelper(img);
+
+    // Case 3: Invalid image.
+    img = QImage(100, 0, QImage::Format_Invalid);
+    dumpQImageDataHelper(img);
+}
+
+template <typename T>
+        void tst_Gdb::dumpQLinkedListHelper(QLinkedList<T> &l)
+{
+    const int size = qMin(l.size(), 1000);
+    const QString &sizeStr = N(size);
+    const QByteArray elemTypeStr = typeToString<T>();
+    QByteArray expected = QByteArray("value='<").append(sizeStr).
+        append(" items>',valuedisabled='true',numchild='").append(sizeStr).
+        append("',childtype='").append(elemTypeStr).append("',childnumchild='").
+        append(typeToNumchild<T>()).append("',children=[");
+    typename QLinkedList<T>::const_iterator iter = l.constBegin();
+    for (int i = 0; i < size; ++i, ++iter) {
+        expected.append("{");
+        const T &curElem = *iter;
+        if (isPointer<T>()) {
+            const QString typeStr = stripPtrType(typeToString<T>());
+            const QByteArray addrStr = valToString(curElem);
+            if (curElem != 0) {
+                expected.append("addr='").append(addrStr).append("',saddr='").
+                        append(addrStr).append("',type='").append(typeStr).
+                        append("',value='").
+                        append(derefValToString(curElem)).append("'");
+            } else {
+                expected.append("addr='").append(ptrToBa(&curElem)).append("',type='").
+                    append(typeStr).append("',value='<null>',numchild='0'");
+            }
+        } else {
+            expected.append("addr='").append(ptrToBa(&curElem)).
+                append("',value='").append(valToString(curElem)).append("'");
+        }
+        expected.append("}");
+        if (i < size - 1)
+            expected.append(",");
+    }
+    if (size < l.size())
+        expected.append(",...");
+    expected.append("]");
+    testDumper(expected, &l, NS"QLinkedList", true, elemTypeStr);
+}
+
+void tst_Gdb::dumpQLinkedList()
+{
+    // Case 1: Simple element type.
+    QLinkedList<int> l;
+
+    // Case 1.1: Empty list.
+    dumpQLinkedListHelper(l);
+
+    // Case 1.2: One element.
+    l.append(2);
+    dumpQLinkedListHelper(l);
+
+    // Case 1.3: Two elements
+    l.append(3);
+    dumpQLinkedListHelper(l);
+
+    // Case 2: Composite element type.
+    QLinkedList<QString> l2;
+
+    // Case 2.1: Empty list.
+    dumpQLinkedListHelper(l2);
+
+    // Case 2.2: One element.
+    l2.append("Teststring 1");
+    dumpQLinkedListHelper(l2);
+
+    // Case 2.3: Two elements.
+    l2.append("Teststring 2");
+    dumpQLinkedListHelper(l2);
+
+    // Case 2.4: > 1000 elements.
+    for (int i = 3; i <= 1002; ++i)
+        l2.append("Test " + N(i));
+
+    // Case 3: Pointer type.
+    QLinkedList<int *> l3;
+    l3.append(new int(5));
+    l3.append(new int(7));
+    l3.append(0);
+    dumpQLinkedListHelper(l3);
+}
+
+    #if 0
+    void tst_Gdb::dumpQLinkedList()
+    {
+        // Case 1: Simple element type.
+        QLinkedList<int> l;
+
+        // Case 1.1: Empty list.
+        testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+            "childtype='int',childnumchild='0',children=[]",
+            &l, NS"QLinkedList", true, "int");
+
+        // Case 1.2: One element.
+        l.append(2);
+        testDumper("value='<1 items>',valuedisabled='true',numchild='1',"
+            "childtype='int',childnumchild='0',children=[{addr='%',value='2'}]"
+                << ptrToBa(l.constBegin().operator->()),
+            &l, NS"QLinkedList", true, "int");
+
+        // Case 1.3: Two elements
+        l.append(3);
+        QByteArray it0 = ptrToBa(l.constBegin().operator->());
+        QByteArray it1 = ptrToBa(l.constBegin().operator++().operator->());
+        testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+            "childtype='int',childnumchild='0',children=[{addr='%',value='2'},"
+            "{addr='%',value='3'}]" << it0 << it1,
+            &l, NS"QLinkedList", true, "int");
+
+        // Case 2: Composite element type.
+        QLinkedList<QString> l2;
+        QLinkedList<QString>::const_iterator iter;
+
+        // Case 2.1: Empty list.
+        testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+            "childtype='"NS"QString',childnumchild='0',children=[]",
+            &l2, NS"QLinkedList", true, NS"QString");
+
+        // Case 2.2: One element.
+        l2.append("Teststring 1");
+        iter = l2.constBegin();
+        qDebug() << *iter;
+        testDumper("value='<1 items>',valuedisabled='true',numchild='1',"
+            "childtype='"NS"QString',childnumchild='0',children=[{addr='%',value='%',}]"
+                << ptrToBa(iter.operator->()) << utfToBase64(*iter),
+            &l2, NS"QLinkedList", true, NS"QString");
+
+        // Case 2.3: Two elements.
+        QByteArray expected = "value='<2 items>',valuedisabled='true',numchild='2',"
+            "childtype='int',childnumchild='0',children=[";
+        iter = l2.constBegin();
+        expected.append("{addr='%',%},"
+            << ptrToBa(iter.operator->()) << utfToBase64(*iter));
+        ++iter;
+        expected.append("{addr='%',%}]"
+            << ptrToBa(iter.operator->()) << utfToBase64(*iter));
+        testDumper(expected,
+            &l, NS"QLinkedList", true, NS"QString");
+
+        // Case 2.4: > 1000 elements.
+        for (int i = 3; i <= 1002; ++i)
+            l2.append("Test " + N(i));
+
+        expected = "value='<1002 items>',valuedisabled='true',"
+            "numchild='1002',childtype='"NS"QString',childnumchild='0',children=['";
+        iter = l2.constBegin();
+        for (int i = 0; i < 1002; ++i, ++iter)
+            expected.append("{addr='%',value='%'},"
+                << ptrToBa(iter.operator->()) << utfToBase64(*iter));
+        expected.append(",...]");
+        testDumper(expected, &l, NS"QLinkedList", true, NS"QString");
+
+
+        // Case 3: Pointer type.
+        QLinkedList<int *> l3;
+        l3.append(new int(5));
+        l3.append(new int(7));
+        l3.append(0);
+        //dumpQLinkedListHelper(l3);
+        testDumper("", &l, NS"QLinkedList", true, NS"QString");
+    }
+    #endif
+
+void tst_Gdb::dumpQList_int()
+{
+    QList<int> ilist;
+    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+        "internal='1',children=[]",
+        &ilist, NS"QList", true, "int");
+    ilist.append(1);
+    ilist.append(2);
+    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+        "internal='1',childtype='int',childnumchild='0',children=["
+        "{addr='" + str(&ilist.at(0)) + "',value='1'},"
+        "{addr='" + str(&ilist.at(1)) + "',value='2'}]",
+        &ilist, NS"QList", true, "int");
+}
+
+void tst_Gdb::dumpQList_char()
+{
+    QList<char> clist;
+    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+        "internal='1',children=[]",
+        &clist, NS"QList", true, "char");
+    clist.append('a');
+    clist.append('b');
+    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+        "internal='1',childtype='char',childnumchild='0',children=["
+        "{addr='" + str(&clist.at(0)) + "',value=''a', ascii=97'},"
+        "{addr='" + str(&clist.at(1)) + "',value=''b', ascii=98'}]",
+        &clist, NS"QList", true, "char");
+}
+
+void tst_Gdb::dumpQList_QString()
+{
+    QList<QString> slist;
+    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+        "internal='1',children=[]",
+        &slist, NS"QList", true, NS"QString");
+    slist.append("a");
+    slist.append("b");
+    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+        "internal='1',childtype='"NS"QString',childnumchild='0',children=["
+        "{addr='" + str(&slist.at(0)) + "',value='YQA=',valueencoded='2'},"
+        "{addr='" + str(&slist.at(1)) + "',value='YgA=',valueencoded='2'}]",
+        &slist, NS"QList", true, NS"QString");
+}
+
+void tst_Gdb::dumpQList_Int3()
+{
+    QList<Int3> i3list;
+    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+        "internal='0',children=[]",
+        &i3list, NS"QList", true, "Int3");
+    i3list.append(Int3());
+    i3list.append(Int3());
+    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+        "internal='0',childtype='Int3',children=["
+        "{addr='" + str(&i3list.at(0)) + "'},"
+        "{addr='" + str(&i3list.at(1)) + "'}]",
+        &i3list, NS"QList", true, "Int3");
+}
+
+void tst_Gdb::dumpQList_QString3()
+{
+    QList<QString3> s3list;
+    testDumper("value='<0 items>',valuedisabled='true',numchild='0',"
+        "internal='0',children=[]",
+        &s3list, NS"QList", true, "QString3");
+    s3list.append(QString3());
+    s3list.append(QString3());
+    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+        "internal='0',childtype='QString3',children=["
+        "{addr='" + str(&s3list.at(0)) + "'},"
+        "{addr='" + str(&s3list.at(1)) + "'}]",
+        &s3list, NS"QList", true, "QString3");
+}
+
+void tst_Gdb::dumpQLocaleHelper(QLocale &loc)
+{
+    QByteArray expected = QByteArray("value='%',type='$T',numchild='8',"
+            "children=[{name='country',%},"
+            "{name='language',%},"
+            "{name='measurementSystem',%},"
+            "{name='numberOptions',%},"
+            "{name='timeFormat_(short)',%},"
+            "{name='timeFormat_(long)',%},"
+            "{name='decimalPoint',%},"
+            "{name='exponential',%},"
+            "{name='percent',%},"
+            "{name='zeroDigit',%},"
+            "{name='groupSeparator',%},"
+            "{name='negativeSign',%}]")
+        << valToString(loc.name())
+        << createExp(&loc, "QLocale", "country()")
+        << createExp(&loc, "QLocale", "language()")
+        << createExp(&loc, "QLocale", "measurementSystem()")
+        << createExp(&loc, "QLocale", "numberOptions()")
+        << generateQStringSpec(loc.timeFormat(QLocale::ShortFormat))
+        << generateQStringSpec(loc.timeFormat())
+        << generateQCharSpec(loc.decimalPoint())
+        << generateQCharSpec(loc.exponential())
+        << generateQCharSpec(loc.percent())
+        << generateQCharSpec(loc.zeroDigit())
+        << generateQCharSpec(loc.groupSeparator())
+        << generateQCharSpec(loc.negativeSign());
+    testDumper(expected, &loc, NS"QLocale", true);
+}
+
+void tst_Gdb::dumpQLocale()
+{
+    QLocale english(QLocale::English);
+    dumpQLocaleHelper(english);
+
+    QLocale german(QLocale::German);
+    dumpQLocaleHelper(german);
+
+    QLocale chinese(QLocale::Chinese);
+    dumpQLocaleHelper(chinese);
+
+    QLocale swahili(QLocale::Swahili);
+    dumpQLocaleHelper(swahili);
+}
+
+template <typename K, typename V>
+        void tst_Gdb::dumpQMapHelper(QMap<K, V> &map)
+{
+    QByteArray sizeStr(valToString(map.size()));
+    size_t nodeSize;
+    size_t valOff;
+    getMapNodeParams<K, V>(nodeSize, valOff);
+    int transKeyOffset = static_cast<int>(2*sizeof(void *)) - static_cast<int>(nodeSize);
+    int transValOffset = transKeyOffset + valOff;
+    bool simpleKey = isSimpleType<K>();
+    bool simpleVal = isSimpleType<V>();
+    QByteArray expected = QByteArray("value='<").append(sizeStr).append(" items>',numchild='").
+        append(sizeStr).append("',extra='simplekey: ").append(N(simpleKey)).
+        append(" isSimpleValue: ").append(N(simpleVal)).
+        append(" keyOffset: ").append(N(transKeyOffset)).append(" valueOffset: ").
+        append(N(transValOffset)).append(" mapnodesize: ").
+        append(N(qulonglong(nodeSize))).append("',children=["); // 64bit Linux hack
+    typedef typename QMap<K, V>::iterator mapIter;
+    for (mapIter it = map.begin(); it != map.end(); ++it) {
+        if (it != map.begin())
+            expected.append(",");
+        const QByteArray keyString =
+            QByteArray(valToString(it.key())).replace("valueencoded","keyencoded");
+        expected.append("{key='").append(keyString).append("',value='").
+            append(valToString(it.value())).append("',");
+        if (simpleKey && simpleVal) {
+            expected.append("type='").append(typeToString<V>()).
+                append("',addr='").append(ptrToBa(&it.value())).append("'");
+        } else {
+            QByteArray keyTypeStr = typeToString<K>();
+            QByteArray valTypeStr = typeToString<V>();
+#if QT_VERSION >= 0x040500
+            expected.append("addr='").
+                append(ptrToBa(reinterpret_cast<char *>(&(*it)) + sizeof(V))).
+                append("',type='"NS"QMapNode<").append(keyTypeStr).append(",").
+                append(valTypeStr).append(MAP_NODE_TYPE_END).append("'");
+#else
+            expected.append("type='"NS"QMapData::Node<").append(keyTypeStr).
+                append(",").append(valTypeStr).append(MAP_NODE_TYPE_END).
+                append("',exp='*('"NS"QMapData::Node<").append(keyTypeStr).
+                append(",").append(valTypeStr).append(MAP_NODE_TYPE_END).
+                append(" >'*)").append(ptrToBa(&(*it))).append("'");
+#endif
+        }
+        expected.append("}");
+    }
+    expected.append("]");
+    mapIter it = map.begin();
+    testDumper(expected, *reinterpret_cast<QMapData **>(&it), NS"QMap",
+               true, getMapType<K,V>(), "", 0, 0, nodeSize, valOff);
+}
+
+void tst_Gdb::dumpQMap()
+{
+    // Case 1: Simple type -> simple type.
+    QMap<int, int> map1;
+
+    // Case 1.1: Empty map.
+    dumpQMapHelper(map1);
+
+    // Case 1.2: One element.
+    map1[2] = 3;
+    dumpQMapHelper(map1);
+
+    // Case 1.3: Two elements.
+    map1[3] = 5;
+    dumpQMapHelper(map1);
+
+    // Case 2: Simple type -> composite type.
+    QMap<int, QString> map2;
+
+    // Case 2.1: Empty Map.
+    dumpQMapHelper(map2);
+
+    // Case 2.2: One element.
+    map2[5] = "String 7";
+    dumpQMapHelper(map2);
+
+    // Case 2.3: Two elements.
+    map2[7] = "String 11";
+    dumpQMapHelper(map2);
+
+    // Case 3: Composite type -> simple type.
+    QMap<QString, int> map3;
+
+    // Case 3.1: Empty map.
+    dumpQMapHelper(map3);
+
+    // Case 3.2: One element.
+    map3["String 13"] = 11;
+    dumpQMapHelper(map3);
+
+    // Case 3.3: Two elements.
+    map3["String 17"] = 13;
+    dumpQMapHelper(map3);
+
+    // Case 4: Composite type -> composite type.
+    QMap<QString, QString> map4;
+
+    // Case 4.1: Empty map.
+    dumpQMapHelper(map4);
+
+    // Case 4.2: One element.
+    map4["String 19"] = "String 23";
+    dumpQMapHelper(map4);
+
+    // Case 4.3: Two elements.
+    map4["String 29"] = "String 31";
+    dumpQMapHelper(map4);
+
+    // Case 4.4: Different value, same key (multimap functionality).
+    map4["String 29"] = "String 37";
+    dumpQMapHelper(map4);
+}
+
+template <typename K, typename V>
+        void tst_Gdb::dumpQMapNodeHelper(QMap<K, V> &m)
+{
+    typename QMap<K, V>::iterator it = m.begin();
+    const K &key = it.key();
+    const V &val = it.value();
+    //const char * const keyType = typeToString(key);
+    QByteArray expected = QByteArray("value='',numchild='2',"
+        "children=[{name='key',addr='").append(ptrToBa(&key)).
+        append("',type='").append(typeToString<K>()).append("',value='").
+        append(valToString(key)).append("'},{name='value',addr='").
+        append(ptrToBa(&val)).append("',type='").append(typeToString<V>()).
+        append("',value='").append(valToString(val)).
+        append("'}]");
+    size_t nodeSize;
+    size_t valOffset;
+    getMapNodeParams<K, V>(nodeSize, valOffset);
+    testDumper(expected, *reinterpret_cast<QMapData **>(&it), NS"QMapNode",
+               true, getMapType<K,V>(), "", 0, 0, nodeSize, valOffset);
+}
+
+void tst_Gdb::dumpQMapNode()
+{
+    // Case 1: simple type -> simple type.
+    QMap<int, int> map;
+    map[2] = 3;
+    dumpQMapNodeHelper(map);
+
+    // Case 2: simple type -> composite type.
+    QMap<int, QString> map2;
+    map2[3] = "String 5";
+    dumpQMapNodeHelper(map2);
+
+    // Case 3: composite type -> simple type.
+    QMap<QString, int> map3;
+    map3["String 7"] = 11;
+    dumpQMapNodeHelper(map3);
+
+    // Case 4: composite type -> composite type.
+    QMap<QString, QString> map4;
+    map4["String 13"] = "String 17";
+    dumpQMapNodeHelper(map4);
+}
+
+void tst_Gdb::dumpQObject()
+{
+    QObject parent;
+    testDumper("value='',valueencoded='2',type='$T',displayedtype='QObject',"
+        "numchild='4'",
+        &parent, NS"QObject", false);
+    testDumper("value='',valueencoded='2',type='$T',displayedtype='QObject',"
+        "numchild='4',children=["
+        "{name='properties',addr='$A',type='$TPropertyList',"
+            "value='<1 items>',numchild='1'},"
+        "{name='signals',addr='$A',type='$TSignalList',"
+            "value='<2 items>',numchild='2'},"
+        "{name='slots',addr='$A',type='$TSlotList',"
+            "value='<2 items>',numchild='2'},"
+        "{name='parent',value='0x0',type='$T *',numchild='0'},"
+        "{name='className',value='QObject',type='',numchild='0'}]",
+        &parent, NS"QObject", true);
+
+#if 0
+    testDumper("numchild='2',value='<2 items>',type='QObjectSlotList',"
+            "children=[{name='2',value='deleteLater()',"
+            "numchild='0',addr='$A',type='QObjectSlot'},"
+        "{name='3',value='_q_reregisterTimers(void*)',"
+            "numchild='0',addr='$A',type='QObjectSlot'}]",
+        &parent, NS"QObjectSlotList", true);
+#endif
+
+    parent.setObjectName("A Parent");
+    testDumper("value='QQAgAFAAYQByAGUAbgB0AA==',valueencoded='2',type='$T',"
+        "displayedtype='QObject',numchild='4'",
+        &parent, NS"QObject", false);
+    QObject child(&parent);
+    testDumper("value='',valueencoded='2',type='$T',"
+        "displayedtype='QObject',numchild='4'",
+        &child, NS"QObject", false);
+    child.setObjectName("A Child");
+    QByteArray ba ="value='QQAgAEMAaABpAGwAZAA=',valueencoded='2',type='$T',"
+        "displayedtype='QObject',numchild='4',children=["
+        "{name='properties',addr='$A',type='$TPropertyList',"
+            "value='<1 items>',numchild='1'},"
+        "{name='signals',addr='$A',type='$TSignalList',"
+            "value='<2 items>',numchild='2'},"
+        "{name='slots',addr='$A',type='$TSlotList',"
+            "value='<2 items>',numchild='2'},"
+        "{name='parent',addr='" + str(&parent) + "',"
+            "value='QQAgAFAAYQByAGUAbgB0AA==',valueencoded='2',type='$T',"
+            "displayedtype='QObject',numchild='1'},"
+        "{name='className',value='QObject',type='',numchild='0'}]";
+    testDumper(ba, &child, NS"QObject", true);
+    connect(&child, SIGNAL(destroyed()), qApp, SLOT(quit()));
+    testDumper(ba, &child, NS"QObject", true);
+    disconnect(&child, SIGNAL(destroyed()), qApp, SLOT(quit()));
+    testDumper(ba, &child, NS"QObject", true);
+    child.setObjectName("A renamed Child");
+    testDumper("value='QQAgAHIAZQBuAGEAbQBlAGQAIABDAGgAaQBsAGQA',valueencoded='2',"
+        "type='$T',displayedtype='QObject',numchild='4'",
+        &child, NS"QObject", false);
+}
+
+void tst_Gdb::dumpQObjectChildListHelper(QObject &o)
+{
+    const QObjectList children = o.children();
+    const int size = children.size();
+    const QString sizeStr = N(size);
+    QByteArray expected = QByteArray("numchild='").append(sizeStr).append("',value='<").
+        append(sizeStr).append(" items>',type='"NS"QObjectChildList',children=[");
+    for (int i = 0; i < size; ++i) {
+        const QObject *child = children.at(i);
+        expected.append("{addr='").append(ptrToBa(child)).append("',value='").
+            append(utfToBase64(child->objectName())).
+            append("',valueencoded='2',type='"NS"QObject',displayedtype='").
+            append(child->metaObject()->className()).append("',numchild='1'}");
+        if (i < size - 1)
+            expected.append(",");
+    }
+    expected.append("]");
+    testDumper(expected, &o, NS"QObjectChildList", true);
+}
+
+void tst_Gdb::dumpQObjectChildList()
+{
+    // Case 1: Object with no children.
+    QObject o;
+    dumpQObjectChildListHelper(o);
+
+    // Case 2: Object with one child.
+    QObject o2(&o);
+    dumpQObjectChildListHelper(o);
+
+    // Case 3: Object with two children.
+    QObject o3(&o);
+    dumpQObjectChildListHelper(o);
+}
+
+void tst_Gdb::dumpQObjectMethodList()
+{
+    QStringListModel m;
+    testDumper("addr='<synthetic>',type='$T',numchild='20',"
+        "childtype='"NS"QMetaMethod::Method',childnumchild='0',children=["
+        "{name='0 0 destroyed(QObject*)',value='<Signal> (1)'},"
+        "{name='1 1 destroyed()',value='<Signal> (1)'},"
+        "{name='2 2 deleteLater()',value='<Slot> (2)'},"
+        "{name='3 3 _q_reregisterTimers(void*)',value='<Slot> (2)'},"
+        "{name='4 4 dataChanged(QModelIndex,QModelIndex)',value='<Signal> (1)'},"
+        "{name='5 5 headerDataChanged(Qt::Orientation,int,int)',value='<Signal> (1)'},"
+        "{name='6 6 layoutChanged()',value='<Signal> (1)'},"
+        "{name='7 7 layoutAboutToBeChanged()',value='<Signal> (1)'},"
+        "{name='8 8 rowsAboutToBeInserted(QModelIndex,int,int)',value='<Signal> (1)'},"
+        "{name='9 9 rowsInserted(QModelIndex,int,int)',value='<Signal> (1)'},"
+        "{name='10 10 rowsAboutToBeRemoved(QModelIndex,int,int)',value='<Signal> (1)'},"
+        "{name='11 11 rowsRemoved(QModelIndex,int,int)',value='<Signal> (1)'},"
+        "{name='12 12 columnsAboutToBeInserted(QModelIndex,int,int)',value='<Signal> (1)'},"
+        "{name='13 13 columnsInserted(QModelIndex,int,int)',value='<Signal> (1)'},"
+        "{name='14 14 columnsAboutToBeRemoved(QModelIndex,int,int)',value='<Signal> (1)'},"
+        "{name='15 15 columnsRemoved(QModelIndex,int,int)',value='<Signal> (1)'},"
+        "{name='16 16 modelAboutToBeReset()',value='<Signal> (1)'},"
+        "{name='17 17 modelReset()',value='<Signal> (1)'},"
+        "{name='18 18 submit()',value='<Slot> (2)'},"
+        "{name='19 19 revert()',value='<Slot> (2)'}]",
+    &m, NS"QObjectMethodList", true);
+}
+
+void tst_Gdb::dumpQObjectPropertyList()
+{
+    // Case 1: Model without a parent.
+    QStringListModel m(QStringList() << "Test1" << "Test2");
+    testDumper("addr='<synthetic>',type='$T',numchild='1',value='<1 items>',"
+        "children=[{name='objectName',type='QString',value='',"
+            "valueencoded='2',numchild='0'}]",
+         &m, NS"QObjectPropertyList", true);
+
+    // Case 2: Model with a parent.
+    QStringListModel m2(&m);
+    testDumper("addr='<synthetic>',type='$T',numchild='1',value='<1 items>',"
+        "children=[{name='objectName',type='QString',value='',"
+            "valueencoded='2',numchild='0'}]",
+         &m2, NS"QObjectPropertyList", true);
+}
+
+static const char *connectionType(uint type)
+{
+    Qt::ConnectionType connType = static_cast<Qt::ConnectionType>(type);
+    const char *output = "unknown";
+    switch (connType) {
+        case Qt::AutoConnection: output = "auto"; break;
+        case Qt::DirectConnection: output = "direct"; break;
+        case Qt::QueuedConnection: output = "queued"; break;
+        case Qt::BlockingQueuedConnection: output = "blockingqueued"; break;
+        case 3: output = "autocompat"; break;
+#if QT_VERSION >= 0x040600
+        case Qt::UniqueConnection: break; // Can't happen.
+#endif
+        default:
+            qWarning() << "Unknown connection type: " << type;
+            break;
+        };
+    return output;
+};
+
+class Cheater : public QObject
+{
+public:
+    static const QObjectPrivate *getPrivate(const QObject &o)
+    {
+        const Cheater &cheater = static_cast<const Cheater&>(o);
+#if QT_VERSION >= 0x040600
+        return dynamic_cast<const QObjectPrivate *>(cheater.d_ptr.data());
+#else
+        return dynamic_cast<const QObjectPrivate *>(cheater.d_ptr);
+#endif
+    }
+};
+
+typedef QVector<QObjectPrivate::ConnectionList> ConnLists;
+
+void tst_Gdb::dumpQObjectSignalHelper(QObject &o, int sigNum)
+{
+    //qDebug() << o.objectName() << sigNum;
+    QByteArray expected("addr='<synthetic>',numchild='1',type='"NS"QObjectSignal'");
+#if QT_VERSION >= 0x040400
+    expected.append(",children=[");
+    const QObjectPrivate *p = Cheater::getPrivate(o);
+    Q_ASSERT(p != 0);
+    const ConnLists *connLists = reinterpret_cast<const ConnLists *>(p->connectionLists);
+    QObjectPrivate::ConnectionList connList =
+        connLists != 0 && connLists->size() > sigNum ?
+        connLists->at(sigNum) : QObjectPrivate::ConnectionList();
+    int i = 0;
+    for (QObjectPrivate::Connection *conn = connList.first; conn != 0;
+         ++i, conn = conn->nextConnectionList) {
+        const QString iStr = N(i);
+        expected.append("{name='").append(iStr).append(" receiver',");
+        if (conn->receiver == &o)
+            expected.append("value='<this>',type='").
+                append(o.metaObject()->className()).
+                append("',numchild='0',addr='").append(ptrToBa(&o)).append("'");
+        else if (conn->receiver == 0)
+            expected.append("value='0x0',type='"NS"QObject *',numchild='0'");
+        else
+            expected.append("addr='").append(ptrToBa(conn->receiver)).append("',value='").
+                append(utfToBase64(conn->receiver->objectName())).append("',valueencoded='2',").
+                append("type='"NS"QObject',displayedtype='").
+                append(conn->receiver->metaObject()->className()).append("',numchild='1'");
+        expected.append("},{name='").append(iStr).append(" slot',type='',value='");
+        if (conn->receiver != 0)
+            expected.append(conn->receiver->metaObject()->method(conn->method).signature());
+        else
+            expected.append("<invalid receiver>");
+        expected.append("',numchild='0'},{name='").append(iStr).append(" type',type='',value='<").
+            append(connectionType(conn->connectionType)).append(" connection>',").
+            append("numchild='0'}");
+        if (conn != connList.last)
+            expected.append(",");
+    }
+    expected.append("],numchild='").append(N(i)).append("'");
+#endif
+    testDumper(expected, &o, NS"QObjectSignal", true, "", "", sigNum);
+}
+
+void tst_Gdb::dumpQObjectSignal()
+{
+    // Case 1: Simple QObject.
+    QObject o;
+    o.setObjectName("Test");
+    testDumper("addr='<synthetic>',numchild='1',type='"NS"QObjectSignal',"
+            "children=[],numchild='0'",
+        &o, NS"QObjectSignal", true, "", "", 0);
+
+    // Case 2: QAbstractItemModel with no connections.
+    QStringListModel m(QStringList() << "Test1" << "Test2");
+    for (int signalIndex = 0; signalIndex < 17; ++signalIndex)
+        dumpQObjectSignalHelper(m, signalIndex);
+
+    // Case 3: QAbstractItemModel with connections to itself and to another
+    //         object, using different connection types.
+    qRegisterMetaType<QModelIndex>("QModelIndex");
+    connect(&m, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)),
+            &o, SLOT(deleteLater()), Qt::DirectConnection);
+    connect(&m, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)),
+            &m, SLOT(revert()), Qt::QueuedConnection);
+    connect(&m, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)),
+            &m, SLOT(submit()), Qt::QueuedConnection);
+    connect(&m, SIGNAL(columnsInserted(const QModelIndex &, int, int)),
+            &m, SLOT(submit()), Qt::BlockingQueuedConnection);
+    connect(&m, SIGNAL(columnsRemoved(const QModelIndex &, int, int)),
+            &m, SLOT(deleteLater()), Qt::AutoConnection);
+#if QT_VERSION >= 0x040600
+    connect(&m, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
+            &m, SLOT(revert()), Qt::UniqueConnection);
+#endif
+    for (int signalIndex = 0; signalIndex < 17; ++signalIndex)
+        dumpQObjectSignalHelper(m, signalIndex);
+}
+
+void tst_Gdb::dumpQObjectSignalList()
+{
+    // Case 1: Simple QObject.
+    QObject o;
+    o.setObjectName("Test");
+
+    testDumper("type='"NS"QObjectSignalList',value='<2 items>',"
+                "addr='$A',numchild='2',children=["
+            "{name='0',value='destroyed(QObject*)',numchild='0',"
+                "addr='$A',type='"NS"QObjectSignal'},"
+            "{name='1',value='destroyed()',numchild='0',"
+                "addr='$A',type='"NS"QObjectSignal'}]",
+        &o, NS"QObjectSignalList", true);
+
+    // Case 2: QAbstractItemModel with no connections.
+    QStringListModel m(QStringList() << "Test1" << "Test2");
+    QByteArray expected = "type='"NS"QObjectSignalList',value='<16 items>',"
+        "addr='$A',numchild='16',children=["
+        "{name='0',value='destroyed(QObject*)',numchild='0',"
+            "addr='$A',type='"NS"QObjectSignal'},"
+        "{name='1',value='destroyed()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSignal'},"
+        "{name='4',value='dataChanged(QModelIndex,QModelIndex)',numchild='0',"
+            "addr='$A',type='"NS"QObjectSignal'},"
+        "{name='5',value='headerDataChanged(Qt::Orientation,int,int)',"
+            "numchild='0',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='6',value='layoutChanged()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSignal'},"
+        "{name='7',value='layoutAboutToBeChanged()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSignal'},"
+        "{name='8',value='rowsAboutToBeInserted(QModelIndex,int,int)',"
+            "numchild='0',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='9',value='rowsInserted(QModelIndex,int,int)',"
+            "numchild='0',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='10',value='rowsAboutToBeRemoved(QModelIndex,int,int)',"
+            "numchild='%',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='11',value='rowsRemoved(QModelIndex,int,int)',"
+            "numchild='%',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='12',value='columnsAboutToBeInserted(QModelIndex,int,int)',"
+            "numchild='%',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='13',value='columnsInserted(QModelIndex,int,int)',"
+            "numchild='%',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='14',value='columnsAboutToBeRemoved(QModelIndex,int,int)',"
+            "numchild='%',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='15',value='columnsRemoved(QModelIndex,int,int)',"
+            "numchild='%',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='16',value='modelAboutToBeReset()',"
+            "numchild='0',addr='$A',type='"NS"QObjectSignal'},"
+        "{name='17',value='modelReset()',"
+            "numchild='0',addr='$A',type='"NS"QObjectSignal'}]";
+
+    testDumper(expected << "0" << "0" << "0" << "0" << "0" << "0",
+        &m, NS"QObjectSignalList", true);
+
+
+    // Case 3: QAbstractItemModel with connections to itself and to another
+    //         object, using different connection types.
+    qRegisterMetaType<QModelIndex>("QModelIndex");
+    connect(&m, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)),
+            &o, SLOT(deleteLater()), Qt::DirectConnection);
+    connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)),
+            &m, SLOT(revert()), Qt::QueuedConnection);
+    connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)),
+            &m, SLOT(submit()), Qt::QueuedConnection);
+    connect(&m, SIGNAL(columnsInserted(QModelIndex, int, int)),
+            &m, SLOT(submit()), Qt::BlockingQueuedConnection);
+    connect(&m, SIGNAL(columnsRemoved(QModelIndex, int, int)),
+            &m, SLOT(deleteLater()), Qt::AutoConnection);
+
+    testDumper(expected << "1" << "1" << "2" << "1" << "0" << "0",
+        &m, NS"QObjectSignalList", true);
+}
+
+QByteArray slotIndexList(const QObject *ob)
+{
+    QByteArray slotIndices;
+    const QMetaObject *mo = ob->metaObject();
+    for (int i = 0; i < mo->methodCount(); ++i) {
+        const QMetaMethod &mm = mo->method(i);
+        if (mm.methodType() == QMetaMethod::Slot) {
+            int slotIndex = mo->indexOfSlot(mm.signature());
+            Q_ASSERT(slotIndex != -1);
+            slotIndices.append(N(slotIndex));
+            slotIndices.append(',');
+        }
+    }
+    slotIndices.chop(1);
+    return slotIndices;
+}
+
+void tst_Gdb::dumpQObjectSlot()
+{
+    // Case 1: Simple QObject.
+    QObject o;
+    o.setObjectName("Test");
+
+    QByteArray slotIndices = slotIndexList(&o);
+    QCOMPARE(slotIndices, QByteArray("2,3"));
+    QCOMPARE(o.metaObject()->indexOfSlot("deleteLater()"), 2);
+
+    QByteArray expected = QByteArray("addr='$A',numchild='1',type='$T',"
+        //"children=[{name='1 sender'}],numchild='1'");
+        "children=[],numchild='0'");
+    qDebug() << "FIXME!";
+    testDumper(expected, &o, NS"QObjectSlot", true, "", "", 2);
+
+
+    // Case 2: QAbstractItemModel with no connections.
+    QStringListModel m(QStringList() << "Test1" << "Test2");
+    slotIndices = slotIndexList(&o);
+
+    QCOMPARE(slotIndices, QByteArray("2,3"));
+    QCOMPARE(o.metaObject()->indexOfSlot("deleteLater()"), 2);
+
+    expected = QByteArray("addr='$A',numchild='1',type='$T',"
+        //"children=[{name='1 sender'}],numchild='1'");
+        "children=[],numchild='0'");
+    qDebug() << "FIXME!";
+    testDumper(expected, &o, NS"QObjectSlot", true, "", "", 2);
+
+
+    // Case 3: QAbstractItemModel with connections to itself and to another
+    //         o, using different connection types.
+    qRegisterMetaType<QModelIndex>("QModelIndex");
+    connect(&m, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)),
+            &o, SLOT(deleteLater()), Qt::DirectConnection);
+    connect(&o, SIGNAL(destroyed(QObject *)),
+            &m, SLOT(revert()), Qt::QueuedConnection);
+    connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)),
+            &m, SLOT(submit()), Qt::QueuedConnection);
+    connect(&m, SIGNAL(columnsInserted(QModelIndex, int, int)),
+            &m, SLOT(submit()), Qt::BlockingQueuedConnection);
+    connect(&m, SIGNAL(columnsRemoved(QModelIndex, int, int)),
+            &m, SLOT(deleteLater()), Qt::AutoConnection);
+#if QT_VERSION >= 0x040600
+    connect(&m, SIGNAL(dataChanged(QModelIndex, QModelIndex)),
+            &m, SLOT(revert()), Qt::UniqueConnection);
+#endif
+    expected = QByteArray("addr='$A',numchild='1',type='$T',"
+        //"children=[{name='1 sender'}],numchild='1'");
+        "children=[],numchild='0'");
+    qDebug() << "FIXME!";
+    testDumper(expected, &o, NS"QObjectSlot", true, "", "", 2);
+
+}
+
+void tst_Gdb::dumpQObjectSlotList()
+{
+    // Case 1: Simple QObject.
+    QObject o;
+    o.setObjectName("Test");
+    testDumper("numchild='2',value='<2 items>',type='$T',"
+        "children=[{name='2',value='deleteLater()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'},"
+        "{name='3',value='_q_reregisterTimers(void*)',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'}]",
+        &o, NS"QObjectSlotList", true);
+
+    // Case 2: QAbstractItemModel with no connections.
+    QStringListModel m(QStringList() << "Test1" << "Test2");
+    testDumper("numchild='4',value='<4 items>',type='$T',"
+        "children=[{name='2',value='deleteLater()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'},"
+        "{name='3',value='_q_reregisterTimers(void*)',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'},"
+        "{name='18',value='submit()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'},"
+        "{name='19',value='revert()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'}]",
+        &m, NS"QObjectSlotList", true);
+
+    // Case 3: QAbstractItemModel with connections to itself and to another
+    //         object, using different connection types.
+    qRegisterMetaType<QModelIndex>("QModelIndex");
+    connect(&m, SIGNAL(columnsAboutToBeInserted(QModelIndex, int, int)),
+            &o, SLOT(deleteLater()), Qt::DirectConnection);
+    connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)),
+            &m, SLOT(revert()), Qt::QueuedConnection);
+    connect(&m, SIGNAL(columnsAboutToBeRemoved(QModelIndex, int, int)),
+            &m, SLOT(submit()), Qt::QueuedConnection);
+    connect(&m, SIGNAL(columnsInserted(QModelIndex, int, int)),
+            &m, SLOT(submit()), Qt::BlockingQueuedConnection);
+    connect(&m, SIGNAL(columnsRemoved(QModelIndex, int, int)),
+            &m, SLOT(deleteLater()), Qt::AutoConnection);
+    connect(&o, SIGNAL(destroyed(QObject *)), &m, SLOT(submit()));
+    testDumper("numchild='4',value='<4 items>',type='$T',"
+        "children=[{name='2',value='deleteLater()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'},"
+        "{name='3',value='_q_reregisterTimers(void*)',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'},"
+        "{name='18',value='submit()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'},"
+        "{name='19',value='revert()',numchild='0',"
+            "addr='$A',type='"NS"QObjectSlot'}]",
+        &m, NS"QObjectSlotList", true);
+}
+
+void tst_Gdb::dumpQPixmap()
+{
+    // Case 1: Null Pixmap.
+    QPixmap p;
+
+    testDumper("value='(0x0)',type='$T',numchild='0'",
+        &p, NS"QPixmap", true);
+
+
+    // Case 2: Uninitialized non-null pixmap.
+    p = QPixmap(20, 100);
+    testDumper("value='(20x100)',type='$T',numchild='0'",
+        &p, NS"QPixmap", true);
+
+
+    // Case 3: Initialized non-null pixmap.
+    const char * const pixmap[] = {
+        "2 24 3 1", "       c None", ".      c #DBD3CB", "+      c #FCFBFA",
+        "  ", "  ", "  ", ".+", ".+", ".+", ".+", ".+", ".+", ".+", ".+", ".+",
+        ".+", ".+", ".+", ".+", ".+", ".+", ".+", ".+", ".+", "  ", "  ", "  "
+    };
+    p = QPixmap(pixmap);
+    testDumper("value='(2x24)',type='$T',numchild='0'",
+        &p, NS"QPixmap", true);
+}
+
+#if QT_VERSION >= 0x040500
+template<typename T>
+void tst_Gdb::dumpQSharedPointerHelper(QSharedPointer<T> &ptr)
+{
+    struct Cheater : public QSharedPointer<T>
+    {
+        static const typename QSharedPointer<T>::Data *getData(const QSharedPointer<T> &p)
+        {
+            return static_cast<const Cheater &>(p).d;
+        }
+    };
+
+    QByteArray expected("value='");
+    QString val1 = ptr.isNull() ? "<null>" : valToString(*ptr.data());
+    QString val2 = isSimpleType<T>() ? val1 : "";
+/*
+    const int *weakAddr;
+    const int *strongAddr;
+    int weakValue;
+    int strongValue;
+    if (!ptr.isNull()) {
+        weakAddr = reinterpret_cast<const int *>(&Cheater::getData(ptr)->weakref);
+        strongAddr = reinterpret_cast<const int *>(&Cheater::getData(ptr)->strongref);
+        weakValue = *weakAddr;
+        strongValue = *strongAddr;
+    } else {
+        weakAddr = strongAddr = 0;
+        weakValue = strongValue = 0;
+    }
+    expected.append(val2).append("',valuedisabled='true',numchild='1',children=[").
+        append("{name='data',addr='").append(ptrToBa(ptr.data())).
+        append("',type='").append(typeToString<T>()).append("',value='").append(val1).
+        append("'},{name='weakref',value='").append(N(weakValue)).
+        append("',type='int',addr='").append(ptrToBa(weakAddr)).append("',numchild='0'},").
+        append("{name='strongref',value='").append(N(strongValue)).
+        append("',type='int',addr='").append(ptrToBa(strongAddr)).append("',numchild='0'}]");
+    testDumper(expected, &ptr, NS"QSharedPointer", true, typeToString<T>());
+*/
+}
+#endif
+
+void tst_Gdb::dumpQSharedPointer()
+{
+#if QT_VERSION >= 0x040500
+    // Case 1: Simple type.
+    // Case 1.1: Null pointer.
+    QSharedPointer<int> simplePtr;
+    dumpQSharedPointerHelper(simplePtr);
+
+    // Case 1.2: Non-null pointer,
+    QSharedPointer<int> simplePtr2(new int(99));
+    dumpQSharedPointerHelper(simplePtr2);
+
+    // Case 1.3: Shared pointer.
+    QSharedPointer<int> simplePtr3 = simplePtr2;
+    dumpQSharedPointerHelper(simplePtr2);
+
+    // Case 1.4: Weak pointer.
+    QWeakPointer<int> simplePtr4(simplePtr2);
+    dumpQSharedPointerHelper(simplePtr2);
+
+    // Case 2: Composite type.
+    // Case 1.1: Null pointer.
+    QSharedPointer<QString> compositePtr;
+    // TODO: This case is not handled in gdbmacros.cpp (segfault!)
+    //dumpQSharedPointerHelper(compoistePtr);
+
+    // Case 1.2: Non-null pointer,
+    QSharedPointer<QString> compositePtr2(new QString("Test"));
+    dumpQSharedPointerHelper(compositePtr2);
+
+    // Case 1.3: Shared pointer.
+    QSharedPointer<QString> compositePtr3 = compositePtr2;
+    dumpQSharedPointerHelper(compositePtr2);
+
+    // Case 1.4: Weak pointer.
+    QWeakPointer<QString> compositePtr4(compositePtr2);
+    dumpQSharedPointerHelper(compositePtr2);
+#endif
+}
+
+void tst_Gdb::dumpQVariant_invalid()
+{
+    QVariant v;
+    testDumper("value='(invalid)',type='$T',numchild='0'",
+        &v, NS"QVariant", false);
+}
+
+void tst_Gdb::dumpQVariant_QString()
+{
+    QVariant v = "abc";
+    testDumper("value='KFFTdHJpbmcpICJhYmMi',valueencoded='5',type='$T',"
+        "numchild='0'",
+        &v, NS"QVariant", true);
+/*
+    FIXME: the QString version should have a child:
+    testDumper("value='KFFTdHJpbmcpICJhYmMi',valueencoded='5',type='$T',"
+        "numchild='1',children=[{name='value',value='IgBhAGIAYwAiAA==',"
+        "valueencoded='4',type='QString',numchild='0'}]",
+        &v, NS"QVariant", true);
+*/
+}
+
+void tst_Gdb::dumpQVariant_QStringList()
+{
+    QVariant v = QStringList() << "Hi";
+    testDumper("value='(QStringList) ',type='$T',numchild='1',"
+        "children=[{name='value',exp='(*('myns::QStringList'*)%)',"
+        "type='QStringList',numchild='1'}]"
+            << QByteArray::number(quintptr(&v)),
+        &v, NS"QVariant", true);
+}
+
+void tst_Gdb::dumpStdVector()
+{
+    std::vector<std::list<int> *> vector;
+    QByteArray inner = "std::list<int> *";
+    QByteArray innerp = "std::list<int>";
+    testDumper("value='<0 items>',valuedisabled='true',numchild='0'",
+        &vector, "std::vector", false, inner, "", sizeof(std::list<int> *));
+    std::list<int> list;
+    vector.push_back(new std::list<int>(list));
+    testDumper("value='<1 items>',valuedisabled='true',numchild='1',"
+        "childtype='" + inner + "',childnumchild='1',"
+        "children=[{addr='" + str(deref(&vector[0])) + "',"
+            "saddr='" + str(deref(&vector[0])) + "',type='" + innerp + "'}]",
+        &vector, "std::vector", true, inner, "", sizeof(std::list<int> *));
+    vector.push_back(0);
+    list.push_back(45);
+    testDumper("value='<2 items>',valuedisabled='true',numchild='2',"
+        "childtype='" + inner + "',childnumchild='1',"
+        "children=[{addr='" + str(deref(&vector[0])) + "',"
+            "saddr='" + str(deref(&vector[0])) + "',type='" + innerp + "'},"
+          "{addr='" + str(&vector[1]) + "',"
+            "type='" + innerp + "',value='<null>',numchild='0'}]",
+        &vector, "std::vector", true, inner, "", sizeof(std::list<int> *));
+    vector.push_back(new std::list<int>(list));
+    vector.push_back(0);
+}
+
+void tst_Gdb::dumpQTextCodecHelper(QTextCodec *codec)
+{
+    const QByteArray name = codec->name().toBase64();
+    QByteArray expected = QByteArray("value='%',valueencoded='1',type='$T',"
+        "numchild='2',children=[{name='name',value='%',type='"NS"QByteArray',"
+        "numchild='0',valueencoded='1'},{name='mibEnum',%}]")
+        << name << name << generateIntSpec(codec->mibEnum());
+    testDumper(expected, codec, NS"QTextCodec", true);
+}
+
+void tst_Gdb::dumpQTextCodec()
+{
+    const QList<QByteArray> &codecNames = QTextCodec::availableCodecs();
+    foreach (const QByteArray &codecName, codecNames)
+        dumpQTextCodecHelper(QTextCodec::codecForName(codecName));
+}
+
+#if QT_VERSION >= 0x040500
+template <typename T1, typename T2>
+        size_t offsetOf(const T1 *klass, const T2 *member)
+{
+    return static_cast<size_t>(reinterpret_cast<const char *>(member) -
+                               reinterpret_cast<const char *>(klass));
+}
+
+template <typename T>
+void tst_Gdb::dumpQWeakPointerHelper(QWeakPointer<T> &ptr)
+{
+    typedef QtSharedPointer::ExternalRefCountData Data;
+    const size_t dataOffset = 0;
+    const Data *d = *reinterpret_cast<const Data **>(
+            reinterpret_cast<const char **>(&ptr) + dataOffset);
+    const int *weakRefPtr = reinterpret_cast<const int *>(&d->weakref);
+    const int *strongRefPtr = reinterpret_cast<const int *>(&d->strongref);
+    T *data = ptr.toStrongRef().data();
+    const QString dataStr = valToString(*data);
+    QByteArray expected("value='");
+    if (isSimpleType<T>())
+        expected.append(dataStr);
+    expected.append("',valuedisabled='true',numchild='1',children=[{name='data',addr='").
+        append(ptrToBa(data)).append("',type='").append(typeToString<T>()).
+        append("',value='").append(dataStr).append("'},{name='weakref',value='").
+        append(valToString(*weakRefPtr)).append("',type='int',addr='").
+        append(ptrToBa(weakRefPtr)).append("',numchild='0'},{name='strongref',value='").
+        append(valToString(*strongRefPtr)).append("',type='int',addr='").
+        append(ptrToBa(strongRefPtr)).append("',numchild='0'}]");
+    testDumper(expected, &ptr, NS"QWeakPointer", true, typeToString<T>());
+}
+#endif
+
+void tst_Gdb::dumpQWeakPointer()
+{
+#if QT_VERSION >= 0x040500
+    // Case 1: Simple type.
+
+    // Case 1.1: Null pointer.
+    QSharedPointer<int> spNull;
+    QWeakPointer<int> wp = spNull.toWeakRef();
+    testDumper("value='<null>',valuedisabled='true',numchild='0'",
+        &wp, NS"QWeakPointer", true, "int");
+
+    // Case 1.2: Weak pointer is unique.
+    QSharedPointer<int> sp(new int(99));
+    wp = sp.toWeakRef();
+    dumpQWeakPointerHelper(wp);
+
+    // Case 1.3: There are other weak pointers.
+    QWeakPointer<int> wp2 = sp.toWeakRef();
+    dumpQWeakPointerHelper(wp);
+
+    // Case 1.4: There are other strong shared pointers as well.
+    QSharedPointer<int> sp2(sp);
+    dumpQWeakPointerHelper(wp);
+
+    // Case 2: Composite type.
+    QSharedPointer<QString> spS(new QString("Test"));
+    QWeakPointer<QString> wpS = spS.toWeakRef();
+    dumpQWeakPointerHelper(wpS);
+#endif
+}
+
+#define VERIFY_OFFSETOF(member)                           \
+do {                                                      \
+    QObjectPrivate *qob = 0;                              \
+    ObjectPrivate *ob = 0;                                \
+    QVERIFY(size_t(&qob->member) == size_t(&ob->member)); \
+} while (0)
+
+
+Thread::Thread(tst_Gdb *test)
+{
+    moveToThread(this);
+    m_test = test;
+    m_proc = 0;
+    m_proc = new QProcess;
+    m_proc->moveToThread(this);
+    qDebug() << "\nTHREAD CREATED" << getpid() << gettid();
+    connect(m_test, SIGNAL(writeToGdb(QByteArray)),
+        this, SLOT(writeToGdbRequested(QByteArray)));
+    connect(m_proc, SIGNAL(error(QProcess::ProcessError)),
+        this, SLOT(handleGdbError(QProcess::ProcessError)));
+    connect(m_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
+        this, SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
+    connect(m_proc, SIGNAL(started()),
+        this, SLOT(handleGdbStarted()));
+    connect(m_proc, SIGNAL(readyReadStandardOutput()),
+        this, SLOT(readStandardOutput()));
+    connect(m_proc, SIGNAL(readyReadStandardError()),
+        this, SLOT(readStandardError()));
+    start();
+}
+
+void Thread::handleGdbError(QProcess::ProcessError)
+{
+    qDebug() << "GDB ERROR: ";
+}
+
+void Thread::handleGdbFinished(int, QProcess::ExitStatus)
+{
+    qDebug() << "GDB FINISHED: ";
+}
+
+void Thread::readStandardOutput()
+{
+    QByteArray ba = m_proc->readAllStandardOutput();
+    if (ba.isEmpty())
+        return;
+    // =library-loaded...
+    if (ba.startsWith("=")) 
+        return;
+    //if (ba.startsWith("~"))
+    //    return;
+    if (!ba.startsWith("~\"locals="))
+        return;
+    //qDebug() << "THREAD GDB OUT: " << ba;
+    //m_output += ba;
+    ba = ba.mid(2, ba.size() - 4);
+    ba = ba.replace("\\\"", "\"");
+    m_output = ba;
+    m_waitCondition.wakeAll();
+}
+
+void Thread::readStandardError()
+{
+    return;
+    QByteArray ba = m_proc->readAllStandardOutput();
+    qDebug() << "THREAD GDB ERR: " << ba;
+    m_error += ba;
+    m_waitCondition.wakeAll();
+}
+
+void Thread::handleGdbStarted()
+{
+    //qDebug() << "\n\nGDB STARTED" << getpid() << gettid() << "\n\n";
+}
+
+void Thread::run()
+{
+    //qDebug() << "\nTHREAD RUN" << getpid() << gettid();
+    m_proc->start("./gdb -i mi --args ./tst_gdb run");
+    m_proc->waitForStarted();
+    m_proc->write("b main\n");
+    m_proc->write("run\n");
+    m_proc->write("handle SIGSTOP stop pass\n");
+    //qDebug() << "\nTHREAD RUNNING";
+    exec();
+}
+
+void tst_Gdb::initTestCase()
+{
+    // FIXME: Wait until gdb proc is running.
+    QTest::qWait(1000);
+}
+
+
+void tst_Gdb::runTestCase(const QByteArray &name, const QByteArray &type,
+    const QByteArrayList &expected)
+{
+    //qDebug() << "\nABOUT TO RUN TEST: " << name << m_thread.m_proc;
+
+    writeToGdb("b " + name);
+
+    for (int i = 0; i != expected.size(); ++i) {
+        if (i == 0)
+            writeToGdb("call " + name + "()");
+        else
+            writeToGdb("next");
+        writeToGdb("bb");
+        m_mutex.lock();
+        m_waitCondition.wait(&m_mutex);
+        QByteArray ba = m_thread.m_output;
+        m_mutex.unlock();
+        //GdbMi locals;
+        //locals.fromString("{" + ba + "}");
+        QByteArray received = ba.replace("\"", "'");
+        //qDebug() << "OUTPUT: " << ba << "\n\n";
+        //qDebug() << "OUTPUT: " << locals.toString() << "\n\n";
+        testDumper(expected.at(i), 0, type, false, received);
+    }
+}
+
+void tst_Gdb::cleanupTestCase()
+{
+    writeToGdb("kill");
+    writeToGdb("quit");
+    //m_thread.m_proc->waitForFinished();
+}
+
+void dumpQStringTest()
+{
+    QString s;
+    s = "hallo";
+    s += "x";
+    s += "y";
+}
+
+void tst_Gdb::dumpQString()
+{
+    QByteArrayList bal;
+
+    bal.append("{iname='local.s',addr='0xbffff19c',name='S',"
+        "type='"NS"QString',value='<not in scope>',numchild='0'}");
+
+    //bal.append("xxx");
+    //bal.append("xxx");
+    runTestCase("dumpQStringTest", NS"QString", bal);
+/*
+    testDumper("value='',valueencoded='2',type='$T',numchild='0'",
+        &s, NS"QString", false);
+    s = "abc";
+    testDumper("value='YQBiAGMA',valueencoded='2',type='$T',numchild='0'",
+        &s, NS"QString", false);
+*/
+}
+
+void dumpQStringListTest()
+{
+    QStringList s;
+}
+
+void tst_Gdb::dumpQStringList()
+{
+    QByteArrayList bal;
+    //bal.append("xxx");
+    runTestCase("dumpQStringListTest", NS"QStringList", bal);
+}
+
+int runit(int &argc, char *argv[])
+{
+    // Plain call. Start the testing.
+    QApplication app(argc, argv);
+    tst_Gdb test;
+    return QTest::qExec(&test, argc, argv);
+}
+
+int main(int argc, char *argv[])
+{
+    if (argc == 2 && QByteArray(argv[1]) == "run") {
+        // We are the debugged process, recursively called and steered
+        // by our spawning alter ego.
+        return 0;
+    }
+
+    return runit(argc, argv);
+}
+
+#include "tst_gdb.moc"
+
diff --git a/tests/auto/debugger/tst_plugin.cpp b/tests/auto/debugger/tst_plugin.cpp
index 5d26a6ac1218a4253003b038873ef856a134f7dd..84ffc58a685e55697e5d7c6586a8396afa254ca0 100644
--- a/tests/auto/debugger/tst_plugin.cpp
+++ b/tests/auto/debugger/tst_plugin.cpp
@@ -24,7 +24,6 @@
 #include <QtCore/private/qobject_p.h>
 
 #include "gdb/gdbmi.h"
-#include "tcf/json.h"
 #include "gdbmacros.h"
 #include "gdbmacros_p.h"