Improve seek backward and outside of function in Decompiler widget (#1916)

* Improve seek backward and outside of function
* Improve seekToReference
This commit is contained in:
Itay Cohen 2019-12-14 14:57:36 +02:00 committed by GitHub
parent 108fff8925
commit 7a34cf2024
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 27 deletions

View File

@ -62,3 +62,25 @@ bool CutterSeekable::isSynchronized()
{ {
return synchronized; return synchronized;
} }
void CutterSeekable::seekToReference(RVA offset)
{
if (offset == RVA_INVALID)
{
return;
}
RVA target;
QList<XrefDescription> refs = Core()->getXRefs(offset, false, false);
if (refs.length()) {
if (refs.length() > 1) {
qWarning() << "Too many references here. Weird behaviour expected.";
}
target = refs.at(0).to;
if (target != RVA_INVALID) {
seek(target);
}
}
}

View File

@ -44,6 +44,12 @@ public:
*/ */
bool isSynchronized(); bool isSynchronized();
/**
* @brief seekToReference will seek to the function or the object which is referenced in a given offset
* @param offset - an address that contains a reference to jump to
*/
void seekToReference(RVA offset);
public slots: public slots:
/** /**
* @brief seekPrev seeks to last location. * @brief seekPrev seeks to last location.

View File

@ -7,6 +7,7 @@
#include "common/TempConfig.h" #include "common/TempConfig.h"
#include "common/SelectionHighlight.h" #include "common/SelectionHighlight.h"
#include "common/Decompiler.h" #include "common/Decompiler.h"
#include "common/CutterSeekable.h"
#include <QTextEdit> #include <QTextEdit>
#include <QPlainTextEdit> #include <QPlainTextEdit>
@ -23,6 +24,9 @@ DecompilerWidget::DecompilerWidget(MainWindow *main, QAction *action) :
syntaxHighlighter = Config()->createSyntaxHighlighter(ui->textEdit->document()); syntaxHighlighter = Config()->createSyntaxHighlighter(ui->textEdit->document());
// Event filter to intercept double clicks in the textbox
ui->textEdit->viewport()->installEventFilter(this);
setupFonts(); setupFonts();
colorsUpdatedSlot(); colorsUpdatedSlot();
@ -88,6 +92,13 @@ DecompilerWidget::DecompilerWidget(MainWindow *main, QAction *action) :
connect(Core(), &CutterCore::commentsChanged, this, &DecompilerWidget::doAutoRefresh); connect(Core(), &CutterCore::commentsChanged, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::instructionChanged, this, &DecompilerWidget::doAutoRefresh); connect(Core(), &CutterCore::instructionChanged, this, &DecompilerWidget::doAutoRefresh);
connect(Core(), &CutterCore::refreshCodeViews, this, &DecompilerWidget::doAutoRefresh); connect(Core(), &CutterCore::refreshCodeViews, this, &DecompilerWidget::doAutoRefresh);
// Esc to seek backward
QAction *seekPrevAction = new QAction(this);
seekPrevAction->setShortcut(Qt::Key_Escape);
seekPrevAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
addAction(seekPrevAction);
connect(seekPrevAction, &QAction::triggered, seekable, &CutterSeekable::seekPrev);
} }
DecompilerWidget::~DecompilerWidget() = default; DecompilerWidget::~DecompilerWidget() = default;
@ -295,3 +306,24 @@ void DecompilerWidget::showDisasContextMenu(const QPoint &pt)
mCtxMenu->exec(ui->textEdit->mapToGlobal(pt)); mCtxMenu->exec(ui->textEdit->mapToGlobal(pt));
doRefresh(); doRefresh();
} }
void DecompilerWidget::seekToReference()
{
size_t pos = ui->textEdit->textCursor().position();
RVA offset = code.OffsetForPosition(pos);
seekable->seekToReference(offset);
}
bool DecompilerWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonDblClick
&& (obj == ui->textEdit || obj == ui->textEdit->viewport())) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
const QTextCursor& cursor = ui->textEdit->cursorForPosition(QPoint(mouseEvent->x(), mouseEvent->y()));
seekToReference();
return true;
}
return MemoryDockWidget::eventFilter(obj, event);
}

View File

@ -70,6 +70,13 @@ private:
void updateCursorPosition(); void updateCursorPosition();
QString getWindowTitle() const override; QString getWindowTitle() const override;
bool eventFilter(QObject *obj, QEvent *event) override;
/**
* @brief a wrapper around CutterSeekable::seekToReference to seek to an object which is
* referenced from the address under cursor
*/
void seekToReference();
}; };
#endif // DECOMPILERWIDGET_H #endif // DECOMPILERWIDGET_H

View File

@ -996,18 +996,7 @@ void DisassemblerGraphView::blockDoubleClicked(GraphView::GraphBlock &block, QMo
QPoint pos) QPoint pos)
{ {
Q_UNUSED(event); Q_UNUSED(event);
seekable->seekToReference(getAddrForMouseEvent(block, &pos));
RVA instr = getAddrForMouseEvent(block, &pos);
if (instr == RVA_INVALID) {
return;
}
QList<XrefDescription> refs = Core()->getXRefs(instr, false, false);
if (refs.length()) {
seekable->seek(refs.at(0).to);
}
if (refs.length() > 1) {
qWarning() << "Too many references here. Weird behaviour expected.";
}
} }
void DisassemblerGraphView::blockHelpEvent(GraphView::GraphBlock &block, QHelpEvent *event, void DisassemblerGraphView::blockHelpEvent(GraphView::GraphBlock &block, QHelpEvent *event,

View File

@ -617,20 +617,7 @@ void DisassemblyWidget::moveCursorRelative(bool up, bool page)
void DisassemblyWidget::jumpToOffsetUnderCursor(const QTextCursor &cursor) void DisassemblyWidget::jumpToOffsetUnderCursor(const QTextCursor &cursor)
{ {
RVA offset = readDisassemblyOffset(cursor); RVA offset = readDisassemblyOffset(cursor);
RVA jump = Core()->getOffsetJump(offset); seekable->seekToReference(offset);
if (jump == RVA_INVALID) {
bool ok;
RVA xref = Core()->cmdj("axfj@" + QString::number(
offset)).array().first().toObject().value("to").toVariant().toULongLong(&ok);
if (ok) {
jump = xref;
}
}
if (jump != RVA_INVALID) {
seekable->seek(jump);
}
} }
bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event) bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event)