diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 4093c8557074a03ffb744d4b908d104d3793ab8b..5bcd3ef0576f2a7e0c387eb565512399a03436d0 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -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) diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index cf1ee9e7e539e8ecbd255238ff8baba2503bd5ea..a79b6af15d25691a100ac83966da69608583808c 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -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; diff --git a/src/plugins/debugger/breakpoint.h b/src/plugins/debugger/breakpoint.h index d00b85b1829d3ee78dbb9fca26369d210b036239..d0d5e713b223b4644f2a7b3ad015520f3f075633 100644 --- a/src/plugins/debugger/breakpoint.h +++ b/src/plugins/debugger/breakpoint.h @@ -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. diff --git a/src/plugins/debugger/breakwindow.cpp b/src/plugins/debugger/breakwindow.cpp index b493f2b5e9ab1f5091f55866d03e112ff7e1abfb..c37bba5f31d4db1a7663304c9427da5b8702ab10 100644 --- a/src/plugins/debugger/breakwindow.cpp +++ b/src/plugins/debugger/breakwindow.cpp @@ -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); diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 4e635ec5fc2ce3c6e74c5e5cd0439a7baaa86177..754c990fe4464357a59d6ea79169412b4dfec661 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -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); } diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 46cf3dc21e215c64452ab37f3cc00889e6475168..3cad92a776837ca7a771cde20e9aba80853d9460 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -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()); diff --git a/src/plugins/debugger/debuggerinternalconstants.h b/src/plugins/debugger/debuggerinternalconstants.h index 73c95ff264c745a6371e387f4445ae6b0eab3b93..675e4f489488ce4a4cf15cbe82aaaff2e8951128 100644 --- a/src/plugins/debugger/debuggerinternalconstants.h +++ b/src/plugins/debugger/debuggerinternalconstants.h @@ -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 diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 8a2c359b5f587ec0877250be5dd060378fdc227b..75ecfd4c40c58e9b58923df4a2cdda089d2c4ea9 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -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; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index e7adbba140e6a22532fb0435e44f0ba2c44b2140..21fbfdb84d8788bcecab2d6715cdecc5783a4524 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -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); diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 199e313b75df9d5eff38d723f6a1837259026024..078e082a0112fcbaad36319dc6cd9e3757ece387 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -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 diff --git a/src/plugins/debugger/watchwindow.h b/src/plugins/debugger/watchwindow.h index 794d7d7f4b22e25ebb480b354da326c0ba0c78bc..3e97372547a79bca692addef8c45a3b15fac5238 100644 --- a/src/plugins/debugger/watchwindow.h +++ b/src/plugins/debugger/watchwindow.h @@ -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());