debugger: re-do state transitions in combined C++/Qml engine

This still needs a lot of work and sanitizing.
This commit is contained in:
hjk
2011-01-14 14:25:02 +01:00
parent adf74394bb
commit 7195c6b5ad
7 changed files with 463 additions and 324 deletions

View File

@@ -114,9 +114,12 @@ enum DebuggerState
InferiorSetupRequested,
InferiorSetupFailed,
InferiorSetupOk,
EngineRunRequested,
EngineRunFailed,
EngineRunOk,
InferiorUnrunnable, // Used in the core dump adapter
InferiorRunRequested, // Debuggee requested to run
@@ -124,16 +127,19 @@ enum DebuggerState
InferiorRunFailed, // Debuggee running
InferiorStopRequested, // Debuggee running, stop requested
InferiorStopSpontaneous, // Debuggee stopped spontaneously
InferiorStopOk, // Debuggee stopped
InferiorStopFailed, // Debuggee not stopped, will kill debugger
InferiorExitOk,
InferiorShutdownRequested,
InferiorShutdownOk,
InferiorShutdownFailed,
InferiorShutdownOk,
EngineShutdownRequested,
EngineShutdownOk,
EngineShutdownFailed,
EngineShutdownOk,
DebuggerFinished
};

View File

@@ -182,7 +182,8 @@ public:
m_threadsHandler(),
m_watchHandler(engine),
m_disassemblerAgent(engine),
m_memoryAgent(engine)
m_memoryAgent(engine),
m_isStateDebugging(false)
{
connect(&m_locationTimer, SIGNAL(timeout()), SLOT(resetLocation()));
}
@@ -229,8 +230,8 @@ public slots:
void raiseApplication()
{
QTC_ASSERT(m_runControl, return);
m_runControl->bringApplicationToForeground(m_inferiorPid);
QTC_ASSERT(runControl(), return);
runControl()->bringApplicationToForeground(m_inferiorPid);
}
void scheduleResetLocation()
@@ -250,6 +251,9 @@ public slots:
public:
DebuggerState state() const { return m_state; }
bool isMasterEngine() const { return m_engine->isMasterEngine(); }
DebuggerRunControl *runControl() const
{ return m_masterEngine ? m_masterEngine->runControl() : m_runControl; }
DebuggerEngine *m_engine; // Not owned.
DebuggerEngine *m_masterEngine; // Not owned
@@ -280,6 +284,8 @@ public:
MemoryAgent m_memoryAgent;
QScopedPointer<TextEditor::BaseTextMark> m_locationMark;
QTimer m_locationTimer;
bool m_isStateDebugging;
};
@@ -310,16 +316,20 @@ const char *DebuggerEngine::stateName(int s)
SN(EngineSetupOk)
SN(EngineSetupFailed)
SN(EngineRunFailed)
SN(EngineRunOk)
SN(InferiorSetupRequested)
SN(InferiorSetupFailed)
SN(InferiorSetupOk)
SN(EngineRunRequested)
SN(InferiorRunRequested)
SN(InferiorRunOk)
SN(InferiorRunFailed)
SN(InferiorUnrunnable)
SN(InferiorStopSpontaneous)
SN(InferiorStopRequested)
SN(InferiorStopOk)
SN(InferiorStopFailed)
SN(InferiorExitOk)
SN(InferiorShutdownRequested)
SN(InferiorShutdownOk)
SN(InferiorShutdownFailed)
@@ -476,6 +486,10 @@ void DebuggerEngine::setRegisterValue(int regnr, const QString &value)
void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) const
{
if (d->m_masterEngine) {
d->m_masterEngine->showMessage(msg, channel, timeout);
return;
}
//if (msg.size() && msg.at(0).isUpper() && msg.at(1).isUpper())
// qDebug() << qPrintable(msg) << "IN STATE" << state();
debuggerCore()->showMessage(msg, channel, timeout);
@@ -488,17 +502,16 @@ void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) c
void DebuggerEngine::startDebugger(DebuggerRunControl *runControl)
{
if (!isSlaveEngine()) {
d->m_progress.setProgressRange(0, 1000);
Core::FutureProgress *fp = Core::ICore::instance()->progressManager()
->addTask(d->m_progress.future(),
tr("Launching"), _("Debugger.Launcher"));
fp->setKeepOnFinish(Core::FutureProgress::DontKeepOnFinish);
d->m_progress.reportStarted();
}
QTC_ASSERT(runControl, notifyEngineSetupFailed(); return);
QTC_ASSERT(!d->m_runControl, notifyEngineSetupFailed(); return);
d->m_progress.setProgressRange(0, 1000);
Core::FutureProgress *fp = Core::ICore::instance()->progressManager()
->addTask(d->m_progress.future(),
tr("Launching"), _("Debugger.Launcher"));
fp->setKeepOnFinish(Core::FutureProgress::DontKeepOnFinish);
d->m_progress.reportStarted();
d->m_runControl = runControl;
d->m_inferiorPid = d->m_startParameters.attachPID > 0
@@ -671,32 +684,42 @@ static bool isAllowedTransition(DebuggerState from, DebuggerState to)
return to == InferiorSetupRequested || to == EngineShutdownRequested;
case InferiorSetupRequested:
return to == EngineRunRequested || to == InferiorSetupFailed;
return to == InferiorSetupOk || to == InferiorSetupFailed;
case InferiorSetupFailed:
return to == EngineShutdownRequested;
case InferiorSetupOk:
return to == EngineRunRequested;
case EngineRunRequested:
return to == InferiorRunRequested || to == InferiorStopRequested
|| to == InferiorUnrunnable || to == EngineRunFailed;
return to == EngineRunOk || EngineRunFailed;
case EngineRunFailed:
return to == EngineShutdownRequested;
case EngineRunOk:
return InferiorRunOk || to == InferiorStopOk
|| to == InferiorUnrunnable;
case InferiorRunRequested:
return to == InferiorRunOk || to == InferiorRunFailed;
case InferiorRunFailed:
return to == InferiorStopOk;
case InferiorRunOk:
return to == InferiorStopRequested || to == InferiorStopOk;
return to == InferiorStopRequested || to == InferiorStopSpontaneous
|| InferiorExitOk;
//|| to == InferiorStopOk;
case InferiorStopRequested:
return to == InferiorStopOk || to == InferiorStopFailed;
case InferiorStopSpontaneous:
return to == InferiorStopOk;
case InferiorStopOk:
return to == InferiorRunRequested || to == InferiorShutdownRequested
|| to == InferiorStopOk;
|| to == InferiorStopOk || InferiorExitOk;
case InferiorStopFailed:
return to == EngineShutdownRequested;
case InferiorExitOk:
return to == InferiorShutdownOk;
case InferiorUnrunnable:
return to == InferiorShutdownRequested;
case InferiorShutdownRequested:
@@ -724,27 +747,28 @@ static bool isAllowedTransition(DebuggerState from, DebuggerState to)
void DebuggerEngine::notifyEngineSetupFailed()
{
showMessage(_("NOTE: ENGINE SETUP FAILED"));
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
setState(EngineSetupFailed);
QTC_ASSERT(d->m_runControl, return);
d->m_runControl->startFailed();
if (isMasterEngine())
runControl()->startFailed();
setState(DebuggerFinished);
}
void DebuggerEngine::notifyEngineSetupOk()
{
showMessage(_("NOTE: ENGINE SETUP OK"));
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << state());
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
setState(EngineSetupOk);
QTC_ASSERT(d->m_runControl, return);
showMessage(_("QUEUE: SETUP INFERIOR"));
QTimer::singleShot(0, d, SLOT(doSetupInferior()));
if (isMasterEngine())
QTimer::singleShot(0, d, SLOT(doSetupInferior()));
}
void DebuggerEnginePrivate::doSetupInferior()
{
QTC_ASSERT(isMasterEngine(), return);
m_engine->showMessage(_("CALL: SETUP INFERIOR"));
QTC_ASSERT(state() == EngineSetupOk, qDebug() << state());
QTC_ASSERT(state() == EngineSetupOk, qDebug() << m_engine << state());
m_progress.setProgressValue(250);
m_engine->setState(InferiorSetupRequested);
m_engine->setupInferior();
@@ -753,22 +777,26 @@ void DebuggerEnginePrivate::doSetupInferior()
void DebuggerEngine::notifyInferiorSetupFailed()
{
showMessage(_("NOTE: INFERIOR SETUP FAILED"));
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state());
setState(InferiorSetupFailed);
d->queueShutdownEngine();
if (isMasterEngine())
d->queueShutdownEngine();
}
void DebuggerEngine::notifyInferiorSetupOk()
{
showMessage(_("NOTE: INFERIOR SETUP OK"));
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << state());
d->queueRunEngine();
QTC_ASSERT(state() == InferiorSetupRequested, qDebug() << this << state());
setState(InferiorSetupOk);
if (isMasterEngine())
d->queueRunEngine();
}
void DebuggerEnginePrivate::doRunEngine()
{
QTC_ASSERT(isMasterEngine(), return);
m_engine->showMessage(_("CALL: RUN ENGINE"));
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
QTC_ASSERT(state() == EngineRunRequested, qDebug() << m_engine << state());
m_progress.setProgressValue(300);
m_engine->runEngine();
}
@@ -778,19 +806,20 @@ void DebuggerEngine::notifyInferiorUnrunnable()
showMessage(_("NOTE: INFERIOR UNRUNNABLE"));
d->m_progress.setProgressValue(1000);
d->m_progress.reportFinished();
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
setState(InferiorUnrunnable);
}
void DebuggerEngine::notifyEngineRunFailed()
{
showMessage(_("NOTE: ENGINE RUN FAILED"));
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
d->m_progress.setProgressValue(900);
d->m_progress.reportCanceled();
d->m_progress.reportFinished();
setState(EngineRunFailed);
d->queueShutdownEngine();
if (isMasterEngine())
d->queueShutdownEngine();
}
void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
@@ -798,9 +827,10 @@ void DebuggerEngine::notifyEngineRunAndInferiorRunOk()
showMessage(_("NOTE: ENGINE RUN AND INFERIOR RUN OK"));
d->m_progress.setProgressValue(1000);
d->m_progress.reportFinished();
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
setState(InferiorRunRequested);
notifyInferiorRunOk();
QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
setState(EngineRunOk);
if (isMasterEngine())
setState(InferiorRunOk);
}
void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
@@ -808,29 +838,30 @@ void DebuggerEngine::notifyEngineRunAndInferiorStopOk()
showMessage(_("NOTE: ENGINE RUN AND INFERIOR STOP OK"));
d->m_progress.setProgressValue(1000);
d->m_progress.reportFinished();
QTC_ASSERT(state() == EngineRunRequested, qDebug() << state());
setState(InferiorStopRequested);
notifyInferiorStopOk();
QTC_ASSERT(state() == EngineRunRequested, qDebug() << this << state());
setState(EngineRunOk);
if (isMasterEngine())
setState(InferiorStopOk);
}
void DebuggerEngine::notifyInferiorRunRequested()
{
showMessage(_("NOTE: INFERIOR RUN REQUESTED"));
QTC_ASSERT(state() == InferiorStopOk, qDebug() << state());
QTC_ASSERT(state() == InferiorStopOk, qDebug() << this << state());
setState(InferiorRunRequested);
}
void DebuggerEngine::notifyInferiorRunOk()
{
showMessage(_("NOTE: INFERIOR RUN OK"));
QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
QTC_ASSERT(state() == InferiorRunRequested, qDebug() << this << state());
setState(InferiorRunOk);
}
void DebuggerEngine::notifyInferiorRunFailed()
{
showMessage(_("NOTE: INFERIOR RUN FAILED"));
QTC_ASSERT(state() == InferiorRunRequested, qDebug() << state());
QTC_ASSERT(state() == InferiorRunRequested, qDebug() << this << state());
setState(InferiorRunFailed);
setState(InferiorStopOk);
if (isDying())
@@ -856,28 +887,32 @@ void DebuggerEngine::notifyInferiorStopOk()
showMessage(_("NOTE: ... IGNORING STOP MESSAGE"));
return;
}
QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
setState(InferiorStopOk);
}
void DebuggerEngine::notifyInferiorSpontaneousStop()
{
showMessage(_("NOTE: INFERIOR SPONTANEOUES STOP"));
QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
setState(InferiorStopOk);
QTC_ASSERT(state() == InferiorRunOk, qDebug() << this << state());
setState(InferiorStopSpontaneous);
if (isMasterEngine())
setState(InferiorStopOk);
}
void DebuggerEngine::notifyInferiorStopFailed()
{
showMessage(_("NOTE: INFERIOR STOP FAILED"));
QTC_ASSERT(state() == InferiorStopRequested, qDebug() << state());
QTC_ASSERT(state() == InferiorStopRequested, qDebug() << this << state());
setState(InferiorStopFailed);
d->queueShutdownEngine();
if (isMasterEngine())
d->queueShutdownEngine();
}
void DebuggerEnginePrivate::doInterruptInferior()
{
QTC_ASSERT(state() == InferiorRunOk, qDebug() << state());
//QTC_ASSERT(isMasterEngine(), return);
QTC_ASSERT(state() == InferiorRunOk, qDebug() << m_engine << state());
m_engine->setState(InferiorStopRequested);
m_engine->showMessage(_("CALL: INTERRUPT INFERIOR"));
m_engine->interruptInferior();
@@ -885,7 +920,8 @@ void DebuggerEnginePrivate::doInterruptInferior()
void DebuggerEnginePrivate::doShutdownInferior()
{
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
//QTC_ASSERT(isMasterEngine(), return);
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << m_engine << state());
resetLocation();
m_targetState = DebuggerFinished;
m_engine->showMessage(_("CALL: SHUTDOWN INFERIOR"));
@@ -895,10 +931,11 @@ void DebuggerEnginePrivate::doShutdownInferior()
void DebuggerEngine::notifyInferiorShutdownOk()
{
showMessage(_("INFERIOR SUCCESSFULLY SHUT DOWN"));
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << state());
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
d->m_lastGoodState = DebuggerNotReady; // A "neutral" value.
setState(InferiorShutdownOk);
d->queueShutdownEngine();
if (isMasterEngine())
d->queueShutdownEngine();
}
void DebuggerEngine::notifyInferiorShutdownFailed()
@@ -906,7 +943,8 @@ void DebuggerEngine::notifyInferiorShutdownFailed()
showMessage(_("INFERIOR SHUTDOWN FAILED"));
QTC_ASSERT(state() == InferiorShutdownRequested, qDebug() << this << state());
setState(InferiorShutdownFailed);
d->queueShutdownEngine();
if (isMasterEngine())
d->queueShutdownEngine();
}
void DebuggerEngine::notifyInferiorIll()
@@ -928,7 +966,8 @@ void DebuggerEngine::notifyInferiorIll()
void DebuggerEnginePrivate::doShutdownEngine()
{
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
QTC_ASSERT(isMasterEngine(), qDebug() << m_engine; return);
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << m_engine << state());
m_targetState = DebuggerFinished;
m_engine->showMessage(_("CALL: SHUTDOWN ENGINE"));
m_engine->shutdownEngine();
@@ -937,28 +976,29 @@ void DebuggerEnginePrivate::doShutdownEngine()
void DebuggerEngine::notifyEngineShutdownOk()
{
showMessage(_("NOTE: ENGINE SHUTDOWN OK"));
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << this << state());
setState(EngineShutdownOk);
d->queueFinishDebugger();
if (isMasterEngine())
d->queueFinishDebugger();
}
void DebuggerEngine::notifyEngineShutdownFailed()
{
showMessage(_("NOTE: ENGINE SHUTDOWN FAILED"));
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state());
QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << this << state());
setState(EngineShutdownFailed);
d->queueFinishDebugger();
if (isMasterEngine())
d->queueFinishDebugger();
}
void DebuggerEnginePrivate::doFinishDebugger()
{
QTC_ASSERT(isMasterEngine(), return);
m_engine->showMessage(_("NOTE: FINISH DEBUGGER"));
QTC_ASSERT(state() == DebuggerFinished, qDebug() << state());
QTC_ASSERT(state() == DebuggerFinished, qDebug() << m_engine << state());
resetLocation();
if (!m_engine->isSlaveEngine()) {
QTC_ASSERT(m_runControl, return);
if (isMasterEngine())
m_runControl->debuggingFinished();
}
}
void DebuggerEngine::notifyEngineIll()
@@ -980,10 +1020,12 @@ void DebuggerEngine::notifyEngineIll()
case InferiorStopOk:
showMessage(_("FORWARDING STATE TO InferiorShutdownFailed"));
setState(InferiorShutdownFailed, true);
d->queueShutdownEngine();
if (isMasterEngine())
d->queueShutdownEngine();
break;
default:
d->queueShutdownEngine();
if (isMasterEngine())
d->queueShutdownEngine();
break;
}
}
@@ -992,14 +1034,16 @@ void DebuggerEngine::notifyEngineSpontaneousShutdown()
{
showMessage(_("NOTE: ENGINE SPONTANEOUS SHUTDOWN"));
setState(EngineShutdownOk, true);
d->queueFinishDebugger();
if (isMasterEngine())
d->queueFinishDebugger();
}
void DebuggerEngine::notifyInferiorExited()
{
qDebug() << "\nSPONTANEUOUS EXIT: " << this << d->m_state;
showMessage(_("NOTE: INFERIOR EXITED"));
d->resetLocation();
/*
// This can be issued in almost any state. We assume, though,
// that at this point of time the inferior is not running anymore,
// even if stop notification were not issued or got lost.
@@ -1009,13 +1053,28 @@ void DebuggerEngine::notifyInferiorExited()
}
setState(InferiorShutdownRequested);
setState(InferiorShutdownOk);
d->queueShutdownEngine();
*/
setState(InferiorExitOk);
if (isMasterEngine()) {
setState(InferiorShutdownOk);
d->queueShutdownEngine();
}
}
void DebuggerEngine::slaveEngineStateChanged(DebuggerEngine *slaveEngine,
DebuggerState state)
{
Q_UNUSED(slaveEngine);
Q_UNUSED(state);
}
void DebuggerEngine::setState(DebuggerState state, bool forced)
{
//qDebug() << "STATUS CHANGE: FROM " << stateName(d->m_state)
// << " TO " << stateName(state);
if (isStateDebugging()) {
qDebug() << "STATUS CHANGE: " << this
<< " FROM " << stateName(d->m_state) << " TO " << stateName(state)
<< isMasterEngine();
}
DebuggerState oldState = d->m_state;
d->m_state = state;
@@ -1024,7 +1083,7 @@ void DebuggerEngine::setState(DebuggerState state, bool forced)
.arg(stateName(oldState)).arg(oldState).arg(stateName(state)).arg(state)
.arg(forced ? " BY FORCE" : "");
if (!forced && !isAllowedTransition(oldState, state))
qDebug() << "UNEXPECTED STATE TRANSITION: " << msg;
qDebug() << "*** UNEXPECTED STATE TRANSITION: " << this << msg;
if (state == DebuggerFinished) {
// Give up ownership on claimed breakpoints.
@@ -1040,16 +1099,31 @@ void DebuggerEngine::setState(DebuggerState state, bool forced)
showMessage(msg, LogDebug);
updateViews();
emit stateChanged(d->m_state);
if (isMasterEngine())
emit stateChanged(d->m_state);
if (isSlaveEngine())
masterEngine()->slaveEngineStateChanged(this, state);
}
void DebuggerEngine::setSilentState(DebuggerState state)
{
qDebug() << "SILENT STATUS CHANGE: " << this
<< " FROM " << stateName(d->m_state) << " TO " << stateName(state)
<< isMasterEngine();
DebuggerState oldState = d->m_state;
d->m_state = state;
if (!isAllowedTransition(oldState, state))
qDebug() << "*** SILENT UNEXPECTED STATE TRANSITION " << this;
}
void DebuggerEngine::updateViews()
{
// The slave engines are not entitled to change the view. Their wishes
// should be coordinated by their master engine.
if (isSlaveEngine())
return;
debuggerCore()->updateState(this);
if (isMasterEngine())
debuggerCore()->updateState(this);
}
bool DebuggerEngine::isSlaveEngine() const
@@ -1057,6 +1131,11 @@ bool DebuggerEngine::isSlaveEngine() const
return d->m_masterEngine != 0;
}
bool DebuggerEngine::isMasterEngine() const
{
return d->m_masterEngine == 0;
}
DebuggerEngine *DebuggerEngine::masterEngine() const
{
return d->m_masterEngine;
@@ -1078,14 +1157,18 @@ bool DebuggerEngine::debuggerActionsEnabled(DebuggerState state)
case InferiorStopRequested:
case InferiorRunRequested:
case InferiorRunFailed:
case InferiorSetupOk:
case DebuggerNotReady:
case EngineSetupRequested:
case EngineSetupOk:
case EngineSetupFailed:
case EngineRunRequested:
case EngineRunFailed:
case EngineRunOk:
case InferiorSetupFailed:
case InferiorStopFailed:
case InferiorStopSpontaneous:
case InferiorExitOk:
case InferiorShutdownRequested:
case InferiorShutdownOk:
case InferiorShutdownFailed:
@@ -1150,7 +1233,7 @@ void DebuggerEngine::progressPing()
DebuggerRunControl *DebuggerEngine::runControl() const
{
return d->m_runControl;
return d->runControl();
}
void DebuggerEngine::setToolTipExpression
@@ -1305,21 +1388,21 @@ void DebuggerEngine::attemptBreakpointSynchronization()
void DebuggerEngine::insertBreakpoint(BreakpointId id)
{
BreakpointState state = breakHandler()->state(id);
QTC_ASSERT(state == BreakpointInsertRequested, qDebug() << state);
QTC_ASSERT(state == BreakpointInsertRequested, qDebug() << id << this << state);
QTC_ASSERT(false, /**/);
}
void DebuggerEngine::removeBreakpoint(BreakpointId id)
{
BreakpointState state = breakHandler()->state(id);
QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << state);
QTC_ASSERT(state == BreakpointRemoveRequested, qDebug() << id << this << state);
QTC_ASSERT(false, /**/);
}
void DebuggerEngine::changeBreakpoint(BreakpointId id)
{
BreakpointState state = breakHandler()->state(id);
QTC_ASSERT(state == BreakpointChangeRequested, qDebug() << state);
QTC_ASSERT(state == BreakpointChangeRequested, qDebug() << id << this << state);
QTC_ASSERT(false, /**/);
}
@@ -1511,6 +1594,16 @@ void DebuggerEngine::handleRemoteSetupFailed(const QString &message)
Q_UNUSED(message);
}
bool DebuggerEngine::isStateDebugging() const
{
return d->m_isStateDebugging;
}
void DebuggerEngine::setStateDebugging(bool on)
{
d->m_isStateDebugging = on;
}
} // namespace Debugger
#include "debuggerengine.moc"

View File

@@ -241,6 +241,7 @@ public:
virtual void updateViews();
bool isSlaveEngine() const;
bool isMasterEngine() const;
DebuggerEngine *masterEngine() const;
signals:
@@ -320,7 +321,7 @@ protected:
virtual void frameUp();
virtual void frameDown();
DebuggerRunControl *runControl() const; // FIXME: Protect.
DebuggerRunControl *runControl() const;
static QString msgWatchpointTriggered(BreakpointId id,
int number, quint64 address);
@@ -338,12 +339,18 @@ protected:
static bool isCppBreakpoint(const Internal::BreakpointParameters &p);
bool isStateDebugging() const;
void setStateDebugging(bool on);
private:
// Wrapper engine needs access to state of its subengines.
friend class Internal::QmlCppEngine;
friend class Internal::DebuggerPluginPrivate;
void setState(DebuggerState state, bool forced = false);
virtual void setState(DebuggerState state, bool forced = false);
virtual void setSilentState(DebuggerState state);
virtual void slaveEngineStateChanged(DebuggerEngine *engine,
DebuggerState state);
friend class DebuggerEnginePrivate;
DebuggerEnginePrivate *d;

View File

@@ -141,7 +141,10 @@ static bool stateAcceptsGdbCommands(DebuggerState state)
return true;
case DebuggerNotReady:
case InferiorStopFailed:
case InferiorStopSpontaneous:
case InferiorSetupOk:
case EngineRunFailed:
case EngineRunOk:
case InferiorRunFailed:
case EngineShutdownOk:
case EngineShutdownFailed:

View File

@@ -5,9 +5,12 @@
#include "debuggercore.h"
#include <qmljseditor/qmljseditorconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <utils/qtcassert.h>
#include <QtCore/QTimer>
namespace Debugger {
@@ -42,14 +45,12 @@ private:
DebuggerEngine *m_qmlEngine;
DebuggerEngine *m_cppEngine;
DebuggerEngine *m_activeEngine;
DebuggerState m_errorState;
};
QmlCppEnginePrivate::QmlCppEnginePrivate()
: m_qmlEngine(0),
m_cppEngine(0),
m_activeEngine(0),
m_errorState(InferiorRunOk)
m_activeEngine(0)
{}
@@ -70,10 +71,12 @@ QmlCppEngine::QmlCppEngine(const DebuggerStartParameters &sp)
}
d->m_activeEngine = d->m_cppEngine;
connect(d->m_cppEngine, SIGNAL(stateChanged(DebuggerState)),
SLOT(slaveEngineStateChanged(DebuggerState)));
connect(d->m_qmlEngine, SIGNAL(stateChanged(DebuggerState)),
SLOT(slaveEngineStateChanged(DebuggerState)));
if (1) {
setStateDebugging(true);
d->m_cppEngine->setStateDebugging(true);
d->m_qmlEngine->setStateDebugging(true);
}
}
QmlCppEngine::~QmlCppEngine()
@@ -217,61 +220,66 @@ void QmlCppEngine::detachDebugger()
void QmlCppEngine::executeStep()
{
notifyInferiorRunRequested();
d->m_activeEngine->executeStep();
}
void QmlCppEngine::executeStepOut()
{
notifyInferiorRunRequested();
d->m_activeEngine->executeStepOut();
}
void QmlCppEngine::executeNext()
{
notifyInferiorRunRequested();
d->m_activeEngine->executeNext();
}
void QmlCppEngine::executeStepI()
{
notifyInferiorRunRequested();
d->m_activeEngine->executeStepI();
}
void QmlCppEngine::executeNextI()
{
notifyInferiorRunRequested();
d->m_activeEngine->executeNextI();
}
void QmlCppEngine::executeReturn()
{
notifyInferiorRunRequested();
d->m_activeEngine->executeReturn();
}
void QmlCppEngine::continueInferior()
{
if (d->m_activeEngine->state() == InferiorStopOk) {
d->m_activeEngine->continueInferior();
qDebug() << "\nMASTER CONTINUE INFERIOR"
<< d->m_cppEngine->state() << d->m_qmlEngine->state();
notifyInferiorRunRequested();
if (d->m_cppEngine->state() == InferiorStopOk) {
d->m_cppEngine->continueInferior();
} else if (d->m_qmlEngine->state() == InferiorStopOk) {
d->m_qmlEngine->continueInferior();
} else {
notifyInferiorRunRequested();
QTC_ASSERT(false, qDebug() << "MASTER CANNOT CONTINUE INFERIOR"
<< d->m_cppEngine->state() << d->m_qmlEngine->state());
notifyEngineIll();
}
}
void QmlCppEngine::interruptInferior()
{
if (d->m_activeEngine->state() == InferiorRunOk) {
d->m_activeEngine->requestInterruptInferior();
} else {
if (d->m_activeEngine->state() == InferiorStopOk && (!checkErrorState(InferiorStopFailed))) {
notifyInferiorStopOk();
}
}
qDebug() << "\nMASTER INTERRUPT INFERIOR";
}
void QmlCppEngine::requestInterruptInferior()
{
qDebug() << "\nMASTER REQUEST INTERUPT INFERIOR";
DebuggerEngine::requestInterruptInferior();
if (d->m_activeEngine->state() == InferiorRunOk) {
d->m_activeEngine->requestInterruptInferior();
}
d->m_cppEngine->requestInterruptInferior();
}
void QmlCppEngine::executeRunToLine(const QString &fileName, int lineNumber)
@@ -306,240 +314,264 @@ void QmlCppEngine::frameDown()
/////////////////////////////////////////////////////////
bool QmlCppEngine::checkErrorState(const DebuggerState stateToCheck)
void QmlCppEngine::setupEngine()
{
if (d->m_errorState != stateToCheck)
return false;
qDebug() << "\nMASTER SETUP ENGINE";
QTC_ASSERT(d->m_cppEngine->state() == DebuggerNotReady, /**/);
QTC_ASSERT(d->m_qmlEngine->state() == DebuggerNotReady, /**/);
d->m_qmlEngine->setSilentState(EngineSetupRequested);
d->m_cppEngine->setSilentState(EngineSetupRequested);
d->m_qmlEngine->setupEngine(); // Always succeeds.
d->m_cppEngine->setupEngine(); // May fail.
}
// reset state ( so that more than one error can accumulate over time )
d->m_errorState = InferiorRunOk;
switch (stateToCheck) {
case InferiorRunOk:
// nothing to do
break;
case EngineRunFailed:
notifyEngineRunFailed();
break;
case EngineSetupFailed:
notifyEngineSetupFailed();
break;
case EngineShutdownFailed:
notifyEngineShutdownFailed();
break;
case InferiorSetupFailed:
notifyInferiorSetupFailed();
break;
case InferiorRunFailed:
notifyInferiorRunFailed();
break;
case InferiorUnrunnable:
notifyInferiorUnrunnable();
break;
case InferiorStopFailed:
notifyInferiorStopFailed();
break;
case InferiorShutdownFailed:
notifyInferiorShutdownFailed();
break;
default:
// unexpected
break;
}
return true;
void QmlCppEngine::notifyEngineRunAndInferiorRunOk()
{
qDebug() << "\nMASTER NOTIFY ENGINE RUN AND INFERIOR RUN OK";
DebuggerEngine::notifyEngineRunAndInferiorRunOk();
}
void QmlCppEngine::notifyInferiorRunOk()
{
qDebug() << "\nMASTER NOTIFY INFERIOR RUN OK";
DebuggerEngine::notifyInferiorRunOk();
}
void QmlCppEngine::setupEngine()
void QmlCppEngine::notifyInferiorSpontaneousStop()
{
d->m_cppEngine->startDebugger(runControl());
qDebug() << "\nMASTER SPONTANEOUS STOP OK";
DebuggerEngine::notifyInferiorSpontaneousStop();
}
void QmlCppEngine::notifyInferiorShutdownOk()
{
qDebug() << "\nMASTER INFERIOR SHUTDOWN OK";
DebuggerEngine::notifyInferiorShutdownOk();
}
void QmlCppEngine::setupInferior()
{
if (!checkErrorState(InferiorSetupFailed)) {
notifyInferiorSetupOk();
}
qDebug() << "\nMASTER SETUP INFERIOR";
QTC_ASSERT(d->m_cppEngine->state() == EngineSetupOk, /**/);
QTC_ASSERT(d->m_qmlEngine->state() == EngineSetupOk, /**/);
d->m_qmlEngine->setSilentState(InferiorSetupRequested);
d->m_cppEngine->setSilentState(InferiorSetupRequested);
d->m_cppEngine->setupInferior();
d->m_qmlEngine->setupInferior();
}
void QmlCppEngine::runEngine()
{
if (!checkErrorState(EngineRunFailed)) {
if (d->m_errorState == InferiorRunOk) {
switch (d->m_activeEngine->state()) {
case InferiorRunOk:
notifyEngineRunAndInferiorRunOk();
break;
case InferiorStopOk:
notifyEngineRunAndInferiorStopOk();
break;
default: // not supported?
notifyEngineRunFailed();
break;
}
} else {
notifyEngineRunFailed();
}
}
qDebug() << "\nMASTER RUN ENGINE";
QTC_ASSERT(d->m_cppEngine->state() == InferiorSetupOk, /**/);
QTC_ASSERT(d->m_qmlEngine->state() == InferiorSetupOk, /**/);
d->m_qmlEngine->setSilentState(EngineRunRequested);
d->m_cppEngine->setSilentState(EngineRunRequested);
d->m_cppEngine->runEngine();
d->m_qmlEngine->runEngine();
}
void QmlCppEngine::shutdownInferior()
{
if (!checkErrorState(InferiorShutdownFailed)) {
if (d->m_cppEngine->state() == InferiorStopOk) {
d->m_cppEngine->quitDebugger();
} else {
notifyInferiorShutdownOk();
}
}
}
void QmlCppEngine::initEngineShutdown()
{
if (d->m_qmlEngine->state() != DebuggerFinished) {
d->m_qmlEngine->quitDebugger();
} else
if (d->m_cppEngine->state() != DebuggerFinished) {
d->m_cppEngine->quitDebugger();
} else
if (state() == EngineSetupRequested) {
if (!runControl() || d->m_errorState == EngineSetupFailed) {
notifyEngineSetupFailed();
} else {
notifyEngineSetupOk();
}
} else
if (state() == InferiorStopRequested) {
checkErrorState(InferiorStopFailed);
} else
if (state() == InferiorShutdownRequested && !checkErrorState(InferiorShutdownFailed)) {
notifyInferiorShutdownOk();
} else
if (state() != DebuggerFinished) {
quitDebugger();
}
qDebug() << "\nMASTER SHUTDOWN INFERIOR";
d->m_qmlEngine->quitDebugger();
}
void QmlCppEngine::shutdownEngine()
{
if (!checkErrorState(EngineShutdownFailed)) {
showStatusMessage(tr("Debugging finished"));
notifyEngineShutdownOk();
}
qDebug() << "\nMASTER SHUTDOWN ENGINE";
QTC_ASSERT(d->m_cppEngine->state() == InferiorShutdownOk, /**/);
QTC_ASSERT(d->m_qmlEngine->state() == InferiorShutdownOk, /**/);
d->m_qmlEngine->setSilentState(EngineShutdownRequested);
d->m_cppEngine->setSilentState(EngineShutdownRequested);
d->m_qmlEngine->shutdownEngine();
d->m_cppEngine->shutdownEngine();
}
void QmlCppEngine::setupSlaveEngine()
void QmlCppEngine::setState(DebuggerState newState, bool forced)
{
if (d->m_qmlEngine->state() == DebuggerNotReady)
d->m_qmlEngine->startDebugger(runControl());
qDebug() << "SET MASTER STATE: " << newState;
qDebug() << " CPP STATE: " << d->m_cppEngine->state();
qDebug() << " QML STATE: " << d->m_qmlEngine->state();
DebuggerEngine::setState(newState, forced);
}
void QmlCppEngine::slaveEngineStateChanged(const DebuggerState newState)
void QmlCppEngine::slaveEngineStateChanged
(DebuggerEngine *slaveEngine, const DebuggerState newState)
{
DebuggerEngine *slaveEngine = qobject_cast<DebuggerEngine *>(sender());
if (newState == InferiorStopOk && slaveEngine != d->m_activeEngine) {
QString engineName = slaveEngine == d->m_cppEngine
? QLatin1String("C++") : QLatin1String("QML");
showStatusMessage(tr("%1 debugger activated").arg(engineName));
d->m_activeEngine = d->m_qmlEngine;
}
const bool isCpp = slaveEngine == d->m_cppEngine;
//const bool isQml = slaveEngine == d->m_qmlEngine;
DebuggerEngine *otherEngine = isCpp ? d->m_qmlEngine : d->m_cppEngine;
qDebug() << "GOT SLAVE STATE: " << slaveEngine << newState;
qDebug() << " OTHER ENGINE: " << otherEngine << otherEngine->state();
qDebug() << " COMBINED ENGINE: " << this << state() << isDying();
switch (newState) {
case InferiorRunOk:
// startup?
if (d->m_qmlEngine->state() == DebuggerNotReady) {
setupSlaveEngine();
} else
if (d->m_cppEngine->state() == DebuggerNotReady) {
setupEngine();
} else
if (state() == EngineSetupRequested) {
case DebuggerNotReady:
case InferiorUnrunnable:
break;
case EngineSetupRequested:
break;
case EngineSetupFailed:
notifyEngineSetupFailed();
break;
case EngineSetupOk:
if (otherEngine->state() == EngineSetupOk)
notifyEngineSetupOk();
} else
// breakpoint?
if (state() == InferiorStopOk) {
continueInferior();
} else
if (state() == InferiorStopRequested) {
checkErrorState(InferiorStopFailed);
} else
if (state() == InferiorRunRequested && (!checkErrorState(InferiorRunFailed)) && (!checkErrorState(InferiorUnrunnable))) {
notifyInferiorRunOk();
else
qDebug() << "... WAITING FOR OTHER ENGINE SETUP...";
break;
case InferiorSetupRequested:
break;
case InferiorSetupFailed:
notifyInferiorSetupFailed();
break;
case InferiorSetupOk:
if (otherEngine->state() == InferiorSetupOk)
notifyInferiorSetupOk();
else
qDebug() << "... WAITING FOR OTHER INFERIOR SETUP...";
break;
case EngineRunRequested:
break;
case EngineRunFailed:
notifyEngineRunFailed();
break;
case EngineRunOk:
if (otherEngine->state() == EngineRunOk) {
// This is conditionalized on isMasterEngine() in the
// base class, so do it here manually.
slaveEngine->setSilentState(InferiorRunOk);
otherEngine->setSilentState(InferiorRunOk);
notifyEngineRunAndInferiorRunOk();
} else {
qDebug() << "... WAITING FOR OTHER ENGINE RUN...";
}
break;
case InferiorRunRequested:
// follow the inferior
if (state() == InferiorStopOk && checkErrorState(InferiorRunOk)) {
continueInferior();
break;
case InferiorRunFailed:
notifyInferiorRunFailed();
break;
case InferiorRunOk:
qDebug() << "PLANNED INFERIOR RUN";
if (otherEngine->state() == InferiorRunOk)
notifyInferiorRunOk();
else
qDebug() << " **** INFERIOR RUN NOT OK ****";
break;
case InferiorStopSpontaneous:
notifyInferiorSpontaneousStop();
slaveEngine->setSilentState(InferiorStopOk);
if (slaveEngine != d->m_activeEngine) {
QString engineName = slaveEngine == d->m_cppEngine
? QLatin1String("C++") : QLatin1String("QML");
showStatusMessage(tr("%1 debugger activated").arg(engineName));
d->m_activeEngine = slaveEngine;
}
break;
case InferiorStopRequested:
// follow the inferior
if (state() == InferiorRunOk && checkErrorState(InferiorRunOk)) {
requestInterruptInferior();
}
break;
case InferiorStopFailed:
notifyInferiorStopFailed();
break;
case InferiorStopOk:
// check breakpoints
if (state() == InferiorRunRequested) {
checkErrorState(InferiorRunFailed);
} else
if (checkErrorState(InferiorRunOk)) {
if (state() == InferiorRunOk) {
requestInterruptInferior();
} else
if (state() == InferiorStopRequested) {
interruptInferior();
if (isDying()) {
qDebug() << "... AN INFERIOR STOPPED DURING SHUTDOWN ";
} else {
if (otherEngine->state() == InferiorShutdownOk) {
qDebug() << "... STOPP ";
} else if (state() == InferiorStopRequested) {
qDebug() << "... AN INFERIOR STOPPED EXPECTEDLY";
notifyInferiorStopOk();
} else {
qDebug() << "... AN INFERIOR STOPPED UNEXPECTEDLY";
notifyInferiorSpontaneousStop();
}
}
break;
case EngineRunFailed:
case EngineSetupFailed:
case EngineShutdownFailed:
case InferiorSetupFailed:
case InferiorRunFailed:
case InferiorUnrunnable:
case InferiorStopFailed:
case InferiorShutdownFailed:
if (d->m_errorState == InferiorRunOk) {
d->m_errorState = newState;
case InferiorExitOk:
slaveEngine->setSilentState(InferiorShutdownOk);
if (otherEngine->state() == InferiorShutdownOk) {
notifyInferiorExited();
} else {
if (state() == InferiorRunOk)
notifyInferiorSpontaneousStop();
otherEngine->notifyInferiorExited();
}
break;
case InferiorShutdownRequested:
break;
case EngineShutdownRequested:
// we have to abort the setup before the sub-engines die
// because we depend on an active runcontrol that will be shut down by the dying engine
if (state() == EngineSetupRequested)
notifyEngineSetupFailed();
case InferiorShutdownFailed:
notifyInferiorShutdownFailed();
break;
case InferiorShutdownOk:
if (otherEngine->state() == InferiorShutdownOk)
notifyInferiorShutdownOk();
else if (otherEngine->state() == InferiorRunOk)
otherEngine->quitDebugger();
else if (otherEngine->state() == InferiorStopOk)
otherEngine->quitDebugger();
break;
case EngineShutdownRequested:
break;
case EngineShutdownFailed:
notifyEngineShutdownFailed();
break;
case EngineShutdownOk:
if (otherEngine->state() == EngineShutdownOk)
notifyEngineShutdownOk();
else
qDebug() << "... WAITING FOR OTHER ENGINE SHUTDOWN...";
break;
case DebuggerFinished:
initEngineShutdown();
break;
default:
break;
break;
}
}
void QmlCppEngine::handleRemoteSetupDone(int gdbServerPort, int qmlPort)
{
//qDebug() << "MASETER REMOTE SETUP DONE";
d->m_qmlEngine->handleRemoteSetupDone(gdbServerPort, qmlPort);
d->m_cppEngine->handleRemoteSetupDone(gdbServerPort, qmlPort);
}
void QmlCppEngine::handleRemoteSetupFailed(const QString &message)
{
//qDebug() << "MASETER REMOTE SETUP FAILED";
d->m_qmlEngine->handleRemoteSetupFailed(message);
d->m_cppEngine->handleRemoteSetupFailed(message);
}

View File

@@ -16,86 +16,83 @@ class DEBUGGER_EXPORT QmlCppEngine : public DebuggerEngine
public:
explicit QmlCppEngine(const DebuggerStartParameters &sp);
virtual ~QmlCppEngine();
~QmlCppEngine();
virtual void setToolTipExpression(const QPoint &mousePos,
void setToolTipExpression(const QPoint &mousePos,
TextEditor::ITextEditor * editor, int cursorPos);
virtual void updateWatchData(const WatchData &data,
void updateWatchData(const WatchData &data,
const WatchUpdateFlags &flags);
virtual void watchPoint(const QPoint &);
virtual void fetchMemory(MemoryAgent *, QObject *,
quint64 addr, quint64 length);
virtual void fetchDisassembler(DisassemblerAgent *);
virtual void activateFrame(int index);
void watchPoint(const QPoint &);
void fetchMemory(MemoryAgent *, QObject *, quint64 addr, quint64 length);
void fetchDisassembler(DisassemblerAgent *);
void activateFrame(int index);
virtual void reloadModules();
virtual void examineModules();
virtual void loadSymbols(const QString &moduleName);
virtual void loadAllSymbols();
virtual void requestModuleSymbols(const QString &moduleName);
void reloadModules();
void examineModules();
void loadSymbols(const QString &moduleName);
void loadAllSymbols();
void requestModuleSymbols(const QString &moduleName);
virtual void reloadRegisters();
virtual void reloadSourceFiles();
virtual void reloadFullStack();
void reloadRegisters();
void reloadSourceFiles();
void reloadFullStack();
virtual void setRegisterValue(int regnr, const QString &value);
virtual unsigned debuggerCapabilities() const;
void setRegisterValue(int regnr, const QString &value);
unsigned debuggerCapabilities() const;
virtual bool isSynchronous() const;
virtual QByteArray qtNamespace() const;
bool isSynchronous() const;
QByteArray qtNamespace() const;
virtual void createSnapshot();
virtual void updateAll();
void createSnapshot();
void updateAll();
virtual void attemptBreakpointSynchronization();
virtual bool acceptsBreakpoint(BreakpointId id) const;
virtual void selectThread(int index);
void attemptBreakpointSynchronization();
bool acceptsBreakpoint(BreakpointId id) const;
void selectThread(int index);
virtual void assignValueInDebugger(const WatchData *data,
void assignValueInDebugger(const WatchData *data,
const QString &expr, const QVariant &value);
DebuggerEngine *cppEngine() const;
virtual void handleRemoteSetupDone(int gdbServerPort, int qmlPort);
virtual void handleRemoteSetupFailed(const QString &message);
void handleRemoteSetupDone(int gdbServerPort, int qmlPort);
void handleRemoteSetupFailed(const QString &message);
protected:
virtual void detachDebugger();
virtual void executeStep();
virtual void executeStepOut();
virtual void executeNext();
virtual void executeStepI();
virtual void executeNextI();
virtual void executeReturn();
virtual void continueInferior();
virtual void interruptInferior();
virtual void requestInterruptInferior();
void detachDebugger();
void executeStep();
void executeStepOut();
void executeNext();
void executeStepI();
void executeNextI();
void executeReturn();
void continueInferior();
void interruptInferior();
void requestInterruptInferior();
virtual void executeRunToLine(const QString &fileName, int lineNumber);
virtual void executeRunToFunction(const QString &functionName);
virtual void executeJumpToLine(const QString &fileName, int lineNumber);
virtual void executeDebuggerCommand(const QString &command);
void executeRunToLine(const QString &fileName, int lineNumber);
void executeRunToFunction(const QString &functionName);
void executeJumpToLine(const QString &fileName, int lineNumber);
void executeDebuggerCommand(const QString &command);
virtual void frameUp();
virtual void frameDown();
void frameUp();
void frameDown();
virtual void notifyInferiorRunOk();
void setupEngine();
void setupInferior();
void runEngine();
void shutdownInferior();
void shutdownEngine();
protected:
virtual void setupEngine();
virtual void setupInferior();
virtual void runEngine();
virtual void shutdownInferior();
virtual void shutdownEngine();
private slots:
void slaveEngineStateChanged(DebuggerState state);
void setupSlaveEngine();
void notifyInferiorRunOk();
void notifyInferiorSpontaneousStop();
void notifyEngineRunAndInferiorRunOk();
void notifyInferiorShutdownOk();
private:
void initEngineShutdown();
bool checkErrorState(DebuggerState stateToCheck);
void engineStateChanged(DebuggerState newState);
void setState(DebuggerState newState, bool forced = false);
void slaveEngineStateChanged(DebuggerEngine *slaveEngine, DebuggerState state);
private:
QScopedPointer<QmlCppEnginePrivate> d;

View File

@@ -208,7 +208,7 @@ void QmlEngine::setupInferior()
connect(&d->m_applicationLauncher,
SIGNAL(bringToForegroundRequested(qint64)),
runControl(),
SLOT(bringApplicationToForeground(qint64)));
SLOT(bringApplicationToForeground(qint64)));
d->m_applicationLauncher.setEnvironment(startParameters().environment);
d->m_applicationLauncher.setWorkingDirectory(startParameters().workingDirectory);
@@ -675,7 +675,8 @@ void QmlEngine::messageReceived(const QByteArray &message)
stream >> command;
if (command == "STOPPED") {
if (state() == InferiorRunOk)
qDebug() << command << this << state();
if (state() == InferiorRunOk || state() == EngineRunOk)
notifyInferiorSpontaneousStop();
QString logString = QString(command);