Commit e760700f authored by hjk's avatar hjk

debugger: overhaul "state machine"

This mainly allows for more precise shutdown and tightens the set
of allowed transitions.
parent 6089bc1b
This diff is collapsed.
...@@ -55,12 +55,12 @@ public: ...@@ -55,12 +55,12 @@ public:
static DebuggerEngine *create(const DebuggerStartParameters &sp, static DebuggerEngine *create(const DebuggerStartParameters &sp,
QString *errorMessage); QString *errorMessage);
virtual void shutdown();
virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos); virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
virtual void setupEngine(); virtual void setupEngine();
virtual void setupInferior(); virtual void setupInferior();
virtual void runEngine(); virtual void runEngine();
virtual void exitDebugger(); virtual void shutdownInferior();
virtual void shutdownEngine();
virtual void detachDebugger(); virtual void detachDebugger();
virtual void updateWatchData(const WatchData &data); virtual void updateWatchData(const WatchData &data);
virtual unsigned debuggerCapabilities() const; virtual unsigned debuggerCapabilities() const;
......
...@@ -79,29 +79,34 @@ enum DebuggerState ...@@ -79,29 +79,34 @@ enum DebuggerState
{ {
DebuggerNotReady, // Debugger not started DebuggerNotReady, // Debugger not started
EngineSettingUp, // Engine starts EngineSetupRequested, // Engine starts
EngineSetupFailed, EngineSetupFailed,
EngineSetupOk, EngineSetupOk,
InferiorUnrunnable, // Used in the core dump adapter InferiorSetupRequested,
InferiorSettingUp,
InferiorSetupFailed, InferiorSetupFailed,
InferiorSetupOk,
InferiorRunningRequested, // Debuggee requested to run EngineRunRequested,
InferiorRunningRequested_Kill, // Debuggee requested to run, but want to kill it EngineRunFailed,
InferiorRunning, // Debuggee running InferiorUnrunnable, // Used in the core dump adapter
InferiorStopping, // Debuggee running, stop requested InferiorRunRequested, // Debuggee requested to run
InferiorStopping_Kill, // Debuggee running, stop requested, want to kill it InferiorRunOk, // Debuggee running
InferiorStopped, // Debuggee stopped InferiorRunFailed, // Debuggee running
InferiorStopFailed, // Debuggee not stopped, will kill debugger
InferiorShuttingDown, InferiorStopRequested, // Debuggee running, stop requested
InferiorShutDown, InferiorStopOk, // Debuggee stopped
InferiorStopFailed, // Debuggee not stopped, will kill debugger
InferiorShutdownRequested,
InferiorShutdownOk,
InferiorShutdownFailed, InferiorShutdownFailed,
EngineShuttingDown EngineShutdownRequested,
EngineShutdownOk,
EngineShutdownFailed,
DebuggerFinished
}; };
enum DebuggerStartMode enum DebuggerStartMode
...@@ -139,21 +144,21 @@ enum LogChannel ...@@ -139,21 +144,21 @@ enum LogChannel
{ {
LogInput, // Used for user input LogInput, // Used for user input
LogMiscInput, // Used for misc stuff in the input pane LogMiscInput, // Used for misc stuff in the input pane
LogOutput, LogOutput,
LogWarning, LogWarning,
LogError, LogError,
LogStatus, // Used for status changed messages LogStatus, // Used for status changed messages
LogTime, // Used for time stamp messages LogTime, // Used for time stamp messages
LogDebug, LogDebug,
LogMisc, LogMisc,
AppOutput, AppOutput,
AppError, AppError,
AppStuff, AppStuff,
StatusBar // LogStatus and also put to the status bar StatusBar // LogStatus and also put to the status bar
}; };
enum ModelRoles enum ModelRoles
{ {
DisplaySourceRole = 32, // Qt::UserRole DisplaySourceRole = 32, // Qt::UserRole
EngineStateRole, EngineStateRole,
......
This diff is collapsed.
...@@ -121,7 +121,6 @@ public: ...@@ -121,7 +121,6 @@ public:
DebuggerEngine(const DebuggerStartParameters &sp); DebuggerEngine(const DebuggerStartParameters &sp);
virtual ~DebuggerEngine(); virtual ~DebuggerEngine();
virtual void shutdown() {}
virtual void setToolTipExpression(const QPoint & /* mousePos */, virtual void setToolTipExpression(const QPoint & /* mousePos */,
TextEditor::ITextEditor * /* editor */, int /* cursorPos */) { } TextEditor::ITextEditor * /* editor */, int /* cursorPos */) { }
void initializeFromTemplate(DebuggerEngine *other); void initializeFromTemplate(DebuggerEngine *other);
...@@ -164,8 +163,6 @@ public: ...@@ -164,8 +163,6 @@ public:
{ Q_UNUSED(expr); Q_UNUSED(value); } { Q_UNUSED(expr); Q_UNUSED(value); }
protected: protected:
virtual void setupEngine() {}
virtual void exitDebugger() {}
virtual void detachDebugger() {} virtual void detachDebugger() {}
virtual void executeStep() {} virtual void executeStep() {}
virtual void executeStepOut() {} virtual void executeStepOut() {}
...@@ -229,6 +226,9 @@ public: ...@@ -229,6 +226,9 @@ public:
void executeReturnX(); void executeReturnX();
DebuggerState state() const; DebuggerState state() const;
DebuggerState lastGoodState() const;
DebuggerState targetState() const;
bool isDying() const { return targetState() == DebuggerFinished; }
// Dumper stuff (common to cdb and gdb). // Dumper stuff (common to cdb and gdb).
bool qtDumperLibraryEnabled() const; bool qtDumperLibraryEnabled() const;
...@@ -251,24 +251,46 @@ public: ...@@ -251,24 +251,46 @@ public:
void openFile(const QString &fileName, int lineNumber = -1); void openFile(const QString &fileName, int lineNumber = -1);
void gotoLocation(const QString &fileName, int lineNumber, bool setMarker); void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
void gotoLocation(const StackFrame &frame, bool setMarker); void gotoLocation(const StackFrame &frame, bool setMarker);
void raiseApplication(); Q_SLOT void raiseApplication();
virtual void quitDebugger() { exitDebugger(); } // called by DebuggerRunControl virtual void quitDebugger(); // called by DebuggerRunControl
protected: protected:
void notifyEngineSetupOk(); void notifyEngineSetupOk();
void notifyEngineSetupFailed(); void notifyEngineSetupFailed();
void notifyEngineRunFailed();
void notifyInferiorSetupOk(); void notifyInferiorSetupOk();
void notifyInferiorSetupFailed(); void notifyInferiorSetupFailed();
void notifyInferiorRunning(); void notifyEngineRunAndInferiorRunOk();
void notifyInferiorStopped(); void notifyEngineRunAndInferiorStopOk();
void notifyInferiorUnrunnable(); // Called by CoreAdapter.
//void notifyInferiorSpontaneousRun();
void notifyInferiorRunRequested();
void notifyInferiorRunOk();
void notifyInferiorRunFailed();
void notifyInferiorStopOk();
void notifyInferiorSpontaneousStop();
void notifyInferiorStopFailed();
void notifyInferiorExited();
void notifyInferiorShutdownOk();
void notifyInferiorShutdownFailed();
void notifyEngineSpontaneousShutdown();
void notifyEngineShutdownOk();
void notifyEngineShutdownFailed();
// Called to initiate shutdown.
void notifyInferiorIll(); void notifyInferiorIll();
void notifyEngineIll();
virtual void setupInferior(); virtual void setupEngine() = 0;
virtual void runEngine(); virtual void setupInferior() = 0;
virtual void runEngine() = 0;
virtual void shutdownInferior() = 0;
virtual void shutdownEngine() = 0;
//private: // FIXME. State transitions //private: // FIXME. State transitions
void setState(DebuggerState state, bool forced = false); void setState(DebuggerState state, bool forced = false);
......
This diff is collapsed.
...@@ -39,7 +39,7 @@ namespace Debugger { ...@@ -39,7 +39,7 @@ namespace Debugger {
namespace Internal { namespace Internal {
AbstractGdbAdapter::AbstractGdbAdapter(GdbEngine *engine, QObject *parent) AbstractGdbAdapter::AbstractGdbAdapter(GdbEngine *engine, QObject *parent)
: QObject(parent), m_engine(engine) : QObject(parent), m_engine(engine)
{ {
} }
...@@ -48,19 +48,20 @@ AbstractGdbAdapter::~AbstractGdbAdapter() ...@@ -48,19 +48,20 @@ AbstractGdbAdapter::~AbstractGdbAdapter()
disconnect(); disconnect();
} }
void AbstractGdbAdapter::shutdown() //void AbstractGdbAdapter::shutdown()
{ //{
} //}
void AbstractGdbAdapter::runAdapter() //void AbstractGdbAdapter::runEngine()
{ //{
qDebug() << "START INFERIOR PHASE 2"; //}
}
/*
const char *AbstractGdbAdapter::inferiorShutdownCommand() const const char *AbstractGdbAdapter::inferiorShutdownCommand() const
{ {
return "kill"; return "kill";
} }
*/
void AbstractGdbAdapter::write(const QByteArray &data) void AbstractGdbAdapter::write(const QByteArray &data)
{ {
...@@ -87,7 +88,7 @@ QString AbstractGdbAdapter::msgInferiorSetupOk() ...@@ -87,7 +88,7 @@ QString AbstractGdbAdapter::msgInferiorSetupOk()
return tr("Application started"); return tr("Application started");
} }
QString AbstractGdbAdapter::msgInferiorRunning() QString AbstractGdbAdapter::msgInferiorRunOk()
{ {
return tr("Application running"); return tr("Application running");
} }
......
...@@ -65,10 +65,11 @@ public: ...@@ -65,10 +65,11 @@ public:
virtual void startAdapter() = 0; virtual void startAdapter() = 0;
virtual void setupInferior() = 0; virtual void setupInferior() = 0;
virtual void runAdapter(); virtual void runEngine() = 0;
virtual void interruptInferior() = 0; virtual void interruptInferior() = 0;
virtual void shutdown(); virtual void shutdownInferior() = 0;
virtual const char *inferiorShutdownCommand() const; virtual void shutdownAdapter() = 0;
//virtual const char *inferiorShutdownCommand() const;
virtual AbstractGdbProcess *gdbProc() = 0; virtual AbstractGdbProcess *gdbProc() = 0;
virtual DumperHandling dumperHandling() const = 0; virtual DumperHandling dumperHandling() const = 0;
...@@ -77,7 +78,7 @@ public: ...@@ -77,7 +78,7 @@ public:
static QString msgInferiorStopFailed(const QString &why); static QString msgInferiorStopFailed(const QString &why);
static QString msgAttachedToStoppedInferior(); static QString msgAttachedToStoppedInferior();
static QString msgInferiorSetupOk(); static QString msgInferiorSetupOk();
static QString msgInferiorRunning(); static QString msgInferiorRunOk();
static QString msgConnectRemoteServerFailed(const QString &why); static QString msgConnectRemoteServerFailed(const QString &why);
// Trk specific stuff // Trk specific stuff
......
...@@ -49,7 +49,7 @@ AbstractPlainGdbAdapter::AbstractPlainGdbAdapter(GdbEngine *engine, ...@@ -49,7 +49,7 @@ AbstractPlainGdbAdapter::AbstractPlainGdbAdapter(GdbEngine *engine,
void AbstractPlainGdbAdapter::setupInferior() void AbstractPlainGdbAdapter::setupInferior()
{ {
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state()); QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (!startParameters().processArgs.isEmpty()) { if (!startParameters().processArgs.isEmpty()) {
QString args = startParameters().processArgs.join(_(" ")); QString args = startParameters().processArgs.join(_(" "));
m_engine->postCommand("-exec-arguments " + toLocalEncoding(args)); m_engine->postCommand("-exec-arguments " + toLocalEncoding(args));
...@@ -60,7 +60,7 @@ void AbstractPlainGdbAdapter::setupInferior() ...@@ -60,7 +60,7 @@ void AbstractPlainGdbAdapter::setupInferior()
void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response) void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
{ {
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state()); QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) { if (response.resultClass == GdbResultDone) {
if (infoTargetNecessary()) { if (infoTargetNecessary()) {
// Old gdbs do not announce the PID for programs without pthreads. // Old gdbs do not announce the PID for programs without pthreads.
...@@ -76,31 +76,33 @@ void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &respon ...@@ -76,31 +76,33 @@ void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &respon
// Extend the message a bit in unknown cases. // Extend the message a bit in unknown cases.
if (!ba.endsWith("File format not recognized")) if (!ba.endsWith("File format not recognized"))
msg = tr("Starting executable failed:\n") + msg; msg = tr("Starting executable failed:\n") + msg;
m_engine->handleInferiorSetupFailed(msg); m_engine->notifyInferiorSetupFailed(msg);
} }
} }
void AbstractPlainGdbAdapter::runAdapter() void AbstractPlainGdbAdapter::runEngine()
{ {
setState(InferiorRunningRequested); QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
m_engine->postCommand("-exec-run", GdbEngine::RunRequest, CB(handleExecRun)); m_engine->postCommand("-exec-run", GdbEngine::RunRequest, CB(handleExecRun));
} }
void AbstractPlainGdbAdapter::handleExecRun(const GdbResponse &response) void AbstractPlainGdbAdapter::handleExecRun(const GdbResponse &response)
{ {
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
if (response.resultClass == GdbResultRunning) { if (response.resultClass == GdbResultRunning) {
QTC_ASSERT(state() == InferiorRunning, qDebug() << state()); m_engine->notifyEngineRunAndInferiorRunOk();
//showStatusMessage(tr("Running..."));
showMessage(_("INFERIOR STARTED")); showMessage(_("INFERIOR STARTED"));
showMessage(msgInferiorSetupOk(), StatusBar); showMessage(msgInferiorSetupOk(), StatusBar);
// FIXME: That's the wrong place for it. // FIXME: That's the wrong place for it.
if (theDebuggerBoolSetting(EnableReverseDebugging)) if (theDebuggerBoolSetting(EnableReverseDebugging))
m_engine->postCommand("target record"); m_engine->postCommand("target record");
} else { } else {
QTC_ASSERT(state() == InferiorRunningRequested, qDebug() << state());
QString msg = fromLocalEncoding(response.data.findChild("msg").data()); QString msg = fromLocalEncoding(response.data.findChild("msg").data());
//QTC_ASSERT(status() == InferiorRunning, /**/); //QTC_ASSERT(status() == InferiorRunOk, /**/);
//interruptInferior(); //interruptInferior();
m_engine->handleInferiorSetupFailed(msg); showMessage(msg);
m_engine->notifyEngineRunFailed();
} }
} }
...@@ -118,10 +120,10 @@ void AbstractPlainGdbAdapter::handleInfoTarget(const GdbResponse &response) ...@@ -118,10 +120,10 @@ void AbstractPlainGdbAdapter::handleInfoTarget(const GdbResponse &response)
m_engine->postCommand("tbreak *0x" + needle.cap(1).toAscii()); m_engine->postCommand("tbreak *0x" + needle.cap(1).toAscii());
// Do nothing here - inferiorPrepared handles the sequencing. // Do nothing here - inferiorPrepared handles the sequencing.
} else { } else {
m_engine->handleInferiorSetupFailed(_("Parsing start address failed")); m_engine->notifyInferiorSetupFailed(_("Parsing start address failed"));
} }
} else if (response.resultClass == GdbResultError) { } else if (response.resultClass == GdbResultError) {
m_engine->handleInferiorSetupFailed(_("Fetching start address failed")); m_engine->notifyInferiorSetupFailed(_("Fetching start address failed"));
} }
} }
......
...@@ -36,13 +36,15 @@ namespace Debugger { ...@@ -36,13 +36,15 @@ namespace Debugger {
namespace Internal { namespace Internal {
class AbstractPlainGdbAdapter : public AbstractGdbAdapter class AbstractPlainGdbAdapter : public AbstractGdbAdapter
{ // Needs tr - context {
// Needs tr - context
Q_OBJECT Q_OBJECT
public: public:
AbstractPlainGdbAdapter(GdbEngine *engine, QObject *parent = 0); AbstractPlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
virtual void setupInferior(); void setupInferior();
virtual void runAdapter(); void runEngine();
protected: protected:
void handleInfoTarget(const GdbResponse &response); void handleInfoTarget(const GdbResponse &response);
......
...@@ -56,7 +56,7 @@ AttachGdbAdapter::AttachGdbAdapter(GdbEngine *engine, QObject *parent) ...@@ -56,7 +56,7 @@ AttachGdbAdapter::AttachGdbAdapter(GdbEngine *engine, QObject *parent)
void AttachGdbAdapter::startAdapter() void AttachGdbAdapter::startAdapter()
{ {
QTC_ASSERT(state() == EngineSettingUp, qDebug() << state()); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
showMessage(_("TRYING TO START ADAPTER")); showMessage(_("TRYING TO START ADAPTER"));
if (!m_engine->startGdb()) if (!m_engine->startGdb())
...@@ -67,34 +67,52 @@ void AttachGdbAdapter::startAdapter() ...@@ -67,34 +67,52 @@ void AttachGdbAdapter::startAdapter()
void AttachGdbAdapter::setupInferior() void AttachGdbAdapter::setupInferior()
{ {
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state()); QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
const qint64 pid = startParameters().attachPID; const qint64 pid = startParameters().attachPID;
m_engine->postCommand("attach " + QByteArray::number(pid), CB(handleAttach)); m_engine->postCommand("attach " + QByteArray::number(pid), CB(handleAttach));
// Task 254674 does not want to remove them // Task 254674 does not want to remove them
//qq->breakHandler()->removeAllBreakpoints(); //qq->breakHandler()->removeAllBreakpoints();
} }
void AttachGdbAdapter::runEngine()
{
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
m_engine->notifyInferiorStopOk();
}
void AttachGdbAdapter::handleAttach(const GdbResponse &response) void AttachGdbAdapter::handleAttach(const GdbResponse &response)
{ {
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state()); QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) { if (response.resultClass == GdbResultDone) {
setState(InferiorStopped);
showMessage(_("INFERIOR ATTACHED")); showMessage(_("INFERIOR ATTACHED"));
showMessage(msgAttachedToStoppedInferior(), StatusBar); showMessage(msgAttachedToStoppedInferior(), StatusBar);
m_engine->handleInferiorPrepared(); m_engine->handleInferiorPrepared();
m_engine->updateAll(); m_engine->updateAll();
} else { } else {
QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data()); QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data());
m_engine->handleInferiorSetupFailed(msg); m_engine->notifyInferiorSetupFailed(msg);
} }
} }
void AttachGdbAdapter::interruptInferior() void AttachGdbAdapter::interruptInferior()
{ {
QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state(); return);
const qint64 pid = startParameters().attachPID; const qint64 pid = startParameters().attachPID;
QTC_ASSERT(pid > 0, return); QTC_ASSERT(pid > 0, return);
if (!interruptProcess(pid)) if (!interruptProcess(pid)) {
showMessage(_("CANNOT INTERRUPT %1").arg(pid)); showMessage(_("CANNOT INTERRUPT %1").arg(pid));
m_engine->notifyInferiorStopFailed();
}
}
void AttachGdbAdapter::shutdownInferior()
{
m_engine->defaultInferiorShutdown("detach");
}
void AttachGdbAdapter::shutdownAdapter()
{
m_engine->notifyAdapterShutdownOk();
} }
} // namespace Internal } // namespace Internal
......
...@@ -50,15 +50,17 @@ class AttachGdbAdapter : public AbstractGdbAdapter ...@@ -50,15 +50,17 @@ class AttachGdbAdapter : public AbstractGdbAdapter
public: public:
AttachGdbAdapter(GdbEngine *engine, QObject *parent = 0); AttachGdbAdapter(GdbEngine *engine, QObject *parent = 0);
virtual DumperHandling dumperHandling() const { return DumperLoadedByGdb; } private:
DumperHandling dumperHandling() const { return DumperLoadedByGdb; }
void startAdapter(); void startAdapter();
void setupInferior(); void setupInferior();
void runEngine();
void interruptInferior(); void interruptInferior();
const char *inferiorShutdownCommand() const { return "detach"; } void shutdownInferior();
AbstractGdbProcess *gdbProc() { return &m_gdbProc; } void shutdownAdapter();
private: AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
void handleAttach(const GdbResponse &response); void handleAttach(const GdbResponse &response);
LocalGdbProcess m_gdbProc; LocalGdbProcess m_gdbProc;
......
...@@ -574,7 +574,7 @@ void GdbEngine::updateAllClassic() ...@@ -574,7 +574,7 @@ void GdbEngine::updateAllClassic()
{ {
PRECONDITION; PRECONDITION;
PENDING_DEBUG("UPDATING ALL\n"); PENDING_DEBUG("UPDATING ALL\n");
QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopped, /**/); QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopOk, /**/);
tryLoadDebuggingHelpersClassic(); tryLoadDebuggingHelpersClassic();
reloadModulesInternal(); reloadModulesInternal();
postCommand("-stack-list-frames", WatchUpdate, postCommand("-stack-list-frames", WatchUpdate,
......
...@@ -59,7 +59,7 @@ CoreGdbAdapter::CoreGdbAdapter(GdbEngine *engine, QObject *parent) ...@@ -59,7 +59,7 @@ CoreGdbAdapter::CoreGdbAdapter(GdbEngine *engine, QObject *parent)
void CoreGdbAdapter::startAdapter() void CoreGdbAdapter::startAdapter()
{ {
QTC_ASSERT(state() == EngineSettingUp, qDebug() << state()); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());