forked from qt-creator/qt-creator
Fixes: debugger: work on process logic
Conflicts: src/plugins/debugger/gdbengine.cpp
This commit is contained in:
@@ -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);
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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.
|
||||||
|
enum StopNeeded { DoesNotNeedStop, NeedsStop };
|
||||||
|
enum Synchronization { NotSynchronized, Synchronized };
|
||||||
void sendCommand(const QString &command,
|
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;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user