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:
static DebuggerEngine *create(const DebuggerStartParameters &sp,
QString *errorMessage);
virtual void shutdown();
virtual void setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
virtual void setupEngine();
virtual void setupInferior();
virtual void runEngine();
virtual void exitDebugger();
virtual void shutdownInferior();
virtual void shutdownEngine();
virtual void detachDebugger();
virtual void updateWatchData(const WatchData &data);
virtual unsigned debuggerCapabilities() const;
......
......@@ -79,29 +79,34 @@ enum DebuggerState
{
DebuggerNotReady, // Debugger not started
EngineSettingUp, // Engine starts
EngineSetupRequested, // Engine starts
EngineSetupFailed,
EngineSetupOk,
InferiorUnrunnable, // Used in the core dump adapter
InferiorSettingUp,
InferiorSetupRequested,
InferiorSetupFailed,
InferiorSetupOk,
InferiorRunningRequested, // Debuggee requested to run
InferiorRunningRequested_Kill, // Debuggee requested to run, but want to kill it
InferiorRunning, // Debuggee running
EngineRunRequested,
EngineRunFailed,
InferiorUnrunnable, // Used in the core dump adapter
InferiorStopping, // Debuggee running, stop requested
InferiorStopping_Kill, // Debuggee running, stop requested, want to kill it
InferiorStopped, // Debuggee stopped
InferiorStopFailed, // Debuggee not stopped, will kill debugger
InferiorRunRequested, // Debuggee requested to run
InferiorRunOk, // Debuggee running
InferiorRunFailed, // Debuggee running
InferiorShuttingDown,
InferiorShutDown,
InferiorStopRequested, // Debuggee running, stop requested
InferiorStopOk, // Debuggee stopped
InferiorStopFailed, // Debuggee not stopped, will kill debugger
InferiorShutdownRequested,
InferiorShutdownOk,
InferiorShutdownFailed,
EngineShuttingDown
EngineShutdownRequested,
EngineShutdownOk,
EngineShutdownFailed,
DebuggerFinished
};
enum DebuggerStartMode
......@@ -139,21 +144,21 @@ enum LogChannel
{
LogInput, // Used for user input
LogMiscInput, // Used for misc stuff in the input pane
LogOutput,
LogWarning,
LogError,
LogOutput,
LogWarning,
LogError,
LogStatus, // Used for status changed messages
LogTime, // Used for time stamp messages
LogDebug,
LogMisc,
AppOutput,
AppError,
LogDebug,
LogMisc,
AppOutput,
AppError,
AppStuff,
StatusBar // LogStatus and also put to the status bar
};
enum ModelRoles
{
};
enum ModelRoles
{
DisplaySourceRole = 32, // Qt::UserRole
EngineStateRole,
......
This diff is collapsed.
......@@ -121,7 +121,6 @@ public:
DebuggerEngine(const DebuggerStartParameters &sp);
virtual ~DebuggerEngine();
virtual void shutdown() {}
virtual void setToolTipExpression(const QPoint & /* mousePos */,
TextEditor::ITextEditor * /* editor */, int /* cursorPos */) { }
void initializeFromTemplate(DebuggerEngine *other);
......@@ -164,8 +163,6 @@ public:
{ Q_UNUSED(expr); Q_UNUSED(value); }
protected:
virtual void setupEngine() {}
virtual void exitDebugger() {}
virtual void detachDebugger() {}
virtual void executeStep() {}
virtual void executeStepOut() {}
......@@ -229,6 +226,9 @@ public:
void executeReturnX();
DebuggerState state() const;
DebuggerState lastGoodState() const;
DebuggerState targetState() const;
bool isDying() const { return targetState() == DebuggerFinished; }
// Dumper stuff (common to cdb and gdb).
bool qtDumperLibraryEnabled() const;
......@@ -251,24 +251,46 @@ public:
void openFile(const QString &fileName, int lineNumber = -1);
void gotoLocation(const QString &fileName, int lineNumber, bool setMarker);
void gotoLocation(const StackFrame &frame, bool setMarker);
void raiseApplication();
virtual void quitDebugger() { exitDebugger(); } // called by DebuggerRunControl
Q_SLOT void raiseApplication();
virtual void quitDebugger(); // called by DebuggerRunControl
protected:
void notifyEngineSetupOk();
void notifyEngineSetupFailed();
void notifyEngineRunFailed();
void notifyInferiorSetupOk();
void notifyInferiorSetupFailed();
void notifyInferiorRunning();
void notifyInferiorStopped();
void notifyEngineRunAndInferiorRunOk();
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 notifyEngineIll();
virtual void setupInferior();
virtual void runEngine();
virtual void setupEngine() = 0;
virtual void setupInferior() = 0;
virtual void runEngine() = 0;
virtual void shutdownInferior() = 0;
virtual void shutdownEngine() = 0;
//private: // FIXME. State transitions
void setState(DebuggerState state, bool forced = false);
......
This diff is collapsed.
......@@ -39,7 +39,7 @@ namespace Debugger {
namespace Internal {
AbstractGdbAdapter::AbstractGdbAdapter(GdbEngine *engine, QObject *parent)
: QObject(parent), m_engine(engine)
: QObject(parent), m_engine(engine)
{
}
......@@ -48,19 +48,20 @@ AbstractGdbAdapter::~AbstractGdbAdapter()
disconnect();
}
void AbstractGdbAdapter::shutdown()
{
}
//void AbstractGdbAdapter::shutdown()
//{
//}
void AbstractGdbAdapter::runAdapter()
{
qDebug() << "START INFERIOR PHASE 2";
}
//void AbstractGdbAdapter::runEngine()
//{
//}
/*
const char *AbstractGdbAdapter::inferiorShutdownCommand() const
{
return "kill";
}
*/
void AbstractGdbAdapter::write(const QByteArray &data)
{
......@@ -87,7 +88,7 @@ QString AbstractGdbAdapter::msgInferiorSetupOk()
return tr("Application started");
}
QString AbstractGdbAdapter::msgInferiorRunning()
QString AbstractGdbAdapter::msgInferiorRunOk()
{
return tr("Application running");
}
......
......@@ -65,10 +65,11 @@ public:
virtual void startAdapter() = 0;
virtual void setupInferior() = 0;
virtual void runAdapter();
virtual void runEngine() = 0;
virtual void interruptInferior() = 0;
virtual void shutdown();
virtual const char *inferiorShutdownCommand() const;
virtual void shutdownInferior() = 0;
virtual void shutdownAdapter() = 0;
//virtual const char *inferiorShutdownCommand() const;
virtual AbstractGdbProcess *gdbProc() = 0;
virtual DumperHandling dumperHandling() const = 0;
......@@ -77,7 +78,7 @@ public:
static QString msgInferiorStopFailed(const QString &why);
static QString msgAttachedToStoppedInferior();
static QString msgInferiorSetupOk();
static QString msgInferiorRunning();
static QString msgInferiorRunOk();
static QString msgConnectRemoteServerFailed(const QString &why);
// Trk specific stuff
......
......@@ -49,7 +49,7 @@ AbstractPlainGdbAdapter::AbstractPlainGdbAdapter(GdbEngine *engine,
void AbstractPlainGdbAdapter::setupInferior()
{
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state());
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (!startParameters().processArgs.isEmpty()) {
QString args = startParameters().processArgs.join(_(" "));
m_engine->postCommand("-exec-arguments " + toLocalEncoding(args));
......@@ -60,7 +60,7 @@ void AbstractPlainGdbAdapter::setupInferior()
void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state());
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
if (infoTargetNecessary()) {
// Old gdbs do not announce the PID for programs without pthreads.
......@@ -76,31 +76,33 @@ void AbstractPlainGdbAdapter::handleFileExecAndSymbols(const GdbResponse &respon
// Extend the message a bit in unknown cases.
if (!ba.endsWith("File format not recognized"))
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));
}
void AbstractPlainGdbAdapter::handleExecRun(const GdbResponse &response)
{
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
if (response.resultClass == GdbResultRunning) {
QTC_ASSERT(state() == InferiorRunning, qDebug() << state());
m_engine->notifyEngineRunAndInferiorRunOk();
//showStatusMessage(tr("Running..."));
showMessage(_("INFERIOR STARTED"));
showMessage(msgInferiorSetupOk(), StatusBar);
// FIXME: That's the wrong place for it.
if (theDebuggerBoolSetting(EnableReverseDebugging))
m_engine->postCommand("target record");
} else {
QTC_ASSERT(state() == InferiorRunningRequested, qDebug() << state());
QString msg = fromLocalEncoding(response.data.findChild("msg").data());
//QTC_ASSERT(status() == InferiorRunning, /**/);
//QTC_ASSERT(status() == InferiorRunOk, /**/);
//interruptInferior();
m_engine->handleInferiorSetupFailed(msg);
showMessage(msg);
m_engine->notifyEngineRunFailed();
}
}
......@@ -118,10 +120,10 @@ void AbstractPlainGdbAdapter::handleInfoTarget(const GdbResponse &response)
m_engine->postCommand("tbreak *0x" + needle.cap(1).toAscii());
// Do nothing here - inferiorPrepared handles the sequencing.
} else {
m_engine->handleInferiorSetupFailed(_("Parsing start address failed"));
m_engine->notifyInferiorSetupFailed(_("Parsing start address failed"));
}
} 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 {
namespace Internal {
class AbstractPlainGdbAdapter : public AbstractGdbAdapter
{ // Needs tr - context
{
// Needs tr - context
Q_OBJECT
public:
AbstractPlainGdbAdapter(GdbEngine *engine, QObject *parent = 0);
virtual void setupInferior();
virtual void runAdapter();
void setupInferior();
void runEngine();
protected:
void handleInfoTarget(const GdbResponse &response);
......
......@@ -56,7 +56,7 @@ AttachGdbAdapter::AttachGdbAdapter(GdbEngine *engine, QObject *parent)
void AttachGdbAdapter::startAdapter()
{
QTC_ASSERT(state() == EngineSettingUp, qDebug() << state());
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
showMessage(_("TRYING TO START ADAPTER"));
if (!m_engine->startGdb())
......@@ -67,34 +67,52 @@ void AttachGdbAdapter::startAdapter()
void AttachGdbAdapter::setupInferior()
{
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state());
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
const qint64 pid = startParameters().attachPID;
m_engine->postCommand("attach " + QByteArray::number(pid), CB(handleAttach));
// Task 254674 does not want to remove them
//qq->breakHandler()->removeAllBreakpoints();
}
void AttachGdbAdapter::runEngine()
{
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
m_engine->notifyInferiorStopOk();
}
void AttachGdbAdapter::handleAttach(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state());
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
setState(InferiorStopped);
showMessage(_("INFERIOR ATTACHED"));
showMessage(msgAttachedToStoppedInferior(), StatusBar);
m_engine->handleInferiorPrepared();
m_engine->updateAll();
} else {
QString msg = QString::fromLocal8Bit(response.data.findChild("msg").data());
m_engine->handleInferiorSetupFailed(msg);
m_engine->notifyInferiorSetupFailed(msg);
}
}
void AttachGdbAdapter::interruptInferior()
{
QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state(); return);
const qint64 pid = startParameters().attachPID;
QTC_ASSERT(pid > 0, return);
if (!interruptProcess(pid))
if (!interruptProcess(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
......
......@@ -50,15 +50,17 @@ class AttachGdbAdapter : public AbstractGdbAdapter
public:
AttachGdbAdapter(GdbEngine *engine, QObject *parent = 0);
virtual DumperHandling dumperHandling() const { return DumperLoadedByGdb; }
private:
DumperHandling dumperHandling() const { return DumperLoadedByGdb; }
void startAdapter();
void setupInferior();
void runEngine();
void interruptInferior();
const char *inferiorShutdownCommand() const { return "detach"; }
AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
void shutdownInferior();
void shutdownAdapter();
private:
AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
void handleAttach(const GdbResponse &response);
LocalGdbProcess m_gdbProc;
......
......@@ -574,7 +574,7 @@ void GdbEngine::updateAllClassic()
{
PRECONDITION;
PENDING_DEBUG("UPDATING ALL\n");
QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopped, /**/);
QTC_ASSERT(state() == InferiorUnrunnable || state() == InferiorStopOk, /**/);
tryLoadDebuggingHelpersClassic();
reloadModulesInternal();
postCommand("-stack-list-frames", WatchUpdate,
......
......@@ -59,7 +59,7 @@ CoreGdbAdapter::CoreGdbAdapter(GdbEngine *engine, QObject *parent)
void CoreGdbAdapter::startAdapter()
{
QTC_ASSERT(state() == EngineSettingUp, qDebug() << state());
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
showMessage(_("TRYING TO START ADAPTER"));
if (!m_engine->startGdb())
......@@ -70,7 +70,7 @@ void CoreGdbAdapter::startAdapter()
void CoreGdbAdapter::setupInferior()
{
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state());
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
m_executable = startParameters().executable;
if (m_executable.isEmpty()) {
#ifdef EXE_FROM_CORE
......@@ -103,7 +103,7 @@ void CoreGdbAdapter::loadExeAndSyms()
void CoreGdbAdapter::handleFileExecAndSymbols(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state());
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
showMessage(tr("Symbols found."), StatusBar);
} else {
......@@ -124,7 +124,7 @@ void CoreGdbAdapter::loadCoreFile()
void CoreGdbAdapter::handleTargetCore(const GdbResponse &response)
{
QTC_ASSERT(state() == InferiorSettingUp, qDebug() << state());
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
if (response.resultClass == GdbResultDone) {
#ifdef EXE_FROM_CORE
if (m_round == 1) {
......@@ -160,22 +160,32 @@ void CoreGdbAdapter::handleTargetCore(const GdbResponse &response)
} else {
QString msg = tr("Attach to core \"%1\" failed:\n").arg(startParameters().coreFile)
+ QString::fromLocal8Bit(response.data.findChild("msg").data());
m_engine->handleInferiorSetupFailed(msg);
m_engine->notifyInferiorSetupFailed(msg);
}
}
void CoreGdbAdapter::runAdapter()
void CoreGdbAdapter::runEngine()
{
QTC_ASSERT(state() == InferiorSetupOk, qDebug() << state());
setState(InferiorUnrunnable);
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
m_engine->notifyInferiorUnrunnable();
m_engine->updateAll();
}
void CoreGdbAdapter::interruptInferior()
{
// A core should never 'run'
// A core never runs, so this cannot be called.
QTC_ASSERT(false, /**/);
}
void CoreGdbAdapter::shutdownInferior()
{
m_engine->notifyInferiorShutdownOk();
}
void CoreGdbAdapter::shutdownAdapter()
{
m_engine->notifyAdapterShutdownOk();
}
} // namespace Internal
} // namespace Debugger
......@@ -59,8 +59,10 @@ private:
void startAdapter();
void setupInferior();
void runAdapter();
void runEngine();
void interruptInferior();
void shutdownInferior();
void shutdownAdapter();
AbstractGdbProcess *gdbProc() { return &m_gdbProc; }
......
This diff is collapsed.
......@@ -110,10 +110,10 @@ private: ////////// General Interface //////////
virtual void runEngine();
virtual unsigned debuggerCapabilities() const;
virtual void exitDebugger();
virtual void quitDebugger();
virtual void detachDebugger();
virtual void shutdown();
virtual void shutdownEngine();
virtual void shutdownInferior();
virtual void executeDebuggerCommand(const QString &command);
virtual QString qtNamespace() const { return m_dumperHelper.qtNamespace(); }
......@@ -136,6 +136,7 @@ private: ////////// Gdb Process Management //////////
void handleGdbExit(const GdbResponse &response);
void handleAdapterStarted();
void defaultInferiorShutdown(const char *cmd);
// Something went wrong with the adapter *before* adapterStarted() was emitted.
// Make sure to clean up everything before emitting this signal.
......@@ -149,7 +150,10 @@ private: ////////// Gdb Process Management //////////
void finishInferiorSetup();
// The adapter is still running just fine, but it failed to acquire a debuggee.
void handleInferiorSetupFailed(const QString &msg);
void notifyInferiorSetupFailed(const QString &msg);
void notifyAdapterShutdownOk();
void notifyAdapterShutdownFailed();
// Something went wrong with the adapter *after* adapterStarted() was emitted.
// Make sure to clean up everything before emitting this signal.
......@@ -530,6 +534,7 @@ private: ////////// View & Data Stuff //////////
int buttons = 0);
QMainWindow *mainWindow() const;
AbstractGdbProcess *gdbProc() const;
void showExecutionError(const QString &message);
static QString m_toolTipExpression;
static QPoint m_toolTipPos;
......
......@@ -68,7 +68,7 @@ AbstractGdbAdapter::DumperHandling LocalPlainGdbAdapter::dumperHandling() const
void LocalPlainGdbAdapter::startAdapter()
{
QTC_ASSERT(state() == EngineSettingUp, qDebug() << state());
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
showMessage(_("TRYING TO START ADAPTER"));
QStringList gdbArgs;
......@@ -94,6 +94,28 @@ void LocalPlainGdbAdapter::startAdapter()
m_engine->handleAdapterStarted();
}
void LocalPlainGdbAdapter::setupInferior()
{
AbstractPlainGdbAdapter::setupInferior();
}
void LocalPlainGdbAdapter::runEngine()
{
AbstractPlainGdbAdapter::runEngine();
}
void LocalPlainGdbAdapter::shutdownInferior()
{
m_engine->defaultInferiorShutdown("kill");
}
void LocalPlainGdbAdapter::shutdownAdapter()
{
showMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
m_outputCollector.shutdown();
m_engine->notifyAdapterShutdownOk();
}
void LocalPlainGdbAdapter::checkForReleaseBuild()
{
// Quick check for a "release" build
......@@ -128,14 +150,10 @@ void LocalPlainGdbAdapter::interruptInferior()
return;
}
if (!interruptProcess(attachedPID))
if (!interruptProcess(attachedPID)) {
showMessage(_("CANNOT INTERRUPT %1").arg(attachedPID));
}
void LocalPlainGdbAdapter::shutdown()
{
showMessage(_("PLAIN ADAPTER SHUTDOWN %1").arg(state()));
m_outputCollector.shutdown();