mirror of
https://github.com/rizinorg/cutter.git
synced 2025-02-21 14:16:08 +00:00
Overview optimization (#1262)
* Overview optimization * Better cache algorithm * Fix a bug of the multiple graphs
This commit is contained in:
parent
31a832c34d
commit
0be50ac36f
@ -200,7 +200,10 @@ void MainWindow::initUI()
|
|||||||
connect(ui->actionOverview, &QAction::toggled, [this](bool checked) {
|
connect(ui->actionOverview, &QAction::toggled, [this](bool checked) {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
overviewDock->userClosed = false;
|
overviewDock->userClosed = false;
|
||||||
adjustOverview();
|
forceUpdateOverview();
|
||||||
|
if (targetGraphDock) {
|
||||||
|
toggleOverview(true, targetGraphDock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
sectionsDock = new SectionsWidget(this, ui->actionSections);
|
sectionsDock = new SectionsWidget(this, ui->actionSections);
|
||||||
@ -298,34 +301,35 @@ void MainWindow::toggleOverview(bool visibility, GraphWidget *targetGraph)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
targetGraphDock = targetGraph;
|
targetGraphDock = targetGraph;
|
||||||
connect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(adjustOverview()));
|
connect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverview()));
|
||||||
connect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(adjustOverview()));
|
connect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(updateOverview()));
|
||||||
connect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(adjustOverview()));
|
connect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(updateOverview()));
|
||||||
connect(targetGraphDock, &GraphWidget::graphClose, [this]() {
|
connect(targetGraphDock, &GraphWidget::graphClose, [this]() {
|
||||||
disconnectOverview();
|
disconnectOverview();
|
||||||
enableOverviewMenu(false);
|
enableOverviewMenu(false);
|
||||||
overviewDock->hide();
|
overviewDock->hide();
|
||||||
});
|
});
|
||||||
connect(overviewDock->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph()));
|
connect(overviewDock->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph()));
|
||||||
connect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::adjustOverview);
|
connect(overviewDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverviewAddr()));
|
||||||
|
connect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::forceUpdateOverview);
|
||||||
connect(overviewDock, &OverviewWidget::graphClose, [this]() {
|
connect(overviewDock, &OverviewWidget::graphClose, [this]() {
|
||||||
ui->actionOverview->setChecked(false);
|
ui->actionOverview->setChecked(false);
|
||||||
if (!core->isGraphEmpty()) {
|
if (!core->isGraphEmpty()) {
|
||||||
overviewDock->userClosed = true;
|
overviewDock->userClosed = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(overviewDock, SIGNAL(resized()), this, SLOT(adjustOverview()));
|
connect(overviewDock, SIGNAL(resized()), this, SLOT(forceUpdateOverview()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::disconnectOverview()
|
void MainWindow::disconnectOverview()
|
||||||
{
|
{
|
||||||
disconnect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(adjustOverview()));
|
disconnect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverview()));
|
||||||
disconnect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(adjustOverview()));
|
disconnect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(updateOverview()));
|
||||||
disconnect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(adjustOverview()));
|
disconnect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(updateOverview()));
|
||||||
disconnect(overviewDock->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph()));
|
disconnect(overviewDock->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph()));
|
||||||
disconnect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::adjustOverview);
|
disconnect(overviewDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverviewAddr()));
|
||||||
disconnect(overviewDock, SIGNAL(resized()), this, SLOT(adjustOverview()));
|
disconnect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::forceUpdateOverview);
|
||||||
disconnect(overviewDock, &QDockWidget::visibilityChanged, this, nullptr);
|
disconnect(overviewDock, SIGNAL(resized()), this, SLOT(forceUpdateOverview()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setOverviewData()
|
void MainWindow::setOverviewData()
|
||||||
@ -334,17 +338,50 @@ void MainWindow::setOverviewData()
|
|||||||
targetGraphDock->graphView->getHeight(), targetGraphDock->graphView->getBlocks());
|
targetGraphDock->graphView->getHeight(), targetGraphDock->graphView->getBlocks());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::adjustOverview()
|
bool MainWindow::isOverviewActive()
|
||||||
{
|
{
|
||||||
if (!overviewDock || overviewDock->userClosed) {
|
if (!overviewDock || overviewDock->userClosed) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (core->isGraphEmpty()) {
|
if (core->isGraphEmpty()) {
|
||||||
enableOverviewMenu(false);
|
enableOverviewMenu(false);
|
||||||
overviewDock->hide();
|
overviewDock->hide();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateOverviewAddr()
|
||||||
|
{
|
||||||
|
overviewDock->graphView->currentFcnAddr = targetGraphDock->graphView->currentFcnAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::forceUpdateOverview()
|
||||||
|
{
|
||||||
|
if (!isOverviewActive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
overviewDock->graphView->useCache = false;
|
||||||
setOverviewData();
|
setOverviewData();
|
||||||
|
drawOverview();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateOverview()
|
||||||
|
{
|
||||||
|
if (!isOverviewActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (overviewDock->graphView->currentFcnAddr != targetGraphDock->graphView->currentFcnAddr) {
|
||||||
|
overviewDock->graphView->useCache = false;
|
||||||
|
setOverviewData();
|
||||||
|
} else {
|
||||||
|
overviewDock->graphView->useCache = true;
|
||||||
|
}
|
||||||
|
drawOverview();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::drawOverview()
|
||||||
|
{
|
||||||
qreal curScale = overviewDock->graphView->current_scale;
|
qreal curScale = overviewDock->graphView->current_scale;
|
||||||
qreal baseScale = targetGraphDock->graphView->current_scale;
|
qreal baseScale = targetGraphDock->graphView->current_scale;
|
||||||
qreal w = targetGraphDock->graphView->viewport()->width() * curScale / baseScale;
|
qreal w = targetGraphDock->graphView->viewport()->width() * curScale / baseScale;
|
||||||
|
@ -137,10 +137,6 @@ public slots:
|
|||||||
void openNewFileFailed();
|
void openNewFileFailed();
|
||||||
|
|
||||||
void toggleOverview(bool visibility, GraphWidget *targetGraph);
|
void toggleOverview(bool visibility, GraphWidget *targetGraph);
|
||||||
void disconnectOverview();
|
|
||||||
void adjustOverview();
|
|
||||||
void adjustGraph();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_actionAbout_triggered();
|
void on_actionAbout_triggered();
|
||||||
void on_actionIssue_triggered();
|
void on_actionIssue_triggered();
|
||||||
@ -193,6 +189,13 @@ private slots:
|
|||||||
void changeDebugView();
|
void changeDebugView();
|
||||||
void changeDefinedView();
|
void changeDefinedView();
|
||||||
|
|
||||||
|
void disconnectOverview();
|
||||||
|
void updateOverview();
|
||||||
|
void forceUpdateOverview();
|
||||||
|
void updateOverviewAddr();
|
||||||
|
void drawOverview();
|
||||||
|
void adjustGraph();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CutterCore *core;
|
CutterCore *core;
|
||||||
|
|
||||||
@ -271,6 +274,7 @@ private:
|
|||||||
|
|
||||||
void updateDockActionsChecked();
|
void updateDockActionsChecked();
|
||||||
void setOverviewData();
|
void setOverviewData();
|
||||||
|
bool isOverviewActive();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // MAINWINDOW_H
|
#endif // MAINWINDOW_H
|
||||||
|
@ -182,6 +182,7 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||||||
QJsonArray functions;
|
QJsonArray functions;
|
||||||
RAnalFunction *fcn = Core()->functionAt(seekable->getOffset());
|
RAnalFunction *fcn = Core()->functionAt(seekable->getOffset());
|
||||||
if (fcn) {
|
if (fcn) {
|
||||||
|
currentFcnAddr = fcn->addr;
|
||||||
QJsonDocument functionsDoc = Core()->cmdj("agJ " + RAddressString(fcn->addr));
|
QJsonDocument functionsDoc = Core()->cmdj("agJ " + RAddressString(fcn->addr));
|
||||||
functions = functionsDoc.array();
|
functions = functionsDoc.array();
|
||||||
}
|
}
|
||||||
@ -211,14 +212,8 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||||||
// Refresh global "empty graph" variable so other widget know there is nothing to show here
|
// Refresh global "empty graph" variable so other widget know there is nothing to show here
|
||||||
Core()->setGraphEmpty(emptyGraph);
|
Core()->setGraphEmpty(emptyGraph);
|
||||||
|
|
||||||
Analysis anal;
|
|
||||||
anal.ready = true;
|
|
||||||
|
|
||||||
QJsonValue funcRef = functions.first();
|
QJsonValue funcRef = functions.first();
|
||||||
QJsonObject func = funcRef.toObject();
|
QJsonObject func = funcRef.toObject();
|
||||||
Function f;
|
|
||||||
f.ready = true;
|
|
||||||
f.entry = func["offset"].toVariant().toULongLong();
|
|
||||||
|
|
||||||
windowTitle = tr("Graph");
|
windowTitle = tr("Graph");
|
||||||
QString funcName = func["name"].toString().trimmed();
|
QString funcName = func["name"].toString().trimmed();
|
||||||
@ -312,15 +307,10 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||||||
}
|
}
|
||||||
disassembly_blocks[db.entry] = db;
|
disassembly_blocks[db.entry] = db;
|
||||||
prepareGraphNode(gb);
|
prepareGraphNode(gb);
|
||||||
f.blocks.push_back(db);
|
|
||||||
|
|
||||||
addBlock(gb);
|
addBlock(gb);
|
||||||
}
|
}
|
||||||
|
|
||||||
anal.functions[f.entry] = f;
|
|
||||||
anal.status = "Ready.";
|
|
||||||
anal.entry = f.entry;
|
|
||||||
|
|
||||||
if (!func["blocks"].toArray().isEmpty()) {
|
if (!func["blocks"].toArray().isEmpty()) {
|
||||||
computeGraph(entry);
|
computeGraph(entry);
|
||||||
}
|
}
|
||||||
|
@ -83,32 +83,6 @@ class DisassemblerGraphView : public GraphView
|
|||||||
bool indirectcall = false;
|
bool indirectcall = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Function {
|
|
||||||
bool ready;
|
|
||||||
ut64 entry;
|
|
||||||
ut64 update_id;
|
|
||||||
std::vector<DisassemblyBlock> blocks;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Analysis {
|
|
||||||
ut64 entry = 0;
|
|
||||||
std::unordered_map<ut64, Function> functions;
|
|
||||||
bool ready = false;
|
|
||||||
ut64 update_id = 0;
|
|
||||||
QString status = "Analyzing...";
|
|
||||||
|
|
||||||
bool find_instr(ut64 addr, ut64 &func, ut64 &instr)
|
|
||||||
{
|
|
||||||
//TODO implement
|
|
||||||
Q_UNUSED(addr);
|
|
||||||
Q_UNUSED(func);
|
|
||||||
Q_UNUSED(instr);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//dummy class
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DisassemblerGraphView(QWidget *parent);
|
DisassemblerGraphView(QWidget *parent);
|
||||||
~DisassemblerGraphView() override;
|
~DisassemblerGraphView() override;
|
||||||
@ -129,7 +103,6 @@ public:
|
|||||||
|
|
||||||
int getWidth() { return width; }
|
int getWidth() { return width; }
|
||||||
int getHeight() { return height; }
|
int getHeight() { return height; }
|
||||||
|
|
||||||
std::unordered_map<ut64, GraphBlock> getBlocks() { return blocks; }
|
std::unordered_map<ut64, GraphBlock> getBlocks() { return blocks; }
|
||||||
public slots:
|
public slots:
|
||||||
void refreshView();
|
void refreshView();
|
||||||
|
@ -381,7 +381,12 @@ QPolygonF GraphView::recalculatePolygon(QPolygonF polygon)
|
|||||||
void GraphView::paintEvent(QPaintEvent *event)
|
void GraphView::paintEvent(QPaintEvent *event)
|
||||||
{
|
{
|
||||||
Q_UNUSED(event);
|
Q_UNUSED(event);
|
||||||
QPainter p(viewport());
|
if (useCache) {
|
||||||
|
drawGraph();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pixmap = QPixmap(viewport()->width(), viewport()->height());
|
||||||
|
QPainter p(&pixmap);
|
||||||
|
|
||||||
p.setRenderHint(QPainter::Antialiasing);
|
p.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
@ -436,10 +441,18 @@ void GraphView::paintEvent(QPaintEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drawGraph();
|
||||||
emit refreshBlock();
|
emit refreshBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphView::drawGraph()
|
||||||
|
{
|
||||||
|
QRectF target(0.0, 0.0, viewport()->width(), viewport()->height());
|
||||||
|
QRectF source(0.0, 0.0, viewport()->width(), viewport()->height());
|
||||||
|
QPainter p(viewport());
|
||||||
|
p.drawPixmap(target, pixmap, source);
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare graph
|
// Prepare graph
|
||||||
// This computes the position and (row/col based) size of the block
|
// This computes the position and (row/col based) size of the block
|
||||||
// Recursively calls itself for each child of the GraphBlock
|
// Recursively calls itself for each child of the GraphBlock
|
||||||
|
@ -104,6 +104,18 @@ public:
|
|||||||
int offset_x = 0;
|
int offset_x = 0;
|
||||||
int offset_y = 0;
|
int offset_y = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief flag to control if the cached pixmap should be used
|
||||||
|
*/
|
||||||
|
bool useCache = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief keep the current addr of the fcn of Graph
|
||||||
|
* Everytime overview updates its contents, it compares this value with the one in Graph
|
||||||
|
* if they aren't same, then Overview needs to update the pixmap cache.
|
||||||
|
*/
|
||||||
|
ut64 currentFcnAddr = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::unordered_map<ut64, GraphBlock> blocks;
|
std::unordered_map<ut64, GraphBlock> blocks;
|
||||||
QColor backgroundColor = QColor(Qt::white);
|
QColor backgroundColor = QColor(Qt::white);
|
||||||
@ -129,6 +141,7 @@ protected:
|
|||||||
virtual void wheelEvent(QWheelEvent *event) override;
|
virtual void wheelEvent(QWheelEvent *event) override;
|
||||||
virtual EdgeConfiguration edgeConfiguration(GraphView::GraphBlock &from, GraphView::GraphBlock *to);
|
virtual EdgeConfiguration edgeConfiguration(GraphView::GraphBlock &from, GraphView::GraphBlock *to);
|
||||||
|
|
||||||
|
void drawGraph();
|
||||||
bool event(QEvent *event) override;
|
bool event(QEvent *event) override;
|
||||||
|
|
||||||
// Mouse events
|
// Mouse events
|
||||||
@ -142,6 +155,12 @@ protected:
|
|||||||
void centerY();
|
void centerY();
|
||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief pixmap that caches the graph nodes
|
||||||
|
*/
|
||||||
|
QPixmap pixmap;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool checkPointClicked(QPointF &point, int x, int y, bool above_y = false);
|
bool checkPointClicked(QPointF &point, int x, int y, bool above_y = false);
|
||||||
|
|
||||||
|
@ -19,14 +19,14 @@ void OverviewView::setData(int baseWidth, int baseHeight, std::unordered_map<ut6
|
|||||||
width = baseWidth;
|
width = baseWidth;
|
||||||
height = baseHeight;
|
height = baseHeight;
|
||||||
blocks = baseBlocks;
|
blocks = baseBlocks;
|
||||||
refreshView();
|
scaleAndCenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
OverviewView::~OverviewView()
|
OverviewView::~OverviewView()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverviewView::refreshView()
|
void OverviewView::scaleAndCenter()
|
||||||
{
|
{
|
||||||
current_scale = (qreal)viewport()->width() / width;
|
current_scale = (qreal)viewport()->width() / width;
|
||||||
qreal h_scale = (qreal)viewport()->height() / height;
|
qreal h_scale = (qreal)viewport()->height() / height;
|
||||||
@ -34,6 +34,11 @@ void OverviewView::refreshView()
|
|||||||
current_scale = h_scale;
|
current_scale = h_scale;
|
||||||
}
|
}
|
||||||
center();
|
center();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OverviewView::refreshView()
|
||||||
|
{
|
||||||
|
scaleAndCenter();
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +99,7 @@ void OverviewView::mousePressEvent(QMouseEvent *event)
|
|||||||
qreal x = event->localPos().x() - w / 2;
|
qreal x = event->localPos().x() - w / 2;
|
||||||
qreal y = event->localPos().y() - h / 2;
|
qreal y = event->localPos().y() - h / 2;
|
||||||
rangeRect = QRectF(x, y, w, h);
|
rangeRect = QRectF(x, y, w, h);
|
||||||
|
useCache = true;
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
emit mouseMoved();
|
emit mouseMoved();
|
||||||
mouseContainsRect(event);
|
mouseContainsRect(event);
|
||||||
@ -113,6 +119,7 @@ void OverviewView::mouseMoveEvent(QMouseEvent *event)
|
|||||||
qreal x = event->localPos().x() - initialDiff.x();
|
qreal x = event->localPos().x() - initialDiff.x();
|
||||||
qreal y = event->localPos().y() - initialDiff.y();
|
qreal y = event->localPos().y() - initialDiff.y();
|
||||||
rangeRect = QRectF(x, y, rangeRect.width(), rangeRect.height());
|
rangeRect = QRectF(x, y, rangeRect.width(), rangeRect.height());
|
||||||
|
useCache = true;
|
||||||
viewport()->update();
|
viewport()->update();
|
||||||
emit mouseMoved();
|
emit mouseMoved();
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/**
|
/**
|
||||||
* @brief refresh the view and adjust the scale
|
* @brief scale and center all nodes in, then run update
|
||||||
*/
|
*/
|
||||||
void refreshView();
|
void refreshView();
|
||||||
|
|
||||||
@ -79,6 +79,11 @@ private:
|
|||||||
*/
|
*/
|
||||||
QPointF initialDiff;
|
QPointF initialDiff;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief calculate the scale to fit the all nodes in and center them in the viewport
|
||||||
|
*/
|
||||||
|
void scaleAndCenter();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief draw the computed blocks passed by Graph
|
* @brief draw the computed blocks passed by Graph
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user