2017-10-02 16:18:40 +00:00
|
|
|
#include "CodeGraphic.h"
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-10-01 19:09:42 +00:00
|
|
|
#include "MainWindow.h"
|
2017-12-07 23:41:15 +00:00
|
|
|
#include "utils/TempConfig.h"
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-04-13 15:14:02 +00:00
|
|
|
#include <QGraphicsView>
|
2017-03-29 10:18:37 +00:00
|
|
|
#include <QComboBox>
|
|
|
|
#include <QGraphicsScene>
|
|
|
|
#include <QGraphicsRectItem>
|
|
|
|
#include <QJsonDocument>
|
|
|
|
#include <QJsonObject>
|
|
|
|
#include <QJsonArray>
|
|
|
|
#include <QJsonParseError>
|
|
|
|
|
|
|
|
GraphicsBar::GraphicsBar(MainWindow *main, QWidget *parent) :
|
2017-10-01 18:08:12 +00:00
|
|
|
QToolBar(main),
|
|
|
|
codeGraphic(new QGraphicsView),
|
|
|
|
main(main)
|
2017-03-29 10:18:37 +00:00
|
|
|
{
|
2017-10-01 18:08:12 +00:00
|
|
|
Q_UNUSED(parent);
|
2017-04-09 17:09:35 +00:00
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
setObjectName("codeGraphics");
|
2017-04-13 15:14:02 +00:00
|
|
|
setWindowTitle(tr("Code bar"));
|
2017-04-09 19:55:06 +00:00
|
|
|
// setMovable(false);
|
2017-03-29 10:18:37 +00:00
|
|
|
setContentsMargins(0, 0, 0, 0);
|
2017-04-07 15:34:24 +00:00
|
|
|
// If line below is used, with the dark theme the paintEvent is not called
|
|
|
|
// and the result is wrong. Something to do with overwriting the style sheet :/
|
|
|
|
//setStyleSheet("QToolBar { border: 0px; border-bottom: 0px; border-top: 0px; border-width: 0px;}");
|
2017-03-29 10:18:37 +00:00
|
|
|
|
|
|
|
this->codeGraphic->setAlignment(Qt::AlignLeft);
|
|
|
|
this->codeGraphic->setMinimumHeight(20);
|
|
|
|
this->codeGraphic->setMaximumHeight(20);
|
|
|
|
this->codeGraphic->setFrameShape(QFrame::NoFrame);
|
|
|
|
|
|
|
|
/*
|
|
|
|
QComboBox *addsCombo = new QComboBox();
|
|
|
|
addsCombo->addItem("");
|
|
|
|
addsCombo->addItem("Entry points");
|
|
|
|
addsCombo->addItem("Marks");
|
|
|
|
*/
|
|
|
|
addWidget(this->codeGraphic);
|
|
|
|
//addWidget(addsCombo);
|
2017-11-19 12:56:10 +00:00
|
|
|
|
2017-12-07 23:41:15 +00:00
|
|
|
connect(Core(), SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA)));
|
|
|
|
connect(Core(), SIGNAL(refreshAll()), this, SLOT(fetchAndPaintData()));
|
2017-12-08 09:55:47 +00:00
|
|
|
|
|
|
|
graphicsScene = new QGraphicsScene(this);
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
|
|
|
|
2017-04-09 19:55:06 +00:00
|
|
|
void GraphicsBar::paintEvent(QPaintEvent *event)
|
|
|
|
{
|
2017-10-01 18:08:12 +00:00
|
|
|
Q_UNUSED(event);
|
2017-04-09 17:09:35 +00:00
|
|
|
|
|
|
|
QPainter painter(this);
|
2017-12-08 09:55:47 +00:00
|
|
|
if(previousWidth != this->codeGraphic->width())
|
|
|
|
{
|
|
|
|
this->fillData();
|
|
|
|
previousWidth = this->codeGraphic->width();
|
|
|
|
}
|
2017-04-09 17:09:35 +00:00
|
|
|
}
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-12-07 23:41:15 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-09 19:55:06 +00:00
|
|
|
void GraphicsBar::fillData()
|
|
|
|
{
|
2017-12-08 09:55:47 +00:00
|
|
|
qDeleteAll(graphicsScene->items());
|
2017-12-07 23:41:15 +00:00
|
|
|
int from = blockMaps.first()["from"].toInt();
|
|
|
|
int to = blockMaps.first()["to"].toInt();
|
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
// Prepare the graph scene
|
|
|
|
int w = this->codeGraphic->width();
|
|
|
|
int h = this->codeGraphic->height();
|
2017-12-08 09:55:47 +00:00
|
|
|
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-04-09 19:55:06 +00:00
|
|
|
const QBrush bg = QBrush(QColor(74, 74, 74));
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-12-08 09:55:47 +00:00
|
|
|
graphicsScene->setBackgroundBrush(bg);
|
2017-03-29 10:18:37 +00:00
|
|
|
this->codeGraphic->setRenderHints(0);
|
2017-12-08 09:55:47 +00:00
|
|
|
this->codeGraphic->setScene(graphicsScene);
|
2017-03-29 10:18:37 +00:00
|
|
|
this->codeGraphic->setRenderHints(QPainter::Antialiasing);
|
|
|
|
this->codeGraphic->setToolTip("gap");
|
|
|
|
|
2017-11-19 12:56:10 +00:00
|
|
|
|
2017-12-07 23:41:15 +00:00
|
|
|
RVA current_address = Core()->getOffset();
|
2017-03-29 10:18:37 +00:00
|
|
|
|
2017-12-07 23:41:15 +00:00
|
|
|
double width_per_byte = (double)w/(double)totalSectionsSize;
|
|
|
|
xToAddress.clear();
|
|
|
|
double x_start = 0.0;
|
2017-11-19 12:56:10 +00:00
|
|
|
|
2017-11-26 12:36:24 +00:00
|
|
|
|
2017-12-07 23:41:15 +00:00
|
|
|
bool draw_cursor = false;
|
|
|
|
double cursor_x = 0.0;
|
2017-11-19 12:56:10 +00:00
|
|
|
|
2017-12-07 23:41:15 +00:00
|
|
|
for(int i=0; i < sections.length(); i++)
|
2017-04-09 19:55:06 +00:00
|
|
|
{
|
2017-12-07 23:41:15 +00:00
|
|
|
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;
|
|
|
|
if (block != 0)
|
2017-04-09 19:55:06 +00:00
|
|
|
{
|
2017-12-07 23:41:15 +00:00
|
|
|
num = size / block;
|
2017-04-03 08:23:21 +00:00
|
|
|
}
|
2017-12-07 23:41:15 +00:00
|
|
|
|
|
|
|
if (num < 1)
|
2017-04-09 19:55:06 +00:00
|
|
|
{
|
2017-12-07 23:41:15 +00:00
|
|
|
num = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int graph_block = local_w / num;
|
2017-12-08 09:55:47 +00:00
|
|
|
if(graph_block == 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2017-12-07 23:41:15 +00:00
|
|
|
int counter = 0;
|
|
|
|
|
|
|
|
for (auto j : mainMap["blocks"].toList())
|
|
|
|
{
|
|
|
|
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())
|
2017-04-09 19:55:06 +00:00
|
|
|
{
|
2017-12-07 23:41:15 +00:00
|
|
|
// 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");
|
2017-12-08 09:55:47 +00:00
|
|
|
graphicsScene->addItem(rect);
|
2017-04-09 19:55:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-12-07 23:41:15 +00:00
|
|
|
// TODO: Make this compatible with theming
|
|
|
|
QGraphicsRectItem *rect = new QGraphicsRectItem(block_x_start, 0, graph_block, h);
|
|
|
|
rect->setPen(Qt::NoPen);
|
|
|
|
if (map["functions"].toInt() > 0)
|
|
|
|
{
|
|
|
|
rect->setBrush(QBrush(QColor(69, 104, 229)));
|
|
|
|
}
|
|
|
|
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));
|
2017-12-08 09:55:47 +00:00
|
|
|
graphicsScene->addItem(rect);
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
2017-12-07 23:41:15 +00:00
|
|
|
|
|
|
|
// 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)));
|
2017-12-08 09:55:47 +00:00
|
|
|
graphicsScene->addItem(rect);
|
2017-12-07 23:41:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2017-03-29 10:18:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|