Use p- in VisualNavbar

This commit is contained in:
Florian Märkl 2018-06-29 14:35:02 +02:00
parent e41d408fda
commit 7e8e182f72
3 changed files with 70 additions and 236 deletions

View File

@ -1537,7 +1537,7 @@ QList<SearchDescription> CutterCore::getAllSearch(QString search_for, QString sp
BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount) BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount)
{ {
QJsonObject statsObj = cmdj("p- " + QString::number(blocksCount)).object(); QJsonObject statsObj = cmdj("p-j " + QString::number(blocksCount)).object();
BlockStatistics ret; BlockStatistics ret;
ret.from = statsObj["from"].toVariant().toULongLong(); ret.from = statsObj["from"].toVariant().toULongLong();
@ -1545,7 +1545,7 @@ BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount)
ret.blocksize = statsObj["blocksize"].toVariant().toULongLong(); ret.blocksize = statsObj["blocksize"].toVariant().toULongLong();
QJsonArray blocksArray = statsObj["blocks"].toArray(); QJsonArray blocksArray = statsObj["blocks"].toArray();
for (QJsonValue value : blocksArray) { for (const QJsonValue &value : blocksArray) {
QJsonObject blockObj = value.toObject(); QJsonObject blockObj = value.toObject();
BlockDescription block; BlockDescription block;
block.addr = blockObj["offset"].toVariant().toULongLong(); block.addr = blockObj["offset"].toVariant().toULongLong();
@ -1572,7 +1572,7 @@ BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount)
ret.blocks << block; ret.blocks << block;
} }
return ret; return ret;
} }

View File

@ -41,8 +41,8 @@ VisualNavbar::VisualNavbar(MainWindow *main, QWidget *parent) :
connect(Core(), SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA))); connect(Core(), SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA)));
connect(Core(), SIGNAL(refreshAll()), this, SLOT(fetchAndPaintData())); connect(Core(), SIGNAL(refreshAll()), this, SLOT(fetchAndPaintData()));
connect(Core(), SIGNAL(functionsChanged()), this, SLOT(updateMetadataAndPaint())); connect(Core(), SIGNAL(functionsChanged()), this, SLOT(fetchAndPaintData()));
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(updateMetadataAndPaint())); connect(Core(), SIGNAL(flagsChanged()), this, SLOT(fetchAndPaintData()));
graphicsScene = new QGraphicsScene(this); graphicsScene = new QGraphicsScene(this);
@ -82,224 +82,85 @@ void VisualNavbar::fetchAndPaintData()
fillData(); fillData();
} }
bool VisualNavbar::sortSectionLessThan(const SectionDescription &section1,
const SectionDescription &section2)
{
return section1.vaddr < section2.vaddr;
}
VisualNavbar::MappedSegment *VisualNavbar::mappedSegmentForAddress(RVA addr)
{
for (int i = 0; i < mappedSegments.length(); i++) {
MappedSegment *mappedSegment = &mappedSegments[i];
if ((mappedSegment->address_from <= addr) && (addr <= mappedSegment->address_to)) {
return mappedSegment;
}
}
return nullptr;
}
void VisualNavbar::fetchData() void VisualNavbar::fetchData()
{ {
// TODO: This code is quite verbose but very readable. The goal is to statsWidth = graphicsView->width();
// experiment until we know what we want and then start to optimize. stats = Core()->getBlockStatistics((unsigned int)statsWidth);
sections = Core()->getAllSections();
// Sort sections so we don't have to filter for overlaps afterwards
qSort(sections.begin(), sections.end(), sortSectionLessThan);
mappedSegments.clear();
for (SectionDescription section : sections) {
bool segment_found = false;
for (int i = 0; i < mappedSegments.count(); i++) {
MappedSegment &mappedSegment = mappedSegments[i];
// Check if the segment contains the section
bool segment_contains_section_start = false;
if ((mappedSegment.address_from <= section.vaddr) &&
(section.vaddr <= mappedSegment.address_to)) {
segment_contains_section_start = true;
}
bool segment_contains_section_end = false;
if ((mappedSegment.address_from <= section.vaddr + section.vsize) &&
(section.vaddr + section.vsize <= mappedSegment.address_to)) {
segment_contains_section_end = true;
}
// Check if the section contains the segment
bool section_contains_segment_start = false;
bool section_contains_segment_end = false;
if ((section.vaddr <= mappedSegment.address_from) &&
(mappedSegment.address_from <= section.vaddr + section.vsize)) {
section_contains_segment_start = true;
}
if ((section.vaddr <= mappedSegment.address_to) &&
(mappedSegment.address_to <= section.vaddr + section.vsize)) {
section_contains_segment_end = true;
}
if (segment_contains_section_start | segment_contains_section_end |
section_contains_segment_start | section_contains_segment_end) {
if (section.vaddr < mappedSegment.address_from) {
mappedSegment.address_from = section.vaddr;
}
if (mappedSegment.address_to < section.vaddr + section.vsize) {
mappedSegment.address_to = section.vaddr + section.vsize;
}
segment_found = true;
mappedSegment.sectionDescriptions.append(section);
break;
}
}
if (!segment_found) {
MappedSegment mappedSegment;
mappedSegment.address_from = section.vaddr;
mappedSegment.address_to = section.vaddr + section.vsize;
mappedSegment.sectionDescriptions.append(section);
mappedSegments.append(mappedSegment);
}
}
// If the file does not contain any sections we get the segments
// from the memory maps instead.
// It treats each map on its own, so overlapping maps will be shown
// seperated.
if (sections.count() == 0) {
QJsonArray maps = Core()->cmdj("omj").array();
for (QJsonValue mapValue : maps) {
QJsonObject map = mapValue.toObject();
MappedSegment mappedSegment;
mappedSegment.address_from = map["from"].toVariant().toULongLong();
mappedSegment.address_to = map["to"].toVariant().toULongLong();
mappedSegments.append(mappedSegment);
}
}
totalMappedSize = 0;
for (auto &mappedSegment : mappedSegments) {
totalMappedSize += mappedSegment.address_to - mappedSegment.address_from;
}
updateMetadata();
} }
void VisualNavbar::updateMetadataAndPaint() enum class DataType: int { Empty, Code, String, Symbol, Count };
{
qWarning() << "Update metadata & paint";
updateMetadata();
fillData();
}
void VisualNavbar::updateMetadata()
{
for (int i = 0; i < mappedSegments.length(); i++) {
mappedSegments[i].functions.clear();
mappedSegments[i].symbols.clear();
mappedSegments[i].strings.clear();
}
QList<FunctionDescription> functions = Core()->getAllFunctions();
for (auto function : functions) {
auto mappedSegment = mappedSegmentForAddress(function.offset);
if (mappedSegment) {
MappedSegmentMetadata metadata;
metadata.address = function.offset;
metadata.size = function.size;
mappedSegment->functions.append(metadata);
}
}
QList<SymbolDescription> symbols = Core()->getAllSymbols();
for (auto symbol : symbols) {
auto mappedSegment = mappedSegmentForAddress(symbol.vaddr);
if (mappedSegment) {
MappedSegmentMetadata metadata;
metadata.address = symbol.vaddr;
metadata.size = 1;
mappedSegment->symbols.append(metadata);
}
}
QList<StringDescription> strings = Core()->getAllStrings();
for (auto string : strings) {
MappedSegment *mappedSegment = mappedSegmentForAddress(string.vaddr);
if (mappedSegment) {
MappedSegmentMetadata metadata;
metadata.address = string.vaddr;
metadata.size = string.string.length();
mappedSegment->strings.append(metadata);
}
}
}
void VisualNavbar::drawMetadata(QList<MappedSegmentMetadata> metadata,
RVA offset,
double x,
double width_per_byte,
double h, QColor color)
{
for (auto s : metadata) {
double block_x = x + ((double)(s.address - offset) * width_per_byte);
double block_width = (double)s.size * width_per_byte;
QGraphicsRectItem *rect = new QGraphicsRectItem(block_x, 0, block_width, h);
rect->setPen(Qt::NoPen);
rect->setBrush(QBrush(color));
graphicsScene->addItem(rect);
}
}
void VisualNavbar::fillData() void VisualNavbar::fillData()
{ {
graphicsScene->clear(); graphicsScene->clear();
xToAddress.clear();
cursorGraphicsItem = nullptr; cursorGraphicsItem = nullptr;
// Do not try to draw if no sections are available.
if (mappedSegments.length() == 0) { graphicsScene->setBackgroundBrush(QBrush(Config()->getColor("gui.navbar.empty")));
if (stats.to <= stats.from) {
return; return;
} }
int w = this->graphicsView->width(); int w = graphicsView->width();
int h = this->graphicsView->height(); int h = graphicsView->height();
double width_per_byte = (double)w / (double)totalMappedSize; RVA totalSize = stats.to - stats.from;
xToAddress.clear();
double current_x = 0;
for (auto mappedSegment : mappedSegments) {
RVA segment_size = mappedSegment.address_to - mappedSegment.address_from;
double segment_width = (double)segment_size * width_per_byte;
QGraphicsRectItem *rect = new QGraphicsRectItem(current_x, 0, segment_width, h);
rect->setBrush(QBrush(Config()->getColor("gui.navbar.empty")));
graphicsScene->addItem(rect);
drawMetadata(mappedSegment.strings,
mappedSegment.address_from,
current_x,
width_per_byte,
h, Config()->getColor("gui.navbar.str"));
drawMetadata(mappedSegment.symbols,
mappedSegment.address_from,
current_x,
width_per_byte,
h, Config()->getColor("gui.navbar.sym"));
drawMetadata(mappedSegment.functions,
mappedSegment.address_from,
current_x,
width_per_byte,
h, Config()->getColor("gui.navbar.code"));
double widthPerByte = (double)w / (double)totalSize;
auto xFromAddr = [widthPerByte] (RVA addr) -> double {
return addr * widthPerByte;
};
std::array<QBrush, static_cast<int>(DataType::Count)> dataTypeBrushes;
dataTypeBrushes[static_cast<int>(DataType::Code)] = QBrush(Config()->getColor("gui.navbar.code"));
dataTypeBrushes[static_cast<int>(DataType::String)] = QBrush(Config()->getColor("gui.navbar.str"));
dataTypeBrushes[static_cast<int>(DataType::Symbol)] = QBrush(Config()->getColor("gui.navbar.sym"));
DataType lastDataType = DataType::Empty;
QGraphicsRectItem *dataItem = nullptr;
QRectF dataItemRect(0.0, 0.0, 0.0, h);
for (const BlockDescription &block : stats.blocks) {
// Keep track of where which memory segment is mapped so we are able to convert from // Keep track of where which memory segment is mapped so we are able to convert from
// address to X coordinate and vice versa. // address to X coordinate and vice versa.
struct xToAddress x2a; XToAddress x2a;
x2a.x_start = current_x; x2a.x_start = xFromAddr(block.addr);
x2a.x_end = current_x + segment_width; x2a.x_end = xFromAddr(block.addr + block.size);
x2a.address_from = mappedSegment.address_from; x2a.address_from = block.addr;
x2a.address_to = mappedSegment.address_to; x2a.address_to = block.addr + block.size;
xToAddress.append(x2a); xToAddress.append(x2a);
current_x += segment_width; DataType dataType;
if (block.functions > 0) {
dataType = DataType::Code;
} else if (block.strings > 0) {
dataType = DataType::String;
} else if (block.symbols > 0) {
dataType = DataType::Symbol;
} else {
continue;
}
if (dataType == lastDataType) {
dataItemRect.setRight(xFromAddr(block.addr + block.size));
dataItem->setRect(dataItemRect);
continue;
}
dataItemRect.setX(xFromAddr(block.addr));
dataItemRect.setRight(xFromAddr(block.addr + block.size));
dataItem = new QGraphicsRectItem();
dataItem->setPen(Qt::NoPen);
dataItem->setBrush(dataTypeBrushes[static_cast<int>(dataType)]);
graphicsScene->addItem(dataItem);
lastDataType = dataType;
} }
// Update scene width // Update scene width
graphicsScene->setSceneRect(graphicsScene->itemsBoundingRect()); graphicsScene->setSceneRect(graphicsScene->itemsBoundingRect());
// Draw cursor
drawCursor(); drawCursor();
} }
@ -375,11 +236,10 @@ double VisualNavbar::addressToLocalX(RVA address)
QList<QString> VisualNavbar::sectionsForAddress(RVA address) QList<QString> VisualNavbar::sectionsForAddress(RVA address)
{ {
QList<QString> ret; QList<QString> ret;
for (auto mappedSegment : mappedSegments) { QList<SectionDescription> sections = Core()->getAllSections();
for (auto section : mappedSegment.sectionDescriptions) { for (const auto &section : sections) {
if ((section.vaddr <= address) && (address <= section.vaddr + section.vsize)) { if (address >= section.vaddr && address < section.vaddr + section.vsize) {
ret.append(section.name); ret << section.name;
}
} }
} }
return ret; return ret;

View File

@ -13,27 +13,13 @@ class VisualNavbar : public QToolBar
{ {
Q_OBJECT Q_OBJECT
struct xToAddress { struct XToAddress {
double x_start; double x_start;
double x_end; double x_end;
RVA address_from; RVA address_from;
RVA address_to; RVA address_to;
}; };
struct MappedSegmentMetadata {
RVA address;
RVA size;
};
struct MappedSegment {
QList<SectionDescription> sectionDescriptions;
QList<MappedSegmentMetadata> functions;
QList<MappedSegmentMetadata> symbols;
QList<MappedSegmentMetadata> strings;
RVA address_from;
RVA address_to;
};
public: public:
explicit VisualNavbar(MainWindow *main, QWidget *parent = nullptr); explicit VisualNavbar(MainWindow *main, QWidget *parent = nullptr);
@ -43,8 +29,6 @@ public slots:
private slots: private slots:
void fetchAndPaintData(); void fetchAndPaintData();
void fetchData(); void fetchData();
void updateMetadataAndPaint();
void updateMetadata();
void fillData(); void fillData();
void drawCursor(); void drawCursor();
void on_seekChanged(RVA addr); void on_seekChanged(RVA addr);
@ -54,30 +38,20 @@ private:
QGraphicsScene *graphicsScene; QGraphicsScene *graphicsScene;
QGraphicsRectItem *cursorGraphicsItem; QGraphicsRectItem *cursorGraphicsItem;
MainWindow *main; MainWindow *main;
RVA totalMappedSize;
QList<SectionDescription> sections;
QList<struct xToAddress> xToAddress;
QList<MappedSegment> mappedSegments; BlockStatistics stats;
int statsWidth;
QList<XToAddress> xToAddress;
// Used to check whether the width changed. If yes we need to re-initialize the scene (slow) // Used to check whether the width changed. If yes we need to re-initialize the scene (slow)
int previousWidth = -1; int previousWidth = -1;
void drawMetadata(QList<MappedSegmentMetadata> metadata,
RVA offset,
double x,
double width_per_byte,
double h, QColor color);
struct MappedSegment *mappedSegmentForAddress(RVA addr);
RVA localXToAddress(double x); RVA localXToAddress(double x);
double addressToLocalX(RVA address); double addressToLocalX(RVA address);
QList<QString> sectionsForAddress(RVA address); QList<QString> sectionsForAddress(RVA address);
QString toolTipForAddress(RVA address); QString toolTipForAddress(RVA address);
static bool sortSectionLessThan(const SectionDescription &section1,
const SectionDescription &section2);
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override;
}; };