Fix & extend CodeGraphic. Adds symbols, strings, etc (#187)

* Fix & extend CodeGraphic. Adds symbols, strings, etc, makes it clickable and shows the current position in the file.

* Don't use designated initializer (fails on AppVeyor).

* CodeGraphic: Change color of symbols to orange for increased contrast.
This commit is contained in:
Thomas (nezza-_-) Roth 2017-12-08 00:41:15 +01:00 committed by xarkes
parent 5ce151da94
commit 5c9dec657d
2 changed files with 184 additions and 46 deletions

View File

@ -1,6 +1,7 @@
#include "CodeGraphic.h"
#include "MainWindow.h"
#include "utils/TempConfig.h"
#include <QGraphicsView>
#include <QComboBox>
@ -40,7 +41,8 @@ GraphicsBar::GraphicsBar(MainWindow *main, QWidget *parent) :
addWidget(this->codeGraphic);
//addWidget(addsCombo);
connect(Core(), SIGNAL(refreshAll()), this, SLOT(fillData()));
connect(Core(), SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA)));
connect(Core(), SIGNAL(refreshAll()), this, SLOT(fetchAndPaintData()));
}
void GraphicsBar::paintEvent(QPaintEvent *event)
@ -51,8 +53,36 @@ void GraphicsBar::paintEvent(QPaintEvent *event)
this->fillData();
}
void GraphicsBar::fetchAndPaintData()
{
fetchData();
fillData();
}
void GraphicsBar::fetchData()
{
TempConfig tempConfig;
tempConfig.set("search.in", QString("io.section"));
sections = Core()->getAllSections();
totalSectionsSize = 0;
blockMaps.clear();
for(SectionDescription section : sections)
{
QString command = "p-j @" + RAddressString(section.vaddr);
QJsonDocument doc = Core()->cmdj(command);
QJsonObject jObject = doc.object();
QVariantMap mainMap = jObject.toVariantMap();
blockMaps.append(mainMap);
totalSectionsSize += section.size;
}
}
void GraphicsBar::fillData()
{
int from = blockMaps.first()["from"].toInt();
int to = blockMaps.first()["to"].toInt();
// Prepare the graph scene
int w = this->codeGraphic->width();
int h = this->codeGraphic->height();
@ -66,17 +96,27 @@ void GraphicsBar::fillData()
this->codeGraphic->setRenderHints(QPainter::Antialiasing);
this->codeGraphic->setToolTip("gap");
// Parse JSON data
QJsonDocument doc = Core()->cmdj("p-j");
//get the jsonObject
QJsonObject jObject = doc.object();
RVA current_address = Core()->getOffset();
//convert the json object to variantmap
QVariantMap mainMap = jObject.toVariantMap();
double width_per_byte = (double)w/(double)totalSectionsSize;
xToAddress.clear();
double x_start = 0.0;
int from = mainMap["from"].toInt();
int to = mainMap["to"].toInt();
bool draw_cursor = false;
double cursor_x = 0.0;
for(int i=0; i < sections.length(); i++)
{
SectionDescription section = sections[i];
double width = ((double)section.size * width_per_byte);
double x_end = x_start + width;
double local_w = x_end - x_start;
QVariantMap mainMap = blockMaps[i];
from = mainMap["from"].toInt();
to = mainMap["to"].toInt();
int block = mainMap["blocksize"].toInt();
int size = (to - from);
int num = 1;
@ -89,18 +129,30 @@ void GraphicsBar::fillData()
{
num = 1;
}
int graph_block = w / num;
int graph_block = local_w / num;
int counter = 0;
for (auto i : mainMap["blocks"].toList())
for (auto j : mainMap["blocks"].toList())
{
QMap<QString, QVariant> map = i.toMap();
QMap<QString, QVariant> map = j.toMap();
// The X of where this block will start
double block_x_start = x_start + (double)(counter * graph_block);
// Keep X start and end as well as the start & end address in a list.
// This is used to convert address to an X position on the bar and vice versa.
struct xToAddress x2a;
x2a.x_start = block_x_start;
x2a.x_end = block_x_start + graph_block;
x2a.address_from = map["offset"].toULongLong();
x2a.address_to = map["offset"].toULongLong() + map["size"].toULongLong();
xToAddress.append(x2a);
if (map.empty())
{
// Fill empty color
// addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen = QPen(), const QBrush &brush = QBrush())
//scene->addRect(counter * graph_block, 0, graph_block ,h, QPen(Qt::NoPen), QBrush(QColor(252, 249, 190)));
QGraphicsRectItem *rect = new QGraphicsRectItem(counter * graph_block, 0, graph_block, h);
// Fill as empty
QGraphicsRectItem *rect = new QGraphicsRectItem(block_x_start, 0, graph_block, h);
rect->setPen(Qt::NoPen);
rect->setBrush(QBrush(QColor(252, 249, 190)));
rect->setToolTip("Data");
@ -108,21 +160,88 @@ void GraphicsBar::fillData()
}
else
{
// Fill type of color
//scene->addRect(counter * graph_block, 0, graph_block ,h, QPen(Qt::NoPen), QBrush(QColor(69, 104, 229)));
QGraphicsRectItem *rect = new QGraphicsRectItem(counter * graph_block, 0, graph_block, h);
// TODO: Make this compatible with theming
QGraphicsRectItem *rect = new QGraphicsRectItem(block_x_start, 0, graph_block, h);
rect->setPen(Qt::NoPen);
if (i.toMap()["functions"].toInt() == 0)
{
rect->setBrush(QBrush(QColor(190, 190, 190)));
}
else
if (map["functions"].toInt() > 0)
{
rect->setBrush(QBrush(QColor(69, 104, 229)));
}
rect->setToolTip("Offset: 0x" + QString::number(i.toMap()["offset"].toInt(), 16) + "\nFunctions: " + QString::number(i.toMap()["functions"].toInt()) + "\nFlags: " + QString::number(i.toMap()["flags"].toInt()));
else if(map["symbols"].toInt() > 0)
{
rect->setBrush(QBrush(QColor(229, 150, 69)));
}
else if(map["strings"].toInt() > 0)
{
rect->setBrush(QBrush(QColor(104, 229, 69)));
}
else
{
rect->setBrush(QBrush(QColor(190, 190, 190)));
}
rect->setToolTip(generateTooltip(section.name, map));
scene->addItem(rect);
}
// Check whether this block contains the current address.
if ((x2a.address_from <= current_address) && (current_address < x2a.address_to))
{
draw_cursor = true;
RVA cursor_offset = (double)(current_address - x2a.address_from) * width_per_byte;
cursor_x = block_x_start + cursor_offset;
}
counter += 1;
}
x_start = x_end;
}
// Draw the red cursor that shows where we are in the file (if we are in one of the rendered sections)
if(draw_cursor)
{
QGraphicsRectItem *rect = new QGraphicsRectItem(cursor_x, 0, 2, h);
rect->setPen(Qt::NoPen);
rect->setBrush(QBrush(QColor(255, 0, 0)));
scene->addItem(rect);
}
}
QString GraphicsBar::generateTooltip(QString section_name, QMap<QString, QVariant> map)
{
QString ret = "";
ret += "Offset: 0x" + QString::number(map["offset"].toInt(), 16) + "\n";
ret += "Section: " + section_name + "\n";
ret += "Size: " + QString::number(map["size"].toInt()) + "\n";
ret += "Functions: " + QString::number(map["functions"].toInt()) + "\n";
ret += "Flags: " + QString::number(map["flags"].toInt()) + "\n";
ret += "Comments: " + QString::number(map["comments"].toInt()) + "\n";
ret += "Symbols: " + QString::number(map["symbols"].toInt()) + "\n";
ret += "Strings: " + QString::number(map["strings"].toInt()) + "\n";
ret += "rwx: " + map["rwx"].toString() + "\n";
return ret;
}
void GraphicsBar::on_seekChanged(RVA addr)
{
Q_UNUSED(addr);
// Re-paint, which will also update the cursor.
this->fillData();
}
void GraphicsBar::mousePressEvent(QMouseEvent *event)
{
event->accept();
// Convert the local X coordinate to an address.
qreal x = event->localPos().x();
for(auto x2a : xToAddress)
{
if ((x2a.x_start <= x) && (x <= x2a.x_end))
{
double offset = (x - x2a.x_start) / (x2a.x_end - x2a.x_start);
double size = x2a.address_to - x2a.address_from;
Core()->seek(x2a.address_from + (offset * size));
break;
}
}
}

View File

@ -3,6 +3,8 @@
#include <QToolBar>
#include "cutter.h"
class MainWindow;
class QGraphicsView;
@ -10,18 +12,35 @@ class GraphicsBar : public QToolBar
{
Q_OBJECT
struct xToAddress {
double x_start;
double x_end;
RVA address_from;
RVA address_to;
};
public:
explicit GraphicsBar(MainWindow *main, QWidget *parent = 0);
public slots:
void paintEvent(QPaintEvent *event);
void paintEvent(QPaintEvent *event) override;
private slots:
void fetchAndPaintData();
void fetchData();
void fillData();
void on_seekChanged(RVA addr);
private:
QGraphicsView *codeGraphic;
MainWindow *main;
RVA totalSectionsSize;
QList<SectionDescription> sections;
QList<QVariantMap> blockMaps;
QList<struct xToAddress> xToAddress;
QString generateTooltip(QString section_name, QMap<QString, QVariant> map);
void mousePressEvent(QMouseEvent *event) override;
};
#endif // GRAPHICSBAR_H