diff --git a/src/plugins/debugger/cdb/coreengine.cpp b/src/plugins/debugger/cdb/coreengine.cpp
index 324d470831f96c312bf8eceebc780f8b74c446f5..f00c4bf317583361ee6efb1f7f1a97d4069df484 100644
--- a/src/plugins/debugger/cdb/coreengine.cpp
+++ b/src/plugins/debugger/cdb/coreengine.cpp
@@ -830,6 +830,11 @@ quint64 CoreEngine::getSourceLineAddress(const QString &file,
     return rc;
 }
 
+void CoreEngine::outputVersion()
+{
+    m_cif.debugControl->OutputVersionInformation(DEBUG_OUTCTL_ALL_CLIENTS);
+}
+
 bool CoreEngine::autoDetectPath(QString *outPath,
                                 QStringList *checkedDirectories /* = 0 */)
 {
diff --git a/src/plugins/debugger/cdb/coreengine.h b/src/plugins/debugger/cdb/coreengine.h
index c73fc7e72da3aa97297f7dea895ff62025bd1aac..c6e25e9cedeb2ffc71e092388721534c6def82eb 100644
--- a/src/plugins/debugger/cdb/coreengine.h
+++ b/src/plugins/debugger/cdb/coreengine.h
@@ -168,6 +168,9 @@ signals:
     // feature of the engine.
     void modulesLoaded();
 
+public  slots:
+    void outputVersion();
+
 protected:
     virtual void timerEvent(QTimerEvent* te);
 
diff --git a/tests/manual/ccdb/cdbapplication.cpp b/tests/manual/ccdb/cdbapplication.cpp
index 8a2ad87451c72a5132ea4d59a288cb26a8bbe4d4..9e2d0e180472b0b35b2758521b325dd05c38426a 100644
--- a/tests/manual/ccdb/cdbapplication.cpp
+++ b/tests/manual/ccdb/cdbapplication.cpp
@@ -34,17 +34,18 @@
 #include "debugeventcallback.h"
 #include "symbolgroupcontext.h"
 #include "stacktracecontext.h"
-
 #include <QtCore/QStringList>
 #include <QtCore/QTimer>
 #include <QtCore/QDebug>
 
 #include <cstdio>
+#include <cerrno>
 
 const char usage[] =
 "CDB command line test tool\n\n"
 "ccdb <Options>\n"
-"Options: -p engine path\n";
+"Options: -p engine path\n"
+"         -c initial_command_file\n";
 
 class PrintfOutputHandler : public CdbCore::DebugOutputBase
 {
@@ -72,7 +73,8 @@ CdbApplication::~CdbApplication()
 
 CdbApplication::InitResult CdbApplication::init()
 {
-    if (!parseOptions()) {
+    FILE *inputFile;
+    if (!parseOptions(&inputFile)) {
         printf(usage);
         return InitUsageShown;
     }
@@ -91,7 +93,7 @@ CdbApplication::InitResult CdbApplication::init()
     connect(m_engine.data(), SIGNAL(watchTimerDebugEvent()), this, SLOT(debugEvent()));
     std::printf("Succeded.\n");
     // Prompt
-    m_promptThread = new CdbPromptThread(this);
+    m_promptThread = new CdbPromptThread(inputFile, this);
     connect(m_promptThread, SIGNAL(finished()), this, SLOT(promptThreadTerminated()));
     connect(m_promptThread, SIGNAL(asyncCommand(int,QString)),
             this, SLOT(asyncCommand(int,QString)), Qt::QueuedConnection);
@@ -99,7 +101,8 @@ CdbApplication::InitResult CdbApplication::init()
             this, SLOT(syncCommand(int,QString)), Qt::BlockingQueuedConnection);
     connect(m_promptThread, SIGNAL(executionCommand(int,QString)),
             this, SLOT(executionCommand(int,QString)), Qt::BlockingQueuedConnection);
-
+    connect(m_engine.data(), SIGNAL(watchTimerDebugEvent()), m_promptThread, SLOT(notifyDebugEvent()),
+            Qt::QueuedConnection);
     m_promptThread->start();
     return InitOk;
 }
@@ -113,23 +116,41 @@ void CdbApplication::promptThreadTerminated()
     quit();
 }
 
-bool CdbApplication::parseOptions()
+bool CdbApplication::parseOptions(FILE **inputFile)
 {
+    *inputFile = NULL;
     const QStringList args = QCoreApplication::arguments();
     const QStringList::const_iterator cend = args.constEnd();
     QStringList::const_iterator it = args.constBegin();
     for (++it; it != cend ; ++it) {
         const QString &a = *it;
-        if (a == QLatin1String("-p")) {
-            ++it;
-            if (it == cend) {
-                std::fprintf(stderr, "Option -p is missing an argument.\n");
+        if (a.startsWith(QLatin1Char('-')) && a.size() >= 2) {
+            switch (a.at(1).toAscii()) {
+            case 'p':
+                ++it;
+                if (it == cend) {
+                    std::fprintf(stderr, "Option -p is missing an argument.\n");
+                    return false;
+                }
+                m_engineDll = *it;
+                break;
+            case 'c':
+                ++it;
+                if (it == cend) {
+                    std::fprintf(stderr, "Option -c is missing an argument.\n");
+                    return false;
+                }
+                *inputFile = std::fopen( it->toLocal8Bit().constData(), "r");
+                if (*inputFile == NULL) {
+                    std::fprintf(stderr, "Cannot open %s: %s\n", qPrintable(*it), std::strerror(errno));
+                    return false;
+                }
+                break;
+
+            default:
+                std::fprintf(stderr, "Invalid option %s\n", qPrintable(a));
                 return false;
             }
-            m_engineDll = *it;
-        } else {
-            std::fprintf(stderr, "Invalid option %s\n", qPrintable(a));
-            return false;
         }
     }
     return true;
@@ -252,6 +273,11 @@ void CdbApplication::syncCommand(int command, const QString &arg)
     case Sync_PrintFrame:
         printFrame(arg);
         break;
+    case Sync_OutputVersion:
+        m_engine->outputVersion();
+        break;
+    case Sync_Python:
+        break;
     case Unknown:
         std::printf("Executing '%s' in code level %d, syntax %d\n",
                     qPrintable(arg), m_engine->codeLevel(), m_engine->expressionSyntax());
@@ -286,7 +312,7 @@ void CdbApplication::executionCommand(int command, const QString &arg)
     }
     if (ok) {
         m_engine->startWatchTimer();
-        m_stackTrace.reset();
+        m_stackTrace = QSharedPointer<CdbCore::StackTraceContext>();
     } else {
         std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
     }
@@ -297,11 +323,17 @@ void CdbApplication::debugEvent()
     QString errorMessage;
     std::printf("Debug event\n");
 
-    CdbCore::StackTraceContext::ThreadIdFrameMap threads;
+    QVector<CdbCore::Thread> threads;
+    QVector<CdbCore::StackFrame> threadFrames;
     ULONG currentThreadId;
-    if (CdbCore::StackTraceContext::getThreads(m_engine->interfaces(), &threads,
-                                               &currentThreadId, &errorMessage)) {
-        printf("%s\n", qPrintable(CdbCore::StackTraceContext::formatThreads(threads)));
+
+    if (CdbCore::StackTraceContext::getThreadList(m_engine->interfaces(), &threads, &currentThreadId, &errorMessage)
+        && CdbCore::StackTraceContext::getStoppedThreadFrames(m_engine->interfaces(), currentThreadId, threads, &threadFrames, &errorMessage)) {
+        const int count = threadFrames.size();
+        for (int i = 0; i  < count; i++) {
+            printf("Thread #%02d ID %10d SYSID %10d %s\n", i,
+                   threads.at(i).id, threads.at(i).systemId, qPrintable(threadFrames.at(i).toString()));
+        }
     } else {
         std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
     }
@@ -310,7 +342,7 @@ void CdbApplication::debugEvent()
         CdbCore::StackTraceContext::create(&m_engine->interfaces(),
                                            0xFFFF, &errorMessage);
     if (trace) {
-        m_stackTrace.reset(trace);
+        m_stackTrace = QSharedPointer<CdbCore::StackTraceContext>(trace);
         printf("%s\n", qPrintable(m_stackTrace->toString()));
     } else {
         std::fprintf(stderr, "%s\n", qPrintable(errorMessage));
diff --git a/tests/manual/ccdb/cdbapplication.h b/tests/manual/ccdb/cdbapplication.h
index 11063795d8ae1819a8a343d09279bc4ef474e8e6..8d68e6414e6f8fc76812a6382b336f56e6587e95 100644
--- a/tests/manual/ccdb/cdbapplication.h
+++ b/tests/manual/ccdb/cdbapplication.h
@@ -37,6 +37,8 @@
 #include <QtCore/QScopedPointer>
 #include <QtCore/QStringList>
 
+#include <cstdio>
+
 namespace CdbCore {
     class CoreEngine;
     class StackTraceContext;
@@ -65,13 +67,13 @@ private slots:
     void processAttached(void *handle);
 
 private:
-    bool parseOptions();
+    bool parseOptions(FILE **inputFile);
     void printFrame(const QString &arg);
     quint64 addQueuedBreakPoint(const QString &arg, QString *errorMessage);
 
     QString m_engineDll;
     QSharedPointer<CdbCore::CoreEngine> m_engine;
-    QScopedPointer<CdbCore::StackTraceContext> m_stackTrace;
+    QSharedPointer<CdbCore::StackTraceContext> m_stackTrace;
     CdbPromptThread *m_promptThread;
     QStringList m_queuedCommands;
     QStringList m_queuedBreakPoints;
diff --git a/tests/manual/ccdb/cdbpromptthread.cpp b/tests/manual/ccdb/cdbpromptthread.cpp
index 1ade3331d7f9b4127c12671b26cc810e79d7592c..c0b01c47891c4d38883ac19aad063f18f0c18826 100644
--- a/tests/manual/ccdb/cdbpromptthread.cpp
+++ b/tests/manual/ccdb/cdbpromptthread.cpp
@@ -29,13 +29,12 @@
 
 #include "cdbpromptthread.h"
 
-#include <cstdio>
 #include <QtCore/QDebug>
 
 static const char help[] =
 "Special commands:\n\n"
 "H                        Display Help\n"
-"q                        Quit\n"
+"V                        Output version\n"
 "E expression             Evaluate C++expression\n"
 "S binary args            Start binary\n"
 "I                        Interrupt\n"
@@ -46,11 +45,17 @@ static const char help[] =
 "B                        Clear breakpoint queue\n"
 "L                        List breakpoints\n"
 "F <n>                    Print stack frame <n>, 0 being top\n"
+"P <cmd>                  Run Python command\n"
+"W                        Synchronous wait for debug event\n"
 "\nThe remaining commands are passed to CDB.\n";
 
-CdbPromptThread::CdbPromptThread(QObject *parent) :
-        QThread(parent)
+CdbPromptThread::CdbPromptThread(FILE *file, QObject *parent) :
+        QThread(parent),
+        m_waitingForDebugEvent(false),
+        m_inputFile(file)
 {
+    if (!m_inputFile)
+        m_inputFile = stdin;
 }
 
 void CdbPromptThread::run()
@@ -60,9 +65,17 @@ void CdbPromptThread::run()
     QString cmd;
     char buf[bufSize];
     std::putc('>', stdout);
+    // When reading from an input file, switch to stdin after reading it out
     while (true) {
-        if (std::fgets(buf, bufSize, stdin) == NULL)
-            break;
+        if (std::fgets(buf, bufSize, m_inputFile) == NULL) {
+            if (m_inputFile == stdin) {
+                break;
+            } else {
+                fclose(m_inputFile);
+                m_inputFile = stdin;
+                continue;
+            }
+        }
         cmd += QString::fromLatin1(buf);
         if (cmd.endsWith(QLatin1Char('\n'))) {
             cmd.truncate(cmd.size() - 1);
@@ -72,6 +85,8 @@ void CdbPromptThread::run()
         }
         std::putc('>', stdout);
     }
+    if (m_inputFile != stdin)
+        fclose(m_inputFile);
 }
 
 // Determine the command
@@ -95,6 +110,12 @@ static Command evaluateCommand(const QString &cmdToken)
             return Execution_StartBinary;
         case 'F':
             return Sync_PrintFrame;
+        case 'P':
+            return Sync_Python;
+        case 'V':
+            return Sync_OutputVersion;
+        case 'W':
+            return WaitCommand;
         default:
             break;
         }
@@ -126,6 +147,12 @@ static Command parseCommand(QString *s)
     return rc;
 }
 
+void CdbPromptThread::notifyDebugEvent()
+{
+    if (m_waitingForDebugEvent)
+        m_debugEventWaitCondition.wakeAll();
+}
+
 bool CdbPromptThread::handleCommand(QString cmd)
 {
     if (cmd == QLatin1String("q"))
@@ -135,6 +162,16 @@ bool CdbPromptThread::handleCommand(QString cmd)
         return true;
     }
     const Command c = parseCommand(&cmd);
+    if (c == WaitCommand) {
+        std::fputs("Waiting for debug event\n", stdout);
+        m_debugEventMutex.lock();
+        m_waitingForDebugEvent = true;
+        m_debugEventWaitCondition.wait(&m_debugEventMutex);
+        m_debugEventMutex.unlock();
+        std::fputs("Debug event received\n", stdout);
+        m_waitingForDebugEvent = false;
+        return true;
+    }
     if (c & AsyncCommand) {
         emit asyncCommand(c, cmd);
         return true;
diff --git a/tests/manual/ccdb/cdbpromptthread.h b/tests/manual/ccdb/cdbpromptthread.h
index 295f26e07f1173a4a63f89e50f754ad894d4de39..4851f079bcac309c57d9059f5e8ccd88a2f4777b 100644
--- a/tests/manual/ccdb/cdbpromptthread.h
+++ b/tests/manual/ccdb/cdbpromptthread.h
@@ -31,6 +31,10 @@
 #define PROMPTTHREAD_H
 
 #include <QtCore/QThread>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QMutex>
+
+#include <cstdio>
 
 enum CommandTypeFlags {
     // Interrupt or something.
@@ -51,18 +55,24 @@ enum Command {
     Sync_QueueBreakPoint  = SyncCommand|3,
     Sync_ListBreakPoints  = SyncCommand|4,
     Sync_PrintFrame       = SyncCommand|5,
+    Sync_OutputVersion    = SyncCommand|6,
+    Sync_Python           = SyncCommand|7,
     Execution_Go          = ExecutionCommand|1,
-    Execution_StartBinary = ExecutionCommand|2
+    Execution_StartBinary = ExecutionCommand|2,
+    WaitCommand           = 0xFFFF
 };
 
 class CdbPromptThread : public QThread
 {
     Q_OBJECT
 public:
-    explicit CdbPromptThread(QObject *parent = 0);
+    explicit CdbPromptThread(FILE *file, QObject *parent = 0);
 
     virtual void run();
 
+public slots:
+    void notifyDebugEvent();
+
 signals:
     void asyncCommand(int command, const QString &arg);
     void syncCommand(int command, const QString &arg);
@@ -70,6 +80,10 @@ signals:
 
 private:
     bool handleCommand(QString);
+    QWaitCondition m_debugEventWaitCondition;
+    QMutex m_debugEventMutex;
+    bool m_waitingForDebugEvent;
+    FILE *m_inputFile;
 };
 
 #endif // PROMPTTHREAD_H