OSDN Git Service

debugger: work on watchpoints (or, "data breakpoints" as they are called now)
authorhjk <qtc-committer@nokia.com>
Tue, 10 May 2011 13:57:33 +0000 (15:57 +0200)
committerhjk <qtc-committer@nokia.com>
Tue, 10 May 2011 13:58:11 +0000 (15:58 +0200)
src/plugins/debugger/breakhandler.cpp
src/plugins/debugger/breakhandler.h
src/plugins/debugger/breakpoint.h
src/plugins/debugger/breakwindow.cpp
src/plugins/debugger/debuggerengine.cpp
src/plugins/debugger/debuggerengine.h
src/plugins/debugger/debuggerinternalconstants.h
src/plugins/debugger/gdb/gdbengine.cpp
src/plugins/debugger/watchhandler.cpp
src/plugins/debugger/watchwindow.cpp
src/plugins/debugger/watchwindow.h

index 4093c85..5bcd3ef 100644 (file)
@@ -287,6 +287,7 @@ BreakpointId BreakHandler::findWatchpoint(const BreakpointParameters &data) cons
         if (it->data.isWatchpoint()
                 && it->data.address == data.address
                 && it->data.size == data.size
+                && it->data.expression == data.expression
                 && it->data.bitpos == data.bitpos)
             return it.key();
     return BreakpointId();
@@ -520,7 +521,9 @@ QVariant BreakHandler::data(const QModelIndex &mi, int role) const
                         || data.type == BreakpointAtSysCall)
                     return typeToString(data.type);
                 if (data.type == WatchpointAtAddress)
-                    return tr("Watchpoint at 0x%1").arg(data.address, 0, 16);
+                    return tr("Data breakpoint at 0x%1").arg(data.address, 0, 16);
+                if (data.type == WatchpointAtExpression)
+                    return tr("Data breakpoint at %1").arg(data.expression);
                 return empty;
             }
             break;
@@ -650,7 +653,7 @@ PROPERTY(int, threadSpec, setThreadSpec)
 PROPERTY(QByteArray, condition, setCondition)
 GETTER(int, lineNumber)
 PROPERTY(quint64, address, setAddress)
-PROPERTY(QByteArray, expression, setExpression)
+PROPERTY(QString, expression, setExpression)
 PROPERTY(int, ignoreCount, setIgnoreCount)
 
 bool BreakHandler::isEnabled(BreakpointId id) const
@@ -1207,6 +1210,8 @@ QIcon BreakHandler::BreakpointItem::icon() const
         return BreakHandler::tracepointIcon();
     if (data.type == WatchpointAtAddress)
         return BreakHandler::watchpointIcon();
+    if (data.type == WatchpointAtExpression)
+        return BreakHandler::watchpointIcon();
     if (!data.enabled)
         return BreakHandler::disabledBreakpointIcon();
     if (state == BreakpointInserted)
index cf1ee9e..a79b6af 100644 (file)
@@ -115,8 +115,8 @@ public:
     void setFileName(BreakpointId, const QString &fileName);
     QString functionName(BreakpointId id) const;
     void setFunctionName(BreakpointId, const QString &functionName);
-    QByteArray expression(BreakpointId id) const;
-    void setExpression(BreakpointId, const QByteArray &expression);
+    QString expression(BreakpointId id) const;
+    void setExpression(BreakpointId, const QString &expression);
     BreakpointType type(BreakpointId id) const;
     void setType(BreakpointId id, const BreakpointType &type);
     quint64 address(BreakpointId id) const;
index d00b85b..d0d5e71 100644 (file)
@@ -144,7 +144,7 @@ public:
     int ignoreCount;         //!< Ignore count associated with breakpoint.
     int lineNumber;          //!< Line in source file.
     quint64 address;         //!< Address for address based watchpoints.
-    QByteArray expression;   //!< Address for expression based watchpoints.
+    QString expression;      //!< Expression for expression based watchpoints.
     uint size;               //!< Size of watched area for watchpoints.
     uint bitpos;             //!< Location of watched bitfield within watched area.
     uint bitsize;            //!< Size of watched bitfield within watched area.
index b493f2b..c37bba5 100644 (file)
@@ -111,15 +111,15 @@ BreakpointDialog::BreakpointDialog(unsigned engineCapabilities, QWidget *parent)
     QStringList types;
     types << tr("File name and line number")
           << tr("Function name")
-          << tr("Memory address")
+          << tr("Break on memory address")
           << tr("Break when C++ exception is thrown")
           << tr("Break when C++ exception is caught")
           << tr("Break when function \"main\" starts")
           << tr("Break when a new process is forked")
           << tr("Break when a new process is executed")
           << tr("Break when a system call is executed")
-          << tr("Break on data access (Watchpoint at address)")
-          << tr("Break on data access (Watchpoint at expression)");
+          << tr("Break on data access at fixed address)")
+          << tr("Break on data access at address given by expression)");
     QTC_ASSERT(types.size() == WatchpointAtExpression, return; )
     m_ui.comboBoxType->addItems(types);
     m_ui.pathChooserFileName->setExpectedKind(Utils::PathChooser::File);
index 4e635ec..754c990 100644 (file)
@@ -1489,32 +1489,32 @@ bool DebuggerEngine::isDying() const
 }
 
 QString DebuggerEngine::msgWatchpointByExpressionTriggered(BreakpointId id,
-    const int number, const QByteArray &expr)
+    const int number, const QString &expr)
 {
     return id
-        ? tr("Watchpoint %1 (%2) at %3 %4 triggered.")
-            .arg(id).arg(number).arg(_(expr))
-        : tr("Internal watchpoint %1 at %2 %4 triggered.")
-            .arg(number).arg(_(expr));
+        ? tr("Data breakpoint %1 (%2) at %3 triggered.")
+            .arg(id).arg(number).arg(expr)
+        : tr("Internal data breakpoint %1 at %2 triggered.")
+            .arg(number).arg(expr);
 }
 
 QString DebuggerEngine::msgWatchpointByExpressionTriggered(BreakpointId id,
-    const int number, const QByteArray &expr, const QString &threadId)
+    const int number, const QString &expr, const QString &threadId)
 {
     return id
-        ? tr("Watchpoint %1 (%2) at %3 in thread %4 triggered.")
-            .arg(id).arg(number).arg(_(expr)).arg(threadId)
-        : tr("Internal watchpoint %1 at %2 in thread %4 triggered.")
-            .arg(number).arg(_(expr)).arg(threadId);
+        ? tr("Data breakpoint %1 (%2) at %3 in thread %4 triggered.")
+            .arg(id).arg(number).arg(expr).arg(threadId)
+        : tr("Internal data breakpoint %1 at %2 in thread %4 triggered.")
+            .arg(number).arg(expr).arg(threadId);
 }
 
 QString DebuggerEngine::msgWatchpointByAddressTriggered(BreakpointId id,
     const int number, quint64 address)
 {
     return id
-        ? tr("Watchpoint %1 (%2) at 0x%3 triggered.")
+        ? tr("Data breakpoint %1 (%2) at 0x%3 triggered.")
             .arg(id).arg(number).arg(address, 0, 16)
-        : tr("Internal watchpoint %1 at 0x%2 triggered.")
+        : tr("Internal data breakpoint %1 at 0x%2 triggered.")
             .arg(number).arg(address, 0, 16);
 }
 
@@ -1522,9 +1522,9 @@ QString DebuggerEngine::msgWatchpointByAddressTriggered(BreakpointId id,
     const int number, quint64 address, const QString &threadId)
 {
     return id
-        ? tr("Watchpoint %1 (%2) at 0x%3 in thread %4 triggered.")
+        ? tr("Data breakpoint %1 (%2) at 0x%3 in thread %4 triggered.")
             .arg(id).arg(number).arg(address, 0, 16).arg(threadId)
-        : tr("Internal watchpoint %1 at 0x%2 in thread %3 triggered.")
+        : tr("Internal data breakpoint %1 at 0x%2 in thread %3 triggered.")
             .arg(id).arg(number).arg(address, 0, 16).arg(threadId);
 }
 
index 46cf3dc..3cad92a 100644 (file)
@@ -364,9 +364,9 @@ protected:
     static QString msgWatchpointByAddressTriggered(BreakpointId id,
         int number, quint64 address, const QString &threadId);
     static QString msgWatchpointByExpressionTriggered(BreakpointId id,
-        int number, const QByteArray &expr);
+        int number, const QString &expr);
     static QString msgWatchpointByExpressionTriggered(BreakpointId id,
-        int number, const QByteArray &expr, const QString &threadId);
+        int number, const QString &expr, const QString &threadId);
     static QString msgBreakpointTriggered(BreakpointId id,
         int number, const QString &threadId);
     static QString msgStopped(const QString &reason = QString());
index 73c95ff..675e4f4 100644 (file)
@@ -83,6 +83,7 @@ enum ModelRoles
     LocalsINameRole,
     LocalsEditTypeRole,     // A QVariant::type describing the item
     LocalsIntegerBaseRole,  // Number base 16, 10, 8, 2
+    LocalsNameRole,
     LocalsExpressionRole,
     LocalsRawExpressionRole,
     LocalsExpandedRole,     // The preferred expanded state to the view
index 8a2c359..75ecfd4 100644 (file)
@@ -2706,7 +2706,7 @@ void GdbEngine::insertBreakpoint(BreakpointId id)
         return;
     }
     if (type == WatchpointAtExpression) {
-        postCommand("watch " + handler->expression(id),
+        postCommand("watch " + handler->expression(id).toLocal8Bit(),
             NeedsStop | RebuildBreakpointModel,
             CB(handleWatchInsert), id);
         return;
index e7adbba..21fbfdb 100644 (file)
@@ -605,6 +605,9 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
         case LocalsEditTypeRole:
             return QVariant(editType(data));
 
+        case LocalsNameRole:
+            return QVariant(data.name);
+
         case LocalsIntegerBaseRole:
             if (isPointerType(data.type)) // Pointers using 0x-convention
                 return QVariant(16);
index 199e313..078e082 100644 (file)
@@ -467,7 +467,7 @@ WatchWindow::WatchWindow(Type type, QWidget *parent)
 
     setFrameStyle(QFrame::NoFrame);
     setAttribute(Qt::WA_MacShowFocusRect, false);
-    setWindowTitle(tr("Locals and Watchers"));
+    setWindowTitle(tr("Locals and Expressions"));
     setIndentation(indentation() * 9/10);
     setUniformRowHeights(true);
     setItemDelegate(new WatchDelegate(this));
@@ -562,24 +562,24 @@ void WatchWindow::mouseDoubleClickEvent(QMouseEvent *ev)
 static inline QString addWatchActionText(QString exp)
 {
     if (exp.isEmpty())
-        return WatchWindow::tr("Watch Expression");
+        return WatchWindow::tr("Evaluate Expression");
     if (exp.size() > 30) {
         exp.truncate(30);
         exp.append(QLatin1String("..."));
     }
-    return WatchWindow::tr("Watch Expression \"%1\"").arg(exp);
+    return WatchWindow::tr("Evaluate Expression \"%1\"").arg(exp);
 }
 
 // Text for add watch action with truncated expression
 static inline QString removeWatchActionText(QString exp)
 {
     if (exp.isEmpty())
-        return WatchWindow::tr("Remove Watch Expression");
+        return WatchWindow::tr("Remove Evaluated Expression");
     if (exp.size() > 30) {
         exp.truncate(30);
         exp.append(QLatin1String("..."));
     }
-    return WatchWindow::tr("Remove Watch Expression \"%1\"").arg(exp);
+    return WatchWindow::tr("Remove Evaluated Expression \"%1\"").arg(exp);
 }
 
 static inline void copyToClipboard(const QString &clipboardText)
@@ -604,8 +604,12 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     const uint size = sizeOf(mi0);
     const quint64 pointerValue = pointerValueOf(mi0);
     const QString exp = mi0.data(LocalsExpressionRole).toString();
+    const QString name = mi0.data(LocalsNameRole).toString();
     const QString type = mi2.data().toString();
 
+    // Offer to open address pointed to or variable address.
+    const bool createPointerActions = pointerValue && pointerValue != address;
+
     const QStringList alternativeFormats =
         mi0.data(LocalsTypeFormatListRole).toStringList();
     const int typeFormat =
@@ -686,44 +690,57 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     const unsigned engineCapabilities = engine->debuggerCapabilities();
     const bool canHandleWatches = engineCapabilities & AddWatcherCapability;
     const DebuggerState state = engine->state();
-    const bool canInsertWatches = (state==InferiorStopOk) || ((state==InferiorRunOk) && engine->acceptsWatchesWhileRunning());
-
-    QMenu menu;
-    QAction *actInsertNewWatchItem = menu.addAction(tr("Insert New Watch Item"));
-    actInsertNewWatchItem->setEnabled(canHandleWatches && canInsertWatches);
-    QAction *actSelectWidgetToWatch = menu.addAction(tr("Select Widget to Watch"));
-    actSelectWidgetToWatch->setEnabled(canHandleWatches && (engine->canWatchWidgets()));
-
-    // Offer to open address pointed to or variable address.
-    const bool createPointerActions = pointerValue && pointerValue != address;
-
-    menu.addSeparator();
+    const bool canInsertWatches = state == InferiorStopOk
+        || (state == InferiorRunOk && engine->acceptsWatchesWhileRunning());
 
+    QMenu breakpointMenu;
+    breakpointMenu.setTitle(tr("Add Data Breakpoint..."));
     QAction *actSetWatchpointAtVariableAddress = 0;
     QAction *actSetWatchpointAtPointerValue = 0;
     const bool canSetWatchpoint = engineCapabilities & WatchpointByAddressCapability;
     if (canSetWatchpoint && address) {
         actSetWatchpointAtVariableAddress =
-            new QAction(tr("Add Watchpoint at Object's Address (0x%1)")
-                .arg(address, 0, 16), &menu);
+            new QAction(tr("Add Data Breakpoint at Object's Address (0x%1)")
+                .arg(address, 0, 16), &breakpointMenu);
         actSetWatchpointAtVariableAddress->
             setChecked(mi0.data(LocalsIsWatchpointAtAddressRole).toBool());
         if (createPointerActions) {
             actSetWatchpointAtPointerValue =
-                new QAction(tr("Add Watchpoint at Referenced Address (0x%1)")
-                    .arg(pointerValue, 0, 16), &menu);
+                new QAction(tr("Add Data Breakpoint at Referenced Address (0x%1)")
+                    .arg(pointerValue, 0, 16), &breakpointMenu);
             actSetWatchpointAtPointerValue->setCheckable(true);
             actSetWatchpointAtPointerValue->
                 setChecked(mi0.data(LocalsIsWatchpointAtPointerValueRole).toBool());
         }
     } else {
         actSetWatchpointAtVariableAddress =
-            new QAction(tr("Add Watchpoint"), &menu);
+            new QAction(tr("Add Data Breakpoint"), &breakpointMenu);
         actSetWatchpointAtVariableAddress->setEnabled(false);
     }
     actSetWatchpointAtVariableAddress->setToolTip(
-        tr("Setting a watchpoint on an address will cause the program "
-           "to stop when the data at the address it modified."));
+        tr("Setting a data breakpoint on an address will cause the program "
+           "to stop when the data at the address is modified."));
+
+    QAction *actSetWatchpointAtExpression =
+            new QAction(tr("Add Data Breakpoint at Expression \"%1\"").arg(name),
+                &breakpointMenu);
+    actSetWatchpointAtExpression->setToolTip(
+        tr("Setting a data breakpoint on an expression will cause the program "
+           "to stop when the data at the address given by the expression "
+           "is modified."));
+
+    breakpointMenu.addAction(actSetWatchpointAtVariableAddress);
+    if (actSetWatchpointAtPointerValue)
+        breakpointMenu.addAction(actSetWatchpointAtPointerValue);
+    breakpointMenu.addAction(actSetWatchpointAtExpression);
+
+    QMenu menu;
+    QAction *actInsertNewWatchItem = menu.addAction(tr("Insert New Evaluated Expression"));
+    actInsertNewWatchItem->setEnabled(canHandleWatches && canInsertWatches);
+    QAction *actSelectWidgetToWatch = menu.addAction(tr("Select Widget to Watch"));
+    actSelectWidgetToWatch->setEnabled(canHandleWatches && (engine->canWatchWidgets()));
+
+    menu.addSeparator();
 
     QAction *actWatchExpression = new QAction(addWatchActionText(exp), &menu);
     actWatchExpression->setEnabled(canHandleWatches && !exp.isEmpty());
@@ -803,9 +820,7 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     menu.addAction(actSelectWidgetToWatch);
     menu.addMenu(&formatMenu);
     menu.addMenu(&memoryMenu);
-    menu.addAction(actSetWatchpointAtVariableAddress);
-    if (actSetWatchpointAtPointerValue)
-        menu.addAction(actSetWatchpointAtPointerValue);
+    menu.addMenu(&breakpointMenu);
     menu.addAction(actCopy);
     menu.addAction(actCopyValue);
     menu.addSeparator();
@@ -868,9 +883,11 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
     } else if (act == actOpenMemoryEditorStackLayout) {
         addStackLayoutMemoryView(currentEngine(), false, mi0.model(), ev->globalPos(), this);
     } else if (act == actSetWatchpointAtVariableAddress) {
-        setWatchpoint(address, size);
+        setWatchpointAtAddress(address, size);
     } else if (act == actSetWatchpointAtPointerValue) {
-        setWatchpoint(pointerValue, 1);
+        setWatchpointAtAddress(pointerValue, sizeof(void *)); // FIXME: an approximation..
+    } else if (act == actSetWatchpointAtExpression) {
+        setWatchpointAtExpression(name);
     } else if (act == actSelectWidgetToWatch) {
         grabMouse(Qt::CrossCursor);
         m_grabbing = true;
@@ -1013,7 +1030,7 @@ void WatchWindow::setModelData
     model()->setData(index, value, role);
 }
 
-void WatchWindow::setWatchpoint(quint64 address, unsigned size)
+void WatchWindow::setWatchpointAtAddress(quint64 address, unsigned size)
 {
     BreakpointParameters data(WatchpointAtAddress);
     data.address = address;
@@ -1027,6 +1044,19 @@ void WatchWindow::setWatchpoint(quint64 address, unsigned size)
     breakHandler()->appendBreakpoint(data);
 }
 
+void WatchWindow::setWatchpointAtExpression(const QString &exp)
+{
+    BreakpointParameters data(WatchpointAtExpression);
+    data.expression = exp;
+    BreakpointId id = breakHandler()->findWatchpoint(data);
+    if (id) {
+        qDebug() << "WATCHPOINT EXISTS";
+        //   removeBreakpoint(index);
+        return;
+    }
+    breakHandler()->appendBreakpoint(data);
+}
+
 } // namespace Internal
 } // namespace Debugger
 
index 794d7d7..3e97372 100644 (file)
@@ -78,7 +78,8 @@ private:
 
     void editItem(const QModelIndex &idx);
     void resetHelper(const QModelIndex &idx);
-    void setWatchpoint(quint64 address, unsigned size);
+    void setWatchpointAtAddress(quint64 address, unsigned size);
+    void setWatchpointAtExpression(const QString &exp);
 
     void setModelData(int role, const QVariant &value = QVariant(),
         const QModelIndex &index = QModelIndex());