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
This commit is contained in:
Oswald Buddenhagen
2009-10-20 11:02:16 +02:00
parent 4b0060c537
commit b3addf14f1
19 changed files with 302 additions and 649 deletions

View File

@@ -824,6 +824,9 @@ void CdbDebugEnginePrivate::processCreatedAttached(ULONG64 processHandle, ULONG6
void CdbDebugEngine::processTerminated(unsigned long exitCode) void CdbDebugEngine::processTerminated(unsigned long exitCode)
{ {
manager()->showDebuggerOutput(LogMisc, tr("The process exited with exit code %1.").arg(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__); setState(InferiorShuttingDown, Q_FUNC_INFO, __LINE__);
m_d->setDebuggeeHandles(0, 0); m_d->setDebuggeeHandles(0, 0);
m_d->clearForRun(); m_d->clearForRun();
@@ -919,14 +922,11 @@ void CdbDebugEnginePrivate::endDebugging(EndDebuggingMode em)
errorMessage.clear(); errorMessage.clear();
} }
// Clean up resources (open files, etc.) // Clean up resources (open files, etc.)
m_engine->setState(AdapterShuttingDown, Q_FUNC_INFO, __LINE__); m_engine->setState(EngineShuttingDown, Q_FUNC_INFO, __LINE__);
clearForRun(); clearForRun();
const HRESULT hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE); const HRESULT hr = m_cif.debugClient->EndSession(DEBUG_END_PASSIVE);
if (SUCCEEDED(hr)) { m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__); if (!SUCCEEDED(hr)) {
} else {
m_engine->setState(AdapterShutdownFailed, Q_FUNC_INFO, __LINE__);
m_engine->setState(DebuggerNotReady, Q_FUNC_INFO, __LINE__);
errorMessage = QString::fromLatin1("There were errors trying to end debugging: %1").arg(msgComFailed("EndSession", hr)); errorMessage = QString::fromLatin1("There were errors trying to end debugging: %1").arg(msgComFailed("EndSession", hr));
manager()->showDebuggerOutput(LogError, errorMessage); manager()->showDebuggerOutput(LogError, errorMessage);
} }

View File

@@ -79,15 +79,13 @@ enum DebuggerState
InferiorStopping, // Debuggee running, stop requested InferiorStopping, // Debuggee running, stop requested
InferiorStopped, // Debuggee stopped InferiorStopped, // Debuggee stopped
InferiorStopFailed, // Debuggee stopped InferiorStopFailed, // Debuggee not stopped, will kill debugger
InferiorShuttingDown, InferiorShuttingDown,
InferiorShutDown, InferiorShutDown,
InferiorShutdownFailed, InferiorShutdownFailed,
AdapterShuttingDown, EngineShuttingDown
//AdapterShutDown, // Use DebuggerNotReady instead
AdapterShutdownFailed,
}; };
enum DebuggerStartMode enum DebuggerStartMode

View File

@@ -101,43 +101,35 @@
// gdbserver, the trk client etc are referred to as 'Adapter', // gdbserver, the trk client etc are referred to as 'Adapter',
// whereas the debugged process is referred to as 'Inferior'. // whereas the debugged process is referred to as 'Inferior'.
// //
// 0 == DebuggerNotReady // 0 == DebuggerNotReady
// | // |
// EngineStarting // EngineStarting
// | // |
// AdapterStarting --> AdapterStartFailed --> 0 // AdapterStarting --> AdapterStartFailed --> 0
// | // |
// AdapterStarted // AdapterStarted ------------------------------------.
// | // | v
// InferiorStarting --> InferiorStartFailed --> 0 // InferiorStarting ----> InferiorStartFailed -------->|
// | // | |
// (core) | (attach) (remote) // (core) | (attach) (term) (remote) |
// .-----------------<-|->--------------------. // .-----------------<-|->------------------. |
// | v | // | v | |
// InferiorUnrunnable | | // InferiorUnrunnable | (plain) | |
// | | v // | | (trk) | |
// | | (plain) // | | | |
// | | (trk) // | .--> InferiorRunningRequested | |
// | | // | | | | |
// | | .------------------------------------. // | | InferiorRunning | |
// | | v | // | | | | |
// | InferiorRunningRequested v | // | | InferiorStopping | |
// | | | | // | | | | |
// | .---- InferiorRunning | | // | '------ InferiorStopped <-----------' |
// | | | | | // | | v
// | | InferiorStopping | | // | InferiorShuttingDown -> InferiorShutdownFailed ---->|
// | | | | | // | | |
// | v v | | // | InferiorShutDown |
// | |<--- InferiorStopped <-----------' | // | | |
// | | | | // '--------> EngineShuttingDown <--------------------------------'
// | | `---------------------------------------'
// | |
// | '---> InferiorShuttingDown -> InferiorShutdownFailed
// | |
// | InferiorShutDown
// | |
// | v
// '------------> AdapterShuttingDown -> AdapterShutdownFailed --> 0
// | // |
// 0 // 0
// //
@@ -208,8 +200,7 @@ static const char *stateName(int s)
SN(InferiorShuttingDown) SN(InferiorShuttingDown)
SN(InferiorShutDown) SN(InferiorShutDown)
SN(InferiorShutdownFailed) SN(InferiorShutdownFailed)
SN(AdapterShuttingDown) SN(EngineShuttingDown)
SN(AdapterShutdownFailed)
} }
return "<unknown>"; return "<unknown>";
#undef SN #undef SN
@@ -1574,7 +1565,7 @@ static bool isAllowedTransition(int from, int to)
case AdapterStarting: case AdapterStarting:
return to == AdapterStarted || to == AdapterStartFailed; return to == AdapterStarted || to == AdapterStartFailed;
case AdapterStarted: case AdapterStarted:
return to == InferiorStarting; return to == InferiorStarting || to == EngineShuttingDown;
case AdapterStartFailed: case AdapterStartFailed:
return to == DebuggerNotReady; return to == DebuggerNotReady;
@@ -1582,37 +1573,38 @@ static bool isAllowedTransition(int from, int to)
return to == InferiorRunningRequested || to == InferiorStopped return to == InferiorRunningRequested || to == InferiorStopped
|| to == InferiorStartFailed || to == InferiorUnrunnable; || to == InferiorStartFailed || to == InferiorUnrunnable;
case InferiorStartFailed: case InferiorStartFailed:
return to == DebuggerNotReady; return to == EngineShuttingDown;
case InferiorRunningRequested: case InferiorRunningRequested:
return to == InferiorRunning; return to == InferiorRunning;
case InferiorRunning: case InferiorRunning:
return to == InferiorStopping || to == InferiorShuttingDown; return to == InferiorStopping;
case InferiorStopping: case InferiorStopping:
return to == InferiorStopped || to == InferiorStopFailed; return to == InferiorStopped || to == InferiorStopFailed;
case InferiorStopped: case InferiorStopped:
return to == InferiorRunningRequested || to == InferiorShuttingDown; return to == InferiorRunningRequested || to == InferiorShuttingDown;
case InferiorStopFailed: case InferiorStopFailed:
return to == DebuggerNotReady; return to == EngineShuttingDown;
case InferiorUnrunnable: case InferiorUnrunnable:
return to == AdapterShuttingDown; return to == EngineShuttingDown;
case InferiorShuttingDown: case InferiorShuttingDown:
return to == InferiorShutDown || to == InferiorShutdownFailed; return to == InferiorShutDown || to == InferiorShutdownFailed;
case InferiorShutDown: case InferiorShutDown:
return to == AdapterShuttingDown; return to == EngineShuttingDown;
case InferiorShutdownFailed:
return to == EngineShuttingDown;
case AdapterShuttingDown: case EngineShuttingDown:
return to == DebuggerNotReady; return to == DebuggerNotReady;
default:
qDebug() << "UNKNOWN STATE: " << from;
} }
qDebug() << "UNKNOWN STATE:" << from;
return false; return false;
} }
void DebuggerManager::setState(DebuggerState state) void DebuggerManager::setState(DebuggerState state, bool forced)
{ {
//STATE_DEBUG("STATUS CHANGE: FROM " << stateName(d->m_state) //STATE_DEBUG("STATUS CHANGE: FROM " << stateName(d->m_state)
// << " TO " << stateName(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); .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))) //if (!((d->m_state == -1 && state == 0) || (d->m_state == 0 && state == 0)))
// qDebug() << msg; // qDebug() << msg;
if (!isAllowedTransition(d->m_state, state)) if (!forced && !isAllowedTransition(d->m_state, state))
qDebug() << "UNEXPECTED STATE TRANSITION: " << msg; qDebug() << "UNEXPECTED STATE TRANSITION: " << msg;
showDebuggerOutput(LogDebug, msg); showDebuggerOutput(LogDebug, msg);
@@ -1715,8 +1707,7 @@ bool DebuggerManager::debuggerActionsEnabled() const
case InferiorShuttingDown: case InferiorShuttingDown:
case InferiorShutDown: case InferiorShutDown:
case InferiorShutdownFailed: case InferiorShutdownFailed:
case AdapterShuttingDown: case EngineShuttingDown:
case AdapterShutdownFailed:
break; break;
} }
return false; return false;
@@ -1793,9 +1784,9 @@ DebuggerState IDebuggerEngine::state() const
return m_manager->state(); 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);
} }
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////

View File

@@ -285,7 +285,7 @@ private:
void cleanupViews(); void cleanupViews();
void setState(DebuggerState state); void setState(DebuggerState state, bool forced = false);
// //
// internal implementation // internal implementation

View File

@@ -47,35 +47,18 @@ AbstractGdbAdapter::~AbstractGdbAdapter()
disconnect(); disconnect();
} }
// This cannot be in the c'tor, as it would not connect the "virtual" slots void AbstractGdbAdapter::shutdown()
void AbstractGdbAdapter::commonInit()
{ {
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(); return "kill";
}
QByteArray AbstractGdbAdapter::readAllStandardError()
{
return m_gdbProc.readAllStandardError();
} }
void AbstractGdbAdapter::write(const QByteArray &data) void AbstractGdbAdapter::write(const QByteArray &data)
{ {
m_gdbProc.write(data); m_engine->m_gdbProc.write(data);
} }
bool AbstractGdbAdapter::isTrkAdapter() const bool AbstractGdbAdapter::isTrkAdapter() const

View File

@@ -42,7 +42,7 @@ namespace Internal {
// debugging and TrkGdbAdapter used for on-device debugging. // debugging and TrkGdbAdapter used for on-device debugging.
// In the PlainGdbAdapter case it's just a wrapper around a QProcess running // 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 // 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 class AbstractGdbAdapter : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -51,34 +51,39 @@ public:
AbstractGdbAdapter(GdbEngine *engine, QObject *parent = 0); AbstractGdbAdapter(GdbEngine *engine, QObject *parent = 0);
virtual ~AbstractGdbAdapter(); virtual ~AbstractGdbAdapter();
QByteArray readAllStandardOutput();
QByteArray readAllStandardError();
virtual void write(const QByteArray &data); virtual void write(const QByteArray &data);
virtual bool isTrkAdapter() const; // isUtterlyBrokenAdapter virtual bool isTrkAdapter() const; // isUtterlyBrokenAdapter
virtual void startAdapter() = 0; virtual void startAdapter() = 0;
virtual void startInferior() = 0; virtual void startInferior() = 0;
virtual void interruptInferior() = 0; virtual void interruptInferior() = 0;
virtual void shutdown() = 0; virtual void shutdown();
virtual const char *inferiorShutdownCommand() const;
virtual bool dumpersAvailable() const = 0; 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: signals:
void adapterStarted(); 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 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); 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 inferiorStartFailed(const QString &msg);
void inferiorShutDown();
void inferiorShutdownFailed(const QString &msg);
void readyReadStandardOutput();
void readyReadStandardError();
protected: protected:
void commonInit();
DebuggerState state() const DebuggerState state() const
{ return m_engine->state(); } { return m_engine->state(); }
void setState(DebuggerState state) void setState(DebuggerState state)
@@ -90,16 +95,7 @@ protected:
void showStatusMessage(const QString &msg) const void showStatusMessage(const QString &msg) const
{ m_engine->showStatusMessage(msg); } { 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; GdbEngine * const m_engine;
QProcess m_gdbProc;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -53,7 +53,6 @@ namespace Internal {
AttachGdbAdapter::AttachGdbAdapter(GdbEngine *engine, QObject *parent) AttachGdbAdapter::AttachGdbAdapter(GdbEngine *engine, QObject *parent)
: AbstractGdbAdapter(engine, parent) : AbstractGdbAdapter(engine, parent)
{ {
commonInit();
} }
void AttachGdbAdapter::startAdapter() void AttachGdbAdapter::startAdapter()
@@ -62,27 +61,12 @@ void AttachGdbAdapter::startAdapter()
setState(AdapterStarting); setState(AdapterStarting);
debugMessage(_("TRYING TO START ADAPTER")); debugMessage(_("TRYING TO START ADAPTER"));
QStringList gdbArgs; if (!m_engine->startGdb())
gdbArgs.prepend(_("mi")); return;
gdbArgs.prepend(_("-i"));
QString location = theDebuggerStringSetting(GdbLocation);
m_gdbProc.start(location, gdbArgs);
}
void AttachGdbAdapter::handleGdbStarted()
{
QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
emit adapterStarted(); emit adapterStarted();
} }
void AttachGdbAdapter::handleGdbError(QProcess::ProcessError error)
{
debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR"));
emit adapterCrashed(m_engine->errorMessage(error));
shutdown();
}
void AttachGdbAdapter::startInferior() void AttachGdbAdapter::startInferior()
{ {
QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
@@ -113,58 +97,5 @@ void AttachGdbAdapter::interruptInferior()
debugMessage(_("CANNOT INTERRUPT %1").arg(pid)); 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 Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -57,16 +57,10 @@ public:
void startAdapter(); void startAdapter();
void startInferior(); void startInferior();
void interruptInferior(); void interruptInferior();
void shutdown(); const char *inferiorShutdownCommand() const { return "detach"; }
private: private:
void handleAttach(const GdbResponse &response); 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 } // namespace Internal

View File

@@ -53,7 +53,6 @@ namespace Internal {
CoreGdbAdapter::CoreGdbAdapter(GdbEngine *engine, QObject *parent) CoreGdbAdapter::CoreGdbAdapter(GdbEngine *engine, QObject *parent)
: AbstractGdbAdapter(engine, parent) : AbstractGdbAdapter(engine, parent)
{ {
commonInit();
} }
void CoreGdbAdapter::startAdapter() void CoreGdbAdapter::startAdapter()
@@ -62,27 +61,12 @@ void CoreGdbAdapter::startAdapter()
setState(AdapterStarting); setState(AdapterStarting);
debugMessage(_("TRYING TO START ADAPTER")); debugMessage(_("TRYING TO START ADAPTER"));
QStringList gdbArgs; if (!m_engine->startGdb())
gdbArgs.prepend(_("mi")); return;
gdbArgs.prepend(_("-i"));
QString location = theDebuggerStringSetting(GdbLocation);
m_gdbProc.start(location, gdbArgs);
}
void CoreGdbAdapter::handleGdbStarted()
{
QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
emit adapterStarted(); emit adapterStarted();
} }
void CoreGdbAdapter::handleGdbError(QProcess::ProcessError error)
{
debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR"));
emit adapterCrashed(m_engine->errorMessage(error));
shutdown();
}
void CoreGdbAdapter::startInferior() void CoreGdbAdapter::startInferior()
{ {
QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
@@ -175,45 +159,12 @@ void CoreGdbAdapter::handleTargetCore2(const GdbResponse &response)
// emit inferiorStartFailed(msg); // emit inferiorStartFailed(msg);
} }
} }
void CoreGdbAdapter::interruptInferior() void CoreGdbAdapter::interruptInferior()
{ {
// A core should never 'run' // A core should never 'run'
QTC_ASSERT(false, /**/); 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 Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -57,18 +57,12 @@ public:
void startAdapter(); void startAdapter();
void startInferior(); void startInferior();
void interruptInferior(); void interruptInferior();
void shutdown();
private: private:
void handleTargetCore1(const GdbResponse &response); void handleTargetCore1(const GdbResponse &response);
void handleDetach1(const GdbResponse &response); void handleDetach1(const GdbResponse &response);
void handleFileExecAndSymbols(const GdbResponse &response); void handleFileExecAndSymbols(const GdbResponse &response);
void handleTargetCore2(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; QString m_executable;
}; };

View File

@@ -105,17 +105,29 @@ namespace Internal {
static bool stateAcceptsGdbCommands(DebuggerState state) static bool stateAcceptsGdbCommands(DebuggerState state)
{ {
return state == AdapterStarted switch (state) {
|| state == InferiorUnrunnable case AdapterStarting:
|| state == InferiorStarting case AdapterStarted:
|| state == InferiorRunningRequested case AdapterStartFailed:
|| state == InferiorRunning case InferiorUnrunnable:
|| state == InferiorStopping case InferiorStarting:
|| state == InferiorStopped case InferiorStartFailed:
|| state == InferiorShuttingDown case InferiorRunningRequested:
|| state == InferiorShutDown case InferiorRunning:
|| state == AdapterShuttingDown; 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() static int &currentToken()
{ {
@@ -217,27 +229,13 @@ GdbEngine::~GdbEngine()
void GdbEngine::connectAdapter() 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()), connect(m_gdbAdapter, SIGNAL(adapterStarted()),
this, SLOT(handleAdapterStarted())); this, SLOT(handleAdapterStarted()));
connect(m_gdbAdapter, SIGNAL(adapterStartFailed(QString,QString)), connect(m_gdbAdapter, SIGNAL(adapterStartFailed(QString,QString)),
this, SLOT(handleAdapterStartFailed(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)), connect(m_gdbAdapter, SIGNAL(inferiorStartFailed(QString)),
this, SLOT(handleInferiorStartFailed(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)), connect(m_gdbAdapter, SIGNAL(adapterCrashed(QString)),
this, SLOT(handleAdapterCrashed(QString))); this, SLOT(handleAdapterCrashed(QString)));
@@ -571,7 +569,7 @@ void GdbEngine::handleResponse(const QByteArray &buff)
void GdbEngine::readGdbStandardError() void GdbEngine::readGdbStandardError()
{ {
qWarning() << "Unexpected gdb stderr:" << m_gdbAdapter->readAllStandardError(); qWarning() << "Unexpected gdb stderr:" << m_gdbProc.readAllStandardError();
} }
void GdbEngine::readGdbStandardOutput() void GdbEngine::readGdbStandardOutput()
@@ -579,7 +577,7 @@ void GdbEngine::readGdbStandardOutput()
int newstart = 0; int newstart = 0;
int scan = m_inbuffer.size(); int scan = m_inbuffer.size();
m_inbuffer.append(m_gdbAdapter->readAllStandardOutput()); m_inbuffer.append(m_gdbProc.readAllStandardOutput());
while (newstart < m_inbuffer.size()) { while (newstart < m_inbuffer.size()) {
int start = newstart; int start = newstart;
@@ -1366,8 +1364,73 @@ QString GdbEngine::fullName(const QStringList &candidates)
void GdbEngine::shutdown() void GdbEngine::shutdown()
{ {
debugMessage(_("INITIATE GDBENGINE SHUTDOWN")); debugMessage(_("INITIATE GDBENGINE SHUTDOWN"));
initializeVariables(); switch (state()) {
m_gdbAdapter->shutdown(); 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() void GdbEngine::detachDebugger()
@@ -1383,8 +1446,7 @@ void GdbEngine::detachDebugger()
void GdbEngine::exitDebugger() // called from the manager void GdbEngine::exitDebugger() // called from the manager
{ {
disconnectDebuggingHelperActions(); disconnectDebuggingHelperActions();
initializeVariables(); shutdown();
m_gdbAdapter->shutdown();
} }
int GdbEngine::currentFrame() const int GdbEngine::currentFrame() const
@@ -1445,17 +1507,17 @@ void GdbEngine::startDebugger(const DebuggerStartParametersPtr &sp)
// initializeVariables()); // initializeVariables());
//QTC_ASSERT(m_gdbAdapter == 0, delete m_gdbAdapter; m_gdbAdapter = 0); //QTC_ASSERT(m_gdbAdapter == 0, delete m_gdbAdapter; m_gdbAdapter = 0);
initializeVariables();
m_startParameters = sp; m_startParameters = sp;
delete m_gdbAdapter; delete m_gdbAdapter;
m_gdbAdapter = createAdapter(sp); m_gdbAdapter = createAdapter(sp);
connectAdapter();
if (startModeAllowsDumpers()) if (startModeAllowsDumpers())
connectDebuggingHelperActions(); connectDebuggingHelperActions();
initializeVariables();
connectAdapter();
m_gdbAdapter->startAdapter(); m_gdbAdapter->startAdapter();
} }
@@ -4089,19 +4151,37 @@ void GdbEngine::gotoLocation(const StackFrame &frame, bool setMarker)
// Starting up & shutting down // 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(_("STARTING GDB ") + gdb);
debugMessage(_("ADAPTER START FAILED"));
Core::ICore::instance()->showWarningWithOptions(tr("Adapter start failed"), msg, QString(),
QLatin1String(Debugger::Constants::DEBUGGER_SETTINGS_CATEGORY), settingsIdHint);
shutdown();
}
void GdbEngine::handleAdapterStarted() m_gdbProc.disconnect(); // From any previous runs
{
setState(AdapterStarted); QString location = gdb;
debugMessage(_("ADAPTER SUCCESSFULLY STARTED, INITIALIZING 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(_("show version"), CB(handleShowVersion));
postCommand(_("help bb"), CB(handleIsSynchroneous)); 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 // Initial attempt to set breakpoints
showStatusMessage(tr("Setting breakpoints...")); showStatusMessage(tr("Setting breakpoints..."));
attemptBreakpointSynchronization(); attemptBreakpointSynchronization();
QTC_ASSERT(m_commandsDoneCallback == 0, /**/); if (m_cookieForToken.isEmpty()) {
m_commandsDoneCallback = &GdbEngine::startInferior; startInferior();
} else {
QTC_ASSERT(m_commandsDoneCallback == 0, /**/);
m_commandsDoneCallback = &GdbEngine::startInferior;
}
} }
void GdbEngine::startInferior() void GdbEngine::startInferior()
@@ -4209,48 +4346,23 @@ void GdbEngine::handleInferiorStartFailed(const QString &msg)
shutdown(); 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) void GdbEngine::handleAdapterCrashed(const QString &msg)
{ {
debugMessage(_("ADAPTER CRASHED")); debugMessage(_("ADAPTER CRASHED"));
switch (state()) {
// All fall-through. // The adapter is expected to have cleaned up after itself when we get here,
case InferiorRunning: // so the effect is about the same as AdapterStartFailed => use it.
setState(InferiorShuttingDown); // Don't bother with state transitions - this can happen in any state and
case InferiorShuttingDown: // the end result is always the same, so it makes little sense to find a
setState(InferiorShutDown); // "path" which does not assert.
case InferiorShutDown: setState(AdapterStartFailed, true);
setState(AdapterShuttingDown);
default: // No point in being friendly here ...
setState(DebuggerNotReady); m_gdbProc.terminate();
}
showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg); showMessageBox(QMessageBox::Critical, tr("Adapter crashed"), msg);
} }
void GdbEngine::handleAdapterShutDown()
{
debugMessage(_("ADAPTER SUCCESSFULLY SHUT DOWN"));
setState(DebuggerNotReady);
}
void GdbEngine::handleAdapterShutdownFailed(const QString &msg)
{
debugMessage(_("ADAPTER SHUTDOWN FAILED"));
showMessageBox(QMessageBox::Critical, tr("Adapter shutdown failed"), msg);
setState(DebuggerNotReady);
}
void GdbEngine::addOptionPages(QList<Core::IOptionsPage*> *opts) const void GdbEngine::addOptionPages(QList<Core::IOptionsPage*> *opts) const
{ {
opts->push_back(new GdbOptionsPage); opts->push_back(new GdbOptionsPage);

View File

@@ -125,14 +125,20 @@ private: ////////// Gdb Process Management //////////
AbstractGdbAdapter *createAdapter(const DebuggerStartParametersPtr &dp); AbstractGdbAdapter *createAdapter(const DebuggerStartParametersPtr &dp);
void connectAdapter(); void connectAdapter();
bool startGdb(const QStringList &args = QStringList(), const QString &gdb = QString());
void startInferior(); void startInferior();
void handleInferiorShutdown(const GdbResponse &response);
void handleGdbExit(const GdbResponse &response);
void gdbInputAvailable(int channel, const QString &msg) void gdbInputAvailable(int channel, const QString &msg)
{ m_manager->showDebuggerInput(channel, msg); } { m_manager->showDebuggerInput(channel, msg); }
void gdbOutputAvailable(int channel, const QString &msg) void gdbOutputAvailable(int channel, const QString &msg)
{ m_manager->showDebuggerOutput(channel, msg); } { m_manager->showDebuggerOutput(channel, msg); }
private slots: private slots:
void handleGdbFinished(int, QProcess::ExitStatus status);
void handleGdbError(QProcess::ProcessError error);
void readGdbStandardOutput(); void readGdbStandardOutput();
void readGdbStandardError(); void readGdbStandardError();
void readDebugeeOutput(const QByteArray &data); void readDebugeeOutput(const QByteArray &data);
@@ -141,12 +147,8 @@ private slots:
void handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint = QString()); void handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint = QString());
void handleInferiorStartFailed(const QString &msg); void handleInferiorStartFailed(const QString &msg);
void handleInferiorShutDown();
void handleInferiorShutdownFailed(const QString &msg);
void handleAdapterCrashed(const QString &msg); void handleAdapterCrashed(const QString &msg);
void handleAdapterShutDown();
void handleAdapterShutdownFailed(const QString &msg);
private: private:
QTextCodec *m_outputCodec; QTextCodec *m_outputCodec;
@@ -154,6 +156,7 @@ private:
QByteArray m_inbuffer; QByteArray m_inbuffer;
QProcess m_gdbProc;
AbstractGdbAdapter *m_gdbAdapter; AbstractGdbAdapter *m_gdbAdapter;
private: ////////// Gdb Command Management ////////// private: ////////// Gdb Command Management //////////

View File

@@ -58,8 +58,6 @@ namespace Internal {
PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent) PlainGdbAdapter::PlainGdbAdapter(GdbEngine *engine, QObject *parent)
: AbstractGdbAdapter(engine, parent) : AbstractGdbAdapter(engine, parent)
{ {
commonInit();
// Output // Output
connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)), connect(&m_outputCollector, SIGNAL(byteDelivery(QByteArray)),
engine, SLOT(readDebugeeOutput(QByteArray))); engine, SLOT(readDebugeeOutput(QByteArray)));
@@ -72,36 +70,27 @@ void PlainGdbAdapter::startAdapter()
debugMessage(_("TRYING TO START ADAPTER")); debugMessage(_("TRYING TO START ADAPTER"));
QStringList gdbArgs; QStringList gdbArgs;
gdbArgs.prepend(_("mi"));
gdbArgs.prepend(_("-i"));
if (!m_outputCollector.listen()) { if (!m_outputCollector.listen()) {
emit adapterStartFailed(tr("Cannot set up communication with child process: %1") emit adapterStartFailed(tr("Cannot set up communication with child process: %1")
.arg(m_outputCollector.errorString()), QString()); .arg(m_outputCollector.errorString()), QString());
return; return;
} }
gdbArgs.prepend(_("--tty=") + m_outputCollector.serverName()); gdbArgs.append(_("--tty=") + m_outputCollector.serverName());
if (!startParameters().workingDir.isEmpty()) if (!startParameters().workingDir.isEmpty())
m_gdbProc.setWorkingDirectory(startParameters().workingDir); m_engine->m_gdbProc.setWorkingDirectory(startParameters().workingDir);
if (!startParameters().environment.isEmpty()) 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(); emit adapterStarted();
} }
void PlainGdbAdapter::handleGdbError(QProcess::ProcessError error)
{
debugMessage(_("PLAIN ADAPTER, HANDLE GDB ERROR"));
emit adapterCrashed(m_engine->errorMessage(error));
}
void PlainGdbAdapter::startInferior() void PlainGdbAdapter::startInferior()
{ {
QTC_ASSERT(state() == InferiorStarting, qDebug() << state()); QTC_ASSERT(state() == InferiorStarting, qDebug() << state());
@@ -159,74 +148,6 @@ void PlainGdbAdapter::shutdown()
{ {
debugMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state())); debugMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
m_outputCollector.shutdown(); 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 } // namespace Internal

View File

@@ -59,17 +59,12 @@ public:
void startInferior(); void startInferior();
void interruptInferior(); void interruptInferior();
void shutdown(); void shutdown();
const char *inferiorShutdownCommand() const { return "kill"; }
private: private:
void handleFileExecAndSymbols(const GdbResponse &response); void handleFileExecAndSymbols(const GdbResponse &response);
void handleKill(const GdbResponse &response);
void handleExit(const GdbResponse &response);
void handleExecRun(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; OutputCollector m_outputCollector;
}; };

View File

@@ -54,8 +54,6 @@ namespace Internal {
RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, QObject *parent) RemoteGdbAdapter::RemoteGdbAdapter(GdbEngine *engine, QObject *parent)
: AbstractGdbAdapter(engine, parent) : AbstractGdbAdapter(engine, parent)
{ {
commonInit();
connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)), connect(&m_uploadProc, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(uploadProcError(QProcess::ProcessError))); this, SLOT(uploadProcError(QProcess::ProcessError)));
connect(&m_uploadProc, SIGNAL(readyReadStandardOutput()), connect(&m_uploadProc, SIGNAL(readyReadStandardOutput()),
@@ -70,12 +68,6 @@ void RemoteGdbAdapter::startAdapter()
setState(AdapterStarting); setState(AdapterStarting);
debugMessage(_("TRYING TO START ADAPTER")); debugMessage(_("TRYING TO START ADAPTER"));
QStringList gdbArgs;
gdbArgs.prepend(_("mi"));
gdbArgs.prepend(_("-i"));
QString location = theDebuggerStringSetting(GdbLocation);
// FIXME: make asynchroneous // FIXME: make asynchroneous
// Start the remote server // Start the remote server
if (startParameters().serverStartScript.isEmpty()) { if (startParameters().serverStartScript.isEmpty()) {
@@ -86,23 +78,13 @@ void RemoteGdbAdapter::startAdapter()
m_uploadProc.waitForStarted(); m_uploadProc.waitForStarted();
} }
// Start the debugger if (!m_engine->startGdb())
m_gdbProc.start(location, gdbArgs); // FIXME: cleanup missing
} return;
void RemoteGdbAdapter::handleGdbStarted()
{
QTC_ASSERT(state() == AdapterStarting, qDebug() << state());
emit adapterStarted(); 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) void RemoteGdbAdapter::uploadProcError(QProcess::ProcessError error)
{ {
QString msg; QString msg;
@@ -232,55 +214,7 @@ void RemoteGdbAdapter::interruptInferior()
void RemoteGdbAdapter::shutdown() void RemoteGdbAdapter::shutdown()
{ {
switch (state()) { // FIXME: cleanup missing
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();
} }
} // namespace Internal } // namespace Internal

View File

@@ -69,12 +69,6 @@ private:
#endif #endif
void handleFileExecAndSymbols(const GdbResponse &response); void handleFileExecAndSymbols(const GdbResponse &response);
void handleTargetRemote(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; QProcess m_uploadProc;
}; };

View File

@@ -204,10 +204,6 @@ TrkGdbAdapter::TrkGdbAdapter(GdbEngine *engine, const TrkOptionsPtr &options) :
#endif #endif
m_gdbServerName = _("127.0.0.1:%1").arg(2222 + portOffset); 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()), connect(&m_rfcommProc, SIGNAL(readyReadStandardError()),
this, SLOT(handleRfcommReadyReadStandardError())); this, SLOT(handleRfcommReadyReadStandardError()));
connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()), connect(&m_rfcommProc, SIGNAL(readyReadStandardOutput()),
@@ -380,17 +376,6 @@ QByteArray TrkGdbAdapter::trkInterruptMessage()
return ba; 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) void TrkGdbAdapter::emitDelayedInferiorStartFailed(const QString &msg)
{ {
m_adapterFailMessage = msg; m_adapterFailMessage = msg;
@@ -437,7 +422,7 @@ void TrkGdbAdapter::waitForTrkConnect()
// "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File // "10 " + formatString("C:\\data\\usingdlls.sisx")); // Open File
//sendTrkMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File //sendTrkMessage(0x4B, 0, "00 00 00 01 73 1C 3A C8"); // Close File
maybeAdapterStarted(); emit adapterStarted();
} }
void TrkGdbAdapter::logMessage(const QString &msg) void TrkGdbAdapter::logMessage(const QString &msg)
@@ -1527,50 +1512,6 @@ void TrkGdbAdapter::interruptInferior()
sendTrkMessage(0x1a, TrkCallback(), trkInterruptMessage(), "Interrupting..."); 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() void TrkGdbAdapter::startAdapter()
{ {
// Retrieve parameters // Retrieve parameters
@@ -1632,13 +1573,12 @@ void TrkGdbAdapter::startAdapter()
connect(m_gdbServer, SIGNAL(newConnection()), connect(m_gdbServer, SIGNAL(newConnection()),
this, SLOT(handleGdbConnection())); this, SLOT(handleGdbConnection()));
logMessage("STARTING GDB");
logMessage(_("### Starting gdb %1").arg(m_options->gdb));
QStringList gdbArgs; QStringList gdbArgs;
gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file gdbArgs.append(QLatin1String("--nx")); // Do not read .gdbinit file
gdbArgs.append(QLatin1String("-i")); if (!m_engine->startGdb(gdbArgs, m_options->gdb)) {
gdbArgs.append(QLatin1String("mi")); cleanup();
m_gdbProc.start(m_options->gdb, gdbArgs); return;
}
waitForTrkConnect(); waitForTrkConnect();
} }
@@ -1792,7 +1732,7 @@ void TrkGdbAdapter::write(const QByteArray &data)
trkReadMemoryMessage(m_session.dataseg, 12)); trkReadMemoryMessage(m_session.dataseg, 12));
return; return;
} }
m_gdbProc.write(data); m_engine->m_gdbProc.write(data);
} }
uint oldPC; uint oldPC;
@@ -1990,79 +1930,7 @@ void TrkGdbAdapter::cleanup()
void TrkGdbAdapter::shutdown() void TrkGdbAdapter::shutdown()
{ {
switch (state()) { cleanup();
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);
}
} }
} // namespace Internal } // namespace Internal

View File

@@ -163,8 +163,6 @@ public:
// //
void start(const QString &program, const QStringList &args, void start(const QString &program, const QStringList &args,
QIODevice::OpenMode mode = QIODevice::ReadWrite); QIODevice::OpenMode mode = QIODevice::ReadWrite);
QByteArray readAllStandardError();
QByteArray readAllStandardOutput();
void write(const QByteArray &data); void write(const QByteArray &data);
bool isTrkAdapter() const { return true; } bool isTrkAdapter() const { return true; }
bool dumpersAvailable() const { return false; } bool dumpersAvailable() const { return false; }
@@ -174,15 +172,12 @@ private:
void startInferior(); void startInferior();
void interruptInferior(); void interruptInferior();
void shutdown(); void shutdown();
void cleanup(); void cleanup();
void emitDelayedAdapterStartFailed(const QString &msg);
Q_SLOT void slotEmitDelayedAdapterStartFailed();
void emitDelayedInferiorStartFailed(const QString &msg); void emitDelayedInferiorStartFailed(const QString &msg);
Q_SLOT void slotEmitDelayedInferiorStartFailed(); Q_SLOT void slotEmitDelayedInferiorStartFailed();
Q_SLOT void waitForTrkConnect(); Q_SLOT void waitForTrkConnect();
void handleKill(const GdbResponse &response);
void handleExit(const GdbResponse &response);
void handleTargetRemote(const GdbResponse &response); void handleTargetRemote(const GdbResponse &response);
void handleFirstContinue(const GdbResponse &response); void handleFirstContinue(const GdbResponse &response);
@@ -285,13 +280,6 @@ private:
bool sendGdbServerPacket(const QByteArray &packet, bool doFlush); bool sendGdbServerPacket(const QByteArray &packet, bool doFlush);
void tryAnswerGdbMemoryRequest(bool buffered); 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 void logMessage(const QString &msg); // triggers output() if m_verbose
Q_SLOT void trkLogMessage(const QString &msg); Q_SLOT void trkLogMessage(const QString &msg);

View File

@@ -123,7 +123,7 @@ public:
protected: protected:
void showStatusMessage(const QString &msg, int timeout = -1); void showStatusMessage(const QString &msg, int timeout = -1);
DebuggerState state() const; DebuggerState state() const;
void setState(DebuggerState state); void setState(DebuggerState state, bool forced = false);
DebuggerManager *manager() const { return m_manager; } DebuggerManager *manager() const { return m_manager; }
DebuggerManager *m_manager; DebuggerManager *m_manager;