Moved disassembly view to its own class

This commit is contained in:
xarkes 2017-10-11 23:07:32 +02:00
parent 7b3d5ea7a7
commit b4867cadef
8 changed files with 481 additions and 525 deletions

View File

@ -181,14 +181,7 @@ void MainWindow::initUI()
/*
* Dock Widgets
*/
dockWidgets.reserve(12);
// Add graph view as dockable
graphDock = new QDockWidget(tr("Graph"), this);
graphDock->setAllowedAreas(Qt::AllDockWidgetAreas);
DisassemblerGraphView *gv = new DisassemblerGraphView(graphDock);
graphDock->setWidget(gv);
dockWidgets.push_back(graphDock);
dockWidgets.reserve(14);
// Add Memory DockWidget
this->memoryDock = new MemoryWidget();
@ -197,6 +190,17 @@ void MainWindow::initUI()
// this->memoryDock->setAttribute(Qt::WA_DeleteOnClose);
// this->add_debug_output( QString::number(this->dockList.length()) );
// Add disassembly view (dockable)
this->disassemblyDock = new DisassemblyView(tr("Disassembly"), this);
dockWidgets.push_back(disassemblyDock);
// Add graph view as dockable
graphDock = new QDockWidget(tr("Graph"), this);
graphDock->setAllowedAreas(Qt::AllDockWidgetAreas);
DisassemblerGraphView *gv = new DisassemblerGraphView(graphDock);
graphDock->setWidget(gv);
dockWidgets.push_back(graphDock);
// Add Sections dock panel
this->sectionsDock = new SectionsDock(this);
dockWidgets.push_back(sectionsDock);
@ -367,7 +371,6 @@ void MainWindow::finalizeOpen()
start_web_server();
showMaximized();
// Initialize syntax highlighters
memoryDock->highlightDisasms();
notepadDock->highlightPreview();
}
@ -510,6 +513,9 @@ void MainWindow::updateFrames()
static bool first_time = true;
//TODO Send signal rather than that
disassemblyDock->refreshDisasm();
if (first_time)
{
for (auto W : dockWidgets)
@ -619,7 +625,7 @@ void MainWindow::on_actionMem_triggered()
this->dockWidgets << newMemDock;
newMemDock->setAttribute(Qt::WA_DeleteOnClose);
this->tabifyDockWidget(this->memoryDock, newMemDock);
newMemDock->refreshDisasm();
//newMemDock->refreshDisasm();
newMemDock->refreshHexdump();
}
@ -752,13 +758,14 @@ void MainWindow::on_actionDisasAdd_comment_triggered()
void MainWindow::restoreDocks()
{
addDockWidget(Qt::RightDockWidgetArea, sectionsDock);
addDockWidget(Qt::LeftDockWidgetArea, this->functionsDock);
addDockWidget(Qt::RightDockWidgetArea, this->sectionsDock);
addDockWidget(Qt::TopDockWidgetArea, this->dashboardDock);
this->tabifyDockWidget(sectionsDock, this->commentsDock);
this->tabifyDockWidget(this->sectionsDock, this->commentsDock);
this->tabifyDockWidget(this->dashboardDock, this->disassemblyDock);
this->tabifyDockWidget(this->dashboardDock, this->graphDock);
this->tabifyDockWidget(this->dashboardDock, this->memoryDock);
this->tabifyDockWidget(this->dashboardDock, this->entrypointDock);
this->tabifyDockWidget(this->dashboardDock, this->functionsDock);
this->tabifyDockWidget(this->dashboardDock, this->flagsDock);
this->tabifyDockWidget(this->dashboardDock, this->stringsDock);
this->tabifyDockWidget(this->dashboardDock, this->relocsDock);
@ -767,7 +774,7 @@ void MainWindow::restoreDocks()
this->tabifyDockWidget(this->dashboardDock, this->symbolsDock);
this->tabifyDockWidget(this->dashboardDock, this->notepadDock);
this->dashboardDock->raise();
sectionsDock->raise();
this->sectionsDock->raise();
this->functionsDock->raise();
}
@ -790,7 +797,6 @@ void MainWindow::hideAllDocks()
void MainWindow::showDefaultDocks()
{
const QList<QDockWidget *> defaultDocks = { sectionsDock,
graphDock,
entrypointDock,
functionsDock,
memoryDock,
@ -799,6 +805,8 @@ void MainWindow::showDefaultDocks()
importsDock,
symbolsDock,
notepadDock,
graphDock,
disassemblyDock,
dashboardDock
};

View File

@ -5,6 +5,7 @@
#include <QList>
#include <memory>
#include "RadareWebServer.h"
#include "widgets/DisassemblyView.h"
#include "cutter.h" // only needed for ut64
class CutterCore;
@ -169,6 +170,7 @@ private slots:
private:
CutterCore *core;
DisassemblyView *disassemblyDock;
QDockWidget *graphDock;
QDockWidget *asmDock;
QDockWidget *calcDock;

View File

@ -73,7 +73,8 @@ SOURCES += \
widgets/Sidebar.cpp \
widgets/StringsWidget.cpp \
widgets/SymbolsWidget.cpp \
menus/DisassemblyContextMenu.cpp
menus/DisassemblyContextMenu.cpp \
widgets/DisassemblyView.cpp
HEADERS += \
cutter.h \
@ -119,7 +120,8 @@ HEADERS += \
widgets/Sidebar.h \
widgets/StringsWidget.h \
widgets/SymbolsWidget.h \
menus/DisassemblyContextMenu.h
menus/DisassemblyContextMenu.h \
widgets/DisassemblyView.h
FORMS += \
widgets/MemoryWidget.ui \

View File

@ -0,0 +1,408 @@
#include "DisassemblyView.h"
#include "menus/DisassemblyContextMenu.h"
#include "dialogs/XrefsDialog.h"
#include "utils/HexAsciiHighlighter.h"
#include "utils/HexHighlighter.h"
#include <QShortcut>
#include <QScrollBar>
DisassemblyView::DisassemblyView(QWidget *parent) :
QDockWidget(parent),
mDisasTextEdit(new QTextEdit(this))
{
// Configure Dock
this->setWidget(mDisasTextEdit);
this->setAllowedAreas(Qt::AllDockWidgetAreas);
// TODO Use Settings
mDisasTextEdit->setFont(QFont("Monospace", 10));
// 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);
// Set Disas context menu
mDisasTextEdit->setContextMenuPolicy(Qt::CustomContextMenu);
connect(mDisasTextEdit, SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(showDisasContextMenu(const QPoint &)));
// x or X to show XRefs
connect(new QShortcut(QKeySequence(Qt::Key_X), mDisasTextEdit),
SIGNAL(activated()), this, SLOT(showXrefsDialog()));
connect(new QShortcut(Qt::SHIFT + Qt::Key_X, mDisasTextEdit),
SIGNAL(activated()), this, SLOT(showXrefsDialog()));
// Scrollbar
connect(mDisasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
// TODO Shortcuts
// Semicolon to add comment
//QShortcut *comment_shortcut = new QShortcut(QKeySequence(Qt::Key_Semicolon), mDisasTextEdit);
//connect(comment_shortcut, SIGNAL(activated()), this, SLOT(on_actionDisasAdd_comment_triggered()));
//comment_shortcut->setContext(Qt::WidgetShortcut);
// N to rename function
//QShortcut *rename_shortcut = new QShortcut(QKeySequence(Qt::Key_N), mDisasTextEdit);
//connect(rename_shortcut, SIGNAL(activated()), this, SLOT(on_actionFunctionsRename_triggered()));
//rename_shortcut->setContext(Qt::WidgetShortcut);
// Esc to seek back
//QShortcut *back_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), mDisasTextEdit);
//connect(back_shortcut, SIGNAL(activated()), this, SLOT(seek_back()));
//back_shortcut->setContext(Qt::WidgetShortcut);
// CTRL + R to refresh the disasm
//QShortcut *refresh_shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_R), mDisasTextEdit);
//connect(refresh_shortcut, SIGNAL(activated()), this, SLOT(refreshDisasm()));
//refresh_shortcut->setContext(Qt::WidgetShortcut);
// Seek signal
connect(CutterCore::getInstance(), SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA)));
}
DisassemblyView::DisassemblyView(const QString &title, QWidget *parent) :
DisassemblyView(parent)
{
this->setWindowTitle(title);
}
void DisassemblyView::highlightCurrentLine()
{
QList<QTextEdit::ExtraSelection> extraSelections;
// Highlight the current line in yellow
if (mDisasTextEdit->isReadOnly())
{
QTextEdit::ExtraSelection selection;
QColor lineColor = QColor(190, 144, 212);
selection.format.setBackground(lineColor);
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = mDisasTextEdit->textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
}
// Highlight the current word
QTextCursor cursor = mDisasTextEdit->textCursor();
cursor.select(QTextCursor::WordUnderCursor);
QTextEdit::ExtraSelection currentWord;
QColor blueColor = QColor(Qt::blue).lighter(160);
currentWord.format.setBackground(blueColor);
currentWord.cursor = cursor;
extraSelections.append(currentWord);
currentWord.cursor.clearSelection();
// Highlight all the words in the document same as the actual one
QString searchString = cursor.selectedText();
QTextDocument *document = mDisasTextEdit->document();
//QTextCursor highlightCursor(document);
QTextEdit::ExtraSelection highlightSelection;
highlightSelection.cursor = cursor;
highlightSelection.format.setBackground(blueColor);
QTextCursor cursor2(document);
cursor2.beginEditBlock();
highlightSelection.cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
while (!highlightSelection.cursor.isNull() && !highlightSelection.cursor.atEnd())
{
highlightSelection.cursor = document->find(searchString, highlightSelection.cursor, QTextDocument::FindWholeWords);
if (!highlightSelection.cursor.isNull())
{
highlightSelection.cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
extraSelections.append(highlightSelection);
}
}
cursor2.endEditBlock();
mDisasTextEdit->setExtraSelections(extraSelections);
}
void DisassemblyView::showDisasContextMenu(const QPoint &pt)
{
DisassemblyContextMenu menu(this->readCurrentDisassemblyOffset(), mDisasTextEdit);
menu.exec(mDisasTextEdit->mapToGlobal(pt));
}
void DisassemblyView::showXrefsDialog()
{
// Get current offset
QTextCursor tc = mDisasTextEdit->textCursor();
tc.select(QTextCursor::LineUnderCursor);
QString lastline = tc.selectedText();
QString ele = lastline.split(" ", QString::SkipEmptyParts)[0];
if (ele.contains("0x"))
{
RVA addr = ele.toLongLong(0, 16);
XrefsDialog *dialog = new XrefsDialog(this);
dialog->fillRefsForAddress(addr, RAddressString(addr), false);
dialog->exec();
}
}
RVA DisassemblyView::readCurrentDisassemblyOffset()
{
// TODO: do this in a different way without parsing the disassembly text
QTextCursor tc = mDisasTextEdit->textCursor();
tc.select(QTextCursor::LineUnderCursor);
QString lastline = tc.selectedText();
QStringList parts = lastline.split(" ", QString::SkipEmptyParts);
if (parts.isEmpty())
return RVA_INVALID;
QString ele = parts[0];
if (!ele.contains("0x"))
return RVA_INVALID;
return ele.toULongLong(0, 16);
}
bool DisassemblyView::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)
{
//this->main->add_debug_output("End is coming");
QTextCursor tc = mDisasTextEdit->textCursor();
tc.movePosition(QTextCursor::End);
RVA offset = readCurrentDisassemblyOffset();
if (offset != RVA_INVALID)
{
CutterCore::getInstance()->seek(offset);
QString raw = CutterCore::getInstance()->cmd("pd 200");
QString txt = raw.section("\n", 1, -1);
//this->disasTextEdit->appendPlainText(" ;\n ; New content here\n ;\n " + txt.trimmed());
mDisasTextEdit->append(txt.trimmed());
}
else
{
tc.movePosition(QTextCursor::End);
tc.select(QTextCursor::LineUnderCursor);
QString lastline = tc.selectedText();
//this->main->addDebugOutput("Last line: " + lastline);
}
loaded = true;
// 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);
}
} */
// Reconnect scroll signals
connect(mDisasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
return loaded;
}
void DisassemblyView::disasmScrolled()
{
loadMoreDisassembly();
}
void DisassemblyView::refreshDisasm()
{
// TODO Very slow mostly because of the highlight
// Prevent further scroll
disconnect(mDisasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
disconnect(mDisasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(on_mDisasTextEdit_cursorPositionChanged()));
QString disas = CutterCore::getInstance()->cmd("pd 200");
mDisasTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
mDisasTextEdit->setPlainText(disas.trimmed());
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 (!loadMoreDisassembly())
break;
mDisasTextEdit->verticalScrollBar()->setValue(0);
}*/
connect(mDisasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
connect(mDisasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(on_mDisasTextEdit_cursorPositionChanged()));
//this->on_mDisasTextEdit_cursorPositionChanged();
this->highlightDisasms();
}
void DisassemblyView::on_mDisasTextEdit_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->memoryDock->setWindowTitle(at);
//this->main->memoryDock->create_graph(ele);
this->setMiniGraph(at);
}
}
*/
}
bool DisassemblyView::eventFilter(QObject *obj, QEvent *event)
{
if ((obj == mDisasTextEdit || obj == mDisasTextEdit->viewport()) && event->type() == QEvent::MouseButtonDblClick)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
//qDebug()<<QString("Click location: (%1,%2)").arg(mouseEvent->x()).arg(mouseEvent->y());
QTextCursor cursor = mDisasTextEdit->cursorForPosition(QPoint(mouseEvent->x(), mouseEvent->y()));
cursor.select(QTextCursor::LineUnderCursor);
QString lastline = cursor.selectedText();
auto eles = lastline.split(" ", QString::SkipEmptyParts);
QString ele = eles.isEmpty() ? "" : eles[0];
if (ele.contains("0x"))
{
QString jump = CutterCore::getInstance()->getOffsetJump(ele);
if (!jump.isEmpty())
{
if (jump.contains("0x"))
{
QString fcn = CutterCore::getInstance()->cmdFunctionAt(jump);
if (!fcn.isEmpty())
{
RVA addr = jump.trimmed().toULongLong(0, 16);
CutterCore::getInstance()->seek(addr);
}
}
else
{
RVA addr = CutterCore::getInstance()->cmd("?v " + jump).toULongLong(0, 16);
CutterCore::getInstance()->seek(addr);
}
}
}
}
return QDockWidget::eventFilter(obj, event);
}
void DisassemblyView::on_seekChanged(RVA offset)
{
Q_UNUSED(offset);
refreshDisasm();
}
void DisassemblyView::highlightDisasms()
{
// Syntax Highliting
// TODO doing new all the time
// TODO Seems very very heavy -- merge it with Graph one
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());
}

View File

@ -0,0 +1,35 @@
#ifndef DISASSEMBLYVIEW_H
#define DISASSEMBLYVIEW_H
#include <QDockWidget>
#include <QTextEdit>
#include "cutter.h"
class DisassemblyView : public QDockWidget
{
Q_OBJECT
public:
explicit DisassemblyView(QWidget *parent = nullptr);
explicit DisassemblyView(const QString &title, QWidget *parent = nullptr);
signals:
public slots:
void highlightCurrentLine();
void disasmScrolled();
void showDisasContextMenu(const QPoint &pt);
void showXrefsDialog();
void on_mDisasTextEdit_cursorPositionChanged();
void on_seekChanged(RVA offset);
void refreshDisasm();
private:
QTextEdit *mDisasTextEdit;
RVA readCurrentDisassemblyOffset();
bool loadMoreDisassembly();
void highlightDisasms();
bool eventFilter(QObject *obj, QEvent *event);
};
#endif // DISASSEMBLYVIEW_H

View File

@ -4,8 +4,6 @@
#include "MainWindow.h"
#include "utils/Helpers.h"
#include "dialogs/XrefsDialog.h"
#include "menus/DisassemblyContextMenu.h"
#include <QTemporaryFile>
#include <QFontDialog>
@ -27,8 +25,6 @@ MemoryWidget::MemoryWidget() :
core(CutterCore::getInstance())
{
ui->setupUi(this);
this->disasTextEdit = ui->disasTextEdit_2;
this->hexOffsetText = ui->hexOffsetText_2;
this->hexHexText = ui->hexHexText_2;
this->hexDisasTextEdit = ui->hexDisasTextEdit_2;
@ -44,13 +40,6 @@ MemoryWidget::MemoryWidget() :
disasm_top_offset = 0;
next_disasm_top_offset = 0;
// Increase asm text edit margin
QTextDocument *asm_docu = this->disasTextEdit->document();
asm_docu->setDocumentMargin(10);
// Setup disasm highlight
connect(ui->disasTextEdit_2, SIGNAL(cursorPositionChanged()), this, SLOT(highlightCurrentLine()));
highlightCurrentLine();
//this->on_actionSettings_menu_1_triggered();
// Setup hex highlight
@ -81,7 +70,6 @@ MemoryWidget::MemoryWidget() :
ui->fcnNameEdit->setTextMargins(5, 0, 0, 0);
// Normalize fonts for other OS
qhelpers::normalizeFont(this->disasTextEdit);
qhelpers::normalizeEditFont(this->hexOffsetText);
qhelpers::normalizeEditFont(this->hexHexText);
qhelpers::normalizeEditFont(this->hexASCIIText);
@ -92,18 +80,10 @@ MemoryWidget::MemoryWidget() :
memMenu->addAction(ui->actionSettings_menu_1);
ui->memSettingsButton_2->setMenu(memMenu);
// Event filter to intercept double clicks in the textbox
ui->disasTextEdit_2->viewport()->installEventFilter(this);
// Set Splitter stretch factor
ui->splitter->setStretchFactor(0, 10);
ui->splitter->setStretchFactor(1, 1);
// Set Disas context menu
ui->disasTextEdit_2->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->disasTextEdit_2, SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(showDisasContextMenu(const QPoint &)));
// Set hexdump context menu
ui->hexHexText_2->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->hexHexText_2, SIGNAL(customContextMenuRequested(const QPoint &)),
@ -128,39 +108,12 @@ MemoryWidget::MemoryWidget() :
connect(ui->hexASCIIText_2->verticalScrollBar(), SIGNAL(valueChanged(int)),
ui->hexHexText_2->verticalScrollBar(), SLOT(setValue(int)));
// x or X to show XRefs
connect(new QShortcut(QKeySequence(Qt::Key_X), ui->disasTextEdit_2),
SIGNAL(activated()), this, SLOT(showXrefsDialog()));
connect(new QShortcut(Qt::SHIFT + Qt::Key_X, ui->disasTextEdit_2),
SIGNAL(activated()), this, SLOT(showXrefsDialog()));
// Space to switch between disassembly and graph
QShortcut *graph_shortcut = new QShortcut(QKeySequence(Qt::Key_Space), this);
connect(graph_shortcut, SIGNAL(activated()), this, SLOT(cycleViews()));
//graph_shortcut->setContext(Qt::WidgetShortcut);
// Semicolon to add comment
QShortcut *comment_shortcut = new QShortcut(QKeySequence(Qt::Key_Semicolon), ui->disasTextEdit_2);
connect(comment_shortcut, SIGNAL(activated()), this, SLOT(on_actionDisasAdd_comment_triggered()));
comment_shortcut->setContext(Qt::WidgetShortcut);
// N to rename function
QShortcut *rename_shortcut = new QShortcut(QKeySequence(Qt::Key_N), ui->disasTextEdit_2);
connect(rename_shortcut, SIGNAL(activated()), this, SLOT(on_actionFunctionsRename_triggered()));
rename_shortcut->setContext(Qt::WidgetShortcut);
// Esc to seek back
QShortcut *back_shortcut = new QShortcut(QKeySequence(Qt::Key_Escape), ui->disasTextEdit_2);
connect(back_shortcut, SIGNAL(activated()), this, SLOT(seek_back()));
back_shortcut->setContext(Qt::WidgetShortcut);
// CTRL + R to refresh the disasm
QShortcut *refresh_shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_R), ui->disasTextEdit_2);
connect(refresh_shortcut, SIGNAL(activated()), this, SLOT(refreshDisasm()));
refresh_shortcut->setContext(Qt::WidgetShortcut);
// Control Disasm and Hex scroll to add more contents
connect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
connect(this->hexASCIIText->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(hexScrolled()));
connect(core, SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA)));
@ -187,78 +140,6 @@ void MemoryWidget::on_cursorAddressChanged(RVA addr)
/*
* Text highlight functions
*/
void MemoryWidget::highlightDisasms()
{
// Syntax Highliting
highlighter = new Highlighter(ui->disasTextEdit_2->document());
highlighter_5 = new Highlighter(ui->hexDisasTextEdit_2->document());
ascii_highlighter = new AsciiHighlighter(ui->hexASCIIText_2->document());
hex_highlighter = new HexHighlighter(ui->hexHexText_2->document());
preview_highlighter = new Highlighter(ui->previewTextEdit->document());
deco_highlighter = new Highlighter(ui->decoTextEdit->document());
}
void MemoryWidget::highlightCurrentLine()
{
QList<QTextEdit::ExtraSelection> extraSelections;
// Highlight the current line in yellow
if (ui->disasTextEdit_2->isReadOnly())
{
QTextEdit::ExtraSelection selection;
QColor lineColor = QColor(190, 144, 212);
selection.format.setBackground(lineColor);
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = ui->disasTextEdit_2->textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
}
// Highlight the current word
QTextCursor cursor = ui->disasTextEdit_2->textCursor();
cursor.select(QTextCursor::WordUnderCursor);
QTextEdit::ExtraSelection currentWord;
QColor blueColor = QColor(Qt::blue).lighter(160);
currentWord.format.setBackground(blueColor);
currentWord.cursor = cursor;
extraSelections.append(currentWord);
currentWord.cursor.clearSelection();
// Highlight all the words in the document same as the actual one
QString searchString = cursor.selectedText();
QTextDocument *document = ui->disasTextEdit_2->document();
//QTextCursor highlightCursor(document);
QTextEdit::ExtraSelection highlightSelection;
highlightSelection.cursor = cursor;
highlightSelection.format.setBackground(blueColor);
QTextCursor cursor2(document);
cursor2.beginEditBlock();
highlightSelection.cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
while (!highlightSelection.cursor.isNull() && !highlightSelection.cursor.atEnd())
{
highlightSelection.cursor = document->find(searchString, highlightSelection.cursor, QTextDocument::FindWholeWords);
if (!highlightSelection.cursor.isNull())
{
highlightSelection.cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
extraSelections.append(highlightSelection);
}
}
cursor2.endEditBlock();
ui->disasTextEdit_2->setExtraSelections(extraSelections);
}
void MemoryWidget::highlightHexCurrentLine()
{
QList<QTextEdit::ExtraSelection> extraSelections;
@ -369,24 +250,6 @@ void MemoryWidget::highlightDecoCurrentLine()
ui->decoTextEdit->setExtraSelections(extraSelections);
}
RVA MemoryWidget::readCurrentDisassemblyOffset()
{
// TODO: do this in a different way without parsing the disassembly text
QTextCursor tc = this->disasTextEdit->textCursor();
tc.select(QTextCursor::LineUnderCursor);
QString lastline = tc.selectedText();
QStringList parts = lastline.split(" ", QString::SkipEmptyParts);
if (parts.isEmpty())
return RVA_INVALID;
QString ele = parts[0];
if (!ele.contains("0x"))
return RVA_INVALID;
return ele.toULongLong(0, 16);
}
MemoryWidget::~MemoryWidget() {}
void MemoryWidget::setup()
@ -422,159 +285,6 @@ void MemoryWidget::fillPlugins()
ui->hexArchComboBox_2->insertItems(0, core->getAsmPluginNames());
}
void MemoryWidget::addTextDisasm(QString txt)
{
//QTextDocument *document = ui->disasTextEdit_2->document();
//document->undo();
ui->disasTextEdit_2->appendPlainText(txt);
}
void MemoryWidget::replaceTextDisasm(QString txt)
{
//QTextDocument *document = ui->disasTextEdit_2->document();
ui->disasTextEdit_2->clear();
//document->undo();
ui->disasTextEdit_2->setPlainText(txt);
}
bool MemoryWidget::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(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
QScrollBar *sb = this->disasTextEdit->verticalScrollBar();
bool loaded = false;
if (sb->value() > sb->maximum() - 10)
{
//this->main->add_debug_output("End is coming");
QTextCursor tc = this->disasTextEdit->textCursor();
tc.movePosition(QTextCursor::End);
RVA offset = readCurrentDisassemblyOffset();
if (offset != RVA_INVALID)
{
core->seek(offset);
QString raw = this->core->cmd("pd 200");
QString txt = raw.section("\n", 1, -1);
//this->disasTextEdit->appendPlainText(" ;\n ; New content here\n ;\n " + txt.trimmed());
this->disasTextEdit->appendPlainText(txt.trimmed());
}
else
{
tc.movePosition(QTextCursor::End);
tc.select(QTextCursor::LineUnderCursor);
QString lastline = tc.selectedText();
//this->main->addDebugOutput("Last line: " + lastline);
}
loaded = true;
// 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);
}
} */
// Reconnect scroll signals
connect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
return loaded;
}
void MemoryWidget::disasmScrolled()
{
loadMoreDisassembly();
}
void MemoryWidget::refreshDisasm()
{
RCoreLocked lcore = this->core->core();
// Prevent further scroll
disconnect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
disconnect(this->disasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(on_disasTextEdit_2_cursorPositionChanged()));
RVA offset = next_disasm_top_offset;
next_disasm_top_offset = RVA_INVALID;
bool offset_changed = offset != RVA_INVALID;
if (offset_changed) // new offset (seek)
{
disasm_top_offset = offset;
this->core->cmd(QString("s %1").arg(offset));
}
else // simple refresh
{
core->cmd(QString("s %1").arg(disasm_top_offset));
}
QString txt2 = this->core->cmd("pd 200");
disasTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
// if the offset changed, jump to the top
// otherwise try to retain the position
int cursor_pos = offset_changed ? 0 : disasTextEdit->textCursor().position();
int scroll_pos = offset_changed ? 0 : disasTextEdit->verticalScrollBar()->value();
this->disasTextEdit->setPlainText(txt2.trimmed());
auto cursor = disasTextEdit->textCursor();
cursor.setPosition(cursor_pos);
disasTextEdit->setTextCursor(cursor);
disasTextEdit->verticalScrollBar()->setValue(scroll_pos);
// 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 (!loadMoreDisassembly())
break;
disasTextEdit->verticalScrollBar()->setValue(scroll_pos);
}
connect(this->disasTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(disasmScrolled()));
connect(this->disasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(on_disasTextEdit_2_cursorPositionChanged()));
this->on_disasTextEdit_2_cursorPositionChanged();
}
void MemoryWidget::refreshHexdump(const QString &where)
{
RCoreLocked lcore = this->core->core();
@ -714,14 +424,6 @@ QList<QString> MemoryWidget::get_hexdump(const QString &offset)
return ret;
}
void MemoryWidget::seek_to(const QString &offset)
{
this->disasTextEdit->moveCursor(QTextCursor::End);
this->disasTextEdit->find(offset, QTextDocument::FindBackward);
this->disasTextEdit->moveCursor(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
}
void MemoryWidget::resizeHexdump()
{
this->hexOffsetText->setMinimumWidth(this->hexOffsetText->document()->size().width());
@ -975,12 +677,6 @@ void MemoryWidget::showHexASCIIContextMenu(const QPoint &pt)
delete menu;
}
void MemoryWidget::showDisasContextMenu(const QPoint &pt)
{
DisassemblyContextMenu menu(this->readCurrentDisassemblyOffset(), ui->disasTextEdit_2);
menu.exec(ui->disasTextEdit_2->mapToGlobal(pt));
}
void MemoryWidget::on_showInfoButton_2_clicked()
{
if (ui->showInfoButton_2->isChecked())
@ -1009,23 +705,6 @@ void MemoryWidget::on_offsetToolButton_clicked()
}
}
void MemoryWidget::showXrefsDialog()
{
// Get current offset
QTextCursor tc = this->disasTextEdit->textCursor();
tc.select(QTextCursor::LineUnderCursor);
QString lastline = tc.selectedText();
QString ele = lastline.split(" ", QString::SkipEmptyParts)[0];
if (ele.contains("0x"))
{
RVA addr = ele.toLongLong(0, 16);
XrefsDialog *x = new XrefsDialog(this);
x->fillRefsForAddress(addr, RAddressString(addr), false);
x->exec();
}
}
/*
* Show widgets
*/
@ -1055,9 +734,9 @@ void MemoryWidget::on_actionSettings_menu_1_triggered()
{
bool ok = true;
// QFont font = QFont("Monospace", 8);
QFont font = QFont("Monospace", 8);
// TODO Use global configuration
QFont font = QFontDialog::getFont(&ok, ui->disasTextEdit_2->font(), this);
//QFont font = QFontDialog::getFont(&ok, ui->disasTextEdit_2->font(), this);
if (ok)
{
@ -1066,11 +745,12 @@ void MemoryWidget::on_actionSettings_menu_1_triggered()
emit fontChanged(font);
}
}
void MemoryWidget::setFonts(QFont font)
{
ui->disasTextEdit_2->setFont(font);
//ui->disasTextEdit_2->setFont(font);
// the user clicked OK and font is set to the font the user selected
ui->disasTextEdit_2->setFont(font);
//ui->disasTextEdit_2->setFont(font);
ui->hexOffsetText_2->setFont(font);
ui->hexHexText_2->setFont(font);
ui->hexASCIIText_2->setFont(font);
@ -1130,13 +810,13 @@ void MemoryWidget::on_hexButton_clicked()
ui->memSideTabWidget_2->setCurrentIndex(1);
}
void MemoryWidget::on_actionSend_to_Notepad_triggered()
/*void MemoryWidget::on_actionSend_to_Notepad_triggered()
{
QTextCursor cursor = ui->disasTextEdit_2->textCursor();
QString text = cursor.selectedText();
// TODO
// this->main->sendToNotepad(text);
}
}*/
void MemoryWidget::on_action8columns_triggered()
{
@ -1396,67 +1076,6 @@ void MemoryWidget::setFcnName(RVA addr)
ui->fcnNameEdit->setText(addr_string);
}
void MemoryWidget::on_disasTextEdit_2_cursorPositionChanged()
{
// Get current offset
QTextCursor tc = this->disasTextEdit->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];
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->memoryDock->setWindowTitle(at);
//this->main->memoryDock->create_graph(ele);
this->setMiniGraph(at);
}
}
}
QString MemoryWidget::normalizeAddr(QString addr)
{
QString base = addr.split("0x")[1].trimmed();
@ -1603,49 +1222,12 @@ void MemoryWidget::resizeEvent(QResizeEvent *event)
QDockWidget::resizeEvent(event);
}
bool MemoryWidget::eventFilter(QObject *obj, QEvent *event)
{
if ((obj == ui->disasTextEdit_2 || obj == ui->disasTextEdit_2->viewport()) && event->type() == QEvent::MouseButtonDblClick)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
//qDebug()<<QString("Click location: (%1,%2)").arg(mouseEvent->x()).arg(mouseEvent->y());
QTextCursor cursor = ui->disasTextEdit_2->cursorForPosition(QPoint(mouseEvent->x(), mouseEvent->y()));
cursor.select(QTextCursor::LineUnderCursor);
QString lastline = cursor.selectedText();
auto eles = lastline.split(" ", QString::SkipEmptyParts);
QString ele = eles.isEmpty() ? "" : eles[0];
if (ele.contains("0x"))
{
QString jump = this->core->getOffsetJump(ele);
if (!jump.isEmpty())
{
if (jump.contains("0x"))
{
QString fcn = this->core->cmdFunctionAt(jump);
if (!fcn.isEmpty())
{
RVA addr = jump.trimmed().toULongLong(0, 16);
this->core->seek(addr);
}
}
else
{
RVA addr = this->core->cmd("?v " + jump).toULongLong(0, 16);
this->core->seek(addr);
}
}
}
}
return QDockWidget::eventFilter(obj, event);
}
void MemoryWidget::setScrollMode()
{
qhelpers::setVerticalScrollMode(ui->xreFromTreeWidget_2);
qhelpers::setVerticalScrollMode(ui->xrefToTreeWidget_2);
}
void MemoryWidget::on_copyMD5_clicked()
{
QString md5 = ui->bytesMD5->text();
@ -1727,12 +1309,7 @@ void MemoryWidget::updateViews(RVA offset)
if (offset != RVA_INVALID)
next_disasm_top_offset = offset;
if (index == 0)
{
// Disasm
this->refreshDisasm();
}
else if (index == 1)
if (index == 1)
{
// Hex
if (this->last_hexdump_fcn != cursor_addr)

View File

@ -35,7 +35,6 @@ public:
void refresh() override;
QPlainTextEdit *disasTextEdit;
QTextEdit *hexOffsetText;
QPlainTextEdit *hexDisasTextEdit;
QTextEdit *hexASCIIText;
@ -58,20 +57,12 @@ signals:
public slots:
void fillPlugins();
void addTextDisasm(QString txt);
void replaceTextDisasm(QString txt);
void refreshDisasm();
void refreshHexdump(const QString &where = QString());
void fill_refs(QList<XrefDescription> refs, QList<XrefDescription> xrefs, QList<int> graph_data);
void fillOffsetInfo(QString off);
void seek_to(const QString &offset);
QString normalize_addr(QString addr);
QString normalizeAddr(QString addr);
@ -80,15 +71,12 @@ public slots:
void switchTheme(bool dark);
void highlightDisasms();
void selectHexPreview();
void showOffsets(bool show);
protected:
void resizeEvent(QResizeEvent *event) override;
bool eventFilter(QObject *obj, QEvent *event) override;
private:
std::unique_ptr<Ui::MemoryWidget> ui;
@ -115,12 +103,9 @@ private slots:
void on_cursorAddressChanged(RVA addr);
void on_seekChanged(RVA addr);
void highlightCurrentLine();
void highlightHexCurrentLine();
void highlightPreviewCurrentLine();
void highlightDecoCurrentLine();
RVA readCurrentDisassemblyOffset();
void setFonts(QFont font);
void highlightHexWords(const QString &str);
@ -132,10 +117,8 @@ private slots:
void on_disasButton_clicked();
void on_hexButton_clicked();
void showDisasContextMenu(const QPoint &pt);
void showHexdumpContextMenu(const QPoint &pt);
void showHexASCIIContextMenu(const QPoint &pt);
void on_actionSend_to_Notepad_triggered();
void on_hexHexText_2_selectionChanged();
void on_hexArchComboBox_2_currentTextChanged(const QString &arg1);
@ -149,12 +132,10 @@ private slots:
void on_action32columns_triggered();
void on_action64columns_triggered();
void disasmScrolled();
void resizeHexdump();
void hexScrolled();
QList<QString> get_hexdump(const QString &offset);
void showXrefsDialog();
void updateViews(RVA offset = RVA_INVALID);
void cycleViews();
void on_xreFromTreeWidget_2_itemDoubleClicked(QTreeWidgetItem *item, int column);
@ -162,7 +143,6 @@ private slots:
void on_xrefFromToolButton_2_clicked();
void on_xrefToToolButton_2_clicked();
void on_codeCombo_2_currentTextChanged(const QString &arg1);
void on_disasTextEdit_2_cursorPositionChanged();
void on_offsetToolButton_clicked();
void on_polarToolButton_clicked();
void on_radarToolButton_clicked();

View File

@ -438,62 +438,6 @@ border-top: 0px;
<property name="handleWidth">
<number>2</number>
</property>
<widget class="QPlainTextEdit" name="disasTextEdit_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Anonymous Pro</family>
<pointsize>13</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="lineWidth">
<number>0</number>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="undoRedoEnabled">
<bool>true</bool>
</property>
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
<property name="plainText">
<string notr="true"/>
</property>
<property name="overwriteMode">
<bool>false</bool>
</property>
<property name="tabStopWidth">
<number>80</number>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
<widget class="QFrame" name="frame_3">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
@ -2883,8 +2827,8 @@ QToolTip {
</resources>
<connections/>
<buttongroups>
<buttongroup name="buttonGroup_2"/>
<buttongroup name="buttonGroup_3"/>
<buttongroup name="buttonGroup"/>
<buttongroup name="buttonGroup_2"/>
</buttongroups>
</ui>