From b3addf14f154cc615b41def18f08f3ded5555957 Mon Sep 17 00:00:00 2001
From: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
Date: Tue, 20 Oct 2009 11:02:16 +0200
Subject: [PATCH] fix shutdown paths

this includes:
- move the gdb ownership back to the engine (thus strip down the
  adaptors as far as possible)
- make gdb startup synchronous
- make adapter shutdown synchronous
- fix the state transitions relating to shutdown
---
 src/plugins/debugger/cdb/cdbdebugengine.cpp   |  12 +-
 src/plugins/debugger/debuggerconstants.h      |   6 +-
 src/plugins/debugger/debuggermanager.cpp      |  95 +++---
 src/plugins/debugger/debuggermanager.h        |   2 +-
 .../debugger/gdb/abstractgdbadapter.cpp       |  25 +-
 src/plugins/debugger/gdb/abstractgdbadapter.h |  38 ++-
 src/plugins/debugger/gdb/attachgdbadapter.cpp |  73 +----
 src/plugins/debugger/gdb/attachgdbadapter.h   |   8 +-
 src/plugins/debugger/gdb/coregdbadapter.cpp   |  55 +---
 src/plugins/debugger/gdb/coregdbadapter.h     |   6 -
 src/plugins/debugger/gdb/gdbengine.cpp        | 276 ++++++++++++------
 src/plugins/debugger/gdb/gdbengine.h          |  11 +-
 src/plugins/debugger/gdb/plaingdbadapter.cpp  |  93 +-----
 src/plugins/debugger/gdb/plaingdbadapter.h    |   7 +-
 src/plugins/debugger/gdb/remotegdbadapter.cpp |  74 +----
 src/plugins/debugger/gdb/remotegdbadapter.h   |   6 -
 src/plugins/debugger/gdb/trkgdbadapter.cpp    | 146 +--------
 src/plugins/debugger/gdb/trkgdbadapter.h      |  14 +-
 src/plugins/debugger/idebuggerengine.h        |   2 +-
 19 files changed, 301 insertions(+), 648 deletions(-)

diff --git a/src/plugins/debugger/cdb/cdbdebugengine.cpp b/src/plugins/debugger/cdb/cdbdebugengine.cpp
index e96c864baa7..d03c68bab7f 100644
--- a/src/plugins/debugger/cdb/cdbdebugengine.cpp
+++ b/src/plugins/debugger/cdb/cdbdebugengine.cpp
@@ -824,6 +824,9 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
 void CdbDebugEngine::processTerminated(unsigned long exitCode)
 {
     manager()->showDebuggerOutput(LogMisc, tr("The process exited with exit code %1.").arg(exitCode));
+    if (m_engine->state() != InferiorStopping)
+        setState(InferiorStopping, Q_FUNC_INFO, __LINE__);
+    setState(InferiorStopped, Q_FUNC_INFO, __LINE__);
     setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__);
     m_d->setDebuggeeHandles(0, 0);
     m_d->clearForRun();
@@ -919,14 +922,11 @@ void CdbDebugEnginePrivate::endDebugging(EndDebuggingMode em)
         errorMessage.clear();
     }
     // Clean up resources (open files, etc.)
-    m_engine->setState(AdapterShuttingDown, Q_FUNC_INFO, __LINE__);
+    m_engine->setState(EngineShuttingDown, Q_FUNC_INFO, __LINE__);
     clearForRun();
     const HRESULT hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE);
-    if (SUCCEEDED(hr)) {
-        m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
-    } else {
-        m_engine->setState(AdapterShutdownFailed, Q_FUNC_INFO, __LINE__);
-        m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
+    m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
+    if (!SUCCEEDED(hr)) {
         errorMessage = QString::fromLatin1("There were errors trying to end debugging: %1").arg(msgComFailed("EndSession", hr));
         manager()->showDebuggerOutput(LogError, errorMessage);
     }
diff --git a/src/plugins/debugger/debuggerconstants.h b/src/plugins/debugger/debuggerconstants.h
index 2100aa873fe..d3bc9d20f40 100644
--- a/src/plugins/debugger/debuggerconstants.h
+++ b/src/plugins/debugger/debuggerconstants.h
@@ -79,15 +79,13 @@ enum DebuggerState
 
     InferiorStopping,           // Debuggee running, stop requested
     InferiorStopped,            // Debuggee stopped
-    InferiorStopFailed,         // Debuggee stopped
+    InferiorStopFailed,         // Debuggee not stopped, will kill debugger
 
     InferiorShuttingDown,
     InferiorShutDown,
     InferiorShutdownFailed,
 
-    AdapterShuttingDown,
-    //AdapterShutDown,          // Use DebuggerNotReady instead
-    AdapterShutdownFailed,
+    EngineShuttingDown
 };
 
 enum DebuggerStartMode
diff --git a/src/plugins/debugger/debuggermanager.cpp b/src/plugins/debugger/debuggermanager.cpp
index c7f541293fc..1bcb97a955c 100644
--- a/src/plugins/debugger/debuggermanager.cpp
+++ b/src/plugins/debugger/debuggermanager.cpp
@@ -101,43 +101,35 @@
 // gdbserver, the trk client etc are referred to as 'Adapter',
 // whereas the debugged process is referred to as 'Inferior'.
 //
-//               0 == DebuggerNotReady
+//              0 == DebuggerNotReady
 //                          |
-//                     EngineStarting
+//                    EngineStarting
 //                          |
-//                     AdapterStarting --> AdapterStartFailed --> 0
+//                    AdapterStarting --> AdapterStartFailed --> 0
 //                          |
-//                     AdapterStarted
-//                          |
-//                     InferiorStarting --> InferiorStartFailed --> 0
-//                          |
-//         (core)           |     (attach) (remote)
-//      .-----------------<-|->--------------------.
-//      |                   v                      |
-//  InferiorUnrunnable      |                      |
-//      |                   |                      v
-//      |                   | (plain)
-//      |                   | (trk)
-//      |                   |
-//      |                   |  .------------------------------------.
-//      |                   |  v                                    |
-//      |              InferiorRunningRequested    v                |
-//      |                   |                      |                |
-//      |        .---- InferiorRunning             |                |
-//      |        |          |                      |                |
-//      |        |     InferiorStopping            |                |
-//      |        |          |                      |                |
-//      |        v          v                      |                |
-//      |        |<--- InferiorStopped <-----------'                |
-//      |        |          |                                       |
-//      |        |          `---------------------------------------'
-//      |        |          
-//      |        '---> InferiorShuttingDown  -> InferiorShutdownFailed
-//      |                   |
-//      |              InferiorShutDown
-//      |                   |
-//      |                   v
-//      '------------> AdapterShuttingDown  -> AdapterShutdownFailed --> 0
+//                    AdapterStarted ------------------------------------.
+//                          |                                            v
+//                   InferiorStarting ----> InferiorStartFailed -------->|
+//                          |                                            |
+//         (core)           |     (attach) (term) (remote)               |
+//      .-----------------<-|->------------------.                       |
+//      |                   v                    |                       |
+//  InferiorUnrunnable      | (plain)            |                       |
+//      |                   | (trk)              |                       |
+//      |                   |                    |                       |
+//      |    .--> InferiorRunningRequested       |                       |
+//      |    |              |                    |                       |
+//      |    |       InferiorRunning             |                       |
+//      |    |              |                    |                       |
+//      |    |       InferiorStopping            |                       |
+//      |    |              |                    |                       |
+//      |    '------ InferiorStopped <-----------'                       |
+//      |                   |                                            v
+//      |          InferiorShuttingDown  ->  InferiorShutdownFailed ---->|
+//      |                   |                                            |
+//      |            InferiorShutDown                                    |
+//      |                   |                                            |
+//      '-------->  EngineShuttingDown  <--------------------------------'
 //                          |
 //                          0
 //
@@ -208,8 +200,7 @@ static const char *stateName(int s)
         SN(InferiorShuttingDown)
         SN(InferiorShutDown)
         SN(InferiorShutdownFailed)
-        SN(AdapterShuttingDown)
-        SN(AdapterShutdownFailed)
+        SN(EngineShuttingDown)
     }
     return "<unknown>";
     #undef SN
@@ -1574,7 +1565,7 @@ static bool isAllowedTransition(int from, int to)
     case AdapterStarting:
         return to == AdapterStarted || to == AdapterStartFailed;
     case AdapterStarted:
-        return to == InferiorStarting;
+        return to == InferiorStarting || to == EngineShuttingDown;
     case AdapterStartFailed:
         return to == DebuggerNotReady;
 
@@ -1582,37 +1573,38 @@ static bool isAllowedTransition(int from, int to)
         return to == InferiorRunningRequested || to == InferiorStopped
             || to == InferiorStartFailed || to == InferiorUnrunnable;
     case InferiorStartFailed:
-        return to == DebuggerNotReady;
+        return to == EngineShuttingDown;
 
     case InferiorRunningRequested:
         return to == InferiorRunning;
     case InferiorRunning:
-        return to == InferiorStopping || to == InferiorShuttingDown;
+        return to == InferiorStopping;
 
     case InferiorStopping:
         return to == InferiorStopped || to == InferiorStopFailed;
     case InferiorStopped:
         return to == InferiorRunningRequested || to == InferiorShuttingDown;
     case InferiorStopFailed:
-        return to == DebuggerNotReady;
+        return to == EngineShuttingDown;
 
     case InferiorUnrunnable:
-        return to == AdapterShuttingDown;
+        return to == EngineShuttingDown;
     case InferiorShuttingDown:
         return to == InferiorShutDown || to == InferiorShutdownFailed;
     case InferiorShutDown:
-        return to == AdapterShuttingDown;
+        return to == EngineShuttingDown;
+    case InferiorShutdownFailed:
+        return to == EngineShuttingDown;
 
-    case AdapterShuttingDown:
+    case EngineShuttingDown:
         return to == DebuggerNotReady;
-
-    default:
-        qDebug() << "UNKNOWN STATE: " << from;
     }
+
+    qDebug() << "UNKNOWN STATE:" << from;
     return false;
 }
 
-void DebuggerManager::setState(DebuggerState state)
+void DebuggerManager::setState(DebuggerState state, bool forced)
 {
     //STATE_DEBUG("STATUS CHANGE: FROM " << stateName(d->m_state)
     //        << " TO " << stateName(state));
@@ -1621,7 +1613,7 @@ void DebuggerManager::setState(DebuggerState state)
         .arg(stateName(d->m_state)).arg(d->m_state).arg(stateName(state)).arg(state);
     //if (!((d->m_state == -1 && state == 0) || (d->m_state == 0 && state == 0)))
     //    qDebug() << msg;
-    if (!isAllowedTransition(d->m_state, state))
+    if (!forced && !isAllowedTransition(d->m_state, state))
         qDebug() << "UNEXPECTED STATE TRANSITION: " << msg;
 
     showDebuggerOutput(LogDebug, msg);
@@ -1715,8 +1707,7 @@ bool DebuggerManager::debuggerActionsEnabled() const
     case InferiorShuttingDown:
     case InferiorShutDown:
     case InferiorShutdownFailed:
-    case AdapterShuttingDown:
-    case AdapterShutdownFailed:
+    case EngineShuttingDown:
         break;
     }
     return false;
@@ -1793,9 +1784,9 @@ DebuggerState IDebuggerEngine::state() const
     return m_manager->state();
 }
 
-void IDebuggerEngine::setState(DebuggerState state)
+void IDebuggerEngine::setState(DebuggerState state, bool forced)
 {
-    m_manager->setState(state);
+    m_manager->setState(state, forced);
 }
 
 //////////////////////////////////////////////////////////////////////
diff --git a/src/plugins/debugger/debuggermanager.h b/src/plugins/debugger/debuggermanager.h
index bc82ec187ba..c82bacb1e0e 100644
--- a/src/plugins/debugger/debuggermanager.h
+++ b/src/plugins/debugger/debuggermanager.h
@@ -285,7 +285,7 @@ private:
 
     void cleanupViews();
 
-    void setState(DebuggerState state);
+    void setState(DebuggerState state, bool forced = false);
 
     //
     // internal implementation
diff --git a/src/plugins/debugger/gdb/abstractgdbadapter.cpp b/src/plugins/debugger/gdb/abstractgdbadapter.cpp
index 52c76107606..cd99fec311e 100644
--- a/src/plugins/debugger/gdb/abstractgdbadapter.cpp
+++ b/src/plugins/debugger/gdb/abstractgdbadapter.cpp
@@ -47,35 +47,18 @@ AbstractGdbAdapter::~AbstractGdbAdapter()
     disconnect();
 }
 
-// This cannot be in the c'tor, as it would not connect the "virtual" slots
-void AbstractGdbAdapter::commonInit()
+void AbstractGdbAdapter::shutdown()
 {
-    QTC_ASSERT(state() == EngineStarting, qDebug() << state());
-    connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
-        this, SLOT(handleGdbError(QProcess::ProcessError)));
-    connect(&m_gdbProc, SIGNAL(started()),
-        this, SLOT(handleGdbStarted()));
-    connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
-        this, SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
-    connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
-        this, SIGNAL(readyReadStandardOutput()));
-    connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
-        this, SIGNAL(readyReadStandardError()));
 }
 
-QByteArray AbstractGdbAdapter::readAllStandardOutput()
+const char *AbstractGdbAdapter::inferiorShutdownCommand() const
 {
-    return m_gdbProc.readAllStandardOutput();
-}
-
-QByteArray AbstractGdbAdapter::readAllStandardError()
-{
-    return m_gdbProc.readAllStandardError();
+    return "kill";
 }
 
 void AbstractGdbAdapter::write(const QByteArray &data)
 {
-    m_gdbProc.write(data);
+    m_engine->m_gdbProc.write(data);
 }
 
 bool AbstractGdbAdapter::isTrkAdapter() const
diff --git a/src/plugins/debugger/gdb/abstractgdbadapter.h b/src/plugins/debugger/gdb/abstractgdbadapter.h
index 7765401e1a6..9dc018e0380 100644
--- a/src/plugins/debugger/gdb/abstractgdbadapter.h
+++ b/src/plugins/debugger/gdb/abstractgdbadapter.h
@@ -42,7 +42,7 @@ namespace Internal {
 // debugging and TrkGdbAdapter used for on-device debugging.
 // In the PlainGdbAdapter case it's just a wrapper around a QProcess running
 // gdb, in the TrkGdbAdapter case it's the interface to the gdb process in
-// the whole rfomm/gdb/gdbserver combo.
+// the whole rfcomm/gdb/gdbserver combo.
 class AbstractGdbAdapter : public QObject
 {
     Q_OBJECT
@@ -51,34 +51,39 @@ public:
     AbstractGdbAdapter(GdbEngine *engine, QObject *parent = 0);
     virtual ~AbstractGdbAdapter();
 
-    QByteArray readAllStandardOutput();
-    QByteArray readAllStandardError();
     virtual void write(const QByteArray &data);
     virtual bool isTrkAdapter() const; // isUtterlyBrokenAdapter
 
     virtual void startAdapter() = 0;
     virtual void startInferior() = 0;
     virtual void interruptInferior() = 0;
-    virtual void shutdown() = 0;
+    virtual void shutdown();
+    virtual const char *inferiorShutdownCommand() const;
 
     virtual bool dumpersAvailable() const = 0;
 
+    static QString msgGdbStopFailed(const QString &why);
+    static QString msgInferiorStopFailed(const QString &why);
+    static QString msgAttachedToStoppedInferior();
+    static QString msgInferiorStarted();
+    static QString msgInferiorRunning();
+    static QString msgConnectRemoteServerFailed(const QString &why);
+
 signals:
     void adapterStarted();
+
+    // Something went wrong with the adapter *before* adapterStarted() was emitted.
+    // Make sure to clean up everything before emitting this signal.
     void adapterStartFailed(const QString &msg, const QString &settingsIdHint);
-    void adapterShutDown();
-    void adapterShutdownFailed(const QString &msg);
+
+    // Something went wrong with the adapter *after* adapterStarted() was emitted.
+    // Make sure to clean up everything before emitting this signal.
     void adapterCrashed(const QString &msg);
 
+    // The adapter is still running just fine, but it failed to acquire a debuggee.
     void inferiorStartFailed(const QString &msg);
-    void inferiorShutDown();
-    void inferiorShutdownFailed(const QString &msg);
     
-    void readyReadStandardOutput();
-    void readyReadStandardError();
-
 protected:
-    void commonInit();
     DebuggerState state() const
         { return m_engine->state(); }
     void setState(DebuggerState state)
@@ -90,16 +95,7 @@ protected:
     void showStatusMessage(const QString &msg) const
         { m_engine->showStatusMessage(msg); }
 
-    static QString msgGdbStopFailed(const QString &why);
-    static QString msgInferiorStopFailed(const QString &why);
-    static QString msgAttachedToStoppedInferior();
-    static QString msgInferiorStarted();
-    static QString msgInferiorRunning();
-    static QString msgConnectRemoteServerFailed(const QString &why);
-
     GdbEngine * const m_engine;
-
-    QProcess m_gdbProc;
 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/gdb/attachgdbadapter.cpp b/src/plugins/debugger/gdb/attachgdbadapter.cpp
index 578884a56bd..f89421e5929 100644
--- a/src/plugins/debugger/gdb/attachgdbadapter.cpp
+++ b/src/plugins/debugger/gdb/attachgdbadapter.cpp
@@ -53,7 +53,6 @@ namespace Internal {
 AttachGdbAdapter::AttachGdbAdapter(GdbEngine *engine, QObject *parent)
     : AbstractGdbAdapter(engine, parent)
 {
-    commonInit();
 }
 
 void AttachGdbAdapter::startAdapter()
@@ -62,27 +61,12 @@ void AttachGdbAdapter::startAdapter()
     setState(AdapterStarting);
     debugMessage(_("TRYING TO START ADAPTER"));
 
-    QStringList gdbArgs;
-    gdbArgs.prepend(_("mi"));
-    gdbArgs.prepend(_("-i"));
-
-    QString location = theDebuggerStringSetting(GdbLocation);
-    m_gdbProc.start(location, gdbArgs);
-}
+    if (!m_engine->startGdb())
+        return;
 
-void AttachGdbAdapter::handleGdbStarted()
-{
-    QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
     emit adapterStarted();
 }
 
-void AttachGdbAdapter::handleGdbError(QProcess::ProcessError error)
-{
-    debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR"));
-    emit adapterCrashed(m_engine->errorMessage(error));
-    shutdown();
-}
-
 void AttachGdbAdapter::startInferior()
 {
     QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
@@ -113,58 +97,5 @@ void AttachGdbAdapter::interruptInferior()
         debugMessage(_("CANNOT INTERRUPT %1").arg(pid));
 }
 
-void AttachGdbAdapter::shutdown()
-{
-    switch (state()) {
-    
-    case InferiorStartFailed:
-        m_engine->postCommand(_("-gdb-exit"));
-        setState(DebuggerNotReady);
-        return;
-
-    case InferiorStopped:
-        setState(InferiorShuttingDown);
-        m_engine->postCommand(_("detach"), CB(handleDetach));
-        return;
-
-    case InferiorShutDown:
-        setState(AdapterShuttingDown);
-        m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit));
-        return;
-
-    default:
-        QTC_ASSERT(false, qDebug() << state());
-    }
-}
-
-void AttachGdbAdapter::handleDetach(const GdbResponse &response)
-{
-    if (response.resultClass == GdbResultDone) {
-        setState(InferiorShutDown);
-        emit inferiorShutDown();
-        shutdown(); // re-iterate...
-    } else {
-        const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data()));
-        setState(InferiorShutdownFailed);
-        emit inferiorShutdownFailed(msg);
-    }
-}
-
-void AttachGdbAdapter::handleExit(const GdbResponse &response)
-{
-    if (response.resultClass == GdbResultDone) {
-        // don't set state here, this will be handled in handleGdbFinished()
-    } else {
-        const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data()));
-        emit adapterShutdownFailed(msg);
-    }
-}
-
-void AttachGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus)
-{
-    debugMessage(_("GDB PROESS FINISHED"));
-    emit adapterShutDown();
-}
-
 } // namespace Internal
 } // namespace Debugger
diff --git a/src/plugins/debugger/gdb/attachgdbadapter.h b/src/plugins/debugger/gdb/attachgdbadapter.h
index 34196725417..1ae5b1c7cae 100644
--- a/src/plugins/debugger/gdb/attachgdbadapter.h
+++ b/src/plugins/debugger/gdb/attachgdbadapter.h
@@ -57,16 +57,10 @@ public:
     void startAdapter();
     void startInferior();
     void interruptInferior();
-    void shutdown();
+    const char *inferiorShutdownCommand() const { return "detach"; }
 
 private:
     void handleAttach(const GdbResponse &response);
-    void handleDetach(const GdbResponse &response);
-    void handleExit(const GdbResponse &response);
-
-    Q_SLOT void handleGdbStarted();
-    Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus);
-    Q_SLOT void handleGdbError(QProcess::ProcessError error);
 };
 
 } // namespace Internal
diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp
index 5f5de78f1fe..7f70b60609b 100644
--- a/src/plugins/debugger/gdb/coregdbadapter.cpp
+++ b/src/plugins/debugger/gdb/coregdbadapter.cpp
@@ -53,7 +53,6 @@ namespace Internal {
 CoreGdbAdapter::CoreGdbAdapter(GdbEngine *engine, QObject *parent)
     : AbstractGdbAdapter(engine, parent)
 {
-    commonInit();
 }
 
 void CoreGdbAdapter::startAdapter()
@@ -62,27 +61,12 @@ void CoreGdbAdapter::startAdapter()
     setState(AdapterStarting);
     debugMessage(_("TRYING TO START ADAPTER"));
 
-    QStringList gdbArgs;
-    gdbArgs.prepend(_("mi"));
-    gdbArgs.prepend(_("-i"));
-
-    QString location = theDebuggerStringSetting(GdbLocation);
-    m_gdbProc.start(location, gdbArgs);
-}
+    if (!m_engine->startGdb())
+        return;
 
-void CoreGdbAdapter::handleGdbStarted()
-{
-    QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
     emit adapterStarted();
 }
 
-void CoreGdbAdapter::handleGdbError(QProcess::ProcessError error)
-{
-    debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR"));
-    emit adapterCrashed(m_engine->errorMessage(error));
-    shutdown();
-}
-
 void CoreGdbAdapter::startInferior()
 {
     QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
@@ -175,45 +159,12 @@ void CoreGdbAdapter::handleTargetCore2(const GdbResponse &response)
        // emit inferiorStartFailed(msg);
     }
 }
+
 void CoreGdbAdapter::interruptInferior()
 {
     // A core should never 'run'
     QTC_ASSERT(false, /**/);
 }
 
-void CoreGdbAdapter::shutdown()
-{
-    switch (state()) {
-
-    case DebuggerNotReady:
-        return;
-
-    case InferiorUnrunnable:
-    case InferiorShutDown:
-        setState(AdapterShuttingDown);
-        m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit));
-        return;
-
-    default:
-        QTC_ASSERT(false, qDebug() << state());
-    }
-}
-
-void CoreGdbAdapter::handleExit(const GdbResponse &response)
-{
-    if (response.resultClass == GdbResultDone) {
-        // don't set state here, this will be handled in handleGdbFinished()
-    } else {
-        const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data()));
-        emit adapterShutdownFailed(msg);
-    }
-}
-
-void CoreGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus)
-{
-    debugMessage(_("GDB PROESS FINISHED"));
-    emit adapterShutDown();
-}
-
 } // namespace Internal
 } // namespace Debugger
diff --git a/src/plugins/debugger/gdb/coregdbadapter.h b/src/plugins/debugger/gdb/coregdbadapter.h
index 4a3fe67799d..69f7d067da2 100644
--- a/src/plugins/debugger/gdb/coregdbadapter.h
+++ b/src/plugins/debugger/gdb/coregdbadapter.h
@@ -57,18 +57,12 @@ public:
     void startAdapter();
     void startInferior();
     void interruptInferior();
-    void shutdown();
 
 private:
     void handleTargetCore1(const GdbResponse &response);
     void handleDetach1(const GdbResponse &response);
     void handleFileExecAndSymbols(const GdbResponse &response);
     void handleTargetCore2(const GdbResponse &response);
-    void handleExit(const GdbResponse &response);
-
-    Q_SLOT void handleGdbStarted();
-    Q_SLOT void handleGdbError(QProcess::ProcessError error);
-    Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus);
 
     QString m_executable;
 };
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 3d63dfe69f5..93916267abb 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -105,17 +105,29 @@ namespace Internal {
 
 static bool stateAcceptsGdbCommands(DebuggerState state)
 {
-    return state == AdapterStarted
-        || state == InferiorUnrunnable
-        || state == InferiorStarting
-        || state == InferiorRunningRequested
-        || state == InferiorRunning
-        || state == InferiorStopping
-        || state == InferiorStopped
-        || state == InferiorShuttingDown
-        || state == InferiorShutDown
-        || state == AdapterShuttingDown;
-};
+    switch (state) {
+    case AdapterStarting:
+    case AdapterStarted:
+    case AdapterStartFailed:
+    case InferiorUnrunnable:
+    case InferiorStarting:
+    case InferiorStartFailed:
+    case InferiorRunningRequested:
+    case InferiorRunning:
+    case InferiorStopping:
+    case InferiorStopped:
+    case InferiorShuttingDown:
+    case InferiorShutDown:
+    case InferiorShutdownFailed:
+        return true;
+    case DebuggerNotReady:
+    case EngineStarting:
+    case InferiorStopFailed:
+    case EngineShuttingDown:
+        break;
+    }
+    return false;
+}
 
 static int &currentToken()
 {
@@ -217,27 +229,13 @@ GdbEngine::~GdbEngine()
 
 void GdbEngine::connectAdapter()
 {
-    // Gdb Process interaction
-    connect(m_gdbAdapter, SIGNAL(readyReadStandardOutput()),
-        this, SLOT(readGdbStandardOutput()));
-    connect(m_gdbAdapter, SIGNAL(readyReadStandardError()),
-        this, SLOT(readGdbStandardError()));
-
     connect(m_gdbAdapter, SIGNAL(adapterStarted()),
         this, SLOT(handleAdapterStarted()));
     connect(m_gdbAdapter, SIGNAL(adapterStartFailed(QString,QString)),
         this, SLOT(handleAdapterStartFailed(QString,QString)));
-    connect(m_gdbAdapter, SIGNAL(adapterShutDown()),
-        this, SLOT(handleAdapterShutDown()));
-    connect(m_gdbAdapter, SIGNAL(adapterShutdownFailed(QString)),
-        this, SLOT(handleAdapterShutdownFailed(QString)));
 
     connect(m_gdbAdapter, SIGNAL(inferiorStartFailed(QString)),
         this, SLOT(handleInferiorStartFailed(QString)));
-    connect(m_gdbAdapter, SIGNAL(inferiorShutDown()),
-        this, SLOT(handleInferiorShutDown()));
-    connect(m_gdbAdapter, SIGNAL(inferiorShutdownFailed(QString)),
-        this, SLOT(handleInferiorShutdownFailed(QString)));
 
     connect(m_gdbAdapter, SIGNAL(adapterCrashed(QString)),
         this, SLOT(handleAdapterCrashed(QString)));
@@ -571,7 +569,7 @@ void GdbEngine::handleResponse(const QByteArray &buff)
 
 void GdbEngine::readGdbStandardError()
 {
-    qWarning() << "Unexpected gdb stderr:" << m_gdbAdapter->readAllStandardError();
+    qWarning() << "Unexpected gdb stderr:" << m_gdbProc.readAllStandardError();
 }
 
 void GdbEngine::readGdbStandardOutput()
@@ -579,7 +577,7 @@ void GdbEngine::readGdbStandardOutput()
     int newstart = 0;
     int scan = m_inbuffer.size();
 
-    m_inbuffer.append(m_gdbAdapter->readAllStandardOutput());
+    m_inbuffer.append(m_gdbProc.readAllStandardOutput());
 
     while (newstart < m_inbuffer.size()) {
         int start = newstart;
@@ -1366,8 +1364,73 @@ QString GdbEngine::fullName(const QStringList &candidates)
 void GdbEngine::shutdown()
 {
     debugMessage(_("INITIATE GDBENGINE SHUTDOWN"));
-    initializeVariables();
-    m_gdbAdapter->shutdown();
+    switch (state()) {
+    case DebuggerNotReady: // Nothing to do! :)
+    case EngineStarting: // We can't get here, really
+    case InferiorShuttingDown: // Will auto-trigger further shutdown steps
+    case EngineShuttingDown: // Do not disturb! :)
+        break;
+    case AdapterStarting: // GDB is up, adapter is "doing something"
+        setState(AdapterStartFailed);
+        m_gdbAdapter->shutdown();
+        // fall-through
+    case AdapterStartFailed: // Adapter "did something", but it did not help
+        // FIXME set some timeout?
+        postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleGdbExit));
+        break;
+    case InferiorRunningRequested:
+    case InferiorRunning:
+    case InferiorStopping:
+    case InferiorStopped:
+        // FIXME set some timeout?
+        postCommand(_(m_gdbAdapter->inferiorShutdownCommand()),
+                    NeedsStop, CB(handleInferiorShutdown));
+        setState(InferiorShuttingDown); // Do it after posting the command!
+        break;
+    case AdapterStarted: // We can't get here, really
+    case InferiorStartFailed:
+    case InferiorShutDown:
+    case InferiorShutdownFailed: // Whatever
+    case InferiorUnrunnable:
+        // FIXME set some timeout?
+        postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleGdbExit));
+        setState(EngineShuttingDown); // Do it after posting the command!
+        break;
+    case InferiorStarting: // This may take some time, so just short-circuit it
+        setState(InferiorStartFailed);
+        // fall-through
+    case InferiorStopFailed: // Tough luck, I guess. But unreachable as of now anyway.
+        setState(EngineShuttingDown);
+        m_gdbProc.terminate();
+        break;
+    }
+}
+
+void GdbEngine::handleInferiorShutdown(const GdbResponse &response)
+{
+    QTC_ASSERT(state() == InferiorShuttingDown, qDebug() << state());
+    if (response.resultClass == GdbResultDone) {
+        debugMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
+        setState(InferiorShutDown);
+    } else {
+        debugMessage(_("INFERIOR SHUTDOWN FAILED"));
+        setState(InferiorShutdownFailed);
+        QString msg = m_gdbAdapter->msgInferiorStopFailed(_(response.data.findChild("msg").data()));
+        showMessageBox(QMessageBox::Critical, tr("Inferior shutdown failed"), msg);
+    }
+    shutdown(); // re-iterate...
+}
+
+void GdbEngine::handleGdbExit(const GdbResponse &response)
+{
+    if (response.resultClass == GdbResultExit) {
+        debugMessage(_("GDB CLAIMS EXIT; WAITING"));
+        // don't set state here, this will be handled in handleGdbFinished()
+    } else {
+        QString msg = m_gdbAdapter->msgGdbStopFailed(_(response.data.findChild("msg").data()));
+        debugMessage(_("GDB WON'T EXIT (%1); KILLING IT").arg(msg));
+        m_gdbProc.terminate();
+    }
 }
 
 void GdbEngine::detachDebugger()
@@ -1383,8 +1446,7 @@ void GdbEngine::detachDebugger()
 void GdbEngine::exitDebugger() // called from the manager
 {
     disconnectDebuggingHelperActions();
-    initializeVariables();
-    m_gdbAdapter->shutdown();
+    shutdown();
 }
 
 int GdbEngine::currentFrame() const
@@ -1445,17 +1507,17 @@ void GdbEngine::startDebugger(const DebuggerStartParametersPtr &sp)
     //    initializeVariables());
     //QTC_ASSERT(m_gdbAdapter == 0, delete m_gdbAdapter; m_gdbAdapter = 0);
 
+    initializeVariables();
+
     m_startParameters = sp;
 
     delete m_gdbAdapter;
     m_gdbAdapter = createAdapter(sp);
+    connectAdapter();
 
     if (startModeAllowsDumpers())
         connectDebuggingHelperActions();
 
-    initializeVariables();
-    connectAdapter();
-
     m_gdbAdapter->startAdapter();
 }
 
@@ -4089,19 +4151,37 @@ void GdbEngine::gotoLocation(const StackFrame &frame, bool setMarker)
 // Starting up & shutting down
 //
 
-void GdbEngine::handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint)
+bool GdbEngine::startGdb(const QStringList &args, const QString &gdb)
 {
-    setState(AdapterStartFailed);
-    debugMessage(_("ADAPTER START FAILED"));
-    Core::ICore::instance()->showWarningWithOptions(tr("Adapter start failed"), msg, QString(),
-						    QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint);
-    shutdown();
-}
+    debugMessage(_("STARTING GDB ") + gdb);
 
-void GdbEngine::handleAdapterStarted()
-{
-    setState(AdapterStarted);
-    debugMessage(_("ADAPTER SUCCESSFULLY STARTED, INITIALIZING GDB"));
+    m_gdbProc.disconnect(); // From any previous runs
+
+    QString location = gdb;
+    if (location.isEmpty())
+        location = theDebuggerStringSetting(GdbLocation);
+    QStringList gdbArgs;
+    gdbArgs << _("-i");
+    gdbArgs << _("mi");
+    gdbArgs += args;
+    m_gdbProc.start(location, gdbArgs);
+
+    if (!m_gdbProc.waitForStarted()) {
+        handleAdapterStartFailed(m_gdbProc.errorString());
+        return false;
+    }
+
+    // Do this only after the process is running, so we get no needless error notifications
+    connect(&m_gdbProc, SIGNAL(error(QProcess::ProcessError)),
+        SLOT(handleGdbError(QProcess::ProcessError)));
+    connect(&m_gdbProc, SIGNAL(finished(int, QProcess::ExitStatus)),
+        SLOT(handleGdbFinished(int, QProcess::ExitStatus)));
+    connect(&m_gdbProc, SIGNAL(readyReadStandardOutput()),
+        SLOT(readGdbStandardOutput()));
+    connect(&m_gdbProc, SIGNAL(readyReadStandardError()),
+        SLOT(readGdbStandardError()));
+
+    debugMessage(_("GDB STARTED, INITIALIZING IT"));
 
     postCommand(_("show version"), CB(handleShowVersion));
     postCommand(_("help bb"), CB(handleIsSynchroneous));
@@ -4185,12 +4265,69 @@ void GdbEngine::handleAdapterStarted()
         }
     }
 
+    return true;
+}
+
+void GdbEngine::handleGdbError(QProcess::ProcessError error)
+{
+    debugMessage(_("HANDLE GDB ERROR"));
+    switch (error) {
+    case QProcess::Crashed:
+        break; // will get a processExited() as well
+    // impossible case QProcess::FailedToStart:
+    case QProcess::ReadError:
+    case QProcess::WriteError:
+    case QProcess::Timedout:
+    default:
+        m_gdbProc.terminate();
+        setState(EngineShuttingDown, true);
+        showMessageBox(QMessageBox::Critical, tr("Gdb I/O Error"),
+                       errorMessage(error));
+        break;
+    }
+}
+
+void GdbEngine::handleGdbFinished(int code, QProcess::ExitStatus type)
+{
+    debugMessage(_("GDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
+    if (state() == EngineShuttingDown) {
+        m_gdbAdapter->shutdown();
+    } else if (state() != AdapterStartFailed) {
+        showMessageBox(QMessageBox::Critical, tr("Unexpected Gdb Exit"),
+                       tr("The gdb process exited unexpectedly (%1).")
+                       .arg((type == QProcess::CrashExit)
+                            ? tr("crashed") : tr("code %1").arg(code)));
+        m_gdbAdapter->shutdown();
+    }
+    initializeVariables();
+    setState(DebuggerNotReady, true);
+}
+
+void GdbEngine::handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint)
+{
+    setState(AdapterStartFailed);
+    debugMessage(_("ADAPTER START FAILED"));
+    Core::ICore::instance()->showWarningWithOptions(
+            tr("Adapter start failed"), msg, QString(),
+            _(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint);
+    shutdown();
+}
+
+void GdbEngine::handleAdapterStarted()
+{
+    setState(AdapterStarted);
+    debugMessage(_("ADAPTER SUCCESSFULLY STARTED"));
+
     // Initial attempt to set breakpoints
     showStatusMessage(tr("Setting breakpoints..."));
     attemptBreakpointSynchronization();
 
-    QTC_ASSERT(m_commandsDoneCallback == 0, /**/);
-    m_commandsDoneCallback = &GdbEngine::startInferior;
+    if (m_cookieForToken.isEmpty()) {
+        startInferior();
+    } else {
+        QTC_ASSERT(m_commandsDoneCallback == 0, /**/);
+        m_commandsDoneCallback = &GdbEngine::startInferior;
+    }
 }
 
 void GdbEngine::startInferior()
@@ -4209,46 +4346,21 @@ void GdbEngine::handleInferiorStartFailed(const QString &msg)
     shutdown();
 }
 
-void GdbEngine::handleInferiorShutDown()
-{
-    debugMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
-}
-
-void GdbEngine::handleInferiorShutdownFailed(const QString &msg)
-{
-    debugMessage(_("INFERIOR SHUTDOWN FAILED"));
-    showMessageBox(QMessageBox::Critical, tr("Inferior shutdown failed"), msg);
-    shutdown(); // continue with adapter shutdown
-}
-
 void GdbEngine::handleAdapterCrashed(const QString &msg)
 {
     debugMessage(_("ADAPTER CRASHED"));
-    switch (state()) {
-        // All fall-through.
-        case InferiorRunning:
-            setState(InferiorShuttingDown);
-        case InferiorShuttingDown:
-            setState(InferiorShutDown);
-        case InferiorShutDown:
-            setState(AdapterShuttingDown);
-        default:
-            setState(DebuggerNotReady);
-    }
-    showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg);
-}
 
-void GdbEngine::handleAdapterShutDown()
-{
-    debugMessage(_("ADAPTER SUCCESSFULLY SHUT DOWN"));
-    setState(DebuggerNotReady);
-}
+    // The adapter is expected to have cleaned up after itself when we get here,
+    // so the effect is about the same as AdapterStartFailed => use it.
+    // Don't bother with state transitions - this can happen in any state and
+    // the end result is always the same, so it makes little sense to find a
+    // "path" which does not assert.
+    setState(AdapterStartFailed, true);
 
-void GdbEngine::handleAdapterShutdownFailed(const QString &msg)
-{
-    debugMessage(_("ADAPTER SHUTDOWN FAILED"));
-    showMessageBox(QMessageBox::Critical, tr("Adapter shutdown failed"), msg);
-    setState(DebuggerNotReady);
+    // No point in being friendly here ...
+    m_gdbProc.terminate();
+
+    showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg);
 }
 
 void GdbEngine::addOptionPages(QList<Core::IOptionsPage*> *opts) const
diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h
index 83f3239c031..91c230dacc9 100644
--- a/src/plugins/debugger/gdb/gdbengine.h
+++ b/src/plugins/debugger/gdb/gdbengine.h
@@ -125,14 +125,20 @@ private: ////////// Gdb Process Management //////////
 
     AbstractGdbAdapter *createAdapter(const DebuggerStartParametersPtr &dp);
     void connectAdapter();
+    bool startGdb(const QStringList &args = QStringList(), const QString &gdb = QString());
     void startInferior();
 
+    void handleInferiorShutdown(const GdbResponse &response);
+    void handleGdbExit(const GdbResponse &response);
+
     void gdbInputAvailable(int channel, const QString &msg)
     { m_manager->showDebuggerInput(channel, msg); }
     void gdbOutputAvailable(int channel, const QString &msg)
     { m_manager->showDebuggerOutput(channel, msg); }
 
 private slots:
+    void handleGdbFinished(int, QProcess::ExitStatus status);
+    void handleGdbError(QProcess::ProcessError error);
     void readGdbStandardOutput();
     void readGdbStandardError();
     void readDebugeeOutput(const QByteArray &data);
@@ -141,12 +147,8 @@ private slots:
     void handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint = QString());
 
     void handleInferiorStartFailed(const QString &msg);
-    void handleInferiorShutDown();
-    void handleInferiorShutdownFailed(const QString &msg);
 
     void handleAdapterCrashed(const QString &msg);
-    void handleAdapterShutDown();
-    void handleAdapterShutdownFailed(const QString &msg);
 
 private:
     QTextCodec *m_outputCodec;
@@ -154,6 +156,7 @@ private:
 
     QByteArray m_inbuffer;
 
+    QProcess m_gdbProc;
     AbstractGdbAdapter *m_gdbAdapter;
 
 private: ////////// Gdb Command Management //////////
diff --git a/src/plugins/debugger/gdb/plaingdbadapter.cpp b/src/plugins/debugger/gdb/plaingdbadapter.cpp
index a879968a3c5..2a16c27628f 100644
--- a/src/plugins/debugger/gdb/plaingdbadapter.cpp
+++ b/src/plugins/debugger/gdb/plaingdbadapter.cpp
@@ -58,8 +58,6 @@ namespace Internal {
 PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent)
     : AbstractGdbAdapter(engine, parent)
 {
-    commonInit();
-
     // Output
     connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)),
         engine, SLOT(readDebugeeOutput(QByteArray)));
@@ -72,36 +70,27 @@ void PlainGdbAdapter::startAdapter()
     debugMessage(_("TRYING TO START ADAPTER"));
 
     QStringList gdbArgs;
-    gdbArgs.prepend(_("mi"));
-    gdbArgs.prepend(_("-i"));
 
     if (!m_outputCollector.listen()) {
         emit adapterStartFailed(tr("Cannot set up communication with child process: %1")
                 .arg(m_outputCollector.errorString()), QString());
         return;
     }
-    gdbArgs.prepend(_("--tty=") + m_outputCollector.serverName());
+    gdbArgs.append(_("--tty=") + m_outputCollector.serverName());
 
     if (!startParameters().workingDir.isEmpty())
-        m_gdbProc.setWorkingDirectory(startParameters().workingDir);
+        m_engine->m_gdbProc.setWorkingDirectory(startParameters().workingDir);
     if (!startParameters().environment.isEmpty())
-        m_gdbProc.setEnvironment(startParameters().environment);
+        m_engine->m_gdbProc.setEnvironment(startParameters().environment);
 
-    m_gdbProc.start(theDebuggerStringSetting(GdbLocation), gdbArgs);
-}
+    if (!m_engine->startGdb(gdbArgs)) {
+        m_outputCollector.shutdown();
+        return;
+    }
 
-void PlainGdbAdapter::handleGdbStarted()
-{
-    QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
     emit adapterStarted();
 }
 
-void PlainGdbAdapter::handleGdbError(QProcess::ProcessError error)
-{
-    debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR"));
-    emit adapterCrashed(m_engine->errorMessage(error));
-}
-
 void PlainGdbAdapter::startInferior()
 {
     QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
@@ -159,74 +148,6 @@ void PlainGdbAdapter::shutdown()
 {
     debugMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
     m_outputCollector.shutdown();
-    switch (state()) {
-    
-    case InferiorRunningRequested:
-    case InferiorRunning:
-    case InferiorStopping:
-    case InferiorStopped:
-        setState(InferiorShuttingDown);
-        m_engine->postCommand(_("kill"), CB(handleKill));
-        return;
-
-    case InferiorShuttingDown:
-        // FIXME: How can we end up here?
-        QTC_ASSERT(false, qDebug() << state());
-        // Fall through.
-
-    case InferiorShutDown:
-        setState(AdapterShuttingDown);
-        m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit));
-        return;
-
-/*
-    case InferiorShutdownFailed:
-        m_gdbProc.terminate();
-        // 20s can easily happen when loading webkit debug information
-        m_gdbProc.waitForFinished(20000);
-        setState(AdapterShuttingDown);
-        debugMessage(_("FORCING TERMINATION: %1").arg(state()));
-        if (state() != QProcess::NotRunning) {
-            debugMessage(_("PROBLEM STOPPING DEBUGGER: STATE %1")
-                .arg(state()));
-            m_gdbProc.kill();
-        }
-        m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit));
-        return;
-*/
-    default:
-        QTC_ASSERT(false, qDebug() << state());
-    }
-}
-
-void PlainGdbAdapter::handleKill(const GdbResponse &response)
-{
-    debugMessage(_("PLAIN ADAPTER HANDLE KILL " + response.toString()));
-    if (response.resultClass == GdbResultDone) {
-        setState(InferiorShutDown);
-        emit inferiorShutDown();
-        shutdown(); // re-iterate...
-    } else {
-        const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data()));
-        setState(InferiorShutdownFailed);
-        emit inferiorShutdownFailed(msg);
-    }
-}
-
-void PlainGdbAdapter::handleExit(const GdbResponse &response)
-{
-    if (response.resultClass == GdbResultDone) {
-        // don't set state here, this will be handled in handleGdbFinished()
-    } else {
-        const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data()));
-        emit adapterShutdownFailed(msg);
-    }
-}
-
-void PlainGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus)
-{
-    debugMessage(_("GDB PROCESS FINISHED"));
-    emit adapterShutDown();
 }
 
 } // namespace Internal
diff --git a/src/plugins/debugger/gdb/plaingdbadapter.h b/src/plugins/debugger/gdb/plaingdbadapter.h
index 52311b372b4..fb445d3b329 100644
--- a/src/plugins/debugger/gdb/plaingdbadapter.h
+++ b/src/plugins/debugger/gdb/plaingdbadapter.h
@@ -59,17 +59,12 @@ public:
     void startInferior();
     void interruptInferior();
     void shutdown();
+    const char *inferiorShutdownCommand() const { return "kill"; }
 
 private:
     void handleFileExecAndSymbols(const GdbResponse &response);
-    void handleKill(const GdbResponse &response);
-    void handleExit(const GdbResponse &response);
     void handleExecRun(const GdbResponse &response);
 
-    Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus status);
-    Q_SLOT void handleGdbError(QProcess::ProcessError error);
-    Q_SLOT void handleGdbStarted();
-
     OutputCollector m_outputCollector;
 };
 
diff --git a/src/plugins/debugger/gdb/remotegdbadapter.cpp b/src/plugins/debugger/gdb/remotegdbadapter.cpp
index 40d598f293d..504e0a56208 100644
--- a/src/plugins/debugger/gdb/remotegdbadapter.cpp
+++ b/src/plugins/debugger/gdb/remotegdbadapter.cpp
@@ -54,8 +54,6 @@ namespace Internal {
 RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, QObject *parent)
     : AbstractGdbAdapter(engine, parent)
 {
-    commonInit();
-
     connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)),
         this, SLOT(uploadProcError(QProcess::ProcessError)));
     connect(&m_uploadProc, SIGNAL(readyReadStandardOutput()),
@@ -70,12 +68,6 @@ void RemoteGdbAdapter::startAdapter()
     setState(AdapterStarting);
     debugMessage(_("TRYING TO START ADAPTER"));
 
-    QStringList gdbArgs;
-    gdbArgs.prepend(_("mi"));
-    gdbArgs.prepend(_("-i"));
-
-    QString location = theDebuggerStringSetting(GdbLocation);
-
     // FIXME: make asynchroneous
     // Start the remote server
     if (startParameters().serverStartScript.isEmpty()) {
@@ -86,23 +78,13 @@ void RemoteGdbAdapter::startAdapter()
         m_uploadProc.waitForStarted();
     }
 
-    // Start the debugger
-    m_gdbProc.start(location, gdbArgs);
-}
+    if (!m_engine->startGdb())
+        // FIXME: cleanup missing
+        return;
 
-void RemoteGdbAdapter::handleGdbStarted()
-{
-    QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
     emit adapterStarted();
 }
 
-void RemoteGdbAdapter::handleGdbError(QProcess::ProcessError error)
-{
-    debugMessage(_("ADAPTER, HANDLE GDB ERROR"));
-    emit adapterCrashed(m_engine->errorMessage(error));
-    shutdown();
-}
-
 void RemoteGdbAdapter::uploadProcError(QProcess::ProcessError error)
 {
     QString msg;
@@ -232,55 +214,7 @@ void RemoteGdbAdapter::interruptInferior()
 
 void RemoteGdbAdapter::shutdown()
 {
-    switch (state()) {
-
-    case InferiorRunning:
-    case InferiorStopped:
-        setState(InferiorShuttingDown);
-        m_engine->postCommand(_("kill"), CB(handleKill));
-        return;
-    
-    default:
-        QTC_ASSERT(false, qDebug() << state());
-        // fall through
-
-    case InferiorStartFailed:
-    case InferiorShutDown:
-        setState(AdapterShuttingDown);
-        m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit));
-        return;
-
-    }
-}
-
-void RemoteGdbAdapter::handleKill(const GdbResponse &response)
-{
-    QTC_ASSERT(state() == InferiorShuttingDown, qDebug() << state());
-    if (response.resultClass == GdbResultDone) {
-        setState(InferiorShutDown);
-        emit inferiorShutDown();
-        shutdown(); // re-iterate...
-    } else {
-        QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data()));
-        setState(InferiorShutdownFailed);
-        emit inferiorShutdownFailed(msg);
-    }
-}
-
-void RemoteGdbAdapter::handleExit(const GdbResponse &response)
-{
-    if (response.resultClass == GdbResultDone) {
-        // don't set state here, this will be handled in handleGdbFinished()
-    } else {
-        QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data()));
-        emit adapterShutdownFailed(msg);
-    }
-}
-
-void RemoteGdbAdapter::handleGdbFinished(int, QProcess::ExitStatus)
-{
-    debugMessage(_("GDB PROESS FINISHED"));
-    emit adapterShutDown();
+    // FIXME: cleanup missing
 }
 
 } // namespace Internal
diff --git a/src/plugins/debugger/gdb/remotegdbadapter.h b/src/plugins/debugger/gdb/remotegdbadapter.h
index 38fc7ac6555..a7f4bc645a4 100644
--- a/src/plugins/debugger/gdb/remotegdbadapter.h
+++ b/src/plugins/debugger/gdb/remotegdbadapter.h
@@ -69,12 +69,6 @@ private:
 #endif
     void handleFileExecAndSymbols(const GdbResponse &response);
     void handleTargetRemote(const GdbResponse &response);
-    void handleKill(const GdbResponse &response);
-    void handleExit(const GdbResponse &response);
-
-    Q_SLOT void handleGdbStarted();
-    Q_SLOT void handleGdbError(QProcess::ProcessError error);
-    Q_SLOT void handleGdbFinished(int, QProcess::ExitStatus);
 
     QProcess m_uploadProc;
 };
diff --git a/src/plugins/debugger/gdb/trkgdbadapter.cpp b/src/plugins/debugger/gdb/trkgdbadapter.cpp
index d517c2ca449..e1405d86f42 100644
--- a/src/plugins/debugger/gdb/trkgdbadapter.cpp
+++ b/src/plugins/debugger/gdb/trkgdbadapter.cpp
@@ -204,10 +204,6 @@ TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
 #endif
     m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset);
 
-    commonInit();
-    connect(&m_gdbProc, SIGNAL(stateChanged(QProcess::ProcessState)),
-        this, SLOT(handleGdbStateChanged(QProcess::ProcessState)));
-
     connect(&m_rfcommProc, SIGNAL(readyReadStandardError()),
         this, SLOT(handleRfcommReadyReadStandardError()));
     connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()),
@@ -380,17 +376,6 @@ QByteArray TrkGdbAdapter::trkInterruptMessage()
     return ba;
 }
 
-void TrkGdbAdapter::emitDelayedAdapterStartFailed(const QString &msg)
-{
-    m_adapterFailMessage = msg;
-    QTimer::singleShot(0, this, SLOT(slotEmitDelayedAdapterStartFailed()));
-}
-
-void TrkGdbAdapter::slotEmitDelayedAdapterStartFailed()
-{
-    emit adapterStartFailed(m_adapterFailMessage, TrkOptionsPage::settingsId());
-}
-
 void TrkGdbAdapter::emitDelayedInferiorStartFailed(const QString &msg)
 {
     m_adapterFailMessage = msg;
@@ -437,7 +422,7 @@ void TrkGdbAdapter::waitForTrkConnect()
     //    "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File
     //sendTrkMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File
 
-    maybeAdapterStarted();
+    emit adapterStarted();
 }
 
 void TrkGdbAdapter::logMessage(const QString &msg)
@@ -1527,50 +1512,6 @@ void TrkGdbAdapter::interruptInferior()
     sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting...");
 }
 
-void TrkGdbAdapter::handleGdbError(QProcess::ProcessError error)
-{
-    if (error == QProcess::FailedToStart) {
-        const QString msg = QString::fromLatin1("GDB: Cannot start '%1': %2. Please check the settings.").arg(m_options->gdb).arg(m_gdbProc.errorString());
-        emitDelayedAdapterStartFailed(msg); // Emitted from QProcess::start() on Windows
-    } else {
-        // Others should trigger handleGdbFinished
-        const QString msg = QString::fromLatin1("GDB: Process error %1: %2").arg(error).arg(m_gdbProc.errorString());
-        logMessage(msg);
-    }
-}
-
-void TrkGdbAdapter::handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus)
-{
-    const QString msg = exitStatus == QProcess::NormalExit ?
-                        QString::fromLatin1("GDB: Process finished (exit code: %1).").arg(exitCode) :
-                        QString::fromLatin1("GDB: Process crashed: %1").arg(m_gdbProc.errorString());
-    if (state() == AdapterStarting) {
-        emitDelayedAdapterStartFailed(msg);// Potentially emitted from QProcess::start() on Windows
-    } else {
-        logMessage(msg);
-        emit adapterShutDown();
-    }
-}
-
-void TrkGdbAdapter::handleGdbStarted()
-{
-    logMessage(QString("GDB: Process Started"));
-    maybeAdapterStarted();
-}
-
-void TrkGdbAdapter::maybeAdapterStarted()
-{
-    QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
-    if (m_gdbProc.state() == QProcess::Running && m_trkDevice.isOpen()) {
-        emit adapterStarted();
-    }
-}
-
-void TrkGdbAdapter::handleGdbStateChanged(QProcess::ProcessState newState)
-{
-    logMessage(_("GDB: Process State %1").arg(newState));
-}
-
 void TrkGdbAdapter::startAdapter()
 {
     // Retrieve parameters
@@ -1632,13 +1573,12 @@ void TrkGdbAdapter::startAdapter()
     connect(m_gdbServer, SIGNAL(newConnection()),
         this, SLOT(handleGdbConnection()));
 
-    logMessage("STARTING GDB");
-    logMessage(_("### Starting gdb %1").arg(m_options->gdb));
     QStringList gdbArgs;
     gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file
-    gdbArgs.append(QLatin1String("-i"));
-    gdbArgs.append(QLatin1String("mi"));
-    m_gdbProc.start(m_options->gdb, gdbArgs);
+    if (!m_engine->startGdb(gdbArgs, m_options->gdb)) {
+        cleanup();
+        return;
+    }
 
     waitForTrkConnect();
 }
@@ -1792,7 +1732,7 @@ void TrkGdbAdapter::write(const QByteArray &data)
            trkReadMemoryMessage(m_session.dataseg, 12));
         return;
     }
-    m_gdbProc.write(data);
+    m_engine->m_gdbProc.write(data);
 }
 
 uint oldPC;
@@ -1990,79 +1930,7 @@ void TrkGdbAdapter::cleanup()
 
 void TrkGdbAdapter::shutdown()
 {
-    switch (state()) {
-    case AdapterStarting:
-    case AdapterStartFailed:
-        cleanup();
-        setState(DebuggerNotReady);
-        return;
-
-    case InferiorStopping:
-    case InferiorRunningRequested:
-    case InferiorRunning:
-        //sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting...");
-        // Fall through.
-
-    case InferiorStopped:
-        //sendTrkMessage(0x41, TrkCallback(), trkDeleteProcessMessage(), "Delete process"); 
-        //sendTrkMessage(0x02, TrkCB(handleDisconnect));
-        setState(InferiorShuttingDown);
-        m_engine->postCommand(_("kill"), CB(handleKill));
-        return;
-
-    case InferiorShutDown:
-        setState(AdapterShuttingDown);
-        cleanup();
-        m_engine->postCommand(_("-gdb-exit"), GdbEngine::ExitRequest, CB(handleExit));
-        return;
-
-/*
-    if (m_options->mode == TrkOptions::BlueTooth
-            && m_rfcommProc.state() == QProcess::Running)
-        m_rfcommProc.kill();
-    m_rfcommProc.terminate();
-    m_rfcommProc.write(ba);
-    m_rfcommProc.terminate();
-    m_rfcommProc.waitForFinished();
-
-    m_gdbProc.kill();
-    m_gdbProc.terminate();
-
-    QByteArray ba;
-    ba.append(0x03);
-    QProcess proc;
-    proc.start("rfcomm release " + m_options->blueToothDevice);
-    proc.waitForFinished();
-    m_gdbProc.waitForFinished(msecs);
-*/
-
-    default:
-        QTC_ASSERT(false, qDebug() << state());
-    }
-}
-
-void TrkGdbAdapter::handleKill(const GdbResponse &response)
-{
-    if (response.resultClass == GdbResultDone) {
-        setState(InferiorShutDown);
-        emit inferiorShutDown();
-        shutdown(); // re-iterate...
-    } else {
-        const QString msg = msgInferiorStopFailed(__(response.data.findChild("msg").data()));
-        setState(InferiorShutdownFailed);
-        emit inferiorShutdownFailed(msg);
-    }
-}
-
-void TrkGdbAdapter::handleExit(const GdbResponse &response)
-{
-    if (response.resultClass == GdbResultDone) {
-        qDebug() << "EXITED, NO MESSAGE...";
-        // don't set state here, this will be handled in handleGdbFinished()
-    } else {
-        const QString msg = msgGdbStopFailed(__(response.data.findChild("msg").data()));
-        emit adapterShutdownFailed(msg);
-    }
+    cleanup();
 }
 
 } // namespace Internal
diff --git a/src/plugins/debugger/gdb/trkgdbadapter.h b/src/plugins/debugger/gdb/trkgdbadapter.h
index 5e2e4939a42..72a996ef01f 100644
--- a/src/plugins/debugger/gdb/trkgdbadapter.h
+++ b/src/plugins/debugger/gdb/trkgdbadapter.h
@@ -163,8 +163,6 @@ public:
     //
     void start(const QString &program, const QStringList &args,
         QIODevice::OpenMode mode = QIODevice::ReadWrite);
-    QByteArray readAllStandardError();
-    QByteArray readAllStandardOutput();
     void write(const QByteArray &data);
     bool isTrkAdapter() const { return true; }
     bool dumpersAvailable() const { return false; }
@@ -174,15 +172,12 @@ private:
     void startInferior();
     void interruptInferior();
     void shutdown();
+
     void cleanup();
-    void emitDelayedAdapterStartFailed(const QString &msg);
-    Q_SLOT void slotEmitDelayedAdapterStartFailed();
     void emitDelayedInferiorStartFailed(const QString &msg);
     Q_SLOT void slotEmitDelayedInferiorStartFailed();
 
     Q_SLOT void waitForTrkConnect();
-    void handleKill(const GdbResponse &response);
-    void handleExit(const GdbResponse &response);
     void handleTargetRemote(const GdbResponse &response);
     void handleFirstContinue(const GdbResponse &response);
 
@@ -285,13 +280,6 @@ private:
     bool sendGdbServerPacket(const QByteArray &packet, bool doFlush);
     void tryAnswerGdbMemoryRequest(bool buffered);
 
-    Q_SLOT void handleGdbError(QProcess::ProcessError error);
-    Q_SLOT void handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus);
-    Q_SLOT void handleGdbStarted();
-    Q_SLOT void handleGdbStateChanged(QProcess::ProcessState newState);
-
-    void maybeAdapterStarted();
-
     void logMessage(const QString &msg);  // triggers output() if m_verbose
     Q_SLOT void trkLogMessage(const QString &msg);
 
diff --git a/src/plugins/debugger/idebuggerengine.h b/src/plugins/debugger/idebuggerengine.h
index 619ac2bddb9..7766b73b7c2 100644
--- a/src/plugins/debugger/idebuggerengine.h
+++ b/src/plugins/debugger/idebuggerengine.h
@@ -123,7 +123,7 @@ public:
 protected:
     void showStatusMessage(const QString &msg, int timeout = -1);
     DebuggerState state() const;
-    void setState(DebuggerState state);
+    void setState(DebuggerState state, bool forced = false);
     DebuggerManager *manager() const { return m_manager; }
     DebuggerManager *m_manager;
 
-- 
GitLab