From f671a58c795a4ac963eec6d76c25995ebf78b2d6 Mon Sep 17 00:00:00 2001 From: hjk <qthjk@ovi.com> Date: Tue, 21 Aug 2012 14:16:07 +0200 Subject: [PATCH] debugger: add support for temporary breakpoints Change-Id: I841c37d21932da0ef354dbbe2fd75cec2fae86d6 Reviewed-by: hjk <qthjk@ovi.com> --- src/plugins/debugger/breakhandler.cpp | 12 ++++++++++ src/plugins/debugger/breakhandler.h | 1 + src/plugins/debugger/breakpoint.cpp | 32 ++++++++++++++------------ src/plugins/debugger/breakpoint.h | 7 +++++- src/plugins/debugger/breakwindow.cpp | 16 +++++++++++++ src/plugins/debugger/gdb/gdbengine.cpp | 13 +++++++++-- 6 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index edc666d7342..86acab94c44 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -321,6 +321,8 @@ void BreakHandler::saveBreakpoints() map.insert(_("threadspec"), data.threadSpec); if (!data.enabled) map.insert(_("disabled"), one); + if (data.oneShot) + map.insert(_("oneshot"), one); if (data.pathUsage != BreakpointPathUsageEngineDefault) map.insert(_("usefullpath"), QString::number(data.pathUsage)); if (data.tracepoint) @@ -373,6 +375,9 @@ void BreakHandler::loadBreakpoints() v = map.value(_("disabled")); if (v.isValid()) data.enabled = !v.toInt(); + v = map.value(_("oneshot")); + if (v.isValid()) + data.oneShot = v.toInt(); v = map.value(_("usefullpath")); if (v.isValid()) data.pathUsage = static_cast<BreakpointPathUsage>(v.toInt()); @@ -768,6 +773,13 @@ bool BreakHandler::isTracepoint(BreakpointModelId id) const 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 { ConstIterator it = m_storage.find(id); diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index e1ca0db6a54..08c0fad0fdf 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -136,6 +136,7 @@ public: void updateLineNumberFromMarker(BreakpointModelId id, int lineNumber); void setMarkerFileAndLine(BreakpointModelId id, const QString &fileName, int lineNumber); + bool isOneShot(BreakpointModelId id) const; bool isWatchpoint(BreakpointModelId id) const; bool isTracepoint(BreakpointModelId id) const; void setTracepoint(BreakpointModelId, bool on); diff --git a/src/plugins/debugger/breakpoint.cpp b/src/plugins/debugger/breakpoint.cpp index cc904fec759..cd0460fa661 100644 --- a/src/plugins/debugger/breakpoint.cpp +++ b/src/plugins/debugger/breakpoint.cpp @@ -180,7 +180,7 @@ BreakpointParameters::BreakpointParameters(BreakpointType t) : type(t), enabled(true), pathUsage(BreakpointPathUsageEngineDefault), ignoreCount(0), lineNumber(0), address(0), size(0), bitpos(0), bitsize(0), threadSpec(-1), - tracepoint(false) + tracepoint(false), oneShot(false) {} BreakpointParts BreakpointParameters::differencesTo @@ -215,31 +215,33 @@ BreakpointParts BreakpointParameters::differencesTo parts |= CommandPart; if (message != rhs.message) parts |= MessagePart; + if (oneShot != rhs.oneShot) + parts |= OneShotPart; return parts; } bool BreakpointParameters::isValid() const { switch (type) { - case Debugger::Internal::BreakpointByFileAndLine: + case BreakpointByFileAndLine: return !fileName.isEmpty() && lineNumber > 0; - case Debugger::Internal::BreakpointByFunction: + case BreakpointByFunction: return !functionName.isEmpty(); - case Debugger::Internal::WatchpointAtAddress: - case Debugger::Internal::BreakpointByAddress: + case WatchpointAtAddress: + case BreakpointByAddress: return address != 0; - case Debugger::Internal::BreakpointAtThrow: - case Debugger::Internal::BreakpointAtCatch: - case Debugger::Internal::BreakpointAtMain: - case Debugger::Internal::BreakpointAtFork: - case Debugger::Internal::BreakpointAtExec: - case Debugger::Internal::BreakpointAtSysCall: - case Debugger::Internal::BreakpointOnQmlSignalEmit: - case Debugger::Internal::BreakpointAtJavaScriptThrow: + case BreakpointAtThrow: + case BreakpointAtCatch: + case BreakpointAtMain: + case BreakpointAtFork: + case BreakpointAtExec: + case BreakpointAtSysCall: + case BreakpointOnQmlSignalEmit: + case BreakpointAtJavaScriptThrow: break; - case Debugger::Internal::WatchpointAtExpression: + case WatchpointAtExpression: return !expression.isEmpty(); - case Debugger::Internal::UnknownType: + case UnknownType: return false; } return true; diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h index 0e61e665f20..48d0060398a 100644 --- a/src/plugins/debugger/breakpoint.h +++ b/src/plugins/debugger/breakpoint.h @@ -174,7 +174,6 @@ enum BreakpointParts ConditionPart = 0x10, IgnoreCountPart = 0x20, ThreadSpecPart = 0x40, - AllConditionParts = ConditionPart|IgnoreCountPart|ThreadSpecPart, ModulePart = 0x80, TracePointPart = 0x100, @@ -183,11 +182,16 @@ enum BreakpointParts PathUsagePart = 0x800, CommandPart = 0x1000, MessagePart = 0x2000, + OneShotPart = 0x4000, + + AllConditionParts = ConditionPart|IgnoreCountPart|ThreadSpecPart + |OneShotPart, AllParts = FileAndLinePart|FunctionPart |ExpressionPart|AddressPart|ConditionPart |IgnoreCountPart|ThreadSpecPart|ModulePart|TracePointPart |EnabledPart|TypePart|PathUsagePart|CommandPart|MessagePart + |OneShotPart }; inline void operator|=(BreakpointParts &p, BreakpointParts r) @@ -234,6 +238,7 @@ public: QString command; //!< command to execute QString message; //!< message bool tracepoint; + bool oneShot; //!< Should this breakpoint trigger only once? }; class BreakpointResponse : public BreakpointParameters diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp index 2c555421a28..83ca9bf359b 100644 --- a/src/plugins/debugger/breakwindow.cpp +++ b/src/plugins/debugger/breakwindow.cpp @@ -128,6 +128,8 @@ private: QLineEdit *m_lineEditFunction; QLabel *m_labelTracepoint; QCheckBox *m_checkBoxTracepoint; + QLabel *m_labelOneShot; + QCheckBox *m_checkBoxOneShot; QLabel *m_labelUseFullPath; QLabel *m_labelModule; QLineEdit *m_lineEditModule; @@ -206,6 +208,10 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent) m_labelTracepoint = new QLabel(tr("T&racepoint only:"), groupBoxAdvanced); 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 = tr("<html><head/><body><p>Determines how the path is specified " "when setting breakpoints:</p><ul>" @@ -288,6 +294,7 @@ BreakpointDialog::BreakpointDialog(BreakpointModelId id, QWidget *parent) basicLayout->addRow(m_labelAddress, m_lineEditAddress); basicLayout->addRow(m_labelExpression, m_lineEditExpression); basicLayout->addRow(m_labelFunction, m_lineEditFunction); + basicLayout->addRow(m_labelOneShot, m_checkBoxOneShot); QFormLayout *advancedLeftLayout = new QFormLayout(); advancedLeftLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); @@ -364,6 +371,9 @@ void BreakpointDialog::setPartsEnabled(unsigned partsMask) m_labelFunction->setEnabled(partsMask & FunctionPart); m_lineEditFunction->setEnabled(partsMask & FunctionPart); + m_labelOneShot->setEnabled(partsMask & OneShotPart); + m_checkBoxOneShot->setEnabled(partsMask & OneShotPart); + m_labelAddress->setEnabled(partsMask & AddressPart); m_lineEditAddress->setEnabled(partsMask & AddressPart); m_labelExpression->setEnabled(partsMask & ExpressionPart); @@ -415,6 +425,8 @@ void BreakpointDialog::clearOtherParts(unsigned partsMask) if (invertedPartsMask & ModulePart) m_lineEditModule->clear(); + if (partsMask & OneShotPart) + m_checkBoxOneShot->setChecked(false); if (invertedPartsMask & TracePointPart) { m_checkBoxTracepoint->setChecked(false); m_textEditCommands->clear(); @@ -449,6 +461,8 @@ void BreakpointDialog::getParts(unsigned partsMask, BreakpointParameters *data) if (partsMask & ModulePart) data->module = m_lineEditModule->text(); + if (partsMask & OneShotPart) + data->oneShot = m_checkBoxOneShot->isChecked(); if (partsMask & TracePointPart) { data->tracepoint = m_checkBoxTracepoint->isChecked(); data->command = m_textEditCommands->toPlainText().trimmed(); @@ -498,6 +512,8 @@ void BreakpointDialog::setParts(unsigned mask, const BreakpointParameters &data) if (mask & ModulePart) m_lineEditModule->setText(data.module); + if (mask & OneShotPart) + m_checkBoxOneShot->setChecked(data.oneShot); if (mask & TracePointPart) m_checkBoxTracepoint->setChecked(data.tracepoint); } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 9925809ec02..cfea2e6e9b2 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -633,8 +633,13 @@ void GdbEngine::handleResponse(const QByteArray &buff) QByteArray nr = result.findChild("id").data(); BreakpointResponseId rid(nr); BreakpointModelId id = handler->findBreakpointByResponseId(rid); - if (id.isValid()) - handler->removeAlienBreakpoint(id); + if (id.isValid()) { + // 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 { qDebug() << "IGNORED ASYNC OUTPUT" << asyncClass << result.toString(); @@ -3140,6 +3145,10 @@ void GdbEngine::insertBreakpoint(BreakpointModelId id) } else { cmd = "-break-insert "; } + + if (handler->isOneShot(id)) + cmd += "-t "; + //if (!data->condition.isEmpty()) // cmd += "-c " + data->condition + ' '; cmd += breakpointLocation(id); -- GitLab