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
This commit is contained in:
Lucas Hosseini 2023-05-11 03:16:06 +02:00 committed by GitHub
parent b63ea5b3e4
commit beec78b4e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 44 additions and 20 deletions

View File

@ -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);
}
}

View File

@ -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();
};

View File

@ -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)

View File

@ -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();

View File

@ -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);
}

View File

@ -51,7 +51,7 @@ public slots:
QList<DisassemblyLine> 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<RVA> topOffsetHistory;
QList<RVA> breakpoints;
void setupFonts();