Graphs : Added Graphs being displayed for the disassembled address with ability to click on branch instruction to display destination blocks
Known issue : scrollbars don't always show when needed nor do they hide when not required..., also depending of the first graph added to the scene, scene position will be displayed on a different position depending on the graph size
This commit is contained in:
parent
d3d986a83d
commit
40ebf00a54
|
|
@ -1236,6 +1236,12 @@ BRIDGE_IMPEXP void GuiDumpAtN(duint va, int index)
|
|||
_gui_sendmessage(GUI_DUMP_AT_N, (void*)va, (void*)index);
|
||||
}
|
||||
|
||||
BRIDGE_IMPEXP void GuiSetControlFlowInfos(CONTROLFLOWINFOS *ctrlFlow)
|
||||
{
|
||||
_gui_sendmessage(GUI_SET_CONTROLFLOWINFOS, (void*) ctrlFlow, nullptr);
|
||||
}
|
||||
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
hInst = hinstDLL;
|
||||
|
|
|
|||
|
|
@ -782,6 +782,7 @@ typedef enum
|
|||
GUI_SET_DEBUGGEE_NOTES, // param1=const char* text, param2=unused
|
||||
GUI_GET_DEBUGGEE_NOTES, // param1=char** text, param2=unused
|
||||
GUI_DUMP_AT_N, // param1=int index, param2=duint va
|
||||
GUI_SET_CONTROLFLOWINFOS // param1=duint *infos, param2=unused
|
||||
} GUIMSG;
|
||||
|
||||
//GUI Typedefs
|
||||
|
|
@ -807,6 +808,12 @@ typedef struct
|
|||
duint size;
|
||||
} ICONDATA;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
duint *blocks;
|
||||
duint *parents;
|
||||
} CONTROLFLOWINFOS;
|
||||
|
||||
//GUI functions
|
||||
BRIDGE_IMPEXP void GuiDisasmAt(duint addr, duint cip);
|
||||
BRIDGE_IMPEXP void GuiSetDebugState(DBGSTATE state);
|
||||
|
|
@ -880,6 +887,7 @@ BRIDGE_IMPEXP void GuiGetGlobalNotes(char** text);
|
|||
BRIDGE_IMPEXP void GuiSetDebuggeeNotes(const char* text);
|
||||
BRIDGE_IMPEXP void GuiGetDebuggeeNotes(char** text);
|
||||
BRIDGE_IMPEXP void GuiDumpAtN(duint va, int index);
|
||||
BRIDGE_IMPEXP void GuiSetControlFlowInfos(CONTROLFLOWINFOS *ctrlFlow);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,15 @@ void ControlFlowAnalysis::Analyse()
|
|||
ticks = GetTickCount();
|
||||
|
||||
dprintf("Analysis finished!\n");
|
||||
|
||||
PARENTMAP *_parentsTemp = new PARENTMAP(_parentMap);
|
||||
BASICBLOCKMAP *_blocksTemp = new BASICBLOCKMAP(_blocks);
|
||||
|
||||
CONTROLFLOWINFOS *ctrlFlow = new CONTROLFLOWINFOS;
|
||||
ctrlFlow->blocks = (duint*) _blocksTemp;
|
||||
ctrlFlow->parents = (duint*) _parentsTemp;
|
||||
|
||||
GuiSetControlFlowInfos(ctrlFlow);
|
||||
}
|
||||
|
||||
void ControlFlowAnalysis::SetMarkers()
|
||||
|
|
@ -134,7 +143,7 @@ void ControlFlowAnalysis::SetMarkers()
|
|||
|
||||
void ControlFlowAnalysis::BasicBlockStarts()
|
||||
{
|
||||
_blockStarts.insert(_base);
|
||||
//_blockStarts.insert(_base);
|
||||
bool bSkipFilling = false;
|
||||
for(duint i = 0; i < _size;)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ private:
|
|||
};
|
||||
|
||||
typedef std::set<duint> UintSet;
|
||||
typedef std::map<duint, UintSet> PARENTMAP;
|
||||
typedef std::map<duint, BasicBlock> BASICBLOCKMAP;
|
||||
|
||||
duint _moduleBase;
|
||||
duint _functionInfoSize;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "Disassembly.h"
|
||||
#include "Configuration.h"
|
||||
#include "Bridge.h"
|
||||
#include "GraphView.h"
|
||||
|
||||
Disassembly::Disassembly(QWidget* parent) : AbstractTableView(parent)
|
||||
{
|
||||
|
|
@ -1408,6 +1409,7 @@ const dsint Disassembly::currentEIP() const
|
|||
|
||||
void Disassembly::disassembleAt(dsint parVA, dsint parCIP)
|
||||
{
|
||||
emit drawGraphAtAddress(parVA);
|
||||
disassembleAt(parVA, parCIP, true, -1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ public:
|
|||
signals:
|
||||
void selectionChanged(dsint parVA);
|
||||
void disassembledAt(dsint parVA, dsint parCIP, bool history, dsint newTableOffset);
|
||||
void drawGraphAtAddress(dsint va);
|
||||
|
||||
public slots:
|
||||
void disassembleAt(dsint parVA, dsint parCIP);
|
||||
|
|
|
|||
|
|
@ -524,6 +524,11 @@ void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
|
|||
emit dumpAtN((duint)param1, (int)param2);
|
||||
}
|
||||
break;
|
||||
case GUI_SET_CONTROLFLOWINFOS:
|
||||
{
|
||||
emit setControlFlowInfos((duint*)param1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ signals:
|
|||
void setDebuggeeNotes(const QString text);
|
||||
void getDebuggeeNotes(void* text);
|
||||
void dumpAtN(duint va, int index);
|
||||
void setControlFlowInfos(duint *controlFlowInfos);
|
||||
|
||||
private:
|
||||
QMutex* mBridgeMutex;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,241 @@
|
|||
#include "GraphEdge.h"
|
||||
|
||||
|
||||
GraphEdge::GraphEdge(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect, QBrush lineColor) : QAbstractGraphicsShapeItem()
|
||||
{
|
||||
_edgeColor = lineColor;
|
||||
|
||||
QList<QPointF> linePoints = calculateLine(start, end, bends, sourceRect, targetRect);
|
||||
// for(auto p : linePoints)
|
||||
// qDebug() << p;
|
||||
QList<QPointF> arrowPoints = calculateArrow(linePoints);
|
||||
_boundingRect = calculateBoundingRect(linePoints, arrowPoints);
|
||||
preparePainterPaths(linePoints, arrowPoints);
|
||||
}
|
||||
|
||||
QRectF GraphEdge::boundingRect() const
|
||||
{
|
||||
return _boundingRect;
|
||||
}
|
||||
|
||||
void GraphEdge::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(widget);
|
||||
|
||||
//save painter
|
||||
painter->save();
|
||||
|
||||
#ifdef _DEBUG
|
||||
//draw bounding rect
|
||||
painter->setPen(QPen(Qt::red, 1));
|
||||
painter->drawRect(boundingRect());
|
||||
#endif //_DEBUG
|
||||
|
||||
//set painter options
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int lineSize = 2;
|
||||
|
||||
//draw line
|
||||
painter->setPen(QPen(_edgeColor, lineSize));
|
||||
painter->drawPath(_line);
|
||||
|
||||
//draw arrow
|
||||
painter->setPen(QPen(_edgeColor, lineSize));
|
||||
painter->drawPath(_arrow);
|
||||
|
||||
//restore painter
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
qreal GraphEdge::calculateDistance(QPointF p1, QPointF p2)
|
||||
{
|
||||
QPointF d = p2 - p1;
|
||||
return sqrt(d.x() * d.x() + d.y() * d.y());
|
||||
}
|
||||
|
||||
QPointF GraphEdge::calculateNearestIntersect(QRectF rect, QPointF p1, QPointF p2)
|
||||
{
|
||||
/*qDebug() << "calculateNearest";
|
||||
qDebug() << "rect" << rect.topLeft() << rect.bottomRight();
|
||||
qDebug() << "p1" << p1;
|
||||
qDebug() << "p2" << p2;*/
|
||||
|
||||
//y=a*x+b
|
||||
//a = dy/dx = (p1.y-p2.y)/(p1.x-p2.x)
|
||||
//b = p1.y - p1.x;
|
||||
|
||||
qreal div = p1.x()-p2.x();
|
||||
|
||||
if(div == 0)
|
||||
{
|
||||
QPointF i1(p1.x(), rect.top());
|
||||
//qDebug() << "i1" << i1;
|
||||
QPointF i2(p1.x(), rect.bottom());
|
||||
//qDebug() << "i2" << i2;
|
||||
|
||||
if(p2.y() < p1.y())
|
||||
return i1;
|
||||
else
|
||||
return i2;
|
||||
}
|
||||
else
|
||||
{
|
||||
QPointF result;
|
||||
qreal bestDist = 10e99;
|
||||
|
||||
qreal a = (p1.y()-p2.y()) / div;
|
||||
qreal b = p1.y() - a * p1.x();
|
||||
//qDebug() << "a" << a << "b" << b;
|
||||
|
||||
//intersect 1
|
||||
//rect.top() = a*x+b;
|
||||
//x = (b - rect.top()) / -a
|
||||
QPointF i1((b - rect.top()) / -a, rect.top());
|
||||
//qDebug() << "i1" << i1;
|
||||
//qDebug() << "consider?" << rect.contains(i1);
|
||||
if(rect.contains(i1))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i1);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i1;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 2
|
||||
//rect.bottom() = a*x+b
|
||||
//x = (b - rect.bottom()) / -a
|
||||
QPointF i2((b - rect.bottom()) / -a, rect.bottom());
|
||||
//qDebug() << "i2" << i2;
|
||||
//qDebug() << "consider?" << rect.contains(i2);
|
||||
if(rect.contains(i2))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i2);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i2;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 3
|
||||
//x=rect.left()
|
||||
QPointF i3(rect.left(), a * rect.left() + b);
|
||||
//qDebug() << "i3" << i3;
|
||||
//qDebug() << "consider?" << rect.contains(i3);
|
||||
if(rect.contains(i3))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i3);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i3;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 4
|
||||
//x=rect.right()
|
||||
QPointF i4(rect.right(), a * rect.right() + b);
|
||||
//qDebug() << "i4" << i4;
|
||||
//qDebug() << "consider?" << rect.contains(i4);
|
||||
if(rect.contains(i4))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i4);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i4;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//qDebug() << " ";
|
||||
}
|
||||
|
||||
QList<QPointF> GraphEdge::calculateLine(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect)
|
||||
{
|
||||
QList<QPointF> linePoints;
|
||||
linePoints << start;
|
||||
for(auto p : bends)
|
||||
linePoints << QPointF(p.m_x, p.m_y);
|
||||
linePoints << end;
|
||||
|
||||
QPointF nearestI = calculateNearestIntersect(sourceRect, linePoints[0], linePoints[1]);
|
||||
linePoints[0]=nearestI;
|
||||
int len = linePoints.length();
|
||||
nearestI = calculateNearestIntersect(targetRect, linePoints[len-1], linePoints[len-2]);
|
||||
linePoints[len-1]=nearestI;
|
||||
|
||||
return linePoints;
|
||||
}
|
||||
|
||||
QList<QPointF> GraphEdge::calculateArrow(const QList<QPointF> & linePoints)
|
||||
{
|
||||
//arrow
|
||||
int len=linePoints.length();
|
||||
QLineF perpLine = QLineF(linePoints[len-1], linePoints[len-2]).normalVector();
|
||||
|
||||
qreal arrowLen = 6;
|
||||
|
||||
QLineF a;
|
||||
a.setP1(linePoints[len-1]);
|
||||
a.setAngle(perpLine.angle() - 45);
|
||||
a.setLength(arrowLen);
|
||||
|
||||
QLineF b;
|
||||
b.setP1(linePoints[len-1]);
|
||||
b.setAngle(perpLine.angle() - 135);
|
||||
b.setLength(arrowLen);
|
||||
|
||||
QLineF c;
|
||||
c.setP1(a.p2());
|
||||
c.setP2(b.p2());
|
||||
|
||||
QList<QPointF> arrowPoints;
|
||||
arrowPoints << a.p1() << a.p2() << b.p1() << b.p2() << c.p1() << c.p2();
|
||||
return arrowPoints;
|
||||
}
|
||||
|
||||
QRectF GraphEdge::calculateBoundingRect(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints)
|
||||
{
|
||||
QList<QPointF> allPoints;
|
||||
allPoints << linePoints << arrowPoints;
|
||||
//find top-left and bottom-right points for the bounding rect
|
||||
QPointF topLeft = allPoints[0];
|
||||
QPointF bottomRight = topLeft;
|
||||
for(auto p : allPoints)
|
||||
{
|
||||
qreal x = p.x();
|
||||
qreal y = p.y();
|
||||
|
||||
if(x < topLeft.x())
|
||||
topLeft.setX(x);
|
||||
if(y < topLeft.y())
|
||||
topLeft.setY(y);
|
||||
|
||||
if(x > bottomRight.x())
|
||||
bottomRight.setX(x);
|
||||
if(y > bottomRight.y())
|
||||
bottomRight.setY(y);
|
||||
}
|
||||
return QRectF(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
void GraphEdge::preparePainterPaths(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints)
|
||||
{
|
||||
//edge line
|
||||
QPolygonF polyLine;
|
||||
for(auto p : linePoints)
|
||||
polyLine << p;
|
||||
_line.addPolygon(polyLine);
|
||||
|
||||
//arrow
|
||||
QPolygonF polyArrow;
|
||||
for(auto p : arrowPoints)
|
||||
polyArrow << p;
|
||||
_arrow.addPolygon(polyArrow);
|
||||
}
|
||||
|
||||
|
|
@ -3,251 +3,27 @@
|
|||
|
||||
#include <ogdf/basic/geometry.h>
|
||||
#include <QGraphicsItem>
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
|
||||
class GraphEdge : public QAbstractGraphicsShapeItem
|
||||
{
|
||||
public:
|
||||
GraphEdge(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect) : QAbstractGraphicsShapeItem()
|
||||
{
|
||||
QList<QPointF> linePoints = calculateLine(start, end, bends, sourceRect, targetRect);
|
||||
for(auto p : linePoints)
|
||||
qDebug() << p;
|
||||
QList<QPointF> arrowPoints = calculateArrow(linePoints);
|
||||
_boundingRect = calculateBoundingRect(linePoints, arrowPoints);
|
||||
preparePainterPaths(linePoints, arrowPoints);
|
||||
}
|
||||
|
||||
QRectF boundingRect() const
|
||||
{
|
||||
return _boundingRect;
|
||||
}
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(widget);
|
||||
|
||||
//save painter
|
||||
painter->save();
|
||||
|
||||
#if _DEBUG
|
||||
//draw bounding rect
|
||||
painter->setPen(QPen(Qt::red, 1));
|
||||
painter->drawRect(boundingRect());
|
||||
#endif //_DEBUG
|
||||
|
||||
//set painter options
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int lineSize = 2;
|
||||
|
||||
//draw line
|
||||
painter->setPen(QPen(Qt::green, lineSize));
|
||||
painter->drawPath(_line);
|
||||
|
||||
//draw arrow
|
||||
painter->setPen(QPen(Qt::green, lineSize));
|
||||
painter->drawPath(_arrow);
|
||||
|
||||
//restore painter
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
qreal calculateDistance(QPointF p1, QPointF p2)
|
||||
{
|
||||
QPointF d = p2 - p1;
|
||||
return sqrt(d.x() * d.x() + d.y() * d.y());
|
||||
}
|
||||
|
||||
QPointF calculateNearestIntersect(QRectF rect, QPointF p1, QPointF p2)
|
||||
{
|
||||
/*qDebug() << "calculateNearest";
|
||||
qDebug() << "rect" << rect.topLeft() << rect.bottomRight();
|
||||
qDebug() << "p1" << p1;
|
||||
qDebug() << "p2" << p2;*/
|
||||
|
||||
//y=a*x+b
|
||||
//a = dy/dx = (p1.y-p2.y)/(p1.x-p2.x)
|
||||
//b = p1.y - p1.x;
|
||||
|
||||
qreal div = p1.x()-p2.x();
|
||||
|
||||
if(div == 0)
|
||||
{
|
||||
QPointF i1(p1.x(), rect.top());
|
||||
//qDebug() << "i1" << i1;
|
||||
QPointF i2(p1.x(), rect.bottom());
|
||||
//qDebug() << "i2" << i2;
|
||||
|
||||
if(p2.y() < p1.y())
|
||||
return i1;
|
||||
else
|
||||
return i2;
|
||||
}
|
||||
else
|
||||
{
|
||||
QPointF result;
|
||||
qreal bestDist = 10e99;
|
||||
|
||||
qreal a = (p1.y()-p2.y()) / div;
|
||||
qreal b = p1.y() - a * p1.x();
|
||||
//qDebug() << "a" << a << "b" << b;
|
||||
|
||||
//intersect 1
|
||||
//rect.top() = a*x+b;
|
||||
//x = (b - rect.top()) / -a
|
||||
QPointF i1((b - rect.top()) / -a, rect.top());
|
||||
//qDebug() << "i1" << i1;
|
||||
//qDebug() << "consider?" << rect.contains(i1);
|
||||
if(rect.contains(i1))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i1);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i1;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 2
|
||||
//rect.bottom() = a*x+b
|
||||
//x = (b - rect.bottom()) / -a
|
||||
QPointF i2((b - rect.bottom()) / -a, rect.bottom());
|
||||
//qDebug() << "i2" << i2;
|
||||
//qDebug() << "consider?" << rect.contains(i2);
|
||||
if(rect.contains(i2))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i2);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i2;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 3
|
||||
//x=rect.left()
|
||||
QPointF i3(rect.left(), a * rect.left() + b);
|
||||
//qDebug() << "i3" << i3;
|
||||
//qDebug() << "consider?" << rect.contains(i3);
|
||||
if(rect.contains(i3))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i3);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i3;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 4
|
||||
//x=rect.right()
|
||||
QPointF i4(rect.right(), a * rect.right() + b);
|
||||
//qDebug() << "i4" << i4;
|
||||
//qDebug() << "consider?" << rect.contains(i4);
|
||||
if(rect.contains(i4))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i4);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i4;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//qDebug() << " ";
|
||||
}
|
||||
|
||||
QList<QPointF> calculateLine(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect)
|
||||
{
|
||||
QList<QPointF> linePoints;
|
||||
linePoints << start;
|
||||
for(auto p : bends)
|
||||
linePoints << QPointF(p.m_x, p.m_y);
|
||||
linePoints << end;
|
||||
|
||||
QPointF nearestI = calculateNearestIntersect(sourceRect, linePoints[0], linePoints[1]);
|
||||
linePoints[0]=nearestI;
|
||||
int len = linePoints.length();
|
||||
nearestI = calculateNearestIntersect(targetRect, linePoints[len-1], linePoints[len-2]);
|
||||
linePoints[len-1]=nearestI;
|
||||
|
||||
return linePoints;
|
||||
}
|
||||
|
||||
QList<QPointF> calculateArrow(const QList<QPointF> & linePoints)
|
||||
{
|
||||
//arrow
|
||||
int len=linePoints.length();
|
||||
QLineF perpLine = QLineF(linePoints[len-1], linePoints[len-2]).normalVector();
|
||||
|
||||
qreal arrowLen = 6;
|
||||
|
||||
QLineF a;
|
||||
a.setP1(linePoints[len-1]);
|
||||
a.setAngle(perpLine.angle() - 45);
|
||||
a.setLength(arrowLen);
|
||||
|
||||
QLineF b;
|
||||
b.setP1(linePoints[len-1]);
|
||||
b.setAngle(perpLine.angle() - 135);
|
||||
b.setLength(arrowLen);
|
||||
|
||||
QLineF c;
|
||||
c.setP1(a.p2());
|
||||
c.setP2(b.p2());
|
||||
|
||||
QList<QPointF> arrowPoints;
|
||||
arrowPoints << a.p1() << a.p2() << b.p1() << b.p2() << c.p1() << c.p2();
|
||||
return arrowPoints;
|
||||
}
|
||||
|
||||
QRectF calculateBoundingRect(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints)
|
||||
{
|
||||
QList<QPointF> allPoints;
|
||||
allPoints << linePoints << arrowPoints;
|
||||
//find top-left and bottom-right points for the bounding rect
|
||||
QPointF topLeft = allPoints[0];
|
||||
QPointF bottomRight = topLeft;
|
||||
for(auto p : allPoints)
|
||||
{
|
||||
qreal x = p.x();
|
||||
qreal y = p.y();
|
||||
|
||||
if(x < topLeft.x())
|
||||
topLeft.setX(x);
|
||||
if(y < topLeft.y())
|
||||
topLeft.setY(y);
|
||||
|
||||
if(x > bottomRight.x())
|
||||
bottomRight.setX(x);
|
||||
if(y > bottomRight.y())
|
||||
bottomRight.setY(y);
|
||||
}
|
||||
return QRectF(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
void preparePainterPaths(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints)
|
||||
{
|
||||
//edge line
|
||||
QPolygonF polyLine;
|
||||
for(auto p : linePoints)
|
||||
polyLine << p;
|
||||
_line.addPolygon(polyLine);
|
||||
|
||||
//arrow
|
||||
QPolygonF polyArrow;
|
||||
for(auto p : arrowPoints)
|
||||
polyArrow << p;
|
||||
_arrow.addPolygon(polyArrow);
|
||||
}
|
||||
GraphEdge(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect, QBrush lineColor = Qt::green);
|
||||
QRectF boundingRect() const;
|
||||
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget);
|
||||
qreal calculateDistance(QPointF p1, QPointF p2);
|
||||
QPointF calculateNearestIntersect(QRectF rect, QPointF p1, QPointF p2);
|
||||
QList<QPointF> calculateLine(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect);
|
||||
QList<QPointF> calculateArrow(const QList<QPointF> & linePoints);
|
||||
QRectF calculateBoundingRect(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints);
|
||||
void preparePainterPaths(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints);
|
||||
|
||||
private:
|
||||
QPainterPath _line;
|
||||
QPainterPath _arrow;
|
||||
QRectF _boundingRect;
|
||||
QBrush _edgeColor;
|
||||
};
|
||||
|
||||
#endif //_GRAPH_EDGE_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,193 @@
|
|||
#include "GraphNode.h"
|
||||
|
||||
GraphNode::GraphNode()
|
||||
{
|
||||
}
|
||||
|
||||
GraphNode::GraphNode(std::vector<Instruction_t> &instructionsVector, duint address)
|
||||
{
|
||||
mAddress = address;
|
||||
mInstructionsVector = instructionsVector;
|
||||
mHighlightInstructionAt = -1;
|
||||
|
||||
updateTokensVector();
|
||||
|
||||
setStyleSheet("border: 1px solid black;");
|
||||
setContentsMargins(0,0,0,0);
|
||||
setMouseTracking(true); // required for mouse move event
|
||||
installEventFilter(this);
|
||||
}
|
||||
|
||||
GraphNode::GraphNode(const GraphNode & other)
|
||||
{
|
||||
setInstructionsVector(other.mInstructionsVector);
|
||||
}
|
||||
|
||||
GraphNode & GraphNode::operator=(const GraphNode & other)
|
||||
{
|
||||
// TODO : Complete this
|
||||
setInstructionsVector(other.mInstructionsVector);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QRectF GraphNode::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, mCachedWidth, mCachedHeight);
|
||||
}
|
||||
|
||||
void GraphNode::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
//draw node contents
|
||||
painter.setPen(Qt::black);
|
||||
painter.setFont(this->mFont);
|
||||
int i = 0;
|
||||
|
||||
int x = mSpacingX/2, y = mLineHeight + mSpacingY/2;
|
||||
|
||||
// Block address
|
||||
painter.fillRect(0, 0, mCachedWidth, mLineHeight, QBrush(Qt::magenta));
|
||||
painter.setPen(Qt::black);
|
||||
painter.drawText(0, 0, mCachedWidth, mLineHeight, Qt::AlignHCenter | Qt::AlignVCenter, "0x" + QString::number(mAddress, 16));
|
||||
|
||||
// Block instructions
|
||||
for(QList<RichTextPainter::CustomRichText_t> &richText : mRichTextVector)
|
||||
{
|
||||
RichTextPainter::paintRichText(&painter, x, y, mCachedWidth, mLineHeight, 0, &richText, QFontMetrics(this->mFont).width(QChar(' ')));
|
||||
|
||||
if(mHighlightInstructionAt == i)
|
||||
painter.fillRect(0, y, mCachedWidth, mLineHeight, QBrush(QColor(0, 0, 0, 150)));
|
||||
|
||||
y += mLineHeight + mLineSpacingY;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
dsint GraphNode::getInstructionIndexAtPos(const QPoint &pos) const
|
||||
{
|
||||
duint instructionIndex = -1;
|
||||
for(duint i = 0; i < mInstructionsVector.size(); i++)
|
||||
{
|
||||
dsint currentInstructionMinHeight = (i+1) * (mLineHeight + mLineSpacingY) + (mSpacingY/2);
|
||||
dsint currentInstructionMaxHeight = (i+2) * (mLineHeight+mLineSpacingY) + (mSpacingY/2);
|
||||
|
||||
if(pos.y() >= currentInstructionMinHeight && pos.y() <= currentInstructionMaxHeight)
|
||||
{
|
||||
instructionIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return instructionIndex;
|
||||
}
|
||||
|
||||
bool GraphNode::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
// Mouse click
|
||||
if(event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
if(mouseEvent->button() != Qt::LeftButton)
|
||||
return true;
|
||||
|
||||
duint clickedInstructionIndex = getInstructionIndexAtPos(mouseEvent->pos());
|
||||
|
||||
// No instruction clicked
|
||||
if(clickedInstructionIndex == -1)
|
||||
return true;
|
||||
|
||||
Instruction_t clickedInstruction = mInstructionsVector.at(clickedInstructionIndex);
|
||||
if(clickedInstruction.branchDestination != 0)
|
||||
emit drawGraphAt(clickedInstruction.branchDestination);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mouse move
|
||||
else if(event->type() == QEvent::MouseMove)
|
||||
{
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
mHighlightInstructionAt = getInstructionIndexAtPos(mouseEvent->pos());
|
||||
repaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Leaving widget area
|
||||
else if(event->type() == QEvent::Leave)
|
||||
{
|
||||
mHighlightInstructionAt = -1;
|
||||
repaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GraphNode::updateTokensVector()
|
||||
{
|
||||
for(duint i=0; i < mInstructionsVector.size(); i++)
|
||||
{
|
||||
mTokensVector.push_back(mInstructionsVector[i].tokens);
|
||||
}
|
||||
|
||||
updateCache();
|
||||
updateRichText();
|
||||
}
|
||||
|
||||
void GraphNode::setInstructionsVector(const std::vector<Instruction_t> &instructionsVector)
|
||||
{
|
||||
mInstructionsVector = instructionsVector;
|
||||
}
|
||||
|
||||
void GraphNode::updateCache()
|
||||
{
|
||||
QString maxInstruction = getLongestInstruction();
|
||||
|
||||
QFontMetrics metrics(this->mFont);
|
||||
mCachedWidth = metrics.width(maxInstruction) + mSpacingX;
|
||||
mCachedHeight =((metrics.height() + mLineSpacingY) * mInstructionsVector.size()) + metrics.height() + mSpacingY; // +metrics.height() => for block address line
|
||||
mLineHeight = metrics.height();
|
||||
}
|
||||
|
||||
void GraphNode::updateRichText()
|
||||
{
|
||||
for(CapstoneTokenizer::InstructionToken &token : mTokensVector)
|
||||
{
|
||||
QList<RichTextPainter::CustomRichText_t> richText;
|
||||
CapstoneTokenizer::TokenToRichText(token, richText, 0);
|
||||
mRichTextVector.push_back(richText);
|
||||
}
|
||||
}
|
||||
|
||||
QString GraphNode::getLongestInstruction()
|
||||
{
|
||||
dsint maxInstructionLength = 0;
|
||||
QString maxInstruction = "";
|
||||
|
||||
for(CapstoneTokenizer::InstructionToken &token : mTokensVector)
|
||||
{
|
||||
dsint currentInstructionLength = 0;
|
||||
QString currentInstruction = "";
|
||||
for(CapstoneTokenizer::SingleToken &singleToken : token.tokens)
|
||||
{
|
||||
currentInstructionLength += singleToken.text.length();
|
||||
currentInstruction += singleToken.text;
|
||||
}
|
||||
|
||||
if(currentInstructionLength > maxInstructionLength)
|
||||
{
|
||||
maxInstructionLength = currentInstructionLength;
|
||||
maxInstruction = currentInstruction;
|
||||
}
|
||||
}
|
||||
|
||||
return maxInstruction;
|
||||
}
|
||||
|
||||
duint GraphNode::address()
|
||||
{
|
||||
return mAddress;
|
||||
}
|
||||
|
|
@ -2,93 +2,52 @@
|
|||
#define _GRAPH_NODE_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QMouseEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QFontMetrics>
|
||||
#include <vector>
|
||||
#include "Imports.h"
|
||||
#include "RichTextPainter.h"
|
||||
#include "capstone_gui.h"
|
||||
#include "QBeaEngine.h"
|
||||
|
||||
class GraphNode : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphNode()
|
||||
{
|
||||
}
|
||||
GraphNode();
|
||||
GraphNode(std::vector<Instruction_t> &instructionsVector, duint address = 0);
|
||||
GraphNode(const GraphNode & other);
|
||||
GraphNode & operator=(const GraphNode & other);
|
||||
QRectF boundingRect() const;
|
||||
void paintEvent(QPaintEvent* event);
|
||||
dsint getInstructionIndexAtPos(const QPoint &pos) const;
|
||||
bool eventFilter(QObject *object, QEvent *event);
|
||||
// void mousePressEvent(QMouseEvent* event);
|
||||
void updateTokensVector();
|
||||
void setInstructionsVector(const std::vector<Instruction_t> &instructionsVector);
|
||||
void updateCache();
|
||||
void updateRichText();
|
||||
QString getLongestInstruction();
|
||||
duint address();
|
||||
|
||||
GraphNode(QString label)
|
||||
{
|
||||
setLabel(label);
|
||||
setStyleSheet("border: 1px solid blue");
|
||||
setContentsMargins(0,0,0,0);
|
||||
}
|
||||
|
||||
GraphNode(const GraphNode & other)
|
||||
{
|
||||
setLabel(other._label);
|
||||
}
|
||||
|
||||
GraphNode & operator=(const GraphNode & other)
|
||||
{
|
||||
setLabel(other._label);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QRectF boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, _cachedWidth, _cachedHeight);
|
||||
}
|
||||
|
||||
void paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
painter.save();
|
||||
|
||||
//draw bounding rectangle
|
||||
QRectF rect = boundingRect();
|
||||
painter.setPen(Qt::red);
|
||||
//painter.drawRect(rect);
|
||||
|
||||
//draw node contents
|
||||
painter.setPen(Qt::black);
|
||||
painter.setFont(this->_font);
|
||||
QRect textRect = QRect(_spacingX, _spacingY, rect.width() - _spacingX, rect.height() - _spacingY);
|
||||
painter.drawText(textRect, _label);
|
||||
|
||||
painter.restore();
|
||||
}
|
||||
|
||||
void mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QMessageBox::information(nullptr, "clicked", _label);
|
||||
}
|
||||
|
||||
void setLabel(const QString & label)
|
||||
{
|
||||
_label = label;
|
||||
updateCache();
|
||||
}
|
||||
|
||||
void updateCache()
|
||||
{
|
||||
QFontMetrics metrics(this->_font);
|
||||
_cachedWidth = metrics.width(this->_label) + _spacingX * 2;
|
||||
_cachedHeight = metrics.height() + _spacingY * 2;
|
||||
}
|
||||
|
||||
QString label()
|
||||
{
|
||||
return _label;
|
||||
}
|
||||
signals:
|
||||
void drawGraphAt(duint va);
|
||||
|
||||
private:
|
||||
QString _label;
|
||||
QFont _font = QFont("Lucida Console", 8, QFont::Normal, false);
|
||||
const qreal _spacingX = 3;
|
||||
const qreal _spacingY = 3;
|
||||
qreal _cachedWidth;
|
||||
qreal _cachedHeight;
|
||||
duint mHighlightInstructionAt;
|
||||
duint mAddress;
|
||||
duint mLineHeight;
|
||||
qreal mCachedWidth;
|
||||
qreal mCachedHeight;
|
||||
const duint mSpacingX = 12;
|
||||
const duint mSpacingY = 12;
|
||||
const duint mLineSpacingY = 3;
|
||||
QFont mFont = QFont("Lucida Console", 8, QFont::Normal, false);
|
||||
std::vector<Instruction_t> mInstructionsVector;
|
||||
std::vector<CapstoneTokenizer::InstructionToken> mTokensVector;
|
||||
std::vector<QList<RichTextPainter::CustomRichText_t> > mRichTextVector;
|
||||
};
|
||||
|
||||
#endif //_GRAPH_NODE_H
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@ public:
|
|||
this->_GA = GA;
|
||||
this->_ogdfNode = ogdfNode;
|
||||
this->_data = data;
|
||||
this->_left = nullptr;
|
||||
this->_right = nullptr;
|
||||
}
|
||||
|
||||
Node<T>* setLeft(Node* left)
|
||||
{
|
||||
return left ? this->_left = makeNodeWithEdge(left) : nullptr;
|
||||
}
|
||||
|
||||
Node<T>* setRight(Node* right)
|
||||
{
|
||||
return right ? this->_right = makeNodeWithEdge(right) : nullptr;
|
||||
|
|
@ -36,17 +36,14 @@ public:
|
|||
{
|
||||
return this->_left;
|
||||
}
|
||||
|
||||
Node<T>* right()
|
||||
{
|
||||
return this->_right;
|
||||
}
|
||||
|
||||
T data()
|
||||
{
|
||||
return this->_data;
|
||||
}
|
||||
|
||||
ogdf::node ogdfNode()
|
||||
{
|
||||
return this->_ogdfNode;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,12 @@
|
|||
#include <vector>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <QMessageBox>
|
||||
#include <ogdf/basic/Graph.h>
|
||||
#include <ogdf/basic/GraphAttributes.h>
|
||||
#include "Imports.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
template <typename T>
|
||||
class Tree
|
||||
|
|
@ -18,27 +22,56 @@ public:
|
|||
this->_G = G;
|
||||
this->_GA = GA;
|
||||
}
|
||||
|
||||
Node<T>* newNode(T data)
|
||||
{
|
||||
auto ogdfNode = _G->newNode();
|
||||
auto node = new Node<T>(_G, _GA, ogdfNode, data);
|
||||
ogdf::node ogdfNode = _G->newNode();
|
||||
Node<T> *node = new Node<T>(_G, _GA, ogdfNode, data);
|
||||
_ogdfDataMap[ogdfNode] = node;
|
||||
_nodePool.push_back(std::unique_ptr<Node<T>>(node));
|
||||
_nodePool.push_back(unique_ptr<Node<T>>(node));
|
||||
return node;
|
||||
}
|
||||
|
||||
Node<T>* findNode(ogdf::node ogdfNode)
|
||||
{
|
||||
auto found = _ogdfDataMap.find(ogdfNode);
|
||||
return found != _ogdfDataMap.end() ? found->second : nullptr;
|
||||
}
|
||||
Node<T>* findNodeByAddress(duint address)
|
||||
{
|
||||
auto it = std::find_if(_ogdfDataMap.begin(), _ogdfDataMap.end(), [address](const pair<ogdf::node, Node<T>* > &itr)
|
||||
{
|
||||
return itr.second->data()->address() == address;
|
||||
});
|
||||
|
||||
// If found
|
||||
if(it != _ogdfDataMap.end())
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for(duint i=0; i < _nodePool.size(); i++)
|
||||
_nodePool[i].reset();
|
||||
|
||||
_nodePool.clear();
|
||||
|
||||
map<ogdf::node, Node<T>*>::iterator it = _ogdfDataMap.begin();
|
||||
for(it; it != _ogdfDataMap.end(); it++)
|
||||
delete it->second;
|
||||
|
||||
_ogdfDataMap.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
ogdf::Graph* _G;
|
||||
ogdf::GraphAttributes* _GA;
|
||||
std::vector<std::unique_ptr<Node<T>>> _nodePool;
|
||||
std::map<ogdf::node, Node<T>*> _ogdfDataMap;
|
||||
vector<unique_ptr<Node<T>>> _nodePool;
|
||||
map<ogdf::node, Node<T>*> _ogdfDataMap;
|
||||
};
|
||||
|
||||
#endif //_TREE_H
|
||||
|
|
|
|||
|
|
@ -1132,6 +1132,7 @@ void CPUDisassembly::decompileFunctionSlot()
|
|||
dsint addr = rvaToVa(getInitialSelection());
|
||||
duint start;
|
||||
duint end;
|
||||
|
||||
if(DbgFunctionGet(addr, &start, &end))
|
||||
{
|
||||
emit displaySnowmanWidget();
|
||||
|
|
|
|||
|
|
@ -1,25 +1,46 @@
|
|||
|
||||
#include "GraphView.h"
|
||||
#include "ui_GraphView.h"
|
||||
#include <QDebug>
|
||||
|
||||
#include "Tree.h"
|
||||
#include "GraphEdge.h"
|
||||
#include "GraphNode.h"
|
||||
#include "QGraphScene.h"
|
||||
|
||||
#include <ogdf/fileformats/GraphIO.h>
|
||||
#include <ogdf/layered/SugiyamaLayout.h>
|
||||
#include <ogdf/layered/OptimalRanking.h>
|
||||
#include <ogdf/layered/MedianHeuristic.h>
|
||||
#include <ogdf/layered/OptimalHierarchyLayout.h>
|
||||
|
||||
#include "Bridge.h"
|
||||
|
||||
GraphView::GraphView(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::GraphView)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setupGraph();
|
||||
mG = nullptr;
|
||||
mGA = nullptr;
|
||||
mSL = nullptr;
|
||||
mOHL = nullptr;
|
||||
mTree = nullptr;
|
||||
mDisas = new QBeaEngine(-1);
|
||||
mScene = new QGraphicsScene(this);
|
||||
mParentsInfo = nullptr;
|
||||
mBasicBlockInfo = nullptr;
|
||||
mGraphNodeVector = new GRAPHNODEVECTOR;
|
||||
bProgramInitialized = false;
|
||||
|
||||
mScene->setBackgroundBrush(QBrush(Qt::black));
|
||||
// ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
// ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
ui->graphicsView->setScene(mScene);
|
||||
|
||||
connect(mScene, SIGNAL(changed(QList<QRectF>)), this, SLOT(sceneChangedSlot(QList<QRectF>)));
|
||||
connect(Bridge::getBridge(), SIGNAL(setControlFlowInfos(duint*)), this, SLOT(setControlFlowInfosSlot(duint*)));
|
||||
connect(Bridge::getBridge(), SIGNAL(disassembleAt(dsint,dsint)), this, SLOT(disassembleAtSlot(dsint, dsint)));
|
||||
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(dbgStateChangedSlot(DBGSTATE)));
|
||||
}
|
||||
|
||||
void GraphView::startControlFlowAnalysis()
|
||||
{
|
||||
DbgCmdExec(QString("cfanalyze").toUtf8().constData());
|
||||
}
|
||||
|
||||
void GraphView::showEvent(QShowEvent *event)
|
||||
{
|
||||
// ui->graphicsView->fitInView(mScene->itemsBoundingRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
void GraphView::setupGraph()
|
||||
|
|
@ -27,97 +48,23 @@ void GraphView::setupGraph()
|
|||
using namespace ogdf;
|
||||
|
||||
//initialize graph
|
||||
Graph G;
|
||||
GraphAttributes GA(G, GraphAttributes::nodeGraphics |
|
||||
GraphAttributes::edgeGraphics |
|
||||
GraphAttributes::nodeLabel |
|
||||
GraphAttributes::nodeStyle |
|
||||
GraphAttributes::edgeType |
|
||||
GraphAttributes::edgeArrow |
|
||||
GraphAttributes::edgeStyle);
|
||||
mG = new Graph;
|
||||
mGA = new GraphAttributes(*mG, GraphAttributes::nodeGraphics |
|
||||
GraphAttributes::edgeGraphics |
|
||||
GraphAttributes::nodeLabel |
|
||||
GraphAttributes::nodeStyle |
|
||||
GraphAttributes::edgeType |
|
||||
GraphAttributes::edgeArrow |
|
||||
GraphAttributes::edgeStyle);
|
||||
|
||||
|
||||
//add nodes
|
||||
Tree<GraphNode*> tree(&G, &GA);
|
||||
auto root = tree.newNode(new GraphNode("rp"));
|
||||
auto left = root->setLeft(tree.newNode(new GraphNode("left 1")));
|
||||
left->setLeft(tree.newNode(new GraphNode("left 2")));
|
||||
left->setRight(tree.newNode(new GraphNode("right 2")));
|
||||
auto right = root->setRight(tree.newNode(new GraphNode("right 1")));
|
||||
right->setLeft(tree.newNode(new GraphNode("left 3")))->setRight(left);
|
||||
right->setRight(tree.newNode(new GraphNode("right 3")))->setRight(tree.newNode(new GraphNode("nice long text :)")))->setLeft(root);
|
||||
mTree = new Tree<GraphNode*>(mG, mGA);
|
||||
|
||||
//adjust node size
|
||||
node v;
|
||||
forall_nodes(v, G)
|
||||
{
|
||||
auto node = tree.findNode(v);
|
||||
if (node)
|
||||
{
|
||||
auto rect = node->data()->boundingRect();
|
||||
GA.width(v) = rect.width();
|
||||
GA.height(v) = rect.height();
|
||||
}
|
||||
}
|
||||
// setupTree();
|
||||
setupTree();
|
||||
|
||||
//do layout
|
||||
OptimalHierarchyLayout* OHL = new OptimalHierarchyLayout;
|
||||
OHL->nodeDistance(25.0);
|
||||
OHL->layerDistance(50.0);
|
||||
OHL->weightBalancing(0.0);
|
||||
OHL->weightSegments(0.0);
|
||||
|
||||
SugiyamaLayout SL;
|
||||
SL.setRanking(new OptimalRanking);
|
||||
SL.setCrossMin(new MedianHeuristic);
|
||||
SL.alignSiblings(false);
|
||||
SL.setLayout(OHL);
|
||||
SL.call(GA);
|
||||
|
||||
QGraphScene* scene = new QGraphScene(this);
|
||||
|
||||
//draw widget contents (nodes)
|
||||
forall_nodes(v, G)
|
||||
{
|
||||
auto node = tree.findNode(v);
|
||||
if (node)
|
||||
{
|
||||
//draw node using x,y
|
||||
auto rect = node->data()->boundingRect();
|
||||
qreal x = GA.x(v) - (rect.width()/2);
|
||||
qreal y = GA.y(v) - (rect.height()/2);
|
||||
node->data()->setGeometry(x, y, rect.width(), rect.height());
|
||||
scene->addWidget(node->data());
|
||||
}
|
||||
}
|
||||
|
||||
//draw edges
|
||||
edge e;
|
||||
forall_edges(e, G)
|
||||
{
|
||||
const auto bends = GA.bends(e);
|
||||
const auto source = e->source();
|
||||
const auto target = e->target();
|
||||
|
||||
GraphNode* sourceGraphNode = tree.findNode(source)->data();
|
||||
GraphNode* targetGraphNode = tree.findNode(target)->data();
|
||||
qDebug() << "edge" << sourceGraphNode->label() << "->" << targetGraphNode->label();
|
||||
|
||||
QRectF sourceRect = sourceGraphNode->geometry();
|
||||
sourceRect.adjust(-4, -4, 4, 4);
|
||||
QRectF targetRect = targetGraphNode->geometry();
|
||||
targetRect.adjust(-4, -4, 4, 4);
|
||||
|
||||
QPointF start(GA.x(source), GA.y(source));
|
||||
QPointF end(GA.x(target), GA.y(target));
|
||||
GraphEdge* edge = new GraphEdge(start, end, bends, sourceRect, targetRect);
|
||||
|
||||
scene->addItem(edge);
|
||||
}
|
||||
|
||||
//draw scene
|
||||
scene->setBackgroundBrush(QBrush(Qt::darkGray));
|
||||
|
||||
ui->graphicsView->setScene(scene);
|
||||
addGraphToScene();
|
||||
|
||||
//make sure there is some spacing
|
||||
QRectF sceneRect = ui->graphicsView->sceneRect();
|
||||
|
|
@ -125,15 +72,352 @@ void GraphView::setupGraph()
|
|||
ui->graphicsView->setSceneRect(sceneRect);
|
||||
|
||||
ui->graphicsView->show();
|
||||
}
|
||||
|
||||
|
||||
void GraphView::setupTree(duint va)
|
||||
{
|
||||
using namespace ogdf;
|
||||
|
||||
QTextStream out(stdout);
|
||||
BASICBLOCKMAP::iterator it;
|
||||
QByteArray byteArray(MAX_STRING_SIZE, 0);
|
||||
std::vector<Instruction_t> instructionsVector;
|
||||
|
||||
// Clear graph and tree
|
||||
mG->clear();
|
||||
mTree->clear();
|
||||
|
||||
if(!va)
|
||||
it = mBasicBlockInfo->begin();
|
||||
else
|
||||
it = mBasicBlockInfo->find(va);
|
||||
|
||||
// Couldn't find the basic block of the VA
|
||||
if(it == mBasicBlockInfo->end())
|
||||
return;
|
||||
|
||||
// Disassemble the instruction at the address
|
||||
duint addr = it->first;
|
||||
duint startAddr = it->second.start;
|
||||
duint endAddr = it->second.end;
|
||||
duint baseAddr = DbgMemFindBaseAddr(addr, 0);
|
||||
|
||||
for(startAddr; startAddr <= endAddr;)
|
||||
{
|
||||
if(!DbgMemRead(startAddr, (unsigned char*)byteArray.data(), 16))
|
||||
return;
|
||||
|
||||
Instruction_t wInstruction = mDisas->DisassembleAt((byte_t*)byteArray.data(), byteArray.length(), 0, baseAddr, startAddr-baseAddr);
|
||||
|
||||
// Add instruction to the vector
|
||||
instructionsVector.push_back(wInstruction);
|
||||
startAddr += wInstruction.length;
|
||||
}
|
||||
|
||||
// Add root node first
|
||||
mGraphNodeVector->push_back(new GraphNode(instructionsVector, addr));
|
||||
connect(mGraphNodeVector->back(), SIGNAL(drawGraphAt(duint)), this, SLOT(drawGraphAtSlot(duint)), Qt::QueuedConnection);
|
||||
|
||||
Node<GraphNode *> *rootNode = mTree->newNode(mGraphNodeVector->back());
|
||||
addAllNodes(it, rootNode);
|
||||
}
|
||||
|
||||
void GraphView::setupGraphLayout()
|
||||
{
|
||||
using namespace ogdf;
|
||||
|
||||
// TODO : Better way to do this
|
||||
if(mOHL && mSL)
|
||||
{
|
||||
mSL->call(*mGA);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mOHL = new OptimalHierarchyLayout;
|
||||
mOHL->nodeDistance(25.0);
|
||||
mOHL->layerDistance(50.0);
|
||||
mOHL->fixedLayerDistance(false);
|
||||
mOHL->weightBalancing(0.0);
|
||||
mOHL->weightSegments(0.0);
|
||||
|
||||
mSL = new SugiyamaLayout;
|
||||
mSL->setRanking(new OptimalRanking);
|
||||
mSL->setCrossMin(new MedianHeuristic);
|
||||
mSL->alignSiblings(false);
|
||||
mSL->setLayout(mOHL);
|
||||
mSL->call(*mGA);
|
||||
}
|
||||
|
||||
void GraphView::addGraphToScene()
|
||||
{
|
||||
using namespace ogdf;
|
||||
|
||||
mScene->clear();
|
||||
ui->graphicsView->viewport()->update();
|
||||
|
||||
// adjust node size
|
||||
node v;
|
||||
forall_nodes(v, *mG)
|
||||
{
|
||||
Node<GraphNode* > *node = mTree->findNode(v);
|
||||
if (node)
|
||||
{
|
||||
QRectF rect = node->data()->boundingRect();
|
||||
mGA->width(v) = rect.width();
|
||||
mGA->height(v) = rect.height();
|
||||
}
|
||||
}
|
||||
|
||||
setupGraphLayout();
|
||||
|
||||
//draw widget contents (nodes)
|
||||
forall_nodes(v, *mG)
|
||||
{
|
||||
Node<GraphNode* > *node = mTree->findNode(v);
|
||||
if (node)
|
||||
{
|
||||
//draw node using x,y
|
||||
QRectF rect = node->data()->boundingRect();
|
||||
qreal x = mGA->x(v) - (rect.width()/2);
|
||||
qreal y = mGA->y(v) - (rect.height()/2);
|
||||
node->data()->setGeometry(x, y, rect.width(), rect.height());
|
||||
mScene->addWidget(node->data());
|
||||
}
|
||||
}
|
||||
|
||||
//draw edges
|
||||
edge e;
|
||||
forall_edges(e, *mG)
|
||||
{
|
||||
const auto bends = mGA->bends(e);
|
||||
const auto source = e->source();
|
||||
const auto target = e->target();
|
||||
|
||||
GraphNode* sourceGraphNode = mTree->findNode(source)->data();
|
||||
GraphNode* targetGraphNode = mTree->findNode(target)->data();
|
||||
|
||||
QRectF sourceRect = sourceGraphNode->geometry();
|
||||
sourceRect.adjust(-4, -4, 4, 4);
|
||||
QRectF targetRect = targetGraphNode->geometry();
|
||||
targetRect.adjust(-4, -4, 4, 4);
|
||||
|
||||
QPointF start(mGA->x(source), mGA->y(source));
|
||||
QPointF end(mGA->x(target), mGA->y(target));
|
||||
|
||||
GraphEdge* edge = nullptr;
|
||||
if(mTree->findNode(source)->left() && mTree->findNode(source)->left()->data()->address() == targetGraphNode->address())
|
||||
edge = new GraphEdge(start, end, bends, sourceRect, targetRect, Qt::green);
|
||||
else
|
||||
edge = new GraphEdge(start, end, bends, sourceRect, targetRect, Qt::red);
|
||||
|
||||
mScene->addItem(edge);
|
||||
}
|
||||
|
||||
// mScene->setSceneRect(mScene->itemsBoundingRect());
|
||||
|
||||
QTextStream out(stdout);
|
||||
out << "*-----------------------------------*"<< endl;
|
||||
out << mScene->sceneRect().x() << endl;
|
||||
out << mScene->sceneRect().y() << endl;
|
||||
out << mScene->sceneRect().width() << endl;
|
||||
ui->graphicsView->ensureVisible(mScene->itemsBoundingRect());
|
||||
|
||||
// ui->graphicsView->fitInView(mScene->sceneRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
void GraphView::addAllNodes(BASICBLOCKMAP::iterator it, Node<GraphNode *> *parentNode)
|
||||
{
|
||||
QTextStream out(stdout);
|
||||
QByteArray byteArray(MAX_STRING_SIZE, 0);
|
||||
duint addr = it->first; // Parent Basic Block addr
|
||||
duint left = it->second.left; // Left child addr
|
||||
duint right = it->second.right; // Right child addr
|
||||
|
||||
// No childs
|
||||
if(!left && !right)
|
||||
return;
|
||||
|
||||
for(int i=0; i < 2; i++)
|
||||
{
|
||||
if((i == 0 && !left) || (i == 1 && !right))
|
||||
continue;
|
||||
|
||||
BASICBLOCKMAP::iterator itChild;
|
||||
Node<GraphNode *> *node = nullptr;
|
||||
|
||||
// Left
|
||||
if(i == 0)
|
||||
{
|
||||
itChild = mBasicBlockInfo->find(left);
|
||||
node = mTree->findNodeByAddress(left);
|
||||
}
|
||||
//Right
|
||||
else
|
||||
{
|
||||
itChild = mBasicBlockInfo->find(right);
|
||||
node = mTree->findNodeByAddress(right);
|
||||
}
|
||||
|
||||
// If we found the basicblock for left or right
|
||||
if(itChild != mBasicBlockInfo->end())
|
||||
{
|
||||
// If the Node doesn't exist yet;
|
||||
std::vector<Instruction_t> instructionsVector;
|
||||
if(node == nullptr)
|
||||
{
|
||||
duint startAddr = itChild->second.start;
|
||||
duint endAddr = itChild->second.end;
|
||||
|
||||
// BaseAddr..
|
||||
duint baseAddr = DbgMemFindBaseAddr(addr, 0);
|
||||
|
||||
// Disassemble the BasicBlock instructions
|
||||
for(startAddr; startAddr <= endAddr;)
|
||||
{
|
||||
DbgMemRead(startAddr, (unsigned char*)byteArray.data(), 16);
|
||||
Instruction_t wInstruction = mDisas->DisassembleAt((byte_t*)byteArray.data(), MAX_STRING_SIZE,0, baseAddr, startAddr-baseAddr);
|
||||
|
||||
instructionsVector.push_back(wInstruction);
|
||||
startAddr += wInstruction.length;
|
||||
}
|
||||
}
|
||||
|
||||
// Add node to left of parentNode
|
||||
if(i == 0)
|
||||
{
|
||||
// Node does not exist, create it
|
||||
if(node == nullptr)
|
||||
{
|
||||
mGraphNodeVector->push_back(new GraphNode(instructionsVector, left));
|
||||
node = mTree->newNode(mGraphNodeVector->back());
|
||||
connect(mGraphNodeVector->back(), SIGNAL(drawGraphAt(duint)), this, SLOT(drawGraphAtSlot(duint)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Node<GraphNode *> *newParentNode = nullptr;
|
||||
|
||||
// Edge already exists between parentNode and left / right, we've been here before..
|
||||
if(parentNode->left() && (parentNode->left()->data()->address() == left || parentNode->left()->data()->address() == right))
|
||||
return;
|
||||
else
|
||||
newParentNode = parentNode->setLeft(node);
|
||||
|
||||
addAllNodes(itChild, newParentNode);
|
||||
}
|
||||
|
||||
// Add node to right of parentNode
|
||||
else if(i == 1)
|
||||
{
|
||||
// Node does not exist, create it
|
||||
if(node == nullptr)
|
||||
{
|
||||
mGraphNodeVector->push_back(new GraphNode(instructionsVector, right));
|
||||
node = mTree->newNode(mGraphNodeVector->back());
|
||||
connect((GraphNode*)(mGraphNodeVector->back()), SIGNAL(drawGraphAt(duint)), this, SLOT(drawGraphAtSlot(duint)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
Node<GraphNode *> *newParentNode = nullptr;
|
||||
|
||||
// Edge already exists between parentNode and left / right
|
||||
if(parentNode->right() && (parentNode->right()->data()->address() == right || parentNode->right()->data()->address() == left))
|
||||
return;
|
||||
else
|
||||
newParentNode = parentNode->setRight(node);
|
||||
|
||||
addAllNodes(itChild, newParentNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//qDebug() << "sceneRect()" << ui->graphicsView->sceneRect();
|
||||
|
||||
GraphIO::drawSVG(GA, "test.svg");
|
||||
}
|
||||
|
||||
GraphView::~GraphView()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void GraphView::setControlFlowInfosSlot(duint *controlFlowInfos)
|
||||
{
|
||||
if(controlFlowInfos)
|
||||
{
|
||||
mParentsInfo = (PARENTMAP*)(((CONTROLFLOWINFOS*)controlFlowInfos)->parents);
|
||||
mBasicBlockInfo = (BASICBLOCKMAP*)(((CONTROLFLOWINFOS*)controlFlowInfos)->blocks);
|
||||
setupGraph();
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::dbgStateChangedSlot(DBGSTATE state)
|
||||
{
|
||||
if(state == initialized)
|
||||
bProgramInitialized = false;
|
||||
}
|
||||
|
||||
void GraphView::sceneChangedSlot(QList<QRectF> rectList)
|
||||
{
|
||||
Q_UNUSED(rectList);
|
||||
// ui->graphicsView->fitInView(mScene->itemsBoundingRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
|
||||
bool GraphView::findBasicBlock(duint &va)
|
||||
{
|
||||
if(!mBasicBlockInfo)
|
||||
return false;
|
||||
|
||||
if(!mBasicBlockInfo->size())
|
||||
return false;
|
||||
|
||||
bool bFound = false;
|
||||
BASICBLOCKMAP::iterator it = mBasicBlockInfo->find(va);
|
||||
|
||||
// If the block was not found by addr, check if it belongs to a basic block
|
||||
if(it == mBasicBlockInfo->end())
|
||||
{
|
||||
for(it = mBasicBlockInfo->begin(); it != mBasicBlockInfo->end(); it++)
|
||||
{
|
||||
|
||||
if(va >= it->second.start && va <= it->second.end)
|
||||
{
|
||||
va = it->first;
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
bFound = true;
|
||||
|
||||
return bFound;
|
||||
}
|
||||
|
||||
void GraphView::drawGraphAtSlot(duint va)
|
||||
{
|
||||
|
||||
bool bFound = findBasicBlock(va);
|
||||
|
||||
if(!bFound)
|
||||
return;
|
||||
|
||||
setupTree(va);
|
||||
addGraphToScene();
|
||||
|
||||
// if(mScene->itemsBoundingRect().height() < ui->graphicsView->height())
|
||||
// ui->graphicsView->verticalScrollBar()->hide();
|
||||
// else
|
||||
// ui->graphicsView->verticalScrollBar()->show();
|
||||
// ui->graphicsView->fitInView(mScene->itemsBoundingRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
void GraphView::disassembleAtSlot(dsint parVA, dsint CIP)
|
||||
{
|
||||
Q_UNUSED(CIP)
|
||||
Q_UNUSED(parVA)
|
||||
|
||||
if(!bProgramInitialized)
|
||||
{
|
||||
startControlFlowAnalysis();
|
||||
bProgramInitialized = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,105 @@
|
|||
#ifndef GRAPHVIEW_H
|
||||
#define GRAPHVIEW_H
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <QWidget>
|
||||
#include <QWheelEvent>
|
||||
#include <QGraphicsScene>
|
||||
#include "QBeaEngine.h"
|
||||
#include "Bridge.h"
|
||||
#include "Tree.h"
|
||||
#include "GraphNode.h"
|
||||
#include "capstone_gui.h"
|
||||
#include <ogdf/fileformats/GraphIO.h>
|
||||
#include <ogdf/layered/SugiyamaLayout.h>
|
||||
#include <ogdf/layered/OptimalRanking.h>
|
||||
#include <ogdf/layered/MedianHeuristic.h>
|
||||
#include <ogdf/layered/OptimalHierarchyLayout.h>
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class GraphView;
|
||||
}
|
||||
|
||||
|
||||
struct BasicBlock
|
||||
{
|
||||
duint start;
|
||||
duint end;
|
||||
duint left;
|
||||
duint right;
|
||||
duint function;
|
||||
|
||||
BasicBlock()
|
||||
{
|
||||
this->start = 0;
|
||||
this->end = 0;
|
||||
this->left = 0;
|
||||
this->right = 0;
|
||||
this->function = 0;
|
||||
}
|
||||
|
||||
BasicBlock(duint start, duint end, duint left, duint right)
|
||||
{
|
||||
this->start = start;
|
||||
this->end = end;
|
||||
this->left = std::min(left, right);
|
||||
this->right = std::max(left, right);
|
||||
this->function = 0;
|
||||
}
|
||||
|
||||
std::string toString()
|
||||
{
|
||||
char buffer[MAX_STRING_SIZE];
|
||||
sprintf_s(buffer, "start:%p,end:%p,left:%p,right:%p,func:%p", start, end, left, right, function);
|
||||
return std::string(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<duint, BasicBlock> BASICBLOCKMAP; //start of block -> block
|
||||
typedef std::map<duint, std::set<duint> > PARENTMAP; //start child -> parents
|
||||
typedef std::vector<GraphNode* > GRAPHNODEVECTOR;
|
||||
typedef std::map<duint, Node<GraphNode *> * > NODEMAP;
|
||||
|
||||
class GraphView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GraphView(QWidget *parent = 0);
|
||||
void startControlFlowAnalysis();
|
||||
void showEvent(QShowEvent *event);
|
||||
~GraphView();
|
||||
|
||||
public slots:
|
||||
void drawGraphAtSlot(duint va);
|
||||
void disassembleAtSlot(dsint parVA, dsint CIP);
|
||||
void setControlFlowInfosSlot(duint *controlFlowInfos);
|
||||
void dbgStateChangedSlot(DBGSTATE state);
|
||||
void sceneChangedSlot(QList<QRectF> rectList);
|
||||
|
||||
private:
|
||||
void setupGraph();
|
||||
|
||||
void setupGraphLayout();
|
||||
void setupTree(duint va = 0);
|
||||
void addGraphToScene();
|
||||
void addAllNodes(BASICBLOCKMAP::iterator it, Node<GraphNode *> *parentNode);
|
||||
bool findBasicBlock(duint &va);
|
||||
QBeaEngine *mDisas;
|
||||
PARENTMAP *mParentsInfo;
|
||||
BASICBLOCKMAP *mBasicBlockInfo;
|
||||
GRAPHNODEVECTOR *mGraphNodeVector;
|
||||
ogdf::Graph *mG;
|
||||
ogdf::GraphAttributes *mGA;
|
||||
ogdf::SugiyamaLayout *mSL;
|
||||
ogdf::OptimalHierarchyLayout *mOHL;
|
||||
QGraphicsScene *mScene;
|
||||
Tree<GraphNode*> *mTree;
|
||||
Ui::GraphView *ui;
|
||||
bool bProgramInitialized;
|
||||
int mIndex = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif // GRAPHVIEW_H
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||
mGraphView = new GraphView(this);
|
||||
mGraphView->setWindowTitle("Graph");
|
||||
mGraphView->setWindowIcon(QIcon(":/icons/images/graph.png"));
|
||||
connect(mCpuWidget->getDisasmWidget(), SIGNAL(drawGraphAtAddress(dsint)), this, SLOT(drawGraphAtAddressSlot(dsint)));
|
||||
|
||||
// Create the tab widget
|
||||
mTabWidget = new MHTabWidget(NULL);
|
||||
|
|
@ -1156,3 +1157,8 @@ void MainWindow::executeOnGuiThread(void* cbGuiThread)
|
|||
{
|
||||
((GUICALLBACK)cbGuiThread)();
|
||||
}
|
||||
|
||||
void MainWindow::drawGraphAtAddressSlot(dsint va)
|
||||
{
|
||||
mGraphView->drawGraphAtSlot(va);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ public slots:
|
|||
void showQWidgetTab(QWidget* qWidget);
|
||||
void closeQWidgetTab(QWidget* qWidget);
|
||||
void executeOnGuiThread(void* cbGuiThread);
|
||||
void drawGraphAtAddressSlot(dsint va);
|
||||
|
||||
private:
|
||||
Ui::MainWindow* ui;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ void QGraphView::wheelEvent(QWheelEvent* event)
|
|||
|
||||
void QGraphView::scalingTime(qreal x)
|
||||
{
|
||||
Q_UNUSED(x)
|
||||
qreal factor = 1.0 + qreal(_numScheduledScalings) / 300.0;
|
||||
scale(factor, factor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,7 +148,9 @@ SOURCES += \
|
|||
Src/Gui/CPUMultiDump.cpp \
|
||||
Src/Gui/GraphView.cpp \
|
||||
Src/Graph/QGraphScene.cpp \
|
||||
Src/QGraphView.cpp
|
||||
Src/QGraphView.cpp \
|
||||
Src/Graph/GraphEdge.cpp \
|
||||
Src/Graph/GraphNode.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
|
|
|
|||
Loading…
Reference in New Issue