Fixes: debugger: work on process logic

Conflicts:

	src/plugins/debugger/gdbengine.cpp
This commit is contained in:
hjk
2009-02-17 17:42:08 +01:00
parent 25c7eb3dff
commit b4a7921832
4 changed files with 89 additions and 41 deletions

View File

@@ -543,6 +543,12 @@ void DebuggerManager::notifyStartupFinished()
showStatusMessage(tr("Startup finished. Debugger ready."), -1); showStatusMessage(tr("Startup finished. Debugger ready."), -1);
} }
void DebuggerManager::notifyInferiorStopRequested()
{
setStatus(DebuggerInferiorStopRequested);
showStatusMessage(tr("Stop requested..."), 5000);
}
void DebuggerManager::notifyInferiorStopped() void DebuggerManager::notifyInferiorStopped()
{ {
resetLocation(); resetLocation();
@@ -657,6 +663,12 @@ void DebuggerManager::toggleBreakpoint(const QString &fileName, int lineNumber)
{ {
QTC_ASSERT(m_engine, return); QTC_ASSERT(m_engine, return);
QTC_ASSERT(m_breakHandler, return); QTC_ASSERT(m_breakHandler, return);
if (status() != DebuggerInferiorRunning && status() != DebuggerInferiorStopped) {
showStatusMessage(tr("Changing breakpoint state requires either a "
"fully running or fully stopped application."));
return;
}
int index = m_breakHandler->indexOf(fileName, lineNumber); int index = m_breakHandler->indexOf(fileName, lineNumber);
if (index == -1) if (index == -1)
m_breakHandler->setBreakpoint(fileName, lineNumber); m_breakHandler->setBreakpoint(fileName, lineNumber);

View File

@@ -151,6 +151,7 @@ private:
// called from the engines after successful startup // called from the engines after successful startup
virtual void notifyStartupFinished() = 0; virtual void notifyStartupFinished() = 0;
virtual void notifyInferiorStopRequested() = 0;
virtual void notifyInferiorStopped() = 0; virtual void notifyInferiorStopped() = 0;
virtual void notifyInferiorUpdateFinished() = 0; virtual void notifyInferiorUpdateFinished() = 0;
virtual void notifyInferiorRunningRequested() = 0; virtual void notifyInferiorRunningRequested() = 0;
@@ -339,6 +340,7 @@ private:
void notifyInferiorStopped(); void notifyInferiorStopped();
void notifyInferiorUpdateFinished(); void notifyInferiorUpdateFinished();
void notifyInferiorRunningRequested(); void notifyInferiorRunningRequested();
void notifyInferiorStopRequested();
void notifyInferiorRunning(); void notifyInferiorRunning();
void notifyInferiorExited(); void notifyInferiorExited();
void notifyInferiorPidChanged(int); void notifyInferiorPidChanged(int);

View File

@@ -115,6 +115,7 @@ enum GdbCommandType
GdbInfoThreads, GdbInfoThreads,
GdbQueryDataDumper1, GdbQueryDataDumper1,
GdbQueryDataDumper2, GdbQueryDataDumper2,
GdbTemporaryContinue,
BreakCondition = 200, BreakCondition = 200,
BreakEnablePending, BreakEnablePending,
@@ -305,6 +306,7 @@ void GdbEngine::initializeVariables()
m_pendingRequests = 0; m_pendingRequests = 0;
m_waitingForBreakpointSynchronizationToContinue = false; m_waitingForBreakpointSynchronizationToContinue = false;
m_waitingForFirstBreakpointToBeHit = false; m_waitingForFirstBreakpointToBeHit = false;
m_commandsToRunOnTemporaryBreak.clear();
} }
void GdbEngine::gdbProcError(QProcess::ProcessError error) void GdbEngine::gdbProcError(QProcess::ProcessError error)
@@ -650,22 +652,29 @@ void GdbEngine::readGdbStandardOutput()
void GdbEngine::interruptInferior() void GdbEngine::interruptInferior()
{ {
if (m_gdbProc.state() == QProcess::NotRunning) qq->notifyInferiorStopRequested();
if (m_gdbProc.state() == QProcess::NotRunning) {
debugMessage("TRYING TO INTERRUPT INFERIOR WITHOUT RUNNING GDB");
qq->notifyInferiorExited();
return; return;
}
if (q->m_attachedPID > 0) { if (q->m_attachedPID > 0) {
if (interruptProcess(q->m_attachedPID)) if (!interruptProcess(q->m_attachedPID))
qq->notifyInferiorStopped(); // qq->notifyInferiorStopped();
//else
debugMessage(QString("CANNOT INTERRUPT %1").arg(q->m_attachedPID));
return; return;
} }
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
sendCommand("-exec-interrupt", GdbExecInterrupt); sendCommand("-exec-interrupt", GdbExecInterrupt);
qq->notifyInferiorStopped(); //qq->notifyInferiorStopped();
#else #else
if (!interruptChildProcess(m_gdbProc.pid()))
// qq->notifyInferiorStopped();
//else
debugMessage(QString("CANNOT STOP INFERIOR")); debugMessage(QString("CANNOT STOP INFERIOR"));
if (interruptChildProcess(m_gdbProc.pid()))
qq->notifyInferiorStopped();
#endif #endif
} }
@@ -684,27 +693,19 @@ void GdbEngine::maybeHandleInferiorPidChanged(const QString &pid0)
} }
void GdbEngine::sendSynchronizedCommand(const QString & command, void GdbEngine::sendSynchronizedCommand(const QString & command,
int type, const QVariant &cookie, bool needStop) int type, const QVariant &cookie, StopNeeded needStop)
{ {
sendCommand(command, type, cookie, needStop, true); sendCommand(command, type, cookie, needStop, Synchronized);
} }
void GdbEngine::sendCommand(const QString &command, int type, void GdbEngine::sendCommand(const QString &command, int type,
const QVariant &cookie, bool needStop, bool synchronized) const QVariant &cookie, StopNeeded needStop, Synchronization synchronized)
{ {
if (m_gdbProc.state() == QProcess::NotRunning) { if (m_gdbProc.state() == QProcess::NotRunning) {
debugMessage("NO GDB PROCESS RUNNING, CMD IGNORED: " + command); debugMessage("NO GDB PROCESS RUNNING, CMD IGNORED: " + command);
return; return;
} }
bool temporarilyStopped = false;
if (needStop && q->status() == DebuggerInferiorRunning) {
q->showStatusMessage(tr("Temporarily stopped"));
interruptInferior();
temporarilyStopped = true;
}
++currentToken();
if (synchronized) { if (synchronized) {
++m_pendingRequests; ++m_pendingRequests;
PENDING_DEBUG(" TYPE " << type << " INCREMENTS PENDING TO: " PENDING_DEBUG(" TYPE " << type << " INCREMENTS PENDING TO: "
@@ -717,26 +718,30 @@ void GdbEngine::sendCommand(const QString &command, int type,
GdbCookie cmd; GdbCookie cmd;
cmd.synchronized = synchronized; cmd.synchronized = synchronized;
cmd.command = command; cmd.command = command;
cmd.command = QString::number(currentToken()) + cmd.command;
if (cmd.command.contains("%1"))
cmd.command = cmd.command.arg(currentToken());
cmd.type = type; cmd.type = type;
cmd.cookie = cookie; cmd.cookie = cookie;
if (needStop && q->status() != DebuggerInferiorStopped
&& q->status() != DebuggerProcessStartingUp) {
// queue the commands that we cannot send at once
QTC_ASSERT(q->status() == DebuggerInferiorRunning,
qDebug() << "STATUS: " << q->status());
q->showStatusMessage(tr("Stopping temporarily."));
debugMessage("QUEUING COMMAND " + cmd.command);
m_commandsToRunOnTemporaryBreak.append(cmd);
interruptInferior();
} else if (!command.isEmpty()) {
++currentToken();
m_cookieForToken[currentToken()] = cmd; m_cookieForToken[currentToken()] = cmd;
cmd.command = QString::number(currentToken()) + cmd.command;
if (cmd.command.contains("%1"))
cmd.command = cmd.command.arg(currentToken());
if (!command.isEmpty()) {
m_gdbProc.write(cmd.command.toLatin1() + "\r\n"); m_gdbProc.write(cmd.command.toLatin1() + "\r\n");
//emit gdbInputAvailable(QString(), " " + currentTime()); //emit gdbInputAvailable(QString(), " " + currentTime());
//emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command); //emit gdbInputAvailable(QString(), "[" + currentTime() + "] " + cmd.command);
emit gdbInputAvailable(QString(), cmd.command); emit gdbInputAvailable(QString(), cmd.command);
} }
if (temporarilyStopped)
sendCommand("-exec-continue");
// slows down
//qApp->processEvents();
} }
void GdbEngine::handleResultRecord(const GdbResultRecord &record) void GdbEngine::handleResultRecord(const GdbResultRecord &record)
@@ -822,6 +827,7 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type,
//handleExecRunToFunction(record); //handleExecRunToFunction(record);
break; break;
case GdbExecInterrupt: case GdbExecInterrupt:
qq->notifyInferiorStopped();
break; break;
case GdbExecJumpToLine: case GdbExecJumpToLine:
handleExecJumpToLine(record); handleExecJumpToLine(record);
@@ -844,6 +850,10 @@ void GdbEngine::handleResult(const GdbResultRecord & record, int type,
case GdbQueryDataDumper2: case GdbQueryDataDumper2:
handleQueryDataDumper2(record); handleQueryDataDumper2(record);
break; break;
case GdbTemporaryContinue:
continueInferior();
q->showStatusMessage(tr("Continuing after temporary stop."));
break;
case BreakList: case BreakList:
handleBreakList(record); handleBreakList(record);
@@ -1104,6 +1114,7 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
//MAC: bool isFirstStop = data.findChild("bkptno").data() == "1"; //MAC: bool isFirstStop = data.findChild("bkptno").data() == "1";
//!MAC: startSymbolName == data.findChild("frame").findChild("func") //!MAC: startSymbolName == data.findChild("frame").findChild("func")
if (m_waitingForFirstBreakpointToBeHit) { if (m_waitingForFirstBreakpointToBeHit) {
qq->notifyInferiorStopped();
m_waitingForFirstBreakpointToBeHit = false; m_waitingForFirstBreakpointToBeHit = false;
// //
// that's the "early stop" // that's the "early stop"
@@ -1143,6 +1154,23 @@ void GdbEngine::handleAsyncOutput(const GdbMi &data)
return; return;
} }
if (!m_commandsToRunOnTemporaryBreak.isEmpty()) {
QTC_ASSERT(q->status() == DebuggerInferiorStopRequested,
qDebug() << "STATUS: " << q->status())
qq->notifyInferiorStopped();
q->showStatusMessage(tr("Temporarily stopped."));
// FIXME: racy
foreach (const GdbCookie &cmd, m_commandsToRunOnTemporaryBreak) {
debugMessage(QString("RUNNING QUEUED COMMAND %1 %2")
.arg(cmd.command).arg(cmd.type));
sendCommand(cmd.command, cmd.type, cmd.cookie);
}
sendCommand("p temporaryStop", GdbTemporaryContinue);
m_commandsToRunOnTemporaryBreak.clear();
q->showStatusMessage(tr("Handling queued commands."));
return;
}
QString msg = data.findChild("consolestreamoutput").data(); QString msg = data.findChild("consolestreamoutput").data();
if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) { if (msg.contains("Stopped due to shared library event") || reason.isEmpty()) {
if (qq->wantsSelectedPluginBreakpoints()) { if (qq->wantsSelectedPluginBreakpoints()) {
@@ -1619,8 +1647,8 @@ void GdbEngine::continueInferior()
{ {
q->resetLocation(); q->resetLocation();
setTokenBarrier(); setTokenBarrier();
qq->notifyInferiorRunningRequested();
emit gdbInputAvailable(QString(), QString()); emit gdbInputAvailable(QString(), QString());
qq->notifyInferiorRunningRequested();
sendCommand("-exec-continue", GdbExecContinue); sendCommand("-exec-continue", GdbExecContinue);
} }
@@ -1636,8 +1664,8 @@ void GdbEngine::handleStart(const GdbResultRecord &response)
//debugMessage("STREAM: " + msg + " " + needle.cap(1)); //debugMessage("STREAM: " + msg + " " + needle.cap(1));
sendCommand("tbreak *0x" + needle.cap(1)); sendCommand("tbreak *0x" + needle.cap(1));
m_waitingForFirstBreakpointToBeHit = true; m_waitingForFirstBreakpointToBeHit = true;
sendCommand("-exec-run");
qq->notifyInferiorRunningRequested(); qq->notifyInferiorRunningRequested();
sendCommand("-exec-run");
} else { } else {
debugMessage("PARSING START ADDRESS FAILED: " + msg); debugMessage("PARSING START ADDRESS FAILED: " + msg);
} }
@@ -1649,8 +1677,8 @@ void GdbEngine::handleStart(const GdbResultRecord &response)
void GdbEngine::stepExec() void GdbEngine::stepExec()
{ {
setTokenBarrier(); setTokenBarrier();
qq->notifyInferiorRunningRequested();
emit gdbInputAvailable(QString(), QString()); emit gdbInputAvailable(QString(), QString());
qq->notifyInferiorRunningRequested();
sendCommand("-exec-step", GdbExecStep); sendCommand("-exec-step", GdbExecStep);
} }
@@ -1671,8 +1699,8 @@ void GdbEngine::stepOutExec()
void GdbEngine::nextExec() void GdbEngine::nextExec()
{ {
setTokenBarrier(); setTokenBarrier();
qq->notifyInferiorRunningRequested();
emit gdbInputAvailable(QString(), QString()); emit gdbInputAvailable(QString(), QString());
qq->notifyInferiorRunningRequested();
sendCommand("-exec-next", GdbExecNext); sendCommand("-exec-next", GdbExecNext);
} }
@@ -1865,8 +1893,8 @@ void GdbEngine::sendInsertBreakpoint(int index)
// cmd += "-c " + data->condition + " "; // cmd += "-c " + data->condition + " ";
cmd += where; cmd += where;
#endif #endif
sendCommand(cmd, BreakInsert, index, true); debugMessage(QString("Current state: %1").arg(q->status()));
//processQueueAndContinue(); sendCommand(cmd, BreakInsert, index, NeedsStop);
} }
void GdbEngine::handleBreakList(const GdbResultRecord &record) void GdbEngine::handleBreakList(const GdbResultRecord &record)
@@ -2103,10 +2131,11 @@ void GdbEngine::attemptBreakpointSynchronization()
foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) { foreach (BreakpointData *data, handler->takeRemovedBreakpoints()) {
QString bpNumber = data->bpNumber; QString bpNumber = data->bpNumber;
debugMessage(QString("DELETING BP %1 IN %2").arg(bpNumber)
.arg(data->markerFileName));
if (!bpNumber.trimmed().isEmpty()) if (!bpNumber.trimmed().isEmpty())
sendCommand("-break-delete " + bpNumber, BreakDelete, 0, true); sendCommand("-break-delete " + bpNumber, BreakDelete, QVariant(),
//else NeedsStop);
// qDebug() << "BP HAS NO NUMBER: " << data->markerFileName;
delete data; delete data;
} }

View File

@@ -158,12 +158,15 @@ private:
// queue". resultNeeded == true increments m_pendingResults on // queue". resultNeeded == true increments m_pendingResults on
// send and decrements on receipt, effectively preventing // send and decrements on receipt, effectively preventing
// watch model updates before everything is finished. // watch model updates before everything is finished.
void sendCommand(const QString & command, enum StopNeeded { DoesNotNeedStop, NeedsStop };
enum Synchronization { NotSynchronized, Synchronized };
void sendCommand(const QString &command,
int type = 0, const QVariant &cookie = QVariant(), int type = 0, const QVariant &cookie = QVariant(),
bool needStop = false, bool synchronized = false); StopNeeded needStop = DoesNotNeedStop,
Synchronization synchronized = NotSynchronized);
void sendSynchronizedCommand(const QString & command, void sendSynchronizedCommand(const QString & command,
int type = 0, const QVariant &cookie = QVariant(), int type = 0, const QVariant &cookie = QVariant(),
bool needStop = false); StopNeeded needStop = DoesNotNeedStop);
void setTokenBarrier(); void setTokenBarrier();
@@ -335,6 +338,8 @@ private:
bool m_waitingForFirstBreakpointToBeHit; bool m_waitingForFirstBreakpointToBeHit;
bool m_modulesListOutdated; bool m_modulesListOutdated;
QList<GdbCookie> m_commandsToRunOnTemporaryBreak;
DebuggerManager *q; DebuggerManager *q;
IDebuggerManagerAccessForEngines *qq; IDebuggerManagerAccessForEngines *qq;
}; };