mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-18 02:36:56 +00:00
DisassemblyWidget (#80)
* Fix scrolling down in DisassemblyWidget * DisassemblyWidget backwards scrolling * DisassemblyWidget with custom scrolling * Temporarily fix HexdumpWidget resizing like crazy * Decouple DisassemblyWidget scrolling from seek * DisassemblyWidget resizing * DisassemblyWidget cursor from seek position * Seek by DisassemblyWidget click * Better up scrolling in DisassemblyWidget * DisassemblyWidget: do not always seek, better bottomOffset * DisassemblyWidget: avoid flicker, retain selection over lines, fix last line selection * Update DisassemblyWidget on comment change * Cleanup DisassemblyWidget scrolling code
This commit is contained in:
parent
638956b41b
commit
9dc51b9801
@ -491,7 +491,7 @@ void MainWindow::updateFrames()
|
||||
static bool first_time = true;
|
||||
|
||||
//TODO Send signal rather than that
|
||||
disassemblyDock->refreshDisasm();
|
||||
disassemblyDock->refreshDisasm(core->getOffset());
|
||||
|
||||
if (first_time)
|
||||
{
|
||||
|
@ -346,8 +346,8 @@ void CutterCore::setComment(RVA addr, QString cmt)
|
||||
|
||||
void CutterCore::delComment(ut64 addr)
|
||||
{
|
||||
CORE_LOCK();
|
||||
r_meta_del(core_->anal, 'C', addr, 1, NULL);
|
||||
cmd("CC- @ " + QString::number(addr));
|
||||
emit commentsChanged();
|
||||
}
|
||||
|
||||
QMap<QString, QList<QList<QString>>> CutterCore::getNestedComments()
|
||||
@ -377,7 +377,7 @@ void CutterCore::seek(QString addr)
|
||||
// here, or refactor radare2 API.
|
||||
CORE_LOCK();
|
||||
cmd(QString("s %1").arg(addr));
|
||||
emit seekChanged(core_->offset);
|
||||
// cmd already does emit seekChanged(core_->offset);
|
||||
}
|
||||
|
||||
void CutterCore::seek(ut64 offset)
|
||||
@ -395,6 +395,43 @@ void CutterCore::seekNext()
|
||||
cmd("s+");
|
||||
}
|
||||
|
||||
RVA CutterCore::prevOpAddr(RVA startAddr, int count)
|
||||
{
|
||||
CORE_LOCK();
|
||||
RVA prev;
|
||||
if (!r_core_prevop_addr(core_, startAddr, count, &prev))
|
||||
{
|
||||
prev = startAddr - count;
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
RVA CutterCore::nextOpAddr(RVA startAddr, int count)
|
||||
{
|
||||
CORE_LOCK();
|
||||
|
||||
QJsonArray array = Core()->cmdj("pdj " + QString::number(count) + "@" + QString::number(startAddr)).array();
|
||||
if (array.isEmpty())
|
||||
{
|
||||
return startAddr + 1;
|
||||
}
|
||||
|
||||
QJsonValue instValue = array.last();
|
||||
if (!instValue.isObject())
|
||||
{
|
||||
return startAddr + 1;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
RVA offset = instValue.toObject()["offset"].toVariant().toULongLong(&ok);
|
||||
if (!ok)
|
||||
{
|
||||
return startAddr + 1;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
RVA CutterCore::getOffset()
|
||||
{
|
||||
return core_->offset;
|
||||
|
@ -215,8 +215,11 @@ public:
|
||||
void seekNext();
|
||||
RVA getOffset();
|
||||
|
||||
RVA prevOpAddr(RVA startAddr, int count);
|
||||
RVA nextOpAddr(RVA startAddr, int count);
|
||||
|
||||
// Graph - Disassembly view priority
|
||||
bool graphPriority = true;
|
||||
bool graphPriority = false;
|
||||
bool graphDisplay = false;
|
||||
|
||||
ut64 math(const QString &expr);
|
||||
|
@ -4,27 +4,42 @@
|
||||
#include "utils/HexAsciiHighlighter.h"
|
||||
#include "utils/HexHighlighter.h"
|
||||
#include "utils/Configuration.h"
|
||||
|
||||
#include <QScrollBar>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
|
||||
DisassemblyWidget::DisassemblyWidget(QWidget *parent) :
|
||||
QDockWidget(parent),
|
||||
mDisasTextEdit(new QTextEdit(this))
|
||||
mDisasScrollArea(new DisassemblyScrollArea(this)),
|
||||
mDisasTextEdit(new DisassemblyTextEdit(this))
|
||||
{
|
||||
// Configure Dock
|
||||
setWidget(mDisasTextEdit);
|
||||
topOffset = bottomOffset = RVA_INVALID;
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout();
|
||||
layout->addWidget(mDisasTextEdit);
|
||||
layout->setMargin(0);
|
||||
mDisasScrollArea->viewport()->setLayout(layout);
|
||||
mDisasScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
setWidget(mDisasScrollArea);
|
||||
|
||||
setAllowedAreas(Qt::AllDockWidgetAreas);
|
||||
setObjectName("DisassemblyWidget");
|
||||
|
||||
mDisasTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
mDisasTextEdit->setFont(Config()->getFont());
|
||||
mDisasTextEdit->setReadOnly(true);
|
||||
mDisasTextEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth);
|
||||
// wrapping breaks readCurrentDisassemblyOffset() at the moment :-(
|
||||
mDisasTextEdit->setWordWrapMode(QTextOption::NoWrap);
|
||||
|
||||
// Increase asm text edit margin
|
||||
QTextDocument *asm_docu = mDisasTextEdit->document();
|
||||
asm_docu->setDocumentMargin(10);
|
||||
|
||||
// Setup disasm highlight
|
||||
connect(mDisasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
|
||||
highlightCurrentLine();
|
||||
|
||||
// Event filter to intercept double clicks in the textbox
|
||||
mDisasTextEdit->viewport()->installEventFilter(this);
|
||||
@ -39,10 +54,25 @@ DisassemblyWidget::DisassemblyWidget(QWidget *parent) :
|
||||
shortcut_x->setContext(Qt::WidgetShortcut);
|
||||
connect(shortcut_x, SIGNAL(activated()), this, SLOT(showXrefsDialog()));
|
||||
|
||||
// Scrollbar
|
||||
connect(mDisasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
|
||||
|
||||
maxLines = 0;
|
||||
updateMaxLines();
|
||||
|
||||
|
||||
connect(mDisasScrollArea, SIGNAL(scrollLines(int)), this, SLOT(scrollInstructions(int)));
|
||||
connect(mDisasScrollArea, SIGNAL(disassemblyResized()), this, SLOT(updateMaxLines()));
|
||||
|
||||
connectCursorPositionChanged(false);
|
||||
connect(mDisasTextEdit->verticalScrollBar(), &QScrollBar::valueChanged, this, [=](int value) {
|
||||
if (value != 0)
|
||||
{
|
||||
mDisasTextEdit->verticalScrollBar()->setValue(0);
|
||||
}
|
||||
});
|
||||
|
||||
// Seek signal
|
||||
connect(CutterCore::getInstance(), SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA)));
|
||||
connect(CutterCore::getInstance(), SIGNAL(commentsChanged()), this, SLOT(refreshDisasm()));
|
||||
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdatedSlot()));
|
||||
}
|
||||
|
||||
@ -57,122 +87,105 @@ QWidget* DisassemblyWidget::getTextWidget()
|
||||
return mDisasTextEdit;
|
||||
}
|
||||
|
||||
QString DisassemblyWidget::readDisasm(RVA offset)
|
||||
QString DisassemblyWidget::readDisasm(const QString &cmd, bool stripLastNewline)
|
||||
{
|
||||
QString cmd = "pd 100";
|
||||
Core()->setConfig("scr.html", true);
|
||||
Core()->setConfig("scr.color", true);
|
||||
if (offset != RVA_INVALID) {
|
||||
cmd += " @ " + QString::number(offset);
|
||||
}
|
||||
QString disas = Core()->cmd(cmd);
|
||||
Core()->setConfig("scr.html", false);
|
||||
Core()->setConfig("scr.color", false);
|
||||
|
||||
if (stripLastNewline)
|
||||
{
|
||||
// ugly hack to remove trailing newline
|
||||
static const auto trimBrRegExp = QRegularExpression("<br />$");
|
||||
disas = disas.remove(trimBrRegExp);
|
||||
}
|
||||
|
||||
return disas.trimmed();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::refreshDisasm()
|
||||
|
||||
void DisassemblyWidget::refreshDisasm(RVA offset)
|
||||
{
|
||||
// Prevent further scroll
|
||||
disconnect(mDisasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
|
||||
disconnect(mDisasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChanged()));
|
||||
|
||||
QString disas = readDisasm();
|
||||
mDisasTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
mDisasTextEdit->setHtml(disas);
|
||||
|
||||
auto cursor = mDisasTextEdit->textCursor();
|
||||
cursor.setPosition(0);
|
||||
mDisasTextEdit->setTextCursor(cursor);
|
||||
mDisasTextEdit->verticalScrollBar()->setValue(0);
|
||||
|
||||
// load more disassembly if necessary
|
||||
/*static const int load_more_limit = 10; // limit passes, so it can't take forever
|
||||
for (int load_more_i = 0; load_more_i < load_more_limit; load_more_i++)
|
||||
if (offset != RVA_INVALID)
|
||||
{
|
||||
if (!loadMoreDisassembly())
|
||||
break;
|
||||
mDisasTextEdit->verticalScrollBar()->setValue(0);
|
||||
}*/
|
||||
|
||||
connect(mDisasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
|
||||
connect(mDisasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChanged()));
|
||||
//this->on_mDisasTextEdit_cursorPositionChanged();
|
||||
|
||||
//this->highlightDisasms();
|
||||
}
|
||||
|
||||
|
||||
bool DisassemblyWidget::loadMoreDisassembly()
|
||||
{
|
||||
/*
|
||||
* Add more disasm as the user scrolls
|
||||
* Not working properly when scrolling upwards
|
||||
* r2 doesn't handle properly 'pd-' for archs with variable instruction size
|
||||
*/
|
||||
|
||||
// Disconnect scroll signals to add more content
|
||||
disconnect(mDisasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
|
||||
|
||||
QScrollBar *sb = mDisasTextEdit->verticalScrollBar();
|
||||
bool loaded = false;
|
||||
|
||||
if (sb->value() > sb->maximum() - 10)
|
||||
{
|
||||
QTextCursor tc = mDisasTextEdit->textCursor();
|
||||
tc.movePosition(QTextCursor::End);
|
||||
tc.movePosition(QTextCursor::StartOfLine);
|
||||
tc.setPosition(tc.position() - 1);
|
||||
mDisasTextEdit->setTextCursor(tc);
|
||||
RVA offset = readCurrentDisassemblyOffset();
|
||||
|
||||
if (offset != RVA_INVALID)
|
||||
{
|
||||
mDisasTextEdit->append(readDisasm(offset));
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
topOffset = offset;
|
||||
}
|
||||
// Code below will be used to append more disasm upwards, one day
|
||||
/* else if (sb->value() < sb->minimum() + 10) {
|
||||
//this->main->add_debug_output("Begining is coming");
|
||||
|
||||
QTextCursor tc = this->disasTextEdit->textCursor();
|
||||
tc.movePosition( QTextCursor::Start );
|
||||
tc.select( QTextCursor::LineUnderCursor );
|
||||
QString firstline = tc.selectedText();
|
||||
//this->main->add_debug_output("First Line: " + firstline);
|
||||
QString ele = firstline.split(" ", QString::SkipEmptyParts)[0];
|
||||
//this->main->add_debug_output("First Offset: " + ele);
|
||||
if (ele.contains("0x")) {
|
||||
int b = this->disasTextEdit->verticalScrollBar()->maximum();
|
||||
this->core->cmd("ss " + ele);
|
||||
this->core->cmd("so -50");
|
||||
QString raw = this->core->cmd("pd 50");
|
||||
//this->main->add_debug_output(raw);
|
||||
//QString txt = raw.section("\n", 1, -1);
|
||||
//this->main->add_debug_output(txt);
|
||||
tc.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
|
||||
//tc.insertText(raw.trimmed() + "\n ;\n ; New content prepended here\n ;\n");
|
||||
int c = this->disasTextEdit->verticalScrollBar()->maximum();
|
||||
int z = c -b;
|
||||
int a = this->disasTextEdit->verticalScrollBar()->sliderPosition();
|
||||
this->disasTextEdit->verticalScrollBar()->setValue(a + z);
|
||||
} else {
|
||||
tc.movePosition( QTextCursor::Start );
|
||||
tc.select( QTextCursor::LineUnderCursor );
|
||||
QString lastline = tc.selectedText();
|
||||
this->main->add_debug_output("Last line: " + lastline);
|
||||
}
|
||||
} */
|
||||
if (maxLines <= 0)
|
||||
{
|
||||
mDisasTextEdit->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reconnect scroll signals
|
||||
connect(mDisasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
|
||||
int horizontalScrollValue = mDisasTextEdit->horizontalScrollBar()->value();
|
||||
mDisasTextEdit->setLockScroll(true); // avoid flicker
|
||||
|
||||
return loaded;
|
||||
QString disas = readDisasm("pd " + QString::number(maxLines) + "@" + QString::number(topOffset), true);
|
||||
|
||||
connectCursorPositionChanged(true);
|
||||
|
||||
mDisasTextEdit->document()->setHtml(disas);
|
||||
|
||||
// get bottomOffset from last visible line.
|
||||
// because pd N may return more than N lines, move maxLines lines down from the top
|
||||
mDisasTextEdit->moveCursor(QTextCursor::Start);
|
||||
QTextCursor tc = mDisasTextEdit->textCursor();
|
||||
tc.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, maxLines-1);
|
||||
mDisasTextEdit->setTextCursor(tc);
|
||||
|
||||
connectCursorPositionChanged(false);
|
||||
|
||||
bottomOffset = readCurrentDisassemblyOffset();
|
||||
if (bottomOffset == RVA_INVALID)
|
||||
{
|
||||
bottomOffset = topOffset;
|
||||
}
|
||||
|
||||
updateCursorPosition();
|
||||
|
||||
mDisasTextEdit->setLockScroll(false);
|
||||
mDisasTextEdit->horizontalScrollBar()->setValue(horizontalScrollValue);
|
||||
}
|
||||
|
||||
|
||||
void DisassemblyWidget::scrollInstructions(int count)
|
||||
{
|
||||
if (count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RVA offset;
|
||||
if (count > 0)
|
||||
{
|
||||
offset = Core()->nextOpAddr(topOffset, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = Core()->prevOpAddr(topOffset, -count);
|
||||
}
|
||||
|
||||
refreshDisasm(offset);
|
||||
}
|
||||
|
||||
|
||||
void DisassemblyWidget::updateMaxLines()
|
||||
{
|
||||
QFontMetrics fontMetrics(mDisasTextEdit->document()->defaultFont());
|
||||
int currentMaxLines = (mDisasTextEdit->height() -
|
||||
(mDisasTextEdit->contentsMargins().top() + mDisasTextEdit->contentsMargins().bottom()
|
||||
+ (int)(mDisasTextEdit->document()->documentMargin() * 2)))
|
||||
/ fontMetrics.lineSpacing();
|
||||
|
||||
if (currentMaxLines != maxLines)
|
||||
{
|
||||
maxLines = currentMaxLines;
|
||||
refreshDisasm();
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::highlightCurrentLine()
|
||||
{
|
||||
QList<QTextEdit::ExtraSelection> extraSelections;
|
||||
@ -241,91 +254,107 @@ void DisassemblyWidget::showDisasContextMenu(const QPoint &pt)
|
||||
RVA DisassemblyWidget::readCurrentDisassemblyOffset()
|
||||
{
|
||||
// TODO: do this in a different way without parsing the disassembly text
|
||||
|
||||
static const QRegularExpression offsetRegExp("^0x[0-9A-Fa-f]*");
|
||||
|
||||
QTextCursor tc = mDisasTextEdit->textCursor();
|
||||
tc.select(QTextCursor::LineUnderCursor);
|
||||
QString lastline = tc.selectedText();
|
||||
QStringList parts = lastline.split("\u00a0", QString::SkipEmptyParts);
|
||||
|
||||
if (parts.isEmpty()) {
|
||||
return RVA_INVALID;
|
||||
while (true)
|
||||
{
|
||||
tc.select(QTextCursor::LineUnderCursor);
|
||||
|
||||
QString line = tc.selectedText();
|
||||
|
||||
auto match = offsetRegExp.match(line);
|
||||
if (match.hasMatch())
|
||||
{
|
||||
return match.captured(0).toULongLong(nullptr, 16);
|
||||
}
|
||||
|
||||
tc.movePosition(QTextCursor::StartOfLine);
|
||||
if (tc.atStart())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
tc.movePosition(QTextCursor::Up);
|
||||
}
|
||||
|
||||
QString ele = parts[0];
|
||||
if (!ele.contains("0x")) {
|
||||
return RVA_INVALID;
|
||||
}
|
||||
|
||||
return ele.toULongLong(0, 16);
|
||||
return RVA_INVALID;
|
||||
}
|
||||
|
||||
void DisassemblyWidget::disasmScrolled()
|
||||
void DisassemblyWidget::updateCursorPosition()
|
||||
{
|
||||
loadMoreDisassembly();
|
||||
connectCursorPositionChanged(true);
|
||||
RVA offset = Core()->getOffset();
|
||||
|
||||
if (offset < topOffset || (offset > bottomOffset && bottomOffset != RVA_INVALID))
|
||||
{
|
||||
mDisasTextEdit->moveCursor(QTextCursor::Start);
|
||||
mDisasTextEdit->setExtraSelections({});
|
||||
}
|
||||
else
|
||||
{
|
||||
RVA currentCursorOffset = readCurrentDisassemblyOffset();
|
||||
QTextCursor originalCursor = mDisasTextEdit->textCursor();
|
||||
|
||||
QTextCursor cursor = originalCursor;
|
||||
cursor.movePosition(QTextCursor::Start);
|
||||
|
||||
while (true)
|
||||
{
|
||||
mDisasTextEdit->setTextCursor(cursor);
|
||||
RVA lineOffset = readCurrentDisassemblyOffset();
|
||||
if (lineOffset == offset)
|
||||
{
|
||||
highlightCurrentLine();
|
||||
break;
|
||||
}
|
||||
else if (lineOffset != RVA_INVALID && lineOffset > offset)
|
||||
{
|
||||
mDisasTextEdit->moveCursor(QTextCursor::Start);
|
||||
mDisasTextEdit->setExtraSelections({});
|
||||
break;
|
||||
}
|
||||
|
||||
cursor.movePosition(QTextCursor::EndOfLine);
|
||||
if (cursor.atEnd())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cursor.movePosition(QTextCursor::Down);
|
||||
}
|
||||
|
||||
// this is true if a seek came from the user clicking on a line.
|
||||
// then the cursor should be restored 1:1 to retain selection and cursor position.
|
||||
if (currentCursorOffset == offset)
|
||||
{
|
||||
mDisasTextEdit->setTextCursor(originalCursor);
|
||||
}
|
||||
}
|
||||
connectCursorPositionChanged(false);
|
||||
}
|
||||
|
||||
void DisassemblyWidget::connectCursorPositionChanged(bool disconnect)
|
||||
{
|
||||
if (disconnect)
|
||||
{
|
||||
QObject::disconnect(mDisasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChanged()));
|
||||
}
|
||||
else
|
||||
{
|
||||
connect(mDisasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChanged()));
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::cursorPositionChanged()
|
||||
{
|
||||
// Get current offset
|
||||
QTextCursor tc = mDisasTextEdit->textCursor();
|
||||
tc.select(QTextCursor::LineUnderCursor);
|
||||
QString lastline = tc.selectedText().trimmed();
|
||||
QList<QString> words = lastline.split(" ", QString::SkipEmptyParts);
|
||||
if (words.length() == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QString ele = words[0];
|
||||
// TODO
|
||||
/*if (ele.contains("0x"))
|
||||
{
|
||||
this->fillOffsetInfo(ele);
|
||||
QString at = this->core->cmdFunctionAt(ele);
|
||||
QString deco = this->core->getDecompiledCode(at);
|
||||
|
||||
|
||||
RVA addr = ele.midRef(2).toULongLong(0, 16);
|
||||
// FIXME per widget CursorAddress no?
|
||||
// this->main->setCursorAddress(addr);
|
||||
|
||||
if (deco != "")
|
||||
{
|
||||
ui->decoTextEdit->setPlainText(deco);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->decoTextEdit->setPlainText("");
|
||||
}
|
||||
// Get jump information to fill the preview
|
||||
QString jump = this->core->getOffsetJump(ele);
|
||||
if (!jump.isEmpty())
|
||||
{
|
||||
// Fill the preview
|
||||
QString jump_code = this->core->cmd("pdf @ " + jump);
|
||||
ui->previewTextEdit->setPlainText(jump_code.trimmed());
|
||||
ui->previewTextEdit->moveCursor(QTextCursor::End);
|
||||
ui->previewTextEdit->find(jump.trimmed(), QTextDocument::FindBackward);
|
||||
ui->previewTextEdit->moveCursor(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->previewTextEdit->setPlainText("");
|
||||
}
|
||||
//this->main->add_debug_output("Fcn at: '" + at + "'");
|
||||
if (this->last_fcn != at)
|
||||
{
|
||||
this->last_fcn = at;
|
||||
//this->main->add_debug_output("New Fcn: '" + this->last_fcn + "'");
|
||||
// Refresh function information at sidebar
|
||||
ui->fcnNameEdit->setText(at);
|
||||
// FIXME TITLE?
|
||||
// this->main->previewDock->setWindowTitle(at);
|
||||
//this->main->previewDock->create_graph(ele);
|
||||
this->setMiniGraph(at);
|
||||
}
|
||||
}
|
||||
*/
|
||||
RVA offset = readCurrentDisassemblyOffset();
|
||||
Core()->seek(offset);
|
||||
}
|
||||
|
||||
|
||||
bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if ((obj == mDisasTextEdit || obj == mDisasTextEdit->viewport()) && event->type() == QEvent::MouseButtonDblClick)
|
||||
@ -368,18 +397,18 @@ void DisassemblyWidget::on_seekChanged(RVA offset)
|
||||
if (!Core()->graphDisplay || !Core()->graphPriority) {
|
||||
this->raise();
|
||||
}
|
||||
refreshDisasm();
|
||||
}
|
||||
|
||||
void DisassemblyWidget::highlightDisasms()
|
||||
{
|
||||
// TODO Useless
|
||||
//Highlighter *highlighter = new Highlighter(mDisasTextEdit->document());
|
||||
//Highlighter *highlighter_5 = new Highlighter(mDisasTextEdit->document());
|
||||
//AsciiHighlighter *ascii_highlighter = new AsciiHighlighter(mDisasTextEdit->document());
|
||||
//HexHighlighter *hex_highlighter = new HexHighlighter(mDisasTextEdit->document());
|
||||
//Highlighter *preview_highlighter = new Highlighter(mDisasTextEdit->document());
|
||||
//Highlighter *deco_highlighter = new Highlighter(mDisasTextEdit->document());
|
||||
if (topOffset != RVA_INVALID && bottomOffset != RVA_INVALID
|
||||
&& offset >= topOffset && offset <= bottomOffset)
|
||||
{
|
||||
// if the line with the seek offset is currently visible, just move the cursor there
|
||||
updateCursorPosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise scroll there
|
||||
refreshDisasm(offset);
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyWidget::fontsUpdatedSlot()
|
||||
@ -403,3 +432,51 @@ void DisassemblyWidget::showXrefsDialog()
|
||||
dialog->exec();
|
||||
}
|
||||
}
|
||||
|
||||
DisassemblyScrollArea::DisassemblyScrollArea(QWidget *parent) : QAbstractScrollArea(parent)
|
||||
{
|
||||
}
|
||||
|
||||
bool DisassemblyScrollArea::viewportEvent(QEvent *event)
|
||||
{
|
||||
int dy = verticalScrollBar()->value() - 5;
|
||||
if (dy != 0)
|
||||
{
|
||||
emit scrollLines(dy);
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::Resize)
|
||||
{
|
||||
emit disassemblyResized();
|
||||
}
|
||||
|
||||
resetScrollBars();
|
||||
return QAbstractScrollArea::viewportEvent(event);
|
||||
}
|
||||
|
||||
void DisassemblyScrollArea::resetScrollBars()
|
||||
{
|
||||
verticalScrollBar()->blockSignals(true);
|
||||
verticalScrollBar()->setRange(0, 10);
|
||||
verticalScrollBar()->setValue(5);
|
||||
verticalScrollBar()->blockSignals(false);
|
||||
}
|
||||
|
||||
bool DisassemblyTextEdit::viewportEvent(QEvent *event)
|
||||
{
|
||||
switch(event->type())
|
||||
{
|
||||
case QEvent::Type::Wheel:
|
||||
return false;
|
||||
default:
|
||||
return QAbstractScrollArea::viewportEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyTextEdit::scrollContentsBy(int dx, int dy)
|
||||
{
|
||||
if (!lockScroll)
|
||||
{
|
||||
QPlainTextEdit::scrollContentsBy(dx, dy);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
#ifndef DISASSEMBLYVIEW_H
|
||||
#define DISASSEMBLYVIEW_H
|
||||
#ifndef DISASSEMBLYWIDGET_H
|
||||
#define DISASSEMBLYWIDGET_H
|
||||
|
||||
#include "cutter.h"
|
||||
#include <QDockWidget>
|
||||
#include <QTextEdit>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QShortcut>
|
||||
|
||||
|
||||
class DisassemblyTextEdit;
|
||||
class DisassemblyScrollArea;
|
||||
|
||||
class DisassemblyWidget : public QDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -14,26 +18,73 @@ public:
|
||||
explicit DisassemblyWidget(const QString &title, QWidget *parent = nullptr);
|
||||
QWidget* getTextWidget();
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
void highlightCurrentLine();
|
||||
void disasmScrolled();
|
||||
void showDisasContextMenu(const QPoint &pt);
|
||||
void cursorPositionChanged();
|
||||
void on_seekChanged(RVA offset);
|
||||
void refreshDisasm();
|
||||
void refreshDisasm(RVA offset = RVA_INVALID);
|
||||
void fontsUpdatedSlot();
|
||||
void showXrefsDialog();
|
||||
|
||||
private:
|
||||
QTextEdit *mDisasTextEdit;
|
||||
private slots:
|
||||
void scrollInstructions(int count);
|
||||
void updateMaxLines();
|
||||
|
||||
QString readDisasm(RVA offset = RVA_INVALID);
|
||||
void cursorPositionChanged();
|
||||
|
||||
private:
|
||||
DisassemblyScrollArea *mDisasScrollArea;
|
||||
DisassemblyTextEdit *mDisasTextEdit;
|
||||
|
||||
RVA topOffset;
|
||||
RVA bottomOffset;
|
||||
int maxLines;
|
||||
|
||||
QString readDisasm(const QString &cmd, bool stripLastNewline);
|
||||
RVA readCurrentDisassemblyOffset();
|
||||
bool loadMoreDisassembly();
|
||||
void highlightDisasms();
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
void updateCursorPosition();
|
||||
|
||||
void connectCursorPositionChanged(bool disconnect);
|
||||
};
|
||||
|
||||
#endif // DISASSEMBLYVIEW_H
|
||||
class DisassemblyScrollArea : public QAbstractScrollArea
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DisassemblyScrollArea(QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void scrollLines(int lines);
|
||||
void disassemblyResized();
|
||||
|
||||
protected:
|
||||
bool viewportEvent(QEvent *event) override;
|
||||
|
||||
private:
|
||||
void resetScrollBars();
|
||||
};
|
||||
|
||||
|
||||
class DisassemblyTextEdit: public QPlainTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DisassemblyTextEdit(QWidget *parent = nullptr)
|
||||
: QPlainTextEdit(parent),
|
||||
lockScroll(false) {}
|
||||
|
||||
void setLockScroll(bool lock) { this->lockScroll = lock; }
|
||||
|
||||
protected:
|
||||
bool viewportEvent(QEvent *event) override;
|
||||
void scrollContentsBy(int dx, int dy) override;
|
||||
|
||||
private:
|
||||
bool lockScroll;
|
||||
};
|
||||
|
||||
#endif // DISASSEMBLYWIDGET_H
|
||||
|
@ -309,7 +309,7 @@ void HexdumpWidget::resizeHexdump()
|
||||
{
|
||||
this->hexOffsetText->setMinimumWidth(this->hexOffsetText->document()->size().width());
|
||||
this->hexHexText->setMinimumWidth(this->hexHexText->document()->size().width());
|
||||
this->hexASCIIText->setMinimumWidth(this->hexASCIIText->document()->size().width());
|
||||
//this->hexASCIIText->setMinimumWidth(this->hexASCIIText->document()->size().width());
|
||||
}
|
||||
|
||||
void HexdumpWidget::hexScrolled()
|
||||
|
Loading…
Reference in New Issue
Block a user