mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-19 02:48:49 +00:00
First implementation of new disassembly widget
This commit is contained in:
parent
21e3944feb
commit
33dca54176
@ -20,6 +20,7 @@ Q_GLOBAL_STATIC(CutterCore, uniqueInstance)
|
|||||||
namespace RJsonKey {
|
namespace RJsonKey {
|
||||||
R_JSON_KEY(addr);
|
R_JSON_KEY(addr);
|
||||||
R_JSON_KEY(addr_end);
|
R_JSON_KEY(addr_end);
|
||||||
|
R_JSON_KEY(arrow);
|
||||||
R_JSON_KEY(baddr);
|
R_JSON_KEY(baddr);
|
||||||
R_JSON_KEY(bind);
|
R_JSON_KEY(bind);
|
||||||
R_JSON_KEY(blocks);
|
R_JSON_KEY(blocks);
|
||||||
@ -2708,6 +2709,7 @@ QList<DisassemblyLine> CutterCore::disassembleLines(RVA offset, int lines)
|
|||||||
DisassemblyLine line;
|
DisassemblyLine line;
|
||||||
line.offset = object[RJsonKey::offset].toVariant().toULongLong();
|
line.offset = object[RJsonKey::offset].toVariant().toULongLong();
|
||||||
line.text = ansiEscapeToHtml(object[RJsonKey::text].toString());
|
line.text = ansiEscapeToHtml(object[RJsonKey::text].toString());
|
||||||
|
line.arrow = object[RJsonKey::arrow].toVariant().toULongLong();
|
||||||
r << line;
|
r << line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,6 +186,7 @@ struct RAsmPluginDescription {
|
|||||||
struct DisassemblyLine {
|
struct DisassemblyLine {
|
||||||
RVA offset;
|
RVA offset;
|
||||||
QString text;
|
QString text;
|
||||||
|
RVA arrow;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BinClassBaseClassDescription {
|
struct BinClassBaseClassDescription {
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QTextBlockUserData>
|
#include <QTextBlockUserData>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QSplitter>
|
||||||
|
|
||||||
|
|
||||||
class DisassemblyTextBlockUserData: public QTextBlockUserData
|
class DisassemblyTextBlockUserData: public QTextBlockUserData
|
||||||
@ -52,13 +54,28 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
|
|||||||
|
|
||||||
setWindowTitle(getWindowTitle());
|
setWindowTitle(getWindowTitle());
|
||||||
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout();
|
// Instantiate the window layout
|
||||||
|
auto *splitter = new QSplitter;
|
||||||
|
|
||||||
|
// Setup the left frame that contains breakpoints and jumps
|
||||||
|
leftPanel = new DisassemblyLeftPanel(this);
|
||||||
|
splitter->addWidget(leftPanel);
|
||||||
|
|
||||||
|
// Setup the disassembly content
|
||||||
|
auto *layout = new QHBoxLayout;
|
||||||
layout->addWidget(mDisasTextEdit);
|
layout->addWidget(mDisasTextEdit);
|
||||||
layout->setMargin(0);
|
layout->setMargin(0);
|
||||||
mDisasScrollArea->viewport()->setLayout(layout);
|
mDisasScrollArea->viewport()->setLayout(layout);
|
||||||
mDisasScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
splitter->addWidget(mDisasScrollArea);
|
||||||
|
|
||||||
setWidget(mDisasScrollArea);
|
// Set current widget to the splitted layout we just created
|
||||||
|
setWidget(splitter);
|
||||||
|
|
||||||
|
// Resize properly
|
||||||
|
QList<int> sizes;
|
||||||
|
sizes.append(3);
|
||||||
|
sizes.append(1); // TODO Probably not the best way to go
|
||||||
|
splitter->setSizes(sizes);
|
||||||
|
|
||||||
setAllowedAreas(Qt::AllDockWidgetAreas);
|
setAllowedAreas(Qt::AllDockWidgetAreas);
|
||||||
|
|
||||||
@ -214,6 +231,16 @@ QString DisassemblyWidget::getWidgetType()
|
|||||||
return "Disassembly";
|
return "Disassembly";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFontMetrics DisassemblyWidget::getFontMetrics()
|
||||||
|
{
|
||||||
|
return mDisasTextEdit->fontMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<DisassemblyLine> DisassemblyWidget::getLines()
|
||||||
|
{
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
void DisassemblyWidget::refreshDisasm(RVA offset)
|
void DisassemblyWidget::refreshDisasm(RVA offset)
|
||||||
{
|
{
|
||||||
if(!disasmRefresh->attemptRefresh(offset == RVA_INVALID ? nullptr : new RVA(offset))) {
|
if(!disasmRefresh->attemptRefresh(offset == RVA_INVALID ? nullptr : new RVA(offset))) {
|
||||||
@ -239,11 +266,12 @@ void DisassemblyWidget::refreshDisasm(RVA offset)
|
|||||||
int horizontalScrollValue = mDisasTextEdit->horizontalScrollBar()->value();
|
int horizontalScrollValue = mDisasTextEdit->horizontalScrollBar()->value();
|
||||||
mDisasTextEdit->setLockScroll(true); // avoid flicker
|
mDisasTextEdit->setLockScroll(true); // avoid flicker
|
||||||
|
|
||||||
QList<DisassemblyLine> disassemblyLines;
|
// Retrieve disassembly lines
|
||||||
{
|
{
|
||||||
TempConfig tempConfig;
|
TempConfig tempConfig;
|
||||||
tempConfig.set("scr.color", COLOR_MODE_16M);
|
tempConfig.set("scr.color", COLOR_MODE_16M)
|
||||||
disassemblyLines = Core()->disassembleLines(topOffset, maxLines);
|
.set("asm.lines", false);
|
||||||
|
lines = Core()->disassembleLines(topOffset, maxLines);
|
||||||
}
|
}
|
||||||
|
|
||||||
connectCursorPositionChanged(true);
|
connectCursorPositionChanged(true);
|
||||||
@ -251,7 +279,7 @@ void DisassemblyWidget::refreshDisasm(RVA offset)
|
|||||||
mDisasTextEdit->document()->clear();
|
mDisasTextEdit->document()->clear();
|
||||||
QTextCursor cursor(mDisasTextEdit->document());
|
QTextCursor cursor(mDisasTextEdit->document());
|
||||||
QTextBlockFormat regular = cursor.blockFormat();
|
QTextBlockFormat regular = cursor.blockFormat();
|
||||||
for (const DisassemblyLine &line : disassemblyLines) {
|
for (const DisassemblyLine &line : lines) {
|
||||||
if (line.offset < topOffset) { // overflow
|
if (line.offset < topOffset) { // overflow
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -267,8 +295,8 @@ void DisassemblyWidget::refreshDisasm(RVA offset)
|
|||||||
cursor.setBlockFormat(regular);
|
cursor.setBlockFormat(regular);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!disassemblyLines.isEmpty()) {
|
if (!lines.isEmpty()) {
|
||||||
bottomOffset = disassemblyLines[qMin(disassemblyLines.size(), maxLines) - 1].offset;
|
bottomOffset = lines[qMin(lines.size(), maxLines) - 1].offset;
|
||||||
if (bottomOffset < topOffset) {
|
if (bottomOffset < topOffset) {
|
||||||
bottomOffset = RVA_MAX;
|
bottomOffset = RVA_MAX;
|
||||||
}
|
}
|
||||||
@ -290,6 +318,9 @@ void DisassemblyWidget::refreshDisasm(RVA offset)
|
|||||||
|
|
||||||
mDisasTextEdit->setLockScroll(false);
|
mDisasTextEdit->setLockScroll(false);
|
||||||
mDisasTextEdit->horizontalScrollBar()->setValue(horizontalScrollValue);
|
mDisasTextEdit->horizontalScrollBar()->setValue(horizontalScrollValue);
|
||||||
|
|
||||||
|
// Refresh the left panel (trigger paintEvent)
|
||||||
|
leftPanel->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -729,3 +760,87 @@ void DisassemblyWidget::seekPrev()
|
|||||||
{
|
{
|
||||||
Core()->seekPrev();
|
Core()->seekPrev();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* Left panel
|
||||||
|
*********************/
|
||||||
|
DisassemblyLeftPanel::DisassemblyLeftPanel(DisassemblyWidget *disas)
|
||||||
|
{
|
||||||
|
this->disas = disas;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DisassemblyLeftPanel::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
|
||||||
|
RVA currentOffset = Core()->getOffset(); // TODO Use the seekable from DisassemblyWidget
|
||||||
|
int rightOffset = size().rwidth();
|
||||||
|
int lineHeight = disas->getFontMetrics().height();
|
||||||
|
QColor arrowColor = ConfigColor("flow");
|
||||||
|
QPainter p(this);
|
||||||
|
QPen pen(arrowColor, 1, Qt::SolidLine, Qt::FlatCap, Qt::RoundJoin);
|
||||||
|
p.setPen(pen);
|
||||||
|
|
||||||
|
QList<DisassemblyLine> lines = disas->getLines();
|
||||||
|
|
||||||
|
// Precompute pixel position of the arrows
|
||||||
|
// TODO This can probably be done in another loop for performance purposes
|
||||||
|
QMap<RVA, int> linesPixPosition;
|
||||||
|
int i = 0;
|
||||||
|
int baseOffset = lineHeight / 2;
|
||||||
|
for (auto l : lines) {
|
||||||
|
linesPixPosition[l.offset] = i * lineHeight + baseOffset;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the lines
|
||||||
|
// TODO Use better var names
|
||||||
|
QPolygon arrow;
|
||||||
|
int direction;
|
||||||
|
int lineFinalHeight;
|
||||||
|
int lineOffset = 10;
|
||||||
|
for (auto l : lines) {
|
||||||
|
// Skip until we reach a line that jumps to a destination
|
||||||
|
if (l.arrow == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute useful variables
|
||||||
|
if (l.arrow > currentOffset) {
|
||||||
|
direction = 1;
|
||||||
|
} else {
|
||||||
|
direction = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool endVisible = true;
|
||||||
|
int currentLineYPos = linesPixPosition[l.offset];
|
||||||
|
lineFinalHeight = linesPixPosition.value(l.arrow, -1);
|
||||||
|
|
||||||
|
if (lineFinalHeight == -1) {
|
||||||
|
if (direction == 1) {
|
||||||
|
lineFinalHeight = 0;
|
||||||
|
} else {
|
||||||
|
lineFinalHeight = size().height();
|
||||||
|
}
|
||||||
|
endVisible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the lines
|
||||||
|
p.drawLine(rightOffset, currentLineYPos, rightOffset - lineOffset, currentLineYPos);
|
||||||
|
p.drawLine(rightOffset - lineOffset, currentLineYPos, rightOffset - lineOffset, lineFinalHeight);
|
||||||
|
|
||||||
|
if (endVisible) {
|
||||||
|
p.drawLine(rightOffset - lineOffset, lineFinalHeight, rightOffset, lineFinalHeight);
|
||||||
|
|
||||||
|
// Draw the arrow
|
||||||
|
arrow.clear();
|
||||||
|
arrow.append(QPoint(rightOffset - 3, lineFinalHeight + 3));
|
||||||
|
arrow.append(QPoint(rightOffset - 3, lineFinalHeight - 3));
|
||||||
|
arrow.append(QPoint(rightOffset, lineFinalHeight));
|
||||||
|
}
|
||||||
|
p.drawConvexPolygon(arrow);
|
||||||
|
|
||||||
|
// Shift next jump line
|
||||||
|
lineOffset += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "MemoryDockWidget.h"
|
#include "MemoryDockWidget.h"
|
||||||
#include "common/CutterSeekable.h"
|
#include "common/CutterSeekable.h"
|
||||||
#include "common/RefreshDeferrer.h"
|
#include "common/RefreshDeferrer.h"
|
||||||
|
#include "common/CachedFontMetrics.h"
|
||||||
|
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
@ -15,6 +16,7 @@
|
|||||||
class DisassemblyTextEdit;
|
class DisassemblyTextEdit;
|
||||||
class DisassemblyScrollArea;
|
class DisassemblyScrollArea;
|
||||||
class DisassemblyContextMenu;
|
class DisassemblyContextMenu;
|
||||||
|
class DisassemblyLeftPanel;
|
||||||
|
|
||||||
class DisassemblyWidget : public MemoryDockWidget
|
class DisassemblyWidget : public MemoryDockWidget
|
||||||
{
|
{
|
||||||
@ -32,6 +34,8 @@ public slots:
|
|||||||
void colorsUpdatedSlot();
|
void colorsUpdatedSlot();
|
||||||
void seekPrev();
|
void seekPrev();
|
||||||
void setPreviewMode(bool previewMode);
|
void setPreviewMode(bool previewMode);
|
||||||
|
QFontMetrics getFontMetrics();
|
||||||
|
QList<DisassemblyLine> getLines();
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void on_seekChanged(RVA offset);
|
void on_seekChanged(RVA offset);
|
||||||
@ -49,6 +53,8 @@ protected:
|
|||||||
DisassemblyContextMenu *mCtxMenu;
|
DisassemblyContextMenu *mCtxMenu;
|
||||||
DisassemblyScrollArea *mDisasScrollArea;
|
DisassemblyScrollArea *mDisasScrollArea;
|
||||||
DisassemblyTextEdit *mDisasTextEdit;
|
DisassemblyTextEdit *mDisasTextEdit;
|
||||||
|
DisassemblyLeftPanel *leftPanel;
|
||||||
|
QList<DisassemblyLine> lines;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RVA topOffset;
|
RVA topOffset;
|
||||||
@ -128,4 +134,18 @@ private:
|
|||||||
bool lockScroll;
|
bool lockScroll;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class This class is used to draw the left pane of the disassembly
|
||||||
|
* widget. Its goal is to draw proper arrows for the jumps of the disassembly.
|
||||||
|
*/
|
||||||
|
class DisassemblyLeftPanel: public QFrame
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DisassemblyLeftPanel(DisassemblyWidget *disas);
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DisassemblyWidget *disas;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // DISASSEMBLYWIDGET_H
|
#endif // DISASSEMBLYWIDGET_H
|
||||||
|
Loading…
Reference in New Issue
Block a user