1
0
Fork 0

Merge pull request #464 from Herz3h/graph_ogdf_new

Graph ogdf new
This commit is contained in:
Duncan Ogilvie 2015-12-19 03:38:33 +01:00
commit 8e745baac5
22 changed files with 1103 additions and 430 deletions

View File

@ -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;

View File

@ -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
}

View File

@ -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;)
{

View File

@ -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;

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View File

@ -0,0 +1,256 @@
#include "GraphEdge.h"
GraphEdge::GraphEdge(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect, EDGE_TYPE edgeType) : QAbstractGraphicsShapeItem()
{
_edgeType = edgeType;
if(_edgeType == EDGE_LEFT)
_edgeColor = Qt::red;
else
_edgeColor = Qt::green;
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);
}
void GraphEdge::setEdgeColor(QBrush edgeColor)
{
_edgeColor = edgeColor;
}
GraphEdge::EDGE_TYPE GraphEdge::getEdgeType()
{
return _edgeType;
}

View File

@ -3,251 +3,36 @@
#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()
enum EDGE_TYPE
{
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);
}
EDGE_RIGHT,
EDGE_LEFT
} ;
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, EDGE_TYPE edgeType);
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);
void setEdgeColor(QBrush edgeColor);
GraphEdge::EDGE_TYPE getEdgeType();
private:
QPainterPath _line;
QPainterPath _arrow;
QRectF _boundingRect;
QBrush _edgeColor;
EDGE_TYPE _edgeType;
};
#endif //_GRAPH_EDGE_H

View File

@ -0,0 +1,208 @@
#include "GraphNode.h"
#include <QStyleOption>
GraphNode::GraphNode() : QFrame()
{
}
GraphNode::GraphNode(std::vector<Instruction_t> &instructionsVector, duint address)
{
mAddress = address;
mInstructionsVector = instructionsVector;
mHighlightInstructionAt = -1;
updateTokensVector();
setAttribute(Qt::WA_TranslucentBackground);
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);
painter.fillRect(0, 0, mCachedWidth, mCachedHeight, Qt::white);
// Draw node borders
painter.setPen(QPen(Qt::black, 1));
painter.drawLine(0, mLineHeight, 0, mCachedHeight-1);
painter.drawLine(mCachedWidth-1, mLineHeight, mCachedWidth-1, mCachedHeight-1);
painter.drawLine(0, mCachedHeight-1, mCachedWidth-1, mCachedHeight-1);
// QStyleOption opt;
// opt.init(this);
// style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
//draw node contents
painter.setFont(this->mFont);
int i = 0;
int x = mSpacingX/2, y = mLineHeight + mSpacingY/2;
// Block address
painter.fillRect(0, 0, mCachedWidth, mLineHeight, Qt::cyan);
painter.setPen(Qt::black);
painter.drawText(0, 0, mCachedWidth, mLineHeight, Qt::AlignHCenter | Qt::AlignVCenter, "0x" + QString::number(mAddress, 16).toUpper());
// 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
{
// Gets the instruction index at the cursor position
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;
}

View File

@ -2,93 +2,53 @@
#define _GRAPH_NODE_H
#include <QWidget>
#include <QFrame>
#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
class GraphNode : public QFrame
{
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

View File

@ -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;

View File

@ -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

View File

@ -1132,6 +1132,7 @@ void CPUDisassembly::decompileFunctionSlot()
dsint addr = rvaToVa(getInitialSelection());
duint start;
duint end;
if(DbgFunctionGet(addr, &start, &end))
{
emit displaySnowmanWidget();

View File

@ -1,25 +1,56 @@
#include "GraphView.h"
#include "ui_GraphView.h"
#include "Configuration.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;
// mNodeGraphEdge = new GRAPHEDGEMAP;
bProgramInitialized = false;
mScene->setBackgroundBrush(ConfigColor("DisassemblyBackgroundColor"));
// 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::setUnconditionalBranchEdgeColor()
{
for(auto const &nodeGraphEdge : mNodeGraphEdge)
{
if(nodeGraphEdge.second.size() == 1)
nodeGraphEdge.second.at(0)->setEdgeColor(Qt::blue);
}
}
void GraphView::setupGraph()
@ -27,97 +58,22 @@ 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();
//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 +81,349 @@ 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);
// Read basic block instructions
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;
mNodeGraphEdge.clear();
mScene->clear();
// 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();
}
}
// Apply the graph layout after we've set the nodes sizes
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, GraphEdge::EDGE_LEFT);
else
edge = new GraphEdge(start, end, bends, sourceRect, targetRect, GraphEdge::EDGE_RIGHT);
mNodeGraphEdge[source].push_back(edge);
mScene->addItem(edge);
}
// Change unconditionalBranches colors to something different than for conditional branches
setUnconditionalBranchEdgeColor();
ui->graphicsView->ensureVisible(mScene->itemsBoundingRect());
ui->graphicsView->setSceneRect(mScene->sceneRect());
}
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())
{
std::vector<Instruction_t> instructionsVector;
// If the Node doesn't exist yet;
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()
{
mScene->clear();
if(mOHL)
delete mOHL;
if(mSL)
delete mSL;
if(mTree)
mTree->clear();
if(mG)
delete mG;
if(mGA)
delete mGA;
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;
}
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();
}
void GraphView::disassembleAtSlot(dsint parVA, dsint CIP)
{
Q_UNUSED(CIP)
Q_UNUSED(parVA)
if(!bProgramInitialized)
{
startControlFlowAnalysis();
bProgramInitialized = true;
}
}

View File

@ -1,25 +1,106 @@
#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>
#include "GraphEdge.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;
typedef std::map<ogdf::node, std::vector<GraphEdge *> > GRAPHEDGEMAP;
class GraphView : public QWidget
{
Q_OBJECT
public:
explicit GraphView(QWidget *parent = 0);
void startControlFlowAnalysis();
void showEvent(QShowEvent *event);
void setUnconditionalBranchEdgeColor();
~GraphView();
public slots:
void drawGraphAtSlot(duint va);
void disassembleAtSlot(dsint parVA, dsint CIP);
void setControlFlowInfosSlot(duint *controlFlowInfos);
void dbgStateChangedSlot(DBGSTATE state);
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;
GRAPHEDGEMAP mNodeGraphEdge;
ogdf::Graph *mG;
ogdf::GraphAttributes *mGA;
ogdf::SugiyamaLayout *mSL;
ogdf::OptimalHierarchyLayout *mOHL;
QGraphicsScene *mScene;
Tree<GraphNode*> *mTree;
Ui::GraphView *ui;
bool bProgramInitialized;
};
#endif // GRAPHVIEW_H

View File

@ -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);
}

View File

@ -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;

View File

@ -1,14 +1,21 @@
#include "QGraphView.h"
#include <QTimeLine>
#include <iostream>
QGraphView::QGraphView(QWidget* parent)
: QGraphicsView(parent)
{
bAnimationFinished = false;
}
void QGraphView::wheelEvent(QWheelEvent* event)
{
if(!(event->modifiers() & Qt::ControlModifier))
{
QGraphicsView::wheelEvent(event);
return;
}
int numDegrees = event->delta() / 8;
int numSteps = numDegrees / 15; // see QWheelEvent documentation
_numScheduledScalings += numSteps;
@ -20,11 +27,19 @@ void QGraphView::wheelEvent(QWheelEvent* event)
connect(anim, SIGNAL (valueChanged(qreal)), SLOT (scalingTime(qreal)));
connect(anim, SIGNAL (finished()), SLOT (animFinished()));
// Center the view on the mouse cursor before zooming, more convenient zoom
QPointF mappedMousePos = this->mapToScene(event->pos().x(), event->pos().y());
if(scene()->itemsBoundingRect().contains(mappedMousePos.x(), mappedMousePos.y()))
centerOn(mappedMousePos.x(), mappedMousePos.y());
anim->start();
bAnimationFinished = false;
}
void QGraphView::scalingTime(qreal x)
{
Q_UNUSED(x)
qreal factor = 1.0 + qreal(_numScheduledScalings) / 300.0;
scale(factor, factor);
}
@ -35,5 +50,7 @@ void QGraphView::animFinished()
_numScheduledScalings--;
else
_numScheduledScalings++;
sender()->~QObject();
bAnimationFinished = true;
}

View File

@ -16,6 +16,8 @@ private slots:
void animFinished();
private:
QPoint mMousePos;
bool bAnimationFinished;
int _numScheduledScalings;
};

View File

@ -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 += \