diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index d9a20d08a809022c2bbcedf5e5129be21aee3054..e194fbdf462e48ffe1907612ad2f93f86a0eaec9 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -406,6 +406,16 @@ BreakpointData *BreakHandler::findBreakpointByNumber(int bpNumber) const return 0; } +BreakpointData *BreakHandler::findWatchPointByAddress(const QByteArray &a) const +{ + for (int index = size() - 1; index >= 0; --index) { + BreakpointData *bd = at(index); + if (bd->type == BreakpointData::WatchpointType && bd->address == a) + return bd; + } + return 0; +} + void BreakHandler::saveBreakpoints() { QList<QVariant> list; diff --git a/src/plugins/debugger/breakhandler.h b/src/plugins/debugger/breakhandler.h index 03d3f557d6918dc067d145e4da1a9bddd554ed52..77ed135d177ea5fee26cc35e891188ba152a3049 100644 --- a/src/plugins/debugger/breakhandler.h +++ b/src/plugins/debugger/breakhandler.h @@ -70,6 +70,7 @@ public: // Find a breakpoint matching approximately the data in needle.bp*, BreakpointData *findSimilarBreakpoint(const BreakpointData &needle) const; BreakpointData *findBreakpointByNumber(int bpNumber) const; + BreakpointData *findWatchPointByAddress(const QByteArray &a) const; void updateMarkers(); QList<BreakpointData *> insertedBreakpoints() const; diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index 3be39eea5ace1fb5a874e016dfb3a780ca78bfdf..c74d4ef777fc70f68137b278aacf05fd12362cb4 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -564,6 +564,23 @@ static inline QString truncateValue(QString v) return v; } +// Get a pointer address from pointer values reported by the debugger. +// Fix CDB formatting of pointers "0x00000000`000003fd class foo *", +// check gdb formatting of characters. +static inline quint64 pointerValue(QString data) +{ + if (data.isEmpty() || !data.startsWith(QLatin1String("0x"))) + return 0; + data.remove(0, 2); + const int blankPos = data.indexOf(QLatin1Char(' ')); + if (blankPos != -1) + data.truncate(blankPos); + data.remove(QLatin1Char('`')); + bool ok; + const quint64 address = data.toULongLong(&ok, 16); + return ok ? address : quint64(0); +} + QVariant WatchModel::data(const QModelIndex &idx, int role) const { const WatchItem *item = watchItem(idx); @@ -636,16 +653,22 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const case IndividualFormatRole: return m_handler->m_individualFormats.value(data.addr, -1); - case AddressRole: { - if (!data.addr.isEmpty()) - return data.addr; - bool ok; - (void) data.value.toULongLong(&ok, 0); - if (ok) - return data.value; - return QVariant(); - } + case AddressRole: + if (!data.addr.isEmpty()) { + bool ok; + const quint64 address = data.addr.toULongLong(&ok, 16); + if (ok) + return QVariant(address); + } + return QVariant(quint64(0)); + + case RawValueRole: + return data.value; + case PointerValue: + if (isPointerType(data.type)) + return pointerValue(data.value); + return QVariant(quint64(0)); default: break; } diff --git a/src/plugins/debugger/watchhandler.h b/src/plugins/debugger/watchhandler.h index 9a4dad79a80a20be84682aba72272611de283e42..daf8507e67e20d5a12ed522a83d5be74500252f3 100644 --- a/src/plugins/debugger/watchhandler.h +++ b/src/plugins/debugger/watchhandler.h @@ -61,7 +61,9 @@ enum WatchRoles TypeFormatListRole, TypeFormatRole, // Used to communicate alternative formats to the view. IndividualFormatRole, - AddressRole, // Some memory address related to the object. + AddressRole, // Memory address of variable as quint64. + RawValueRole, // Unformatted value as string. + PointerValue // Pointer value (address) as quint64. }; enum IntegerFormat diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp index 209944278a0021ea21e96c506f49676258b76686..b3782448a2e98992c46266bcdd2a5e3b835e817d 100644 --- a/src/plugins/debugger/watchwindow.cpp +++ b/src/plugins/debugger/watchwindow.cpp @@ -204,13 +204,26 @@ void WatchWindow::dropEvent(QDropEvent *ev) //QTreeView::dropEvent(ev); } +static inline void addWatchPoint(DebuggerManager *manager, quint64 address) +{ + const QByteArray addressBA = QByteArray("0x") + QByteArray::number(address, 16); + if (manager->breakHandler()->findWatchPointByAddress(addressBA)) + return; + BreakpointData *data = new BreakpointData; + data->type = BreakpointData::WatchpointType; + data->address = addressBA; + manager->breakHandler()->appendBreakpoint(data); + manager->attemptBreakpointSynchronization(); +} + void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) { const QModelIndex idx = indexAt(ev->pos()); const QModelIndex mi0 = idx.sibling(idx.row(), 0); const QModelIndex mi1 = idx.sibling(idx.row(), 1); const QModelIndex mi2 = idx.sibling(idx.row(), 2); - const QString addr = model()->data(mi0, AddressRole).toString(); + const quint64 address = model()->data(mi0, AddressRole).toULongLong(); + const quint64 pointerValue = model()->data(mi0, PointerValue).toULongLong(); const QString exp = model()->data(mi0, ExpressionRole).toString(); const QString type = model()->data(mi2).toString(); @@ -255,9 +268,9 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) QMenu individualFormatMenu; QList<QAction *> individualFormatActions; QAction *clearIndividualFormatAction = 0; - if (idx.isValid() && !addr.isEmpty()) { + if (idx.isValid() && address) { individualFormatMenu.setTitle( - tr("Change Format for Object at %1").arg(addr)); + tr("Change Format for Object at 0x%1").arg(address, 0, 16)); if (alternativeFormats.isEmpty()) { individualFormatMenu.setEnabled(false); } else { @@ -292,27 +305,39 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) QAction *actSelectWidgetToWatch = menu.addAction(tr("Select Widget to Watch")); actSelectWidgetToWatch->setEnabled(canHandleWatches); - const QString address = model()->data(mi0, AddressRole).toString(); - QAction *actWatchKnownMemory = 0; - QAction *actWatchUnknownMemory = + QAction *actOpenMemoryEditAtVariableAddress = 0; + QAction *actOpenMemoryEditAtPointerValue = 0; + QAction *actOpenMemoryEditor = new QAction(tr("Open Memory Editor..."), &menu); const bool canShowMemory = engineCapabilities & ShowMemoryCapability; - actWatchUnknownMemory->setEnabled(actionsEnabled && canShowMemory); - - if (canShowMemory && !address.isEmpty()) - actWatchKnownMemory = - new QAction(tr("Open Memory Editor at %1").arg(address), &menu); + actOpenMemoryEditor->setEnabled(actionsEnabled && canShowMemory); + + // Offer to open address pointed to or variable address. + const bool createPointerActions = pointerValue && pointerValue != address; + + const QString openMemoryEditorFormat = tr("Open Memory Editor at 0x%1"); + if (canShowMemory && address) + actOpenMemoryEditAtVariableAddress = + new QAction(openMemoryEditorFormat.arg(address, 0, 16), &menu); + if (createPointerActions) + actOpenMemoryEditAtPointerValue = + new QAction(openMemoryEditorFormat.arg(pointerValue, 0, 16), &menu); menu.addSeparator(); - QAction *actSetWatchpoint = 0; + QAction *actSetWatchPointAtVariableAddress = 0; + QAction *actSetWatchPointAtPointerValue= 0; const bool canSetWatchpoint = engineCapabilities & WatchpointCapability; - if (canSetWatchpoint && !address.isEmpty()) { - actSetWatchpoint = - new QAction(tr("Break on Changing Contents of %1").arg(address), &menu); + if (canSetWatchpoint && address) { + const QString watchPointFormat = tr("Break on Changing Contents of 0x%1"); + actSetWatchPointAtVariableAddress = + new QAction(watchPointFormat.arg(address, 0, 16), &menu); + if (createPointerActions) + actSetWatchPointAtPointerValue = + new QAction(watchPointFormat.arg(pointerValue, 0, 16), &menu); } else { - actSetWatchpoint = + actSetWatchPointAtVariableAddress = new QAction(tr("Break on Changing Contents"), &menu); - actSetWatchpoint->setEnabled(false); + actSetWatchPointAtVariableAddress->setEnabled(false); } QAction *actWatchOrRemove; @@ -330,10 +355,14 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) menu.addAction(actSelectWidgetToWatch); menu.addMenu(&typeFormatMenu); menu.addMenu(&individualFormatMenu); - if (actWatchKnownMemory) - menu.addAction(actWatchKnownMemory); - menu.addAction(actWatchUnknownMemory); - menu.addAction(actSetWatchpoint); + if (actOpenMemoryEditAtVariableAddress) + menu.addAction(actOpenMemoryEditAtVariableAddress); + if (actOpenMemoryEditAtPointerValue) + menu.addAction(actOpenMemoryEditAtPointerValue); + menu.addAction(actOpenMemoryEditor); + menu.addAction(actSetWatchPointAtVariableAddress); + if (actSetWatchPointAtPointerValue) + menu.addAction(actSetWatchPointAtPointerValue); menu.addSeparator(); menu.addAction(theDebuggerAction(RecheckDebuggingHelpers)); @@ -361,6 +390,8 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) menu.addAction(theDebuggerAction(SettingsDialog)); QAction *act = menu.exec(ev->globalPos()); + if (act == 0) + return; if (act == actAdjustColumnWidths) { resizeColumnsToContents(); @@ -369,27 +400,29 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev) } else if (act == actInsertNewWatchItem) { theDebuggerAction(WatchExpression) ->trigger(WatchHandler::watcherEditPlaceHolder()); - } else if (actWatchKnownMemory != 0 && act == actWatchKnownMemory) { + } else if (act == actOpenMemoryEditAtVariableAddress) { (void) new MemoryViewAgent(m_manager, address); - } else if (actWatchUnknownMemory != 0 && act == actWatchUnknownMemory) { + } else if (act == actOpenMemoryEditAtPointerValue) { + (void) new MemoryViewAgent(m_manager, pointerValue); + } else if (act == actOpenMemoryEditor) { AddressDialog dialog; if (dialog.exec() == QDialog::Accepted) { (void) new MemoryViewAgent(m_manager, dialog.address()); } - } else if (act == actSetWatchpoint) { - BreakpointData *data = new BreakpointData; - data->type = BreakpointData::WatchpointType; - data->address = address.toLatin1(); - m_manager->breakHandler()->appendBreakpoint(data); - m_manager->attemptBreakpointSynchronization(); + } else if (act == actSetWatchPointAtVariableAddress) { + addWatchPoint(m_manager, address); + } else if (act == actSetWatchPointAtVariableAddress) { + addWatchPoint(m_manager, address); + } else if (act == actSetWatchPointAtPointerValue) { + addWatchPoint(m_manager, pointerValue); } else if (act == actSelectWidgetToWatch) { grabMouse(Qt::CrossCursor); m_grabbing = true; } else if (act == actClearCodeModelSnapshot) { m_manager->clearCppCodeModelSnapshot(); - } else if (clearTypeFormatAction && act == clearTypeFormatAction) { + } else if (act == clearTypeFormatAction) { model()->setData(mi1, -1, TypeFormatRole); - } else if (clearIndividualFormatAction && act == clearIndividualFormatAction) { + } else if (act == clearIndividualFormatAction) { model()->setData(mi1, -1, IndividualFormatRole); } else { for (int i = 0; i != typeFormatActions.size(); ++i) {