From a945e96377cf0c8b72a96ce6de2bb5889abc62c2 Mon Sep 17 00:00:00 2001
From: hjk <qtc-committer@nokia.com>
Date: Wed, 5 May 2010 12:41:52 +0200
Subject: [PATCH] Revive TCF agent

This mainly reverts commit ba47987e67cea19ce22ee186322e37fc5111a57e.

Conflicts:

	src/plugins/debugger/debugger.pro
	src/plugins/debugger/debuggermanager.cpp
	src/plugins/debugger/debuggermanager.h
	src/plugins/debugger/debuggerplugin.cpp
	src/plugins/debugger/debuggerplugin.h
---
 src/plugins/debugger/Debugger.pluginspec |   1 +
 src/plugins/debugger/attachtcfdialog.ui  |  95 ++++
 src/plugins/debugger/debugger.pro        |   2 +
 src/plugins/debugger/debuggerconstants.h |   1 +
 src/plugins/debugger/debuggerdialogs.cpp |  90 ++++
 src/plugins/debugger/debuggerdialogs.h   |  26 ++
 src/plugins/debugger/debuggermanager.cpp |  20 +-
 src/plugins/debugger/debuggermanager.h   |   4 +
 src/plugins/debugger/debuggerplugin.cpp  |  56 ++-
 src/plugins/debugger/debuggerplugin.h    |   2 +
 src/plugins/debugger/tcf/json.cpp        | 372 +++++++++++++++
 src/plugins/debugger/tcf/json.h          | 100 ++++
 src/plugins/debugger/tcf/tcf.pri         |  11 +
 src/plugins/debugger/tcf/tcfengine.cpp   | 569 +++++++++++++++++++++++
 src/plugins/debugger/tcf/tcfengine.h     | 168 +++++++
 15 files changed, 1511 insertions(+), 6 deletions(-)
 create mode 100644 src/plugins/debugger/attachtcfdialog.ui
 create mode 100644 src/plugins/debugger/tcf/json.cpp
 create mode 100644 src/plugins/debugger/tcf/json.h
 create mode 100644 src/plugins/debugger/tcf/tcf.pri
 create mode 100644 src/plugins/debugger/tcf/tcfengine.cpp
 create mode 100644 src/plugins/debugger/tcf/tcfengine.h

diff --git a/src/plugins/debugger/Debugger.pluginspec b/src/plugins/debugger/Debugger.pluginspec
index 18f56e3a383..a396d7569a0 100644
--- a/src/plugins/debugger/Debugger.pluginspec
+++ b/src/plugins/debugger/Debugger.pluginspec
@@ -23,6 +23,7 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
         <argument name="-disable-cdb">Disable Cdb debugger engine</argument>
         <argument name="-disable-gdb">Disable Gdb debugger engine</argument>
         <argument name="-disable-sdb">Disable Qt Script debugger engine</argument>
+        <argument name="-disable-tcf">Disable Tcf debugger engine</argument>
         <argument name="-debug" parameter="pid-or-corefile">Attach to Process-Id or Core file</argument>
         <argument name="-wincrashevent" parameter="event-handle">Event handle used for attaching to crashed processes</argument>
     </argumentList>
diff --git a/src/plugins/debugger/attachtcfdialog.ui b/src/plugins/debugger/attachtcfdialog.ui
new file mode 100644
index 00000000000..c890f11ff95
--- /dev/null
+++ b/src/plugins/debugger/attachtcfdialog.ui
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AttachTcfDialog</class>
+ <widget class="QDialog" name="AttachTcfDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>310</width>
+    <height>224</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Start Debugger</string>
+  </property>
+  <layout class="QVBoxLayout">
+   <property name="spacing">
+    <number>6</number>
+   </property>
+   <property name="margin">
+    <number>9</number>
+   </property>
+   <item>
+    <layout class="QFormLayout" name="formLayout">
+     <property name="fieldGrowthPolicy">
+      <enum>QFormLayout::ExpandingFieldsGrow</enum>
+     </property>
+     <item row="0" column="0">
+      <widget class="QLabel" name="channelLabel">
+       <property name="text">
+        <string>Host and port:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="channelLineEdit">
+       <property name="text">
+        <string notr="true">localhost:5115</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="architectureLabel">
+       <property name="text">
+        <string>Architecture:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QComboBox" name="architectureComboBox"/>
+     </item>
+     <item row="2" column="1">
+      <widget class="QCheckBox" name="useServerStartScriptCheckBox"/>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="useServerStartScriptLabel">
+       <property name="text">
+        <string>Use server start script:</string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1">
+      <widget class="Utils::PathChooser" name="serverStartScript" native="true"/>
+     </item>
+     <item row="3" column="0">
+      <widget class="QLabel" name="serverStartScriptLabel">
+       <property name="text">
+        <string>Server start script:</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>Utils::PathChooser</class>
+   <extends>QWidget</extends>
+   <header location="global">utils/pathchooser.h</header>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro
index 6bbfe497439..666019ae24e 100644
--- a/src/plugins/debugger/debugger.pro
+++ b/src/plugins/debugger/debugger.pro
@@ -80,6 +80,7 @@ SOURCES += breakhandler.cpp \
 
 FORMS += attachexternaldialog.ui \
     attachcoredialog.ui \
+    attachtcfdialog.ui \
     breakbyfunction.ui \
     breakcondition.ui \
     dumperoptionpage.ui \
@@ -103,6 +104,7 @@ include(cdb/cdb.pri)
 include(gdb/gdb.pri)
 include(script/script.pri)
 include(pdb/pdb.pri)
+include(tcf/tcf.pri)
 include(shared/shared.pri)
 
 OTHER_FILES += Debugger.pluginspec
diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h
index d958246fbf8..eb6786d9c82 100644
--- a/src/plugins/debugger/debuggerconstants.h
+++ b/src/plugins/debugger/debuggerconstants.h
@@ -112,6 +112,7 @@ enum DebuggerStartMode
     StartExternal,         // Start binary found in file system
     AttachExternal,        // Attach to running process by process id
     AttachCrashedExternal, // Attach to crashed process by process id
+    AttachTcf,             // Attach to a running Target Communication Framework agent
     AttachCore,            // Attach to a core file
     StartRemote            // Start and attach to a remote process
 };
diff --git a/src/plugins/debugger/debuggerdialogs.cpp b/src/plugins/debugger/debuggerdialogs.cpp
index dc36ee52ad6..3f07315ef87 100644
--- a/src/plugins/debugger/debuggerdialogs.cpp
+++ b/src/plugins/debugger/debuggerdialogs.cpp
@@ -32,6 +32,7 @@
 
 #include "ui_attachcoredialog.h"
 #include "ui_attachexternaldialog.h"
+#include "ui_attachtcfdialog.h"
 #include "ui_startexternaldialog.h"
 #include "ui_startremotedialog.h"
 
@@ -413,6 +414,95 @@ void AttachExternalDialog::pidChanged(const QString &pid)
 }
 
 
+///////////////////////////////////////////////////////////////////////
+//
+// AttachTcfDialog
+//
+///////////////////////////////////////////////////////////////////////
+
+AttachTcfDialog::AttachTcfDialog(QWidget *parent)
+  : QDialog(parent),
+    m_ui(new Ui::AttachTcfDialog)
+{
+    m_ui->setupUi(this);
+    m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true);
+    m_ui->serverStartScript->setExpectedKind(Utils::PathChooser::File);
+    m_ui->serverStartScript->setPromptDialogTitle(tr("Select Executable"));
+
+    connect(m_ui->useServerStartScriptCheckBox, SIGNAL(toggled(bool)), 
+        this, SLOT(updateState()));
+    
+    connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+    connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+    updateState();
+}
+
+AttachTcfDialog::~AttachTcfDialog()
+{
+    delete m_ui;
+}
+
+void AttachTcfDialog::setRemoteChannel(const QString &channel)
+{
+    m_ui->channelLineEdit->setText(channel);
+}
+
+QString AttachTcfDialog::remoteChannel() const
+{
+    return m_ui->channelLineEdit->text();
+}
+
+void AttachTcfDialog::setRemoteArchitectures(const QStringList &list)
+{
+    m_ui->architectureComboBox->clear();
+    if (!list.isEmpty()) {
+        m_ui->architectureComboBox->insertItems(0, list);
+        m_ui->architectureComboBox->setCurrentIndex(0);
+    }
+}
+
+void AttachTcfDialog::setRemoteArchitecture(const QString &arch)
+{
+    int index = m_ui->architectureComboBox->findText(arch);
+    if (index != -1)
+        m_ui->architectureComboBox->setCurrentIndex(index);
+}
+
+QString AttachTcfDialog::remoteArchitecture() const
+{
+    int index = m_ui->architectureComboBox->currentIndex();
+    return m_ui->architectureComboBox->itemText(index);
+}
+
+void AttachTcfDialog::setServerStartScript(const QString &scriptName)
+{
+    m_ui->serverStartScript->setPath(scriptName);
+}
+
+QString AttachTcfDialog::serverStartScript() const
+{
+    return m_ui->serverStartScript->path();
+}
+
+void AttachTcfDialog::setUseServerStartScript(bool on)
+{
+    m_ui->useServerStartScriptCheckBox->setChecked(on);
+}
+
+bool AttachTcfDialog::useServerStartScript() const
+{
+    return m_ui->useServerStartScriptCheckBox->isChecked();
+}
+
+void AttachTcfDialog::updateState()
+{
+    bool enabled = m_ui->useServerStartScriptCheckBox->isChecked();
+    m_ui->serverStartScriptLabel->setEnabled(enabled);
+    m_ui->serverStartScript->setEnabled(enabled);
+}
+
+
 ///////////////////////////////////////////////////////////////////////
 //
 // StartExternalDialog
diff --git a/src/plugins/debugger/debuggerdialogs.h b/src/plugins/debugger/debuggerdialogs.h
index 7b9fedca8da..13ad67358f8 100644
--- a/src/plugins/debugger/debuggerdialogs.h
+++ b/src/plugins/debugger/debuggerdialogs.h
@@ -42,6 +42,7 @@ class QDialogButtonBox;
 namespace Ui {
 class AttachCoreDialog;
 class AttachExternalDialog;
+class AttachTcfDialog;
 class StartExternalDialog;
 class StartRemoteDialog;
 } // namespace Ui
@@ -107,6 +108,31 @@ private:
     ProcessListFilterModel *m_model;
 };
 
+class AttachTcfDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit AttachTcfDialog(QWidget *parent);
+    ~AttachTcfDialog();
+
+    void setRemoteChannel(const QString &host);
+    void setRemoteArchitecture(const QString &arch);
+    void setRemoteArchitectures(const QStringList &arches);
+    QString remoteChannel() const;
+    QString remoteArchitecture() const;
+    void setServerStartScript(const QString &scriptName);
+    QString serverStartScript() const;
+    void setUseServerStartScript(bool on);
+    bool useServerStartScript() const;
+
+private slots:
+    void updateState();
+
+private:
+    Ui::AttachTcfDialog *m_ui;
+};
+
 class StartExternalDialog : public QDialog
 {
     Q_OBJECT
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index ac645e19c3f..9b09cd09b4d 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -157,6 +157,7 @@ namespace Internal {
 IDebuggerEngine *createGdbEngine(DebuggerManager *parent);
 IDebuggerEngine *createScriptEngine(DebuggerManager *parent);
 IDebuggerEngine *createPdbEngine(DebuggerManager *parent);
+IDebuggerEngine *createTcfEngine(DebuggerManager *parent);
 
 // The createCdbEngine function takes a list of options pages it can add to.
 // This allows for having a "enabled" toggle on the page independently
@@ -251,6 +252,7 @@ static Debugger::Internal::IDebuggerEngine *gdbEngine = 0;
 static Debugger::Internal::IDebuggerEngine *scriptEngine = 0;
 static Debugger::Internal::IDebuggerEngine *cdbEngine = 0;
 static Debugger::Internal::IDebuggerEngine *pdbEngine = 0;
+static Debugger::Internal::IDebuggerEngine *tcfEngine = 0;
 
 struct DebuggerManagerPrivate
 {
@@ -345,6 +347,7 @@ DebuggerManager::~DebuggerManager()
     doDelete(pdbEngine);
     doDelete(gdbEngine);
     doDelete(cdbEngine);
+    doDelete(tcfEngine);
 
     doDelete(d->m_breakHandler);
     doDelete(d->m_threadsHandler);
@@ -357,6 +360,7 @@ DebuggerManager::~DebuggerManager()
     doDelete(gdbEngine);
     doDelete(scriptEngine);
     doDelete(cdbEngine);
+    doDelete(tcfEngine);
     #undef doDelete
     DebuggerManagerPrivate::instance = 0;
     delete d;
@@ -664,6 +668,11 @@ QList<Core::IOptionsPage*> DebuggerManager::initializeEngines(unsigned enabledTy
         //pdbEngine->addOptionPages(&rc);
     }
 
+    if (enabledTypeFlags & TcfEngineType) {
+        tcfEngine = createTcfEngine(this);
+        tcfEngine->addOptionPages(&rc);
+    }
+
     d->m_engine = 0;
     STATE_DEBUG(gdbEngine << cdbEngine << scriptEngine
         << pdbEngine << rc.size());
@@ -1038,6 +1047,9 @@ static IDebuggerEngine *debuggerEngineForExecutable(const QString &executable,
 // Debugger type for mode
 static IDebuggerEngine *debuggerEngineForMode(DebuggerStartMode startMode, QString *errorMessage)
 {
+    if (startMode == AttachTcf)
+        return tcfEngine;
+
 #ifdef Q_OS_WIN
     // Preferably Windows debugger for attaching locally.
     if (startMode != StartRemote && cdbEngine)
@@ -1676,10 +1688,12 @@ void DebuggerManager::showQtDumperLibraryWarning(const QString &details)
         dialog.setDetailedText(details);
     dialog.exec();
     if (dialog.clickedButton() == qtPref) {
-        Core::ICore::instance()->showOptionsDialog(_(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
-                                                   _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
+        Core::ICore::instance()->showOptionsDialog(
+            _(Qt4ProjectManager::Constants::QT_SETTINGS_CATEGORY),
+            _(Qt4ProjectManager::Constants::QTVERSION_SETTINGS_PAGE_ID));
     } else if (dialog.clickedButton() == helperOff) {
-        theDebuggerAction(UseDebuggingHelpers)->setValue(qVariantFromValue(false), false);
+        theDebuggerAction(UseDebuggingHelpers)
+            ->setValue(qVariantFromValue(false), false);
     }
 }
 
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index 9c2ee51f876..6ba60846420 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -92,6 +92,7 @@ class CdbDumperHelper;
 class CdbDumperInitThread;
 class CdbExceptionLoggerEventCallback;
 class GdbEngine;
+class TcfEngine;
 class CdbDebugEngine;
 class CdbDebugEnginePrivate;
 class TrkGdbAdapter;
@@ -140,10 +141,12 @@ enum DebuggerEngineTypeFlags
     ScriptEngineType  = 0x02,
     CdbEngineType     = 0x04,
     PdbEngineType     = 0x08,
+    TcfEngineType     = 0x10,
     AllEngineTypes = GdbEngineType
         | ScriptEngineType
         | CdbEngineType
         | PdbEngineType
+        | TcfEngineType
 };
 
 QDebug operator<<(QDebug d, DebuggerState state);
@@ -171,6 +174,7 @@ public:
     friend class Internal::GdbEngine;
     friend class Internal::ScriptEngine;
     friend class Internal::PdbEngine;
+    friend class Internal::TcfEngine;
     friend class Internal::CdbDebugEngine;
     friend class Internal::CdbDebugEnginePrivate;
     friend class Internal::TrkGdbAdapter;
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index 530eca53e4e..70541e03d69 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -122,6 +122,7 @@ const char * const M_DEBUG_START_DEBUGGING = "QtCreator.Menu.Debug.StartDebuggin
 const char * const STARTEXTERNAL        = "Debugger.StartExternal";
 const char * const ATTACHEXTERNAL       = "Debugger.AttachExternal";
 const char * const ATTACHCORE           = "Debugger.AttachCore";
+const char * const ATTACHTCF            = "Debugger.AttachTcf";
 const char * const ATTACHREMOTE         = "Debugger.AttachRemote";
 const char * const DETACH               = "Debugger.Detach";
 
@@ -625,7 +626,7 @@ static bool parseArgument(QStringList::const_iterator &it,
         }
         return true;
     }
-    // engine disabling
+    // Engine disabling.
     if (option == _("-disable-cdb")) {
         *enabledEngines &= ~Debugger::CdbEngineType;
         return true;
@@ -638,14 +639,18 @@ static bool parseArgument(QStringList::const_iterator &it,
         *enabledEngines &= ~Debugger::ScriptEngineType;
         return true;
     }
+    if (option == QLatin1String("-disable-tcf")) {
+        *enabledEngines &= ~TcfEngineType;
+        return true;
+    }
 
     *errorMessage = DebuggerPlugin::tr("Invalid debugger option: %1").arg(option);
     return false;
 }
 
 static bool parseArguments(const QStringList &args,
-                           DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters,
-                           unsigned *enabledEngines, QString *errorMessage)
+   DebuggerPlugin::AttachRemoteParameters *attachRemoteParameters,
+   unsigned *enabledEngines, QString *errorMessage)
 {
     const QStringList::const_iterator cend = args.constEnd();
     for (QStringList::const_iterator it = args.constBegin(); it != cend; ++it)
@@ -747,6 +752,13 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess
     m_attachCoreAction->setText(tr("Attach to Core..."));
     connect(m_attachCoreAction, SIGNAL(triggered()), this, SLOT(attachCore()));
 
+    m_attachTcfAction = new QAction(this);
+    m_attachTcfAction->setText(tr("Attach to Running Tcf Agent..."));
+    m_attachTcfAction->setToolTip(tr("This attaches to a running "
+        "'Target Communication Framework' agent."));
+    connect(m_attachTcfAction, SIGNAL(triggered()),
+        this, SLOT(attachRemoteTcf()));
+
     m_startRemoteAction = new QAction(this);
     m_startRemoteAction->setText(tr("Start and Attach to Remote Application..."));
     connect(m_startRemoteAction, SIGNAL(triggered()),
@@ -779,9 +791,14 @@ bool DebuggerPlugin::initialize(const QStringList &arguments, QString *errorMess
 
     cmd = am->registerAction(m_attachCoreAction,
         Constants::ATTACHCORE, globalcontext);
+
     cmd->setAttribute(Command::CA_Hide);
     mstart->addAction(cmd, CC::G_DEFAULT_ONE);
 
+    cmd = am->registerAction(m_attachTcfAction,
+        Constants::ATTACHTCF, globalcontext);
+    mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE);
+
     cmd = am->registerAction(m_startRemoteAction,
         Constants::ATTACHREMOTE, globalcontext);
     cmd->setAttribute(Command::CA_Hide);
@@ -1520,6 +1537,39 @@ void DebuggerPlugin::toggleBreakpoint()
         m_manager->toggleBreakpoint(fileName, lineNumber);
 }
 
+void DebuggerPlugin::attachRemoteTcf()
+{
+    const DebuggerStartParametersPtr sp(new DebuggerStartParameters);
+    AttachTcfDialog dlg(m_uiSwitcher->mainWindow());
+    QStringList arches;
+    arches.append(_("i386:x86-64:intel"));
+    dlg.setRemoteArchitectures(arches);
+    dlg.setRemoteChannel(
+            configValue(_("LastTcfRemoteChannel")).toString());
+    dlg.setRemoteArchitecture(
+            configValue(_("LastTcfRemoteArchitecture")).toString());
+    dlg.setServerStartScript(
+            configValue(_("LastTcfServerStartScript")).toString());
+    dlg.setUseServerStartScript(
+            configValue(_("LastTcfUseServerStartScript")).toBool());
+    if (dlg.exec() != QDialog::Accepted)
+        return;
+    setConfigValue(_("LastTcfRemoteChannel"), dlg.remoteChannel());
+    setConfigValue(_("LastTcfRemoteArchitecture"), dlg.remoteArchitecture());
+    setConfigValue(_("LastTcfServerStartScript"), dlg.serverStartScript());
+    setConfigValue(_("LastTcfUseServerStartScript"), dlg.useServerStartScript());
+    sp->remoteChannel = dlg.remoteChannel();
+    sp->remoteArchitecture = dlg.remoteArchitecture();
+    sp->serverStartScript = dlg.serverStartScript();
+    sp->startMode = AttachTcf;
+    if (dlg.useServerStartScript())
+        sp->serverStartScript = dlg.serverStartScript();
+
+    if (RunControl *runControl = m_debuggerRunControlFactory->create(sp))
+        ProjectExplorerPlugin::instance()
+            ->startRunControl(runControl, PE::DEBUGMODE);
+}
+
 #include "debuggerplugin.moc"
 
 Q_EXPORT_PLUGIN(DebuggerPlugin)
diff --git a/src/plugins/debugger/debuggerplugin.h b/src/plugins/debugger/debuggerplugin.h
index bb53708f63c..251446db0a8 100644
--- a/src/plugins/debugger/debuggerplugin.h
+++ b/src/plugins/debugger/debuggerplugin.h
@@ -120,6 +120,7 @@ private slots:
     void attachExternalApplication();
     void attachCore();
     void attachCmdLine();
+    void attachRemoteTcf();
 
     void enableReverseDebuggingTriggered(const QVariant &value);
     void languageChanged(const QString &debuggerLanguage);
@@ -153,6 +154,7 @@ private:
     QAction *m_startRemoteAction;
     QAction *m_attachExternalAction;
     QAction *m_attachCoreAction;
+    QAction *m_attachTcfAction;
     QAction *m_detachAction;
     QComboBox *m_langBox;
     QToolButton *m_reverseToolButton;
diff --git a/src/plugins/debugger/tcf/json.cpp b/src/plugins/debugger/tcf/json.cpp
new file mode 100644
index 00000000000..f8bf75b0ca5
--- /dev/null
+++ b/src/plugins/debugger/tcf/json.cpp
@@ -0,0 +1,372 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "json.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QByteArray>
+#include <QtCore/QTextStream>
+
+#include <ctype.h>
+
+//#define DEBUG_JASON
+#ifdef DEBUG_JASON
+#define JDEBUG(s) qDebug() << s
+#else
+#define JDEBUG(s)
+#endif
+
+namespace Debugger {
+namespace Internal {
+
+static void skipSpaces(const char *&from, const char *to)
+{
+    while (from != to && isspace(*from))
+        ++from;
+}
+
+QTextStream &operator<<(QTextStream &os, const JsonValue &mi)
+{
+    return os << mi.toString();
+}
+
+void JsonValue::parsePair(const char *&from, const char *to)
+{
+    skipSpaces(from, to);
+    JDEBUG("parsePair: " << QByteArray(from, to - from));
+    m_name = parseCString(from, to);
+    skipSpaces(from, to);
+    while (from < to && *from != ':') {
+        JDEBUG("not a colon" << *from);
+        ++from;
+    }
+    ++from;
+    parseValue(from, to);
+    skipSpaces(from, to);
+}
+
+QByteArray JsonValue::parseNumber(const char *&from, const char *to)
+{
+    QByteArray result;
+    while (from < to && *from >= '0' && *from <= '9')
+        result.append(*from++);
+    return result;
+}
+
+QByteArray JsonValue::parseCString(const char *&from, const char *to)
+{
+    QByteArray result;
+    JDEBUG("parseCString: " << QByteArray(from, to - from));
+    if (*from != '"') {
+        qDebug() << "JSON Parse Error, double quote expected";
+        ++from; // So we don't hang
+        return QByteArray();
+    }
+    const char *ptr = from;
+    ++ptr;
+    while (ptr < to) {
+        if (*ptr == '"') {
+            ++ptr;
+            result = QByteArray(from + 1, ptr - from - 2);
+            break;
+        }
+        if (*ptr == '\\') {
+            ++ptr;
+            if (ptr == to) {
+                qDebug() << "JSON Parse Error, unterminated backslash escape";
+                from = ptr; // So we don't hang
+                return QByteArray();
+            }
+        }
+        ++ptr;
+    }
+    from = ptr;
+
+    int idx = result.indexOf('\\');
+    if (idx >= 0) {
+        char *dst = result.data() + idx;
+        const char *src = dst + 1, *end = result.data() + result.length();
+        do {
+            char c = *src++;
+            switch (c) {
+                case 'a': *dst++ = '\a'; break;
+                case 'b': *dst++ = '\b'; break;
+                case 'f': *dst++ = '\f'; break;
+                case 'n': *dst++ = '\n'; break;
+                case 'r': *dst++ = '\r'; break;
+                case 't': *dst++ = '\t'; break;
+                case 'v': *dst++ = '\v'; break;
+                case '"': *dst++ = '"'; break;
+                case '\\': *dst++ = '\\'; break;
+                default:
+                    {
+                        int chars = 0;
+                        uchar prod = 0;
+                        forever {
+                            if (c < '0' || c > '7') {
+                                --src;
+                                break;
+                            }
+                            prod = prod * 8 + c - '0';
+                            if (++chars == 3 || src == end)
+                                break;
+                            c = *src++;
+                        }
+                        if (!chars) {
+                            qDebug() << "JSON Parse Error, unrecognized backslash escape";
+                            return QByteArray();
+                        }
+                        *dst++ = prod;
+                    }
+            }
+            while (src != end) {
+                char c = *src++;
+                if (c == '\\')
+                    break;
+                *dst++ = c;
+            }
+        } while (src != end);
+        *dst = 0;
+        result.truncate(dst - result.data());
+    }
+
+    JDEBUG("parseCString, got " << result);
+    return result;
+}
+
+void JsonValue::parseValue(const char *&from, const char *to)
+{
+    JDEBUG("parseValue: " << QByteArray(from, to - from));
+    switch (*from) {
+        case '{':
+            parseObject(from, to);
+            break;
+        case '[':
+            parseArray(from, to);
+            break;
+        case '"':
+            m_type = String;
+            m_data = parseCString(from, to);
+            break;
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            m_type = Number;
+            m_data = parseNumber(from, to);
+        default:
+            break;
+    }
+}
+
+void JsonValue::parseObject(const char *&from, const char *to)
+{
+    JDEBUG("parseObject: " << QByteArray(from, to - from));
+    QTC_ASSERT(*from == '{', /**/);
+    ++from;
+    m_type = Object;
+    while (from < to) {
+        if (*from == '}') {
+            ++from;
+            break;
+        }
+        JsonValue child;
+        child.parsePair(from, to);
+        if (!child.isValid())
+            return;
+        m_children += child;
+        if (*from == ',')
+            ++from;
+    }
+}
+
+void JsonValue::parseArray(const char *&from, const char *to)
+{
+    JDEBUG("parseArray: " << QByteArray(from, to - from));
+    QTC_ASSERT(*from == '[', /**/);
+    ++from;
+    m_type = Array;
+    while (from < to) {
+        if (*from == ']') {
+            ++from;
+            break;
+        }
+        JsonValue child;
+        child.parseValue(from, to);
+        if (child.isValid())
+            m_children += child;
+        if (*from == ',')
+            ++from;
+    }
+}
+
+void JsonValue::setStreamOutput(const QByteArray &name, const QByteArray &content)
+{
+    if (content.isEmpty())
+        return;
+    JsonValue child;
+    child.m_type = String;
+    child.m_name = name;
+    child.m_data = content;
+    m_children += child;
+    if (m_type == Invalid)
+        m_type = Object;
+}
+
+static QByteArray ind(int indent)
+{
+    return QByteArray(2 * indent, ' ');
+}
+
+void JsonValue::dumpChildren(QByteArray * str, bool multiline, int indent) const
+{
+    for (int i = 0; i < m_children.size(); ++i) {
+        if (i != 0) {
+            *str += ',';
+            if (multiline)
+                *str += '\n';
+        }
+        if (multiline)
+            *str += ind(indent);
+        *str += m_children.at(i).toString(multiline, indent);
+    }
+}
+
+class MyString : public QString {
+public:
+    ushort at(int i) const { return constData()[i].unicode(); }
+};
+
+template<class ST, typename CT>
+inline ST escapeCStringTpl(const ST &ba)
+{
+    ST ret;
+    ret.reserve(ba.length() * 2);
+    for (int i = 0; i < ba.length(); ++i) {
+        CT c = ba.at(i);
+        switch (c) {
+            case '\\': ret += "\\\\"; break;
+            case '\a': ret += "\\a"; break;
+            case '\b': ret += "\\b"; break;
+            case '\f': ret += "\\f"; break;
+            case '\n': ret += "\\n"; break;
+            case '\r': ret += "\\r"; break;
+            case '\t': ret += "\\t"; break;
+            case '\v': ret += "\\v"; break;
+            case '"': ret += "\\\""; break;
+            default:
+                if (c < 32 || c == 127) {
+                    ret += '\\';
+                    ret += '0' + (c >> 6);
+                    ret += '0' + ((c >> 3) & 7);
+                    ret += '0' + (c & 7);
+                } else {
+                    ret += c;
+                }
+        }
+    }
+    return ret;
+}
+
+QString JsonValue::escapeCString(const QString &ba)
+{
+    return escapeCStringTpl<MyString, ushort>(static_cast<const MyString &>(ba));
+}
+
+QByteArray JsonValue::escapeCString(const QByteArray &ba)
+{
+    return escapeCStringTpl<QByteArray, uchar>(ba);
+}
+
+QByteArray JsonValue::toString(bool multiline, int indent) const
+{
+    QByteArray result;
+    switch (m_type) {
+        case Invalid:
+            if (multiline)
+                result += ind(indent) + "Invalid\n";
+            else
+                result += "Invalid";
+            break;
+        case String:
+            if (!m_name.isEmpty())
+                result += m_name + "=";
+            result += '"' + escapeCString(m_data) + '"';
+            break;
+        case Number:
+            if (!m_name.isEmpty())
+                result += '"' + m_name + "\":";
+            result += m_data;
+            break;
+        case Object:
+            if (!m_name.isEmpty())
+                result += m_name + '=';
+            if (multiline) {
+                result += "{\n";
+                dumpChildren(&result, multiline, indent + 1);
+                result += '\n' + ind(indent) + "}";
+            } else {
+                result += "{";
+                dumpChildren(&result, multiline, indent + 1);
+                result += "}";
+            }
+            break;
+        case Array:
+            if (!m_name.isEmpty())
+                result += m_name + "=";
+            if (multiline) {
+                result += "[\n";
+                dumpChildren(&result, multiline, indent + 1);
+                result += '\n' + ind(indent) + "]";
+            } else {
+                result += "[";
+                dumpChildren(&result, multiline, indent + 1);
+                result += "]";
+            }
+            break;
+    }
+    return result;
+}
+
+void JsonValue::fromString(const QByteArray &ba)
+{
+    const char *from = ba.constBegin();
+    const char *to = ba.constEnd();
+    parseValue(from, to);
+}
+
+JsonValue JsonValue::findChild(const char *name) const
+{
+    for (int i = 0; i < m_children.size(); ++i)
+        if (m_children.at(i).m_name == name)
+            return m_children.at(i);
+    return JsonValue();
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/tcf/json.h b/src/plugins/debugger/tcf/json.h
new file mode 100644
index 00000000000..18c42a57b6f
--- /dev/null
+++ b/src/plugins/debugger/tcf/json.h
@@ -0,0 +1,100 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_JSON_H
+#define DEBUGGER_JSON_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+
+namespace Debugger {
+namespace Internal {
+
+class JsonValue
+{
+public:
+    JsonValue() : m_type(Invalid) {}
+    explicit JsonValue(const QByteArray &str) { fromString(str); }
+
+    QByteArray m_name;
+    QByteArray m_data;
+    QList<JsonValue> m_children;
+
+    enum Type {
+        Invalid,
+        String,
+        Number,
+        Object,
+        Array,
+    };
+
+    Type m_type;
+
+    inline Type type() const { return m_type; }
+    inline QByteArray name() const { return m_name; }
+    inline bool hasName(const char *name) const { return m_name == name; }
+
+    inline bool isValid() const { return m_type != Invalid; }
+    inline bool isNumber() const { return m_type == Number; }
+    inline bool isString() const { return m_type == String; }
+    inline bool isObject() const { return m_type == Object; }
+    inline bool isArray() const { return m_type == Array; }
+
+
+    inline QByteArray data() const { return m_data; }
+    inline const QList<JsonValue> &children() const { return m_children; }
+    inline int childCount() const { return m_children.size(); }
+
+    const JsonValue &childAt(int index) const { return m_children[index]; }
+    JsonValue &childAt(int index) { return m_children[index]; }
+    JsonValue findChild(const char *name) const;
+
+    QByteArray toString(bool multiline = false, int indent = 0) const;
+    void fromString(const QByteArray &str);
+    void setStreamOutput(const QByteArray &name, const QByteArray &content);
+
+private:
+    static QByteArray parseCString(const char *&from, const char *to);
+    static QByteArray parseNumber(const char *&from, const char *to);
+    static QByteArray escapeCString(const QByteArray &ba);
+    static QString escapeCString(const QString &ba);
+    void parsePair(const char *&from, const char *to);
+    void parseValue(const char *&from, const char *to);
+    void parseObject(const char *&from, const char *to);
+    void parseArray(const char *&from, const char *to);
+
+    void dumpChildren(QByteArray *str, bool multiline, int indent) const;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+//Q_DECLARE_METATYPE(GdbDebugger::Internal::JsonValue);
+
+#endif // DEBUGGER_JSON_H
diff --git a/src/plugins/debugger/tcf/tcf.pri b/src/plugins/debugger/tcf/tcf.pri
new file mode 100644
index 00000000000..faaad28f759
--- /dev/null
+++ b/src/plugins/debugger/tcf/tcf.pri
@@ -0,0 +1,11 @@
+HEADERS += \
+    $$PWD/json.h \
+    $$PWD/tcfengine.h \
+
+SOURCES += \
+    $$PWD/json.cpp \
+    $$PWD/tcfengine.cpp \
+
+FORMS += 
+
+RESOURCES += 
diff --git a/src/plugins/debugger/tcf/tcfengine.cpp b/src/plugins/debugger/tcf/tcfengine.cpp
new file mode 100644
index 00000000000..7982e4e5192
--- /dev/null
+++ b/src/plugins/debugger/tcf/tcfengine.cpp
@@ -0,0 +1,569 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "tcfengine.h"
+
+#include "debuggerstringutils.h"
+#include "debuggerdialogs.h"
+#include "breakhandler.h"
+#include "debuggerconstants.h"
+#include "debuggermanager.h"
+#include "moduleshandler.h"
+#include "registerhandler.h"
+#include "stackhandler.h"
+#include "watchhandler.h"
+#include "watchutils.h"
+#include "moduleshandler.h"
+#include "json.h"
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTimer>
+
+#include <QtGui/QAction>
+#include <QtGui/QApplication>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+#include <QtGui/QToolTip>
+
+#include <QtNetwork/QTcpSocket>
+
+#define DEBUG_TCF 1
+#if DEBUG_TCF
+#   define SDEBUG(s) qDebug() << s
+#else
+#   define SDEBUG(s)
+#endif
+# define XSDEBUG(s) qDebug() << s
+
+#define CB(callback) &TcfEngine::callback, STRINGIFY(callback)
+
+//#define USE_CONGESTION_CONTROL
+
+static QByteArray C(const QByteArray &ba1,
+    const QByteArray &ba2 = QByteArray(),
+    const QByteArray &ba3 = QByteArray(),
+    const QByteArray &ba4 = QByteArray(),
+    const QByteArray &ba5 = QByteArray())
+{
+    QByteArray result = ba1;
+    if (!ba2.isEmpty()) { result += '\0'; result += ba2; }
+    if (!ba3.isEmpty()) { result += '\0'; result += ba3; }
+    if (!ba4.isEmpty()) { result += '\0'; result += ba4; }
+    if (!ba5.isEmpty()) { result += '\0'; result += ba5; }
+    return result;
+}
+
+namespace Debugger {
+namespace Internal {
+
+///////////////////////////////////////////////////////////////////////
+//
+// TcfCommand
+//
+///////////////////////////////////////////////////////////////////////
+
+
+QString TcfEngine::TcfCommand::toString() const
+{
+    return quoteUnprintableLatin1(command);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// TcfEngine
+//
+///////////////////////////////////////////////////////////////////////
+
+TcfEngine::TcfEngine(DebuggerManager *manager)
+    : IDebuggerEngine(manager)
+{
+    m_congestion = 0;
+    m_inAir = 0;
+
+    m_sendTimer.setSingleShot(true);
+    m_sendTimer.setInterval(100); // ms
+    connect(&m_sendTimer, SIGNAL(timeout()), this, SLOT(handleSendTimer()));
+
+    m_socket = new QTcpSocket(this);
+    connect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected()));
+    connect(m_socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
+    connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
+        this, SLOT(socketError(QAbstractSocket::SocketError)));
+
+    //void aboutToClose ()
+    //void bytesWritten ( qint64 bytes )
+    //void readChannelFinished ()
+    connect(m_socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()));
+
+    //connect(m_socket, SIGNAL(hostFound())
+    //connect(m_socket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy, QAuthenticator *)))
+    //connect(m_socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+    //    thism SLOT(socketStateChanged(QAbstractSocket::SocketState)));
+}
+
+TcfEngine::~TcfEngine()
+{
+}
+
+void TcfEngine::socketReadyRead()
+{
+    //XSDEBUG("TcfEngine::socketReadyRead()");
+    m_inbuffer.append(m_socket->readAll());
+    int pos = 0;
+    while (1) {
+        // the  "\3" is followed by either "\1" or "\2"
+        int next = m_inbuffer.indexOf("\3", pos);
+        //qDebug() << "pos: " << pos << "next: " << next;
+        if (next == -1)
+            break;
+        handleResponse(m_inbuffer.mid(pos, next - pos));
+        pos = next + 2; 
+    }
+    m_inbuffer.clear();
+}
+
+void TcfEngine::socketConnected()
+{
+    showStatusMessage("Socket connected.");
+    m_socket->waitForConnected(2000);
+    //sendCommand("Locator", "redirect", "ID");
+}
+
+void TcfEngine::socketDisconnected()
+{
+    XSDEBUG("FIXME:  TcfEngine::socketDisconnected()");
+}
+
+void TcfEngine::socketError(QAbstractSocket::SocketError)
+{
+    QString msg = tr("%1.").arg(m_socket->errorString());
+    //QMessageBox::critical(q->mainWindow(), tr("Error"), msg);
+    showStatusMessage(msg);
+    manager()->notifyInferiorExited();
+}
+
+void TcfEngine::executeDebuggerCommand(const QString &command)
+{
+    QByteArray cmd = command.toUtf8();
+    cmd = cmd.mid(cmd.indexOf(' ') + 1);
+    QByteArray null;
+    null.append('\0');
+    // FIXME: works for single-digit escapes only
+    cmd.replace("\\0", null);
+    cmd.replace("\\1", "\1");
+    cmd.replace("\\3", "\3");
+    TcfCommand tcf;
+    tcf.command = cmd;
+    enqueueCommand(tcf);
+}
+
+void TcfEngine::shutdown()
+{
+    m_congestion = 0;
+    m_inAir = 0;
+    m_services.clear();
+    exitDebugger(); 
+}
+
+void TcfEngine::exitDebugger()
+{
+    SDEBUG("TcfEngine::exitDebugger()");
+    manager()->notifyInferiorExited();
+}
+
+void TcfEngine::startDebugger(const DebuggerStartParametersPtr &sp)
+{
+    setState(InferiorRunningRequested);
+    showStatusMessage(tr("Running requested..."), 5000);
+    const int pos = sp->remoteChannel.indexOf(QLatin1Char(':'));
+    const QString host = sp->remoteChannel.left(pos);
+    const quint16 port = sp->remoteChannel.mid(pos + 1).toInt();
+    //QTimer::singleShot(0, this, SLOT(runInferior()));
+    m_socket->connectToHost(host, port);
+    emit startSuccessful();
+}
+
+void TcfEngine::continueInferior()
+{
+    SDEBUG("TcfEngine::continueInferior()");
+}
+
+void TcfEngine::runInferior()
+{
+}
+
+void TcfEngine::interruptInferior()
+{
+    XSDEBUG("TcfEngine::interruptInferior()");
+}
+
+void TcfEngine::executeStep()
+{
+    //SDEBUG("TcfEngine::executeStep()");
+}
+
+void TcfEngine::executeStepI()
+{
+    //SDEBUG("TcfEngine::executeStepI()");
+}
+
+void TcfEngine::executeStepOut()
+{
+    //SDEBUG("TcfEngine::executeStepOut()");
+}
+
+void TcfEngine::executeNext()
+{
+    //SDEBUG("TcfEngine::nextExec()");
+}
+
+void TcfEngine::executeNextI()
+{
+    //SDEBUG("TcfEngine::executeNextI()");
+}
+
+void TcfEngine::executeRunToLine(const QString &fileName, int lineNumber)
+{
+    Q_UNUSED(fileName)
+    Q_UNUSED(lineNumber)
+    SDEBUG("FIXME:  TcfEngine::executeRunToLine()");
+}
+
+void TcfEngine::executeRunToFunction(const QString &functionName)
+{
+    Q_UNUSED(functionName)
+    XSDEBUG("FIXME:  TcfEngine::executeRunToFunction()");
+}
+
+void TcfEngine::executeJumpToLine(const QString &fileName, int lineNumber)
+{
+    Q_UNUSED(fileName)
+    Q_UNUSED(lineNumber)
+    XSDEBUG("FIXME:  TcfEngine::executeJumpToLine()");
+}
+
+void TcfEngine::activateFrame(int index)
+{
+    Q_UNUSED(index)
+}
+
+void TcfEngine::selectThread(int index)
+{
+    Q_UNUSED(index)
+}
+
+void TcfEngine::attemptBreakpointSynchronization()
+{
+}
+
+void TcfEngine::loadSymbols(const QString &moduleName)
+{
+    Q_UNUSED(moduleName)
+}
+
+void TcfEngine::loadAllSymbols()
+{
+}
+
+void TcfEngine::reloadModules()
+{
+}
+
+void TcfEngine::requestModuleSymbols(const QString &moduleName)
+{
+    Q_UNUSED(moduleName)
+}
+
+
+void TcfEngine::handleResponse(const QByteArray &response)
+{
+    static QTime lastTime;
+
+    //debugMessage(_("            "), currentTime());
+    QList<QByteArray> parts = response.split('\0');
+    if (parts.size() < 2 || !parts.last().isEmpty()) {
+        SDEBUG("WRONG RESPONSE PACKET LAYOUT" << parts);
+        //if (response.isEmpty())
+            acknowledgeResult();
+        return;
+    }
+    parts.removeLast(); // always empty
+    QByteArray tag = parts.at(0);
+    int n = parts.size();
+    if (n == 2 && tag == "N") { // unidentified command
+        int token = parts.at(1).toInt();
+        TcfCommand tcf = m_cookieForToken[token];
+        SDEBUG("COMMAND NOT RECOGNIZED FOR TOKEN" << token << tcf.toString());
+        showDebuggerOutput(LogOutput, QString::number(token) + "^"
+               + "NOT RECOQNIZED: " + quoteUnprintableLatin1(response));
+        acknowledgeResult();
+    } else if (n == 2 && tag == "F") { // flow control
+        m_congestion = parts.at(1).toInt();
+        SDEBUG("CONGESTION: " << m_congestion);
+    } else if (n == 4 && tag == "R") { // result data
+        acknowledgeResult();
+        int token = parts.at(1).toInt();
+        QByteArray message = parts.at(2);
+        JsonValue data(parts.at(3));
+        showDebuggerOutput(LogOutput, QString("%1^%2%3").arg(token)
+            .arg(quoteUnprintableLatin1(response))
+            .arg(QString::fromUtf8(data.toString())));
+        TcfCommand tcf = m_cookieForToken[token];
+        JsonValue result(data);
+        SDEBUG("GOOD RESPONSE: " << quoteUnprintableLatin1(response));
+        if (tcf.callback)
+            (this->*(tcf.callback))(result, tcf.cookie);
+    } else if (n == 3 && tag == "P") { // progress data (partial result)
+        //int token = parts.at(1).toInt();
+        QByteArray data = parts.at(2);
+        SDEBUG(_("\nTCF PARTIAL:") << quoteUnprintableLatin1(response));
+    } else if (n == 4 && tag == "E") { // an event
+        QByteArray service = parts.at(1);
+        QByteArray eventName = parts.at(2);
+        JsonValue data(parts.at(3));
+        if (eventName != "peerHeartBeat")
+            SDEBUG(_("\nTCF EVENT:") << quoteUnprintableLatin1(response)
+                << data.toString());
+        if (service == "Locator" && eventName == "Hello") {
+            m_services.clear();
+            foreach (const JsonValue &service, data.children())
+                m_services.append(service.data());
+            QTimer::singleShot(0, this, SLOT(startDebugging()));
+        }
+    } else {
+        SDEBUG("UNKNOWN RESPONSE PACKET:"
+            << quoteUnprintableLatin1(response) << parts);
+    }
+}
+
+void TcfEngine::startDebugging()
+{
+    //foreach (const QByteArray &service, m_services) {
+    //    postCommand(CB(handleRunControlGetChildren),
+    //        service, "getChildren", "\"\"");
+    //}
+
+    postCommand(C("Diagnostics", "getChildren", "\"\""),
+        CB(handleRunControlGetChildren));
+    postCommand(C("Streams", "getChildren", "\"\""));
+    postCommand(C("Expressions", "getChildren", "\"\""));
+    postCommand(C("SysMonitor", "getChildren", "\"\""));
+    //postCommand(C("FileSystem", "getChildren", "\"\""));
+    //postCommand(C("Processes", "getChildren", "\"\""));
+    //postCommand(CB(handleRunControlGetChildren), "LineNumbers", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Symbols", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "StackTrace", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Registers", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Memory", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Breakpoints", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "RunControl", "getChildren");
+    //postCommand(CB(handleRunControlGetChildren), "Locator", "getChildren");
+
+
+    //postCommand(CB(handleRunControlSuspend),
+    //    "RunControl", "suspend", "\"Thread1\"");
+    //postCommand(CB(handleRunControlSuspend),
+    //    "RunControl", "getContext", "\"P12318\"");
+
+    //postCommand(C("Locator", "sync"), CB(handleRunControlGetChildren));
+    //postCommand("Locator", "redirect", "ID");
+
+    //postCommand(C("FileSystem", "open", "\"/bin/ls\"", "1", "2", "3"),
+    //    CB(handleRunControlGetChildren));
+    postCommand(C("FileSystem", "stat", "\"/bin/ls\""),
+        CB(handleRunControlGetChildren));
+}
+
+void TcfEngine::postCommand(const QByteArray &cmd,
+    TcfCommandCallback callback, const char *callbackName)
+{
+    static int token = 20;
+    ++token;
+    
+    //const char marker_eom = -1;
+    //const char marker_eos = -2;
+    //const char marker_null = -3;
+
+    QByteArray ba = "C";
+    ba.append('\0');
+    ba.append(QByteArray::number(token));
+    ba.append('\0');
+    ba.append(cmd);
+    ba.append('\0');
+    ba.append('\3');
+    ba.append('\1');
+
+    TcfCommand tcf;
+    tcf.command = ba;
+    tcf.callback = callback;
+    tcf.callbackName = callbackName;
+    tcf.token = token;
+
+    m_cookieForToken[token] = tcf;
+
+    enqueueCommand(tcf);
+}
+
+// Congestion control does not seem to work that way. Basically it's
+// already too late when we get a flow control packet
+void TcfEngine::enqueueCommand(const TcfCommand &cmd)
+{
+#ifdef USE_CONGESTION_CONTROL
+    // congestion controled
+    if (m_congestion <= 0 && m_sendQueue.isEmpty()) {
+        //SDEBUG("DIRECT SEND" << cmd.toString());
+        sendCommandNow(cmd);
+    } else {
+        SDEBUG("QUEUE " << cmd.toString());
+        m_sendQueue.enqueue(cmd);
+        m_sendTimer.start();
+    }
+#else
+    // synchrounously
+    if (m_inAir == 0)
+        sendCommandNow(cmd);
+    else
+        m_sendQueue.enqueue(cmd);
+#endif
+}
+
+void TcfEngine::handleSendTimer()
+{
+    QTC_ASSERT(!m_sendQueue.isEmpty(), return);
+
+    if (m_congestion > 0) {
+        // not ready...
+        SDEBUG("WAITING FOR CONGESTION TO GO DOWN...");
+        m_sendTimer.start();
+    } else {
+        // go!
+        sendCommandNow(m_sendQueue.dequeue());
+    }
+}
+
+void TcfEngine::sendCommandNow(const TcfCommand &cmd)
+{
+    ++m_inAir;
+    int result = m_socket->write(cmd.command);
+    Q_UNUSED(result)
+    m_socket->flush();
+    showDebuggerInput(LogInput, QString::number(cmd.token) + " " + cmd.toString());
+    SDEBUG("SEND " <<  cmd.toString()); //<< " " << QString::number(result));
+}
+
+void TcfEngine::acknowledgeResult()
+{
+#if !defined(USE_CONGESTION_CONTROL)
+    QTC_ASSERT(m_inAir == 1, /**/);
+    m_inAir = 0;
+    if (!m_sendQueue.isEmpty())
+        sendCommandNow(m_sendQueue.dequeue());
+#endif
+}
+
+void TcfEngine::handleRunControlSuspend(const JsonValue &data, const QVariant &)
+{
+    SDEBUG("HANDLE RESULT" << data.toString());
+}
+
+void TcfEngine::handleRunControlGetChildren(const JsonValue &data, const QVariant &)
+{
+    SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString());
+}
+
+void TcfEngine::handleSysMonitorGetChildren(const JsonValue &data, const QVariant &)
+{
+    SDEBUG("HANDLE RUN CONTROL GET CHILDREN" << data.toString());
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Tooltip specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+static WatchData m_toolTip;
+static QPoint m_toolTipPos;
+static QHash<QString, WatchData> m_toolTipCache;
+
+void TcfEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
+{
+    Q_UNUSED(mousePos)
+    Q_UNUSED(editor)
+    Q_UNUSED(cursorPos)
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Watch specific stuff
+//
+//////////////////////////////////////////////////////////////////////
+
+void TcfEngine::assignValueInDebugger(const QString &expression,
+    const QString &value)
+{
+    XSDEBUG("ASSIGNING: " << expression + '=' + value);
+    updateLocals();
+}
+
+void TcfEngine::updateLocals()
+{
+}
+
+void TcfEngine::updateWatchData(const WatchData &)
+{
+    //qq->watchHandler()->rebuildModel();
+    showStatusMessage(tr("Stopped."), 5000);
+}
+
+void TcfEngine::updateSubItem(const WatchData &data0)
+{
+    Q_UNUSED(data0)
+    QTC_ASSERT(false, return);
+}
+
+void TcfEngine::debugMessage(const QString &msg)
+{
+    showDebuggerOutput(LogDebug, msg);
+}
+
+IDebuggerEngine *createTcfEngine(DebuggerManager *manager)
+{
+    return new TcfEngine(manager);
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/tcf/tcfengine.h b/src/plugins/debugger/tcf/tcfengine.h
new file mode 100644
index 00000000000..79b8079d7d1
--- /dev/null
+++ b/src/plugins/debugger/tcf/tcfengine.h
@@ -0,0 +1,168 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DEBUGGER_TCFENGINE_H
+#define DEBUGGER_TCFENGINE_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtCore/QPoint>
+#include <QtCore/QProcess>
+#include <QtCore/QQueue>
+#include <QtCore/QSet>
+#include <QtCore/QTimer>
+#include <QtCore/QVariant>
+
+#include <QtNetwork/QAbstractSocket>
+
+QT_BEGIN_NAMESPACE
+class QTcpSocket;
+QT_END_NAMESPACE
+
+#include "idebuggerengine.h"
+#include "debuggermanager.h"
+#include "json.h"
+
+namespace Debugger {
+namespace Internal {
+
+class ScriptAgent;
+class WatchData;
+
+class TcfEngine : public IDebuggerEngine
+{
+    Q_OBJECT
+
+public:
+    explicit TcfEngine(DebuggerManager *parent);
+    ~TcfEngine();
+
+private:
+    // IDebuggerEngine implementation
+    void executeStep();
+    void executeStepOut();
+    void executeNext();
+    void executeStepI();
+    void executeNextI();
+
+    void shutdown();
+    void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
+    void startDebugger(const DebuggerStartParametersPtr &sp);
+    void exitDebugger();
+
+    void continueInferior();
+    Q_SLOT void runInferior();
+    void interruptInferior();
+
+    void executeRunToLine(const QString &fileName, int lineNumber);
+    void executeRunToFunction(const QString &functionName);
+    void executeJumpToLine(const QString &fileName, int lineNumber);
+
+    void activateFrame(int index);
+    void selectThread(int index);
+
+    void attemptBreakpointSynchronization();
+
+    void assignValueInDebugger(const QString &expr, const QString &value);
+    void executeDebuggerCommand(const QString & command);
+
+    void loadSymbols(const QString &moduleName);
+    void loadAllSymbols();
+    void requestModuleSymbols(const QString &moduleName);
+    void reloadModules();
+    void reloadRegisters() {}
+    void reloadSourceFiles() {}
+    void reloadFullStack() {}
+
+    bool supportsThreads() const { return true; }
+    void maybeBreakNow(bool byFunction);
+    void updateWatchData(const WatchData &data);
+    void updateLocals();
+    void updateSubItem(const WatchData &data);
+
+    Q_SLOT void socketConnected();
+    Q_SLOT void socketDisconnected();
+    Q_SLOT void socketError(QAbstractSocket::SocketError);
+    Q_SLOT void socketReadyRead();
+
+    void handleResponse(const QByteArray &ba);
+    void handleRunControlSuspend(const JsonValue &response, const QVariant &);
+    void handleRunControlGetChildren(const JsonValue &response, const QVariant &);
+    void handleSysMonitorGetChildren(const JsonValue &response, const QVariant &);
+
+private:
+    Q_SLOT void startDebugging();
+
+    typedef void (TcfEngine::*TcfCommandCallback)
+        (const JsonValue &record, const QVariant &cookie);
+
+    struct TcfCommand
+    {
+        TcfCommand() : flags(0), token(-1), callback(0), callbackName(0) {}
+
+        QString toString() const;
+
+        int flags;
+        int token;
+        TcfCommandCallback callback;
+        const char *callbackName;
+        QByteArray command;
+        QVariant cookie;
+    };
+
+    void postCommand(const QByteArray &cmd,
+        TcfCommandCallback callback = 0, const char *callbackName = 0);
+    void sendCommandNow(const TcfCommand &command);
+    void debugMessage(const QString &msg);
+
+    QHash<int, TcfCommand> m_cookieForToken;
+
+    QQueue<TcfCommand> m_sendQueue;
+    
+    // timer based congestion control. does not seem to work well.
+    void enqueueCommand(const TcfCommand &command);
+    Q_SLOT void handleSendTimer();
+    int m_congestion;
+    QTimer m_sendTimer;
+
+    // synchrounous communication
+    void acknowledgeResult();
+    int m_inAir;
+
+    QTcpSocket *m_socket;
+    QByteArray m_inbuffer;
+    QList<QByteArray> m_services;
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // DEBUGGER_TCFENGINE_H
-- 
GitLab