debugger: add support for temporary breakpoints

Change-Id: I841c37d21932da0ef354dbbe2fd75cec2fae86d6
Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
hjk
2012-08-21 14:16:07 +02:00
parent c2b78b8fdf
commit f671a58c79
6 changed files with 63 additions and 18 deletions

View File

@@ -321,6 +321,8 @@ void BreakHandler::saveBreakpoints()
map.insert(_("threadspec"), data.threadSpec); map.insert(_("threadspec"), data.threadSpec);
if (!data.enabled) if (!data.enabled)
map.insert(_("disabled"), one); map.insert(_("disabled"), one);
if (data.oneShot)
map.insert(_("oneshot"), one);
if (data.pathUsage != BreakpointPathUsageEngineDefault) if (data.pathUsage != BreakpointPathUsageEngineDefault)
map.insert(_("usefullpath"), QString::number(data.pathUsage)); map.insert(_("usefullpath"), QString::number(data.pathUsage));
if (data.tracepoint) if (data.tracepoint)
@@ -373,6 +375,9 @@ void BreakHandler::loadBreakpoints()
v = map.value(_("disabled")); v = map.value(_("disabled"));
if (v.isValid()) if (v.isValid())
data.enabled = !v.toInt(); data.enabled = !v.toInt();
v = map.value(_("oneshot"));
if (v.isValid())
data.oneShot = v.toInt();
v = map.value(_("usefullpath")); v = map.value(_("usefullpath"));
if (v.isValid()) if (v.isValid())
data.pathUsage = static_cast<BreakpointPathUsage>(v.toInt()); data.pathUsage = static_cast<BreakpointPathUsage>(v.toInt());
@@ -768,6 +773,13 @@ bool BreakHandler::isTracepoint(BreakpointModelId id) const
return it->data.tracepoint; return it->data.tracepoint;
} }
bool BreakHandler::isOneShot(BreakpointModelId id) const
{
ConstIterator it = m_storage.find(id);
BREAK_ASSERT(it != m_storage.end(), return false);
return it->data.oneShot;
}
bool BreakHandler::needsChildren(BreakpointModelId id) const bool BreakHandler::needsChildren(BreakpointModelId id) const
{ {
ConstIterator it = m_storage.find(id); ConstIterator it = m_storage.find(id);

View File

@@ -136,6 +136,7 @@ public:
void updateLineNumberFromMarker(BreakpointModelId id, int lineNumber); void updateLineNumberFromMarker(BreakpointModelId id, int lineNumber);
void setMarkerFileAndLine(BreakpointModelId id, void setMarkerFileAndLine(BreakpointModelId id,
const QString &fileName, int lineNumber); const QString &fileName, int lineNumber);
bool isOneShot(BreakpointModelId id) const;
bool isWatchpoint(BreakpointModelId id) const; bool isWatchpoint(BreakpointModelId id) const;
bool isTracepoint(BreakpointModelId id) const; bool isTracepoint(BreakpointModelId id) const;
void setTracepoint(BreakpointModelId, bool on); void setTracepoint(BreakpointModelId, bool on);

View File

@@ -180,7 +180,7 @@ BreakpointParameters::BreakpointParameters(BreakpointType t)
: type(t), enabled(true), pathUsage(BreakpointPathUsageEngineDefault), : type(t), enabled(true), pathUsage(BreakpointPathUsageEngineDefault),
ignoreCount(0), lineNumber(0), address(0), size(0), ignoreCount(0), lineNumber(0), address(0), size(0),
bitpos(0), bitsize(0), threadSpec(-1), bitpos(0), bitsize(0), threadSpec(-1),
tracepoint(false) tracepoint(false), oneShot(false)
{} {}
BreakpointParts BreakpointParameters::differencesTo BreakpointParts BreakpointParameters::differencesTo
@@ -215,31 +215,33 @@ BreakpointParts BreakpointParameters::differencesTo
parts |= CommandPart; parts |= CommandPart;
if (message != rhs.message) if (message != rhs.message)
parts |= MessagePart; parts |= MessagePart;
if (oneShot != rhs.oneShot)
parts |= OneShotPart;
return parts; return parts;
} }
bool BreakpointParameters::isValid() const bool BreakpointParameters::isValid() const
{ {
switch (type) { switch (type) {
case Debugger::Internal::BreakpointByFileAndLine: case BreakpointByFileAndLine:
return !fileName.isEmpty() && lineNumber > 0; return !fileName.isEmpty() && lineNumber > 0;
case Debugger::Internal::BreakpointByFunction: case BreakpointByFunction:
return !functionName.isEmpty(); return !functionName.isEmpty();
case Debugger::Internal::WatchpointAtAddress: case WatchpointAtAddress:
case Debugger::Internal::BreakpointByAddress: case BreakpointByAddress:
return address != 0; return address != 0;
case Debugger::Internal::BreakpointAtThrow: case BreakpointAtThrow:
case Debugger::Internal::BreakpointAtCatch: case BreakpointAtCatch:
case Debugger::Internal::BreakpointAtMain: case BreakpointAtMain:
case Debugger::Internal::BreakpointAtFork: case BreakpointAtFork:
case Debugger::Internal::BreakpointAtExec: case BreakpointAtExec:
case Debugger::Internal::BreakpointAtSysCall: case BreakpointAtSysCall:
case Debugger::Internal::BreakpointOnQmlSignalEmit: case BreakpointOnQmlSignalEmit:
case Debugger::Internal::BreakpointAtJavaScriptThrow: case BreakpointAtJavaScriptThrow:
break; break;
case Debugger::Internal::WatchpointAtExpression: case WatchpointAtExpression:
return !expression.isEmpty(); return !expression.isEmpty();
case Debugger::Internal::UnknownType: case UnknownType:
return false; return false;
} }
return true; return true;

View File

@@ -174,7 +174,6 @@ enum BreakpointParts
ConditionPart = 0x10, ConditionPart = 0x10,
IgnoreCountPart = 0x20, IgnoreCountPart = 0x20,
ThreadSpecPart = 0x40, ThreadSpecPart = 0x40,
AllConditionParts = ConditionPart|IgnoreCountPart|ThreadSpecPart,
ModulePart = 0x80, ModulePart = 0x80,
TracePointPart = 0x100, TracePointPart = 0x100,
@@ -183,11 +182,16 @@ enum BreakpointParts
PathUsagePart = 0x800, PathUsagePart = 0x800,
CommandPart = 0x1000, CommandPart = 0x1000,
MessagePart = 0x2000, MessagePart = 0x2000,
OneShotPart = 0x4000,
AllConditionParts = ConditionPart|IgnoreCountPart|ThreadSpecPart
|OneShotPart,
AllParts = FileAndLinePart|FunctionPart AllParts = FileAndLinePart|FunctionPart
|ExpressionPart|AddressPart|ConditionPart |ExpressionPart|AddressPart|ConditionPart
|IgnoreCountPart|ThreadSpecPart|ModulePart|TracePointPart |IgnoreCountPart|ThreadSpecPart|ModulePart|TracePointPart
|EnabledPart|TypePart|PathUsagePart|CommandPart|MessagePart |EnabledPart|TypePart|PathUsagePart|CommandPart|MessagePart
|OneShotPart
}; };
inline void operator|=(BreakpointParts &p, BreakpointParts r) inline void operator|=(BreakpointParts &p, BreakpointParts r)
@@ -234,6 +238,7 @@ public:
QString command; //!< command to execute QString command; //!< command to execute
QString message; //!< message QString message; //!< message
bool tracepoint; bool tracepoint;
bool oneShot; //!< Should this breakpoint trigger only once?
}; };
class BreakpointResponse : public BreakpointParameters class BreakpointResponse : public BreakpointParameters

View File

@@ -128,6 +128,8 @@ private:
QLineEdit *m_lineEditFunction; QLineEdit *m_lineEditFunction;
QLabel *m_labelTracepoint; QLabel *m_labelTracepoint;
QCheckBox *m_checkBoxTracepoint; QCheckBox *m_checkBoxTracepoint;
QLabel *m_labelOneShot;
QCheckBox *m_checkBoxOneShot;
QLabel *m_labelUseFullPath; QLabel *m_labelUseFullPath;
QLabel *m_labelModule; QLabel *m_labelModule;
QLineEdit *m_lineEditModule; QLineEdit *m_lineEditModule;
@@ -206,6 +208,10 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent)
m_labelTracepoint = new QLabel(tr("T&racepoint only:"), groupBoxAdvanced); m_labelTracepoint = new QLabel(tr("T&racepoint only:"), groupBoxAdvanced);
m_labelTracepoint->setBuddy(m_checkBoxTracepoint); m_labelTracepoint->setBuddy(m_checkBoxTracepoint);
m_checkBoxOneShot = new QCheckBox(groupBoxAdvanced);
m_labelOneShot = new QLabel(tr("&One shot only:"), groupBoxAdvanced);
m_labelOneShot->setBuddy(m_checkBoxOneShot);
const QString pathToolTip = const QString pathToolTip =
tr("<html><head/><body><p>Determines how the path is specified " tr("<html><head/><body><p>Determines how the path is specified "
"when setting breakpoints:</p><ul>" "when setting breakpoints:</p><ul>"
@@ -288,6 +294,7 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent)
basicLayout->addRow(m_labelAddress, m_lineEditAddress); basicLayout->addRow(m_labelAddress, m_lineEditAddress);
basicLayout->addRow(m_labelExpression, m_lineEditExpression); basicLayout->addRow(m_labelExpression, m_lineEditExpression);
basicLayout->addRow(m_labelFunction, m_lineEditFunction); basicLayout->addRow(m_labelFunction, m_lineEditFunction);
basicLayout->addRow(m_labelOneShot, m_checkBoxOneShot);
QFormLayout *advancedLeftLayout = new QFormLayout(); QFormLayout *advancedLeftLayout = new QFormLayout();
advancedLeftLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); advancedLeftLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
@@ -364,6 +371,9 @@ void BreakpointDialog::setPartsEnabled(unsigned partsMask)
m_labelFunction->setEnabled(partsMask & FunctionPart); m_labelFunction->setEnabled(partsMask & FunctionPart);
m_lineEditFunction->setEnabled(partsMask & FunctionPart); m_lineEditFunction->setEnabled(partsMask & FunctionPart);
m_labelOneShot->setEnabled(partsMask & OneShotPart);
m_checkBoxOneShot->setEnabled(partsMask & OneShotPart);
m_labelAddress->setEnabled(partsMask & AddressPart); m_labelAddress->setEnabled(partsMask & AddressPart);
m_lineEditAddress->setEnabled(partsMask & AddressPart); m_lineEditAddress->setEnabled(partsMask & AddressPart);
m_labelExpression->setEnabled(partsMask & ExpressionPart); m_labelExpression->setEnabled(partsMask & ExpressionPart);
@@ -415,6 +425,8 @@ void BreakpointDialog::clearOtherParts(unsigned partsMask)
if (invertedPartsMask & ModulePart) if (invertedPartsMask & ModulePart)
m_lineEditModule->clear(); m_lineEditModule->clear();
if (partsMask & OneShotPart)
m_checkBoxOneShot->setChecked(false);
if (invertedPartsMask & TracePointPart) { if (invertedPartsMask & TracePointPart) {
m_checkBoxTracepoint->setChecked(false); m_checkBoxTracepoint->setChecked(false);
m_textEditCommands->clear(); m_textEditCommands->clear();
@@ -449,6 +461,8 @@ void BreakpointDialog::getParts(unsigned partsMask, BreakpointParameters *data)
if (partsMask & ModulePart) if (partsMask & ModulePart)
data->module = m_lineEditModule->text(); data->module = m_lineEditModule->text();
if (partsMask & OneShotPart)
data->oneShot = m_checkBoxOneShot->isChecked();
if (partsMask & TracePointPart) { if (partsMask & TracePointPart) {
data->tracepoint = m_checkBoxTracepoint->isChecked(); data->tracepoint = m_checkBoxTracepoint->isChecked();
data->command = m_textEditCommands->toPlainText().trimmed(); data->command = m_textEditCommands->toPlainText().trimmed();
@@ -498,6 +512,8 @@ void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data)
if (mask & ModulePart) if (mask & ModulePart)
m_lineEditModule->setText(data.module); m_lineEditModule->setText(data.module);
if (mask & OneShotPart)
m_checkBoxOneShot->setChecked(data.oneShot);
if (mask & TracePointPart) if (mask & TracePointPart)
m_checkBoxTracepoint->setChecked(data.tracepoint); m_checkBoxTracepoint->setChecked(data.tracepoint);
} }

View File

@@ -633,8 +633,13 @@ void GdbEngine::handleResponse(const QByteArray &buff)
QByteArray nr = result.findChild("id").data(); QByteArray nr = result.findChild("id").data();
BreakpointResponseId rid(nr); BreakpointResponseId rid(nr);
BreakpointModelId id = handler->findBreakpointByResponseId(rid); BreakpointModelId id = handler->findBreakpointByResponseId(rid);
if (id.isValid()) if (id.isValid()) {
handler->removeAlienBreakpoint(id); // This also triggers when a temporary breakpoint is hit.
// We do not really want that, as this loses all information.
// FIXME: Use a special marker for this case?
if (!handler->isOneShot(id))
handler->removeAlienBreakpoint(id);
}
} else { } else {
qDebug() << "IGNORED ASYNC OUTPUT" qDebug() << "IGNORED ASYNC OUTPUT"
<< asyncClass << result.toString(); << asyncClass << result.toString();
@@ -3140,6 +3145,10 @@ void GdbEngine::insertBreakpoint(BreakpointModelId id)
} else { } else {
cmd = "-break-insert "; cmd = "-break-insert ";
} }
if (handler->isOneShot(id))
cmd += "-t ";
//if (!data->condition.isEmpty()) //if (!data->condition.isEmpty())
// cmd += "-c " + data->condition + ' '; // cmd += "-c " + data->condition + ' ';
cmd += breakpointLocation(id); cmd += breakpointLocation(id);