From: Christoph Egger Date: Fri, 28 Nov 2014 21:52:02 +0000 (+0100) Subject: Add CFGScene QGraphicsScene taking care of BasicBlock stuff X-Git-Tag: v0.1~162 X-Git-Url: https://git.siccegge.de//index.cgi?p=frida%2Ffrida.git;a=commitdiff_plain;h=6cc8f405b8d89a53f655625fe05506009130fd81 Add CFGScene QGraphicsScene taking care of BasicBlock stuff Rearranges BasicBlocks to look nicely and draws the arrows. There is lots of stuff left here like backwards edges that are just ignored for now. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 87bed5a..d5080b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,6 +42,7 @@ SET(frida_SOURCES src/main.cxx src/gui/Mainwindow.cxx src/gui/widgets/BasicBlockWidget.cxx + src/gui/widgets/CFGScene.cxx src/gui/widgets/ScriptingDock.cxx src/disassembler/Disassembler.cxx src/disassembler/llvm/LLVMDisassembler.cxx @@ -51,6 +52,7 @@ SET(frida_HEADERS src/gui/qt.hxx src/gui/Mainwindow.hxx src/gui/widgets/BasicBlockWidget.hxx + src/gui/widgets/CFGScene.hxx src/gui/widgets/ScriptingDock.hxx src/disassembler/llvm/LLVMDisassembler.hxx src/disassembler/Disassembler.hxx diff --git a/src/gui/Mainwindow.cxx b/src/gui/Mainwindow.cxx index c00c8f8..9a8310c 100644 --- a/src/gui/Mainwindow.cxx +++ b/src/gui/Mainwindow.cxx @@ -1,6 +1,7 @@ #include "Mainwindow.hxx" #include "qt.hxx" #include "disassembler/llvm/LLVMDisassembler.hxx" +#include "widgets/CFGScene.hxx" #include #include @@ -76,7 +77,7 @@ namespace { BasicBlockWidget * local__add_basic_block(BasicBlock * block, Disassembler * dis, std::map& known_blocks, - QGraphicsScene * scene, uint64_t starty, uint64_t startx) { + CFGScene * scene, uint64_t starty, uint64_t startx) { decltype(known_blocks.begin()) old; if ((old = known_blocks.find(block->getStartAddress())) != known_blocks.end()) @@ -91,7 +92,7 @@ namespace { scene->addItem(widget); widget->setFlag(QGraphicsItem::ItemIsMovable, true); - widget->moveBy(100*startx, 10*(block->getStartAddress() - starty)); + widget->moveBy(100*startx, block->getStartAddress() - starty); dis->printEachInstruction(block->getStartAddress(), block->getEndAddress(), [&](uint8_t* bytes, size_t byte_count, const std::string& line) { @@ -125,7 +126,7 @@ void Mainwindow::populateSymbolInformation(Function* fun) { QTabWidget * w = new QTabWidget(); // CFG - QGraphicsScene * scene = new QGraphicsScene; + CFGScene * scene = new CFGScene; BasicBlock * block = disassembler->getBasicBlock(fun->getStartAddress()); diff --git a/src/gui/widgets/BasicBlockWidget.hxx b/src/gui/widgets/BasicBlockWidget.hxx index bc579a9..dd2fa30 100644 --- a/src/gui/widgets/BasicBlockWidget.hxx +++ b/src/gui/widgets/BasicBlockWidget.hxx @@ -5,6 +5,7 @@ #include "disassembler/BasicBlock.hxx" #include #include +#include class BasicBlockWidget : public QGraphicsItem { @@ -15,37 +16,26 @@ public: QRectF boundingRect() const { qreal penWidth = 1; - - - if (next[0]) { - if (next[1]) { - result |= QRectF(QPointF(x + dx/3, y+dy), - mapFromScene(next[0]->getEntry())); - } else { - result |= QRectF(QPointF(x + dx/2, y+dy), - mapFromScene(next[0]->getEntry())); - } - } - if (next[1]) - result |= QRectF(QPointF(x + 2*dx/3, y+dy), - mapFromScene(next[1]->getEntry())); - QRectF result(- penWidth / 2, - penWidth / 2, width + penWidth, height + penWidth); return result; } - void mouseMoveEvent(QGraphicsSceneMouseEvent *event) { + + void mouseMoveEvent(QGraphicsSceneMouseEvent * event) { QGraphicsItem::mouseMoveEvent(event); - std::for_each(previous.begin(), previous.end(), - [&] (BasicBlockWidget * item) { - item->update(boundingRect() | item->boundingRect()); - }); + scene()->update(); } QPointF getEntry() const { return mapToScene(QPointF(width/2, 0)); } + std::tuple getExits() const { + return std::make_tuple(mapToScene(QPointF( width/3, height)), + mapToScene(QPointF( width/2, height)), + mapToScene(QPointF(2*width/3, height))); + } + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->fillRect(0, 0, width, height, QColor(0xcc, 0xcc, 0xff, 0xff)); @@ -53,24 +43,7 @@ public: painter->drawRect(0, 0, width, height); painter->drawText(5, 15, name); if (_widget.rowCount() != 0) - _widget.render(painter); - - if (next[0]) { - if (next[1]) { - painter->setPen(QColor(0x00, 0xff, 0x00, 0xff)); - painter->drawLine(QPointF(x + dx/3, y+dy), - mapFromScene(next[0]->getEntry())); - } else { - painter->setPen(QColor(0x00, 0x00, 0x00, 0xff)); - painter->drawLine(QPointF(x + dx/2, y+dy), - mapFromScene(next[0]->getEntry())); - } - } - painter->setPen(QColor(0xff, 0x00, 0x00, 0xff)); - if (next[1]) - painter->drawLine(QPointF(x + 2*dx/3, y+dy), - mapFromScene(next[1]->getEntry())); - + _widget.render(painter, QPoint(5, 20)); } void addPrevious(BasicBlockWidget * widget) { @@ -82,6 +55,10 @@ public: next[1] = right; } + BasicBlockWidget ** getNext() { + return next; + } + private: uint32_t width, height; QTableWidget _widget; diff --git a/src/gui/widgets/CFGScene.cxx b/src/gui/widgets/CFGScene.cxx new file mode 100644 index 0000000..7bed8f1 --- /dev/null +++ b/src/gui/widgets/CFGScene.cxx @@ -0,0 +1,62 @@ +#include "CFGScene.hxx" + +void CFGScene::drawBackground(QPainter* painter, const QRectF & rect) { + QGraphicsScene::drawBackground(painter, rect); + + spaceWidgets(); + + for (BasicBlockWidget * widget : widgets) { + QPointF kopf = widget->getEntry(); + painter->setPen(QColor(0x00, 0xff, 0x00, 0xff)); + painter->drawLine(kopf, kopf - QPointF(0, 20)); + + auto tails = widget->getExits(); + auto next = widget->getNext(); + if (NULL != next[0]) { + if (NULL != next[1]) { + painter->setPen(QColor(0xff, 0x00, 0x00, 0xff)); + painter->drawLine(std::get<0>(tails), std::get<0>(tails) + QPointF(0, 20)); + drawLine(painter, std::get<0>(tails) + QPointF(0, 20), next[1]->getEntry() - QPointF(0, 20)); + painter->setPen(QColor(0x00, 0xff, 0x00, 0xff)); + painter->drawLine(std::get<2>(tails), std::get<2>(tails) + QPointF(0, 20)); + drawLine(painter, std::get<2>(tails) + QPointF(0, 20), next[0]->getEntry() - QPointF(0, 20)); + } else { + painter->setPen(QColor(0x00, 0x00, 0x00, 0xff)); + painter->drawLine(std::get<1>(tails), std::get<1>(tails) + QPointF(0, 20)); + drawLine(painter, std::get<1>(tails) + QPointF(0, 20), next[0]->getEntry() - QPointF(0, 20)); + } + } + } +} + +void CFGScene::drawLine(QPainter* painter, QPointF from, QPointF to, bool left) { + if ((to - from).y() > 0) { + QPointF angle1(from + QPointF(0, (to - from).y())), angle2(to - QPointF(0, (to - from).y() / 2)); + painter->drawLine(from, angle1); + painter->drawLine(angle1, to); + } +} + +void CFGScene::spaceWidgets() { + bool changed = false; + do { + changed = false; + for (BasicBlockWidget * widget : widgets) { + QPointF out(std::get<0>(widget->getExits())); + BasicBlockWidget ** next = widget->getNext(); + + if (NULL != next[0] + && (next[0]->getEntry() - widget->getEntry()).y() > 0 + && (next[0]->getEntry() - out).y() < 50) { + next[0]->moveBy(0, 1); + changed = true; + } + if (NULL != next[1] + && (next[1]->getEntry() - widget->getEntry()).y() > 0 + && (next[1]->getEntry() - out).y() < 50) { + next[1]->moveBy(0, 1); + changed = true; + } + } + } while (changed); +} diff --git a/src/gui/widgets/CFGScene.hxx b/src/gui/widgets/CFGScene.hxx new file mode 100644 index 0000000..6baa618 --- /dev/null +++ b/src/gui/widgets/CFGScene.hxx @@ -0,0 +1,30 @@ +#ifndef INCLUDE__CFGScene_hxx +#define INCLUDE__CFGScene_hxx + +#include "gui/qt.hxx" +#include "BasicBlockWidget.hxx" + +#include + +class CFGScene : public QGraphicsScene { +public: + CFGScene(QWidget * parent = 0) + : QGraphicsScene(parent) {} + + // Take special care when adding a BasicBlock to the scene as we + // need to draw arrows for it later on + void addItem(BasicBlockWidget* block) { + widgets.push_back(block); + QGraphicsScene::addItem(block); + } + + virtual void drawBackground(QPainter* painter, const QRectF & rect); +private: + std::vector widgets; + + void drawLine(QPainter* painter, QPointF from, QPointF to, bool left = true); + + void spaceWidgets(); +}; + +#endif