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