forked from qt-creator/qt-creator
debugger: sanitize breakpoint setting sequences
This commit is contained in:
@@ -255,10 +255,10 @@ void GdbEngine::initializeVariables()
|
||||
|
||||
invalidateSourcesList();
|
||||
m_sourcesListUpdating = false;
|
||||
m_breakListUpdating = false;
|
||||
m_oldestAcceptableToken = -1;
|
||||
m_outputCodec = QTextCodec::codecForLocale();
|
||||
m_pendingWatchRequests = 0;
|
||||
m_pendingBreakpointRequests = 0;
|
||||
m_commandsDoneCallback = 0;
|
||||
m_commandsToRunOnTemporaryBreak.clear();
|
||||
m_cookieForToken.clear();
|
||||
@@ -719,11 +719,16 @@ void GdbEngine::postCommandHelper(const GdbCommand &cmd)
|
||||
|
||||
if (cmd.flags & RebuildWatchModel) {
|
||||
++m_pendingWatchRequests;
|
||||
PENDING_DEBUG(" MODEL:" << cmd.command << "=>" << cmd.callbackName
|
||||
PENDING_DEBUG(" WATCH MODEL:" << cmd.command << "=>" << cmd.callbackName
|
||||
<< "INCREMENTS PENDING TO" << m_pendingWatchRequests);
|
||||
} else if (cmd.flags & RebuildBreakpointModel) {
|
||||
++m_pendingBreakpointRequests;
|
||||
PENDING_DEBUG(" BRWAKPOINT MODEL:" << cmd.command << "=>" << cmd.callbackName
|
||||
<< "INCREMENTS PENDING TO" << m_pendingBreakpointRequests);
|
||||
} else {
|
||||
PENDING_DEBUG(" OTHER (IN):" << cmd.command << "=>" << cmd.callbackName
|
||||
<< "LEAVES PENDING AT" << m_pendingWatchRequests);
|
||||
<< "LEAVES PENDING WATCH AT" << m_pendingWatchRequests
|
||||
<< "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
|
||||
}
|
||||
|
||||
if ((cmd.flags & NeedsStop) || !m_commandsToRunOnTemporaryBreak.isEmpty()) {
|
||||
@@ -942,14 +947,23 @@ void GdbEngine::handleResultRecord(GdbResponse *response)
|
||||
if (cmd.flags & RebuildWatchModel) {
|
||||
--m_pendingWatchRequests;
|
||||
PENDING_DEBUG(" WATCH" << cmd.command << "=>" << cmd.callbackName
|
||||
<< "DECREMENTS PENDING TO" << m_pendingWatchRequests);
|
||||
<< "DECREMENTS PENDING WATCH TO" << m_pendingWatchRequests);
|
||||
if (m_pendingWatchRequests <= 0) {
|
||||
PENDING_DEBUG("\n\n ... AND TRIGGERS MODEL UPDATE\n");
|
||||
PENDING_DEBUG("\n\n ... AND TRIGGERS WATCH MODEL UPDATE\n");
|
||||
rebuildWatchModel();
|
||||
}
|
||||
} else if (cmd.flags & RebuildBreakpointModel) {
|
||||
--m_pendingBreakpointRequests;
|
||||
PENDING_DEBUG(" BREAKPOINT" << cmd.command << "=>" << cmd.callbackName
|
||||
<< "DECREMENTS PENDING TO" << m_pendingWatchRequests);
|
||||
if (m_pendingBreakpointRequests <= 0) {
|
||||
PENDING_DEBUG("\n\n ... AND TRIGGERS BREAKPOINT MODEL UPDATE\n");
|
||||
attemptBreakpointSynchronization();
|
||||
}
|
||||
} else {
|
||||
PENDING_DEBUG(" OTHER (OUT):" << cmd.command << "=>" << cmd.callbackName
|
||||
<< "LEAVES PENDING AT" << m_pendingWatchRequests);
|
||||
<< "LEAVES PENDING WATCH AT" << m_pendingWatchRequests
|
||||
<< "LEAVES PENDING BREAKPOINT AT" << m_pendingBreakpointRequests);
|
||||
}
|
||||
|
||||
// Commands were queued, but we were in RunningRequested state, so the interrupt
|
||||
@@ -1103,7 +1117,6 @@ void GdbEngine::handleAqcuiredInferior()
|
||||
|
||||
// It's nicer to see a bit of the world we live in.
|
||||
reloadModulesInternal();
|
||||
attemptBreakpointSynchronization();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1312,20 +1325,22 @@ void GdbEngine::handleStop1(const GdbMi &data)
|
||||
return;
|
||||
}
|
||||
|
||||
// This is for display only.
|
||||
if (m_modulesListOutdated)
|
||||
reloadModulesInternal(); // This is for display only
|
||||
if (m_sourcesListOutdated && theDebuggerBoolSetting(UsePreciseBreakpoints))
|
||||
reloadSourceFilesInternal(); // This needs to be done before fullName() may need it
|
||||
reloadModulesInternal();
|
||||
|
||||
if (!hasPython()) {
|
||||
if (m_breakListOutdated)
|
||||
// This needs to be done before fullName() may need it.
|
||||
if (m_sourcesListOutdated && theDebuggerBoolSetting(UsePreciseBreakpoints))
|
||||
reloadSourceFilesInternal();
|
||||
|
||||
if (m_breakListOutdated) {
|
||||
reloadBreakListInternal();
|
||||
} else {
|
||||
// Older gdb versions do not produce "library loaded" messages
|
||||
// so the breakpoint update is not triggered.
|
||||
if (m_gdbVersion < 70000 && !m_isMacGdb
|
||||
&& manager()->breakHandler()->size() > 0)
|
||||
reloadBreakListInternal();
|
||||
else
|
||||
// Older gdb versions do not produce "library loaded" messages
|
||||
// so the breakpoint update is not triggered.
|
||||
if (m_gdbVersion < 70000 && !m_isMacGdb && !m_breakListUpdating
|
||||
&& manager()->breakHandler()->size() > 0)
|
||||
reloadBreakListInternal();
|
||||
}
|
||||
|
||||
if (reason == "breakpoint-hit") {
|
||||
@@ -2035,8 +2050,7 @@ void GdbEngine::breakpointDataFromOutput(BreakpointData *data, const GdbMi &bkpt
|
||||
|
||||
QString GdbEngine::breakLocation(const QString &file) const
|
||||
{
|
||||
QTC_ASSERT(!m_breakListOutdated, /* */)
|
||||
QTC_ASSERT(!m_breakListUpdating, /* */)
|
||||
//QTC_ASSERT(!m_breakListOutdated, /* */)
|
||||
QString where = m_fullToShortName.value(file);
|
||||
if (where.isEmpty())
|
||||
return QFileInfo(file).fileName();
|
||||
@@ -2057,28 +2071,30 @@ void GdbEngine::sendInsertBreakpoint(int index)
|
||||
where = data->funcName.toLatin1();
|
||||
}
|
||||
|
||||
// set up fallback in case of pending breakpoints which aren't handled
|
||||
// by the MI interface
|
||||
// Set up fallback in case of pending breakpoints which aren't handled
|
||||
// by the MI interface.
|
||||
QByteArray cmd;
|
||||
if (m_isMacGdb)
|
||||
cmd = "-break-insert -l -1 -f ";
|
||||
else if (m_gdbAdapter->isTrkAdapter())
|
||||
cmd = "-break-insert -h -f ";
|
||||
else if (m_gdbVersion >= 60800) // Probably some earlier version would work as well ...
|
||||
else if (m_gdbVersion >= 60800)
|
||||
// Probably some earlier version would work as well.
|
||||
cmd = "-break-insert -f ";
|
||||
else
|
||||
cmd = "-break-insert ";
|
||||
//if (!data->condition.isEmpty())
|
||||
// cmd += "-c " + data->condition + ' ';
|
||||
cmd += where;
|
||||
postCommand(cmd, NeedsStop, CB(handleBreakInsert), index);
|
||||
postCommand(cmd, NeedsStop | RebuildBreakpointModel,
|
||||
CB(handleBreakInsert), index);
|
||||
}
|
||||
|
||||
void GdbEngine::reloadBreakListInternal()
|
||||
{
|
||||
m_breakListUpdating = true;
|
||||
// "Discardable" as long as we do in each step
|
||||
postCommand("-break-list", NeedsStop | Discardable, CB(handleBreakList));
|
||||
postCommand("-break-list",
|
||||
NeedsStop | RebuildBreakpointModel,
|
||||
CB(handleBreakList));
|
||||
}
|
||||
|
||||
void GdbEngine::handleBreakList(const GdbResponse &response)
|
||||
@@ -2129,9 +2145,7 @@ void GdbEngine::handleBreakList(const GdbMi &table)
|
||||
//qDebug() << "CANNOT HANDLE RESPONSE" << bkpts.at(index).toString();
|
||||
}
|
||||
|
||||
m_breakListUpdating = false;
|
||||
m_breakListOutdated = false;
|
||||
attemptBreakpointSynchronization();
|
||||
}
|
||||
|
||||
void GdbEngine::handleBreakIgnore(const GdbResponse &response)
|
||||
@@ -2196,7 +2210,6 @@ void GdbEngine::handleBreakInsert(const GdbResponse &response)
|
||||
GdbMi bkpt = response.data.findChild("bkpt");
|
||||
breakpointDataFromOutput(data, bkpt);
|
||||
//#endif
|
||||
attemptBreakpointSynchronization();
|
||||
} else {
|
||||
if (m_gdbVersion < 60800 && !m_isMacGdb) {
|
||||
// This gdb version doesn't "do" pending breakpoints.
|
||||
@@ -2267,7 +2280,6 @@ void GdbEngine::handleBreakInfo(const GdbResponse &response)
|
||||
QString str = QString::fromLocal8Bit(
|
||||
response.data.findChild("consolestreamoutput").data());
|
||||
extractDataFromInfoBreak(str, handler->at(found));
|
||||
attemptBreakpointSynchronization(); // trigger "ready"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2286,15 +2298,13 @@ void GdbEngine::handleBreakInsert1(const GdbResponse &response)
|
||||
BreakpointData *data = handler->at(index);
|
||||
data->bpNumber = "<unavailable>";
|
||||
}
|
||||
attemptBreakpointSynchronization(); // trigger "ready"
|
||||
}
|
||||
|
||||
void GdbEngine::attemptBreakpointSynchronization()
|
||||
{
|
||||
//QTC_ASSERT(!m_breakListUpdating,
|
||||
// qDebug() << "BREAK LIST CURRENTLY UPDATING"; return);
|
||||
QTC_ASSERT(!m_sourcesListUpdating,
|
||||
qDebug() << "SOURCES LIST CURRENTLY UPDATING"; return);
|
||||
debugMessage(tr("ATTEMPT BREAKPOINT SYNC"));
|
||||
|
||||
switch (state()) {
|
||||
case InferiorStarting:
|
||||
@@ -2332,6 +2342,7 @@ void GdbEngine::attemptBreakpointSynchronization()
|
||||
reloadBreakListInternal();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_breakListOutdated) {
|
||||
reloadBreakListInternal();
|
||||
return;
|
||||
@@ -2342,7 +2353,8 @@ void GdbEngine::attemptBreakpointSynchronization()
|
||||
foreach (BreakpointData *data, handler->takeDisabledBreakpoints()) {
|
||||
QByteArray bpNumber = data->bpNumber;
|
||||
if (!bpNumber.trimmed().isEmpty()) {
|
||||
postCommand("-break-disable " + bpNumber, NeedsStop);
|
||||
postCommand("-break-disable " + bpNumber,
|
||||
NeedsStop | RebuildBreakpointModel);
|
||||
data->bpEnabled = false;
|
||||
}
|
||||
}
|
||||
@@ -2350,7 +2362,8 @@ void GdbEngine::attemptBreakpointSynchronization()
|
||||
foreach (BreakpointData *data, handler->takeEnabledBreakpoints()) {
|
||||
QByteArray bpNumber = data->bpNumber;
|
||||
if (!bpNumber.trimmed().isEmpty()) {
|
||||
postCommand("-break-enable " + bpNumber, NeedsStop);
|
||||
postCommand("-break-enable " + bpNumber,
|
||||
NeedsStop | RebuildBreakpointModel);
|
||||
data->bpEnabled = true;
|
||||
}
|
||||
}
|
||||
@@ -2360,7 +2373,8 @@ void GdbEngine::attemptBreakpointSynchronization()
|
||||
debugMessage(_("DELETING BP " + bpNumber + " IN "
|
||||
+ data->markerFileName.toLocal8Bit()));
|
||||
if (!bpNumber.trimmed().isEmpty())
|
||||
postCommand("-break-delete " + bpNumber, NeedsStop);
|
||||
postCommand("-break-delete " + bpNumber,
|
||||
NeedsStop | RebuildBreakpointModel);
|
||||
delete data;
|
||||
}
|
||||
|
||||
@@ -2372,19 +2386,23 @@ void GdbEngine::attemptBreakpointSynchronization()
|
||||
} else if (data->bpNumber.toInt()) {
|
||||
if (data->bpMultiple && data->bpFileName.isEmpty()) {
|
||||
postCommand("info break " + data->bpNumber,
|
||||
RebuildBreakpointModel,
|
||||
CB(handleBreakInfo), data->bpNumber.toInt());
|
||||
continue;
|
||||
}
|
||||
// update conditions if needed
|
||||
if (data->condition != data->bpCondition && !data->conditionsMatch())
|
||||
postCommand("condition " + data->bpNumber + ' ' + data->condition,
|
||||
CB(handleBreakCondition), index);
|
||||
RebuildBreakpointModel,
|
||||
CB(handleBreakCondition), index);
|
||||
// update ignorecount if needed
|
||||
if (data->ignoreCount != data->bpIgnoreCount)
|
||||
postCommand("ignore " + data->bpNumber + ' ' + data->ignoreCount,
|
||||
CB(handleBreakIgnore), index);
|
||||
RebuildBreakpointModel,
|
||||
CB(handleBreakIgnore), index);
|
||||
if (!data->enabled && data->bpEnabled) {
|
||||
postCommand("-break-disable " + data->bpNumber, NeedsStop);
|
||||
postCommand("-break-disable " + data->bpNumber,
|
||||
NeedsStop | RebuildBreakpointModel);
|
||||
data->bpEnabled = false;
|
||||
}
|
||||
}
|
||||
@@ -3418,6 +3436,7 @@ void GdbEngine::handleChildren(const WatchData &data0, const GdbMi &item,
|
||||
void GdbEngine::updateLocals(const QVariant &cookie)
|
||||
{
|
||||
m_pendingWatchRequests = 0;
|
||||
m_pendingBreakpointRequests = 0;
|
||||
if (hasPython())
|
||||
updateLocalsPython(QByteArray());
|
||||
else
|
||||
@@ -4121,6 +4140,7 @@ void GdbEngine::handleInferiorPrepared()
|
||||
|
||||
// Initial attempt to set breakpoints
|
||||
showStatusMessage(tr("Setting breakpoints..."));
|
||||
debugMessage(tr("Setting breakpoints..."));
|
||||
attemptBreakpointSynchronization();
|
||||
|
||||
if (m_cookieForToken.isEmpty()) {
|
||||
|
||||
@@ -102,7 +102,8 @@ private: ////////// General Interface //////////
|
||||
|
||||
virtual void addOptionPages(QList<Core::IOptionsPage*> *opts) const;
|
||||
|
||||
virtual bool checkConfiguration(int toolChain, QString *errorMessage, QString *settingsPage= 0) const;
|
||||
virtual bool checkConfiguration(int toolChain, QString *errorMessage,
|
||||
QString *settingsPage = 0) const;
|
||||
virtual void startDebugger(const DebuggerStartParametersPtr &sp);
|
||||
virtual unsigned debuggerCapabilities() const;
|
||||
virtual void exitDebugger();
|
||||
@@ -149,7 +150,8 @@ private slots:
|
||||
void readDebugeeOutput(const QByteArray &data);
|
||||
|
||||
void handleAdapterStarted();
|
||||
void handleAdapterStartFailed(const QString &msg, const QString &settingsIdHint = QString());
|
||||
void handleAdapterStartFailed(const QString &msg,
|
||||
const QString &settingsIdHint = QString());
|
||||
|
||||
void handleInferiorPrepared();
|
||||
|
||||
@@ -169,17 +171,26 @@ private:
|
||||
|
||||
private: ////////// Gdb Command Management //////////
|
||||
|
||||
public: // otherwise the Qt flag macros are unhappy
|
||||
public: // Otherwise the Qt flag macros are unhappy.
|
||||
enum GdbCommandFlag {
|
||||
NoFlags = 0,
|
||||
NeedsStop = 1, // The command needs a stopped inferior
|
||||
Discardable = 2, // No need to wait for the reply before continuing inferior
|
||||
RebuildWatchModel = 4, // Trigger model rebuild when no such commands are pending any more
|
||||
// The command needs a stopped inferior.
|
||||
NeedsStop = 1,
|
||||
// No need to wait for the reply before continuing inferior.
|
||||
Discardable = 2,
|
||||
// Trigger watch model rebuild when no such commands are pending anymore.
|
||||
RebuildWatchModel = 4,
|
||||
WatchUpdate = Discardable | RebuildWatchModel,
|
||||
NonCriticalResponse = 8, // We can live without recieving an answer
|
||||
RunRequest = 16, // Callback expects GdbResultRunning instead of GdbResultDone
|
||||
ExitRequest = 32, // Callback expects GdbResultExit instead of GdbResultDone
|
||||
LosesChild = 64 // Auto-set inferior shutdown related states
|
||||
// We can live without recieving an answer.
|
||||
NonCriticalResponse = 8,
|
||||
// Callback expects GdbResultRunning instead of GdbResultDone.
|
||||
RunRequest = 16,
|
||||
// Callback expects GdbResultExit instead of GdbResultDone.
|
||||
ExitRequest = 32,
|
||||
// Auto-set inferior shutdown related states.
|
||||
LosesChild = 64,
|
||||
// Trigger breakpoint model rebuild when no such commands are pending anymore.
|
||||
RebuildBreakpointModel = 128,
|
||||
};
|
||||
Q_DECLARE_FLAGS(GdbCommandFlags, GdbCommandFlag)
|
||||
private:
|
||||
@@ -204,7 +215,7 @@ private: ////////// Gdb Command Management //////////
|
||||
QTime postTime;
|
||||
};
|
||||
|
||||
// type and cookie are sender-internal data, opaque for the "event
|
||||
// Type and cookie are sender-internal data, opaque for the "event
|
||||
// queue". resultNeeded == true increments m_pendingResults on
|
||||
// send and decrements on receipt, effectively preventing
|
||||
// watch model updates before everything is finished.
|
||||
@@ -239,15 +250,16 @@ private: ////////// Gdb Command Management //////////
|
||||
QByteArray m_pendingConsoleStreamOutput;
|
||||
QByteArray m_pendingLogStreamOutput;
|
||||
|
||||
// contains the first token number for the current round
|
||||
// This contains the first token number for the current round
|
||||
// of evaluation. Responses with older tokens are considers
|
||||
// out of date and discarded.
|
||||
int m_oldestAcceptableToken;
|
||||
|
||||
int m_pendingWatchRequests; // Watch updating commands in flight
|
||||
int m_pendingBreakpointRequests; // Watch updating commands in flight
|
||||
|
||||
typedef void (GdbEngine::*CommandsDoneCallback)();
|
||||
// function called after all previous responses have been received
|
||||
// This function is called after all previous responses have been received.
|
||||
CommandsDoneCallback m_commandsDoneCallback;
|
||||
|
||||
QList<GdbCommand> m_commandsToRunOnTemporaryBreak;
|
||||
@@ -402,7 +414,6 @@ private: ////////// View & Data Stuff //////////
|
||||
bool m_sourcesListOutdated;
|
||||
bool m_sourcesListUpdating;
|
||||
bool m_breakListOutdated;
|
||||
bool m_breakListUpdating;
|
||||
|
||||
//
|
||||
// Stack specific stuff
|
||||
@@ -459,7 +470,6 @@ private: ////////// View & Data Stuff //////////
|
||||
void handleVarCreate(const GdbResponse &response);
|
||||
void handleVarAssign(const GdbResponse &response);
|
||||
void handleEvaluateExpressionClassic(const GdbResponse &response);
|
||||
//void handleToolTip(const GdbResponse &response);
|
||||
void handleQueryDebuggingHelperClassic(const GdbResponse &response);
|
||||
void handleDebuggingHelperValue2Classic(const GdbResponse &response);
|
||||
void handleDebuggingHelperValue3Classic(const GdbResponse &response);
|
||||
|
||||
@@ -142,6 +142,7 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
|
||||
//for (int i = 0; i != list.size(); ++i)
|
||||
// qDebug() << "LOCAL: " << list.at(i).toString();
|
||||
|
||||
#if 0
|
||||
data = all.findChild("bkpts");
|
||||
if (data.isValid()) {
|
||||
BreakHandler *handler = manager()->breakHandler();
|
||||
@@ -175,6 +176,7 @@ void GdbEngine::handleStackFramePython(const GdbResponse &response)
|
||||
}
|
||||
handler->updateMarkers();
|
||||
}
|
||||
#endif
|
||||
|
||||
//PENDING_DEBUG("AFTER handleStackFrame()");
|
||||
// FIXME: This should only be used when updateLocals() was
|
||||
|
||||
Reference in New Issue
Block a user