From beec78b4e206b88f7cb8e0b1e0180a5069d6ce54 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Thu, 11 May 2023 03:16:06 +0200 Subject: [PATCH] Keep topOffset history in disassembly widget. (#3171) This commit adds support for a `topOffset` history (on top of the rizin-managed history), that keeps track of the offset of the top instruction in the disassembly widget. closes #2970 --- src/common/CutterSeekable.cpp | 12 ++++++------ src/common/CutterSeekable.h | 12 ++++++++---- src/core/Cutter.cpp | 8 ++++---- src/core/Cutter.h | 7 +++++-- src/widgets/DisassemblyWidget.cpp | 20 +++++++++++++++++--- src/widgets/DisassemblyWidget.h | 5 ++++- 6 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/common/CutterSeekable.cpp b/src/common/CutterSeekable.cpp index f8b0805a..12ef7b7b 100644 --- a/src/common/CutterSeekable.cpp +++ b/src/common/CutterSeekable.cpp @@ -13,18 +13,18 @@ CutterSeekable::~CutterSeekable() {} void CutterSeekable::setSynchronization(bool sync) { synchronized = sync; - onCoreSeekChanged(Core()->getOffset()); + onCoreSeekChanged(Core()->getOffset(), CutterCore::SeekHistoryType::New); emit syncChanged(); } -void CutterSeekable::onCoreSeekChanged(RVA addr) +void CutterSeekable::onCoreSeekChanged(RVA addr, CutterCore::SeekHistoryType type) { if (synchronized && widgetOffset != addr) { - updateSeek(addr, true); + updateSeek(addr, type, true); } } -void CutterSeekable::updateSeek(RVA addr, bool localOnly) +void CutterSeekable::updateSeek(RVA addr, CutterCore::SeekHistoryType type, bool localOnly) { previousOffset = widgetOffset; widgetOffset = addr; @@ -32,7 +32,7 @@ void CutterSeekable::updateSeek(RVA addr, bool localOnly) Core()->seek(addr); } - emit seekableSeekChanged(addr); + emit seekableSeekChanged(addr, type); } void CutterSeekable::seekPrev() @@ -40,7 +40,7 @@ void CutterSeekable::seekPrev() if (synchronized) { Core()->seekPrev(); } else { - this->seek(previousOffset); + this->seek(previousOffset, CutterCore::SeekHistoryType::Undo); } } diff --git a/src/common/CutterSeekable.h b/src/common/CutterSeekable.h index b8663cbe..85af3de7 100644 --- a/src/common/CutterSeekable.h +++ b/src/common/CutterSeekable.h @@ -19,8 +19,12 @@ public: * signal will be emitted. * In any case, CutterSeekable::seekableSeekChanged is emitted. * @param addr the location to seek at. + * @param type the type of seek wrt history (Undo, Redo, or New) */ - void seek(RVA addr) { updateSeek(addr, false); } + void seek(RVA addr, CutterCore::SeekHistoryType type = CutterCore::SeekHistoryType::New) + { + updateSeek(addr, type, false); + } /** * @brief setSynchronization sets @@ -67,7 +71,7 @@ private slots: /** * @brief onCoreSeekChanged */ - void onCoreSeekChanged(RVA addr); + void onCoreSeekChanged(RVA addr, CutterCore::SeekHistoryType type); private: /** @@ -91,9 +95,9 @@ private: * @brief internal method for changing the seek * @param localOnly whether the seek should be updated globally if synchronized */ - void updateSeek(RVA addr, bool localOnly); + void updateSeek(RVA addr, CutterCore::SeekHistoryType type, bool localOnly); signals: - void seekableSeekChanged(RVA addr); + void seekableSeekChanged(RVA addr, CutterCore::SeekHistoryType type); void syncChanged(); }; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 7a18898c..ebbd2142 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1002,19 +1002,19 @@ void CutterCore::seekPrev() { CORE_LOCK(); rz_core_seek_undo(core); - updateSeek(); + updateSeek(SeekHistoryType::Undo); } void CutterCore::seekNext() { CORE_LOCK(); rz_core_seek_redo(core); - updateSeek(); + updateSeek(SeekHistoryType::Redo); } -void CutterCore::updateSeek() +void CutterCore::updateSeek(SeekHistoryType type) { - emit seekChanged(getOffset()); + emit seekChanged(getOffset(), type); } RVA CutterCore::prevOpAddr(RVA startAddr, int count) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 5138807d..dd9e67c8 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -172,6 +172,8 @@ public: return returner; } + enum class SeekHistoryType { New, Undo, Redo }; + CutterJson cmdj(const char *str); CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } QString cmdTask(const QString &str); @@ -324,7 +326,7 @@ public: void seekSilent(QString thing) { seekSilent(math(thing)); } void seekPrev(); void seekNext(); - void updateSeek(); + void updateSeek(SeekHistoryType type = SeekHistoryType::New); /** * @brief Raise a memory widget showing current offset, prefer last active * memory widget. @@ -794,8 +796,9 @@ signals: /** * @brief seekChanged is emitted each time Rizin's seek value is modified * @param offset + * @param historyType */ - void seekChanged(RVA offset); + void seekChanged(RVA offset, SeekHistoryType type = SeekHistoryType::New); void toggleDebugView(); diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 6cafb532..4d3dbe2b 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -327,6 +327,7 @@ void DisassemblyWidget::scrollInstructions(int count) } refreshDisasm(offset); + topOffsetHistory[topOffsetHistoryPos] = offset; } bool DisassemblyWidget::updateMaxLines() @@ -660,19 +661,32 @@ QString DisassemblyWidget::getWindowTitle() const return tr("Disassembly"); } -void DisassemblyWidget::on_seekChanged(RVA offset) +void DisassemblyWidget::on_seekChanged(RVA offset, CutterCore::SeekHistoryType type) { + if (type == CutterCore::SeekHistoryType::New) { + // Erase previous history past this point. + topOffsetHistory.erase(topOffsetHistory.begin() + topOffsetHistoryPos + 1, + topOffsetHistory.end()); + topOffsetHistory.push_back(offset); + topOffsetHistoryPos = topOffsetHistory.size() - 1; + } else if (type == CutterCore::SeekHistoryType::Undo) { + --topOffsetHistoryPos; + } else if (type == CutterCore::SeekHistoryType::Redo) { + ++topOffsetHistoryPos; + } if (!seekFromCursor) { cursorLineOffset = 0; cursorCharOffset = 0; } - if (topOffset != RVA_INVALID && offset >= topOffset && offset <= bottomOffset) { + if (topOffset != RVA_INVALID && offset >= topOffset && offset <= bottomOffset + && type == CutterCore::SeekHistoryType::New) { // if the line with the seek offset is currently visible, just move the cursor there updateCursorPosition(); + topOffsetHistory[topOffsetHistoryPos] = topOffset; } else { // otherwise scroll there - refreshDisasm(offset); + refreshDisasm(topOffsetHistory[topOffsetHistoryPos]); } mCtxMenu->setOffset(offset); } diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 1ab16216..05a47579 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -51,7 +51,7 @@ public slots: QList getLines(); protected slots: - void on_seekChanged(RVA offset); + void on_seekChanged(RVA offset, CutterCore::SeekHistoryType type); void refreshIfInRange(RVA offset); void refreshDisasm(RVA offset = RVA_INVALID); @@ -87,6 +87,9 @@ private: void keyPressEvent(QKeyEvent *event) override; QString getWindowTitle() const override; + int topOffsetHistoryPos = 0; + QList topOffsetHistory; + QList breakpoints; void setupFonts();