diff --git a/src/Cutter.cpp b/src/Cutter.cpp index 66ca90f9..196ab652 100644 --- a/src/Cutter.cpp +++ b/src/Cutter.cpp @@ -1537,7 +1537,7 @@ QList CutterCore::getAllSearch(QString search_for, QString sp 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; ret.from = statsObj["from"].toVariant().toULongLong(); @@ -1545,7 +1545,7 @@ BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount) ret.blocksize = statsObj["blocksize"].toVariant().toULongLong(); QJsonArray blocksArray = statsObj["blocks"].toArray(); - for (QJsonValue value : blocksArray) { + for (const QJsonValue &value : blocksArray) { QJsonObject blockObj = value.toObject(); BlockDescription block; block.addr = blockObj["offset"].toVariant().toULongLong(); @@ -1572,7 +1572,7 @@ BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount) ret.blocks << block; } - + return ret; } diff --git a/src/widgets/VisualNavbar.cpp b/src/widgets/VisualNavbar.cpp index e22963d9..e8eee37b 100644 --- a/src/widgets/VisualNavbar.cpp +++ b/src/widgets/VisualNavbar.cpp @@ -41,8 +41,8 @@ VisualNavbar::VisualNavbar(MainWindow *main, QWidget *parent) : connect(Core(), SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA))); connect(Core(), SIGNAL(refreshAll()), this, SLOT(fetchAndPaintData())); - connect(Core(), SIGNAL(functionsChanged()), this, SLOT(updateMetadataAndPaint())); - connect(Core(), SIGNAL(flagsChanged()), this, SLOT(updateMetadataAndPaint())); + connect(Core(), SIGNAL(functionsChanged()), this, SLOT(fetchAndPaintData())); + connect(Core(), SIGNAL(flagsChanged()), this, SLOT(fetchAndPaintData())); graphicsScene = new QGraphicsScene(this); @@ -82,224 +82,85 @@ void VisualNavbar::fetchAndPaintData() fillData(); } -bool VisualNavbar::sortSectionLessThan(const SectionDescription §ion1, - const SectionDescription §ion2) -{ - 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() { - // TODO: This code is quite verbose but very readable. The goal is to - // experiment until we know what we want and then start to optimize. - 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(); + statsWidth = graphicsView->width(); + stats = Core()->getBlockStatistics((unsigned int)statsWidth); } -void VisualNavbar::updateMetadataAndPaint() -{ - 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 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 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 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 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); - } -} +enum class DataType: int { Empty, Code, String, Symbol, Count }; void VisualNavbar::fillData() { graphicsScene->clear(); + xToAddress.clear(); 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; } - int w = this->graphicsView->width(); - int h = this->graphicsView->height(); + int w = graphicsView->width(); + int h = graphicsView->height(); - double width_per_byte = (double)w / (double)totalMappedSize; - 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")); + RVA totalSize = stats.to - stats.from; + double widthPerByte = (double)w / (double)totalSize; + auto xFromAddr = [widthPerByte] (RVA addr) -> double { + return addr * widthPerByte; + }; + + std::array(DataType::Count)> dataTypeBrushes; + dataTypeBrushes[static_cast(DataType::Code)] = QBrush(Config()->getColor("gui.navbar.code")); + dataTypeBrushes[static_cast(DataType::String)] = QBrush(Config()->getColor("gui.navbar.str")); + dataTypeBrushes[static_cast(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 // address to X coordinate and vice versa. - struct xToAddress x2a; - x2a.x_start = current_x; - x2a.x_end = current_x + segment_width; - x2a.address_from = mappedSegment.address_from; - x2a.address_to = mappedSegment.address_to; + XToAddress x2a; + x2a.x_start = xFromAddr(block.addr); + x2a.x_end = xFromAddr(block.addr + block.size); + x2a.address_from = block.addr; + x2a.address_to = block.addr + block.size; 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(dataType)]); + graphicsScene->addItem(dataItem); + + lastDataType = dataType; } // Update scene width graphicsScene->setSceneRect(graphicsScene->itemsBoundingRect()); - // Draw cursor drawCursor(); } @@ -375,11 +236,10 @@ double VisualNavbar::addressToLocalX(RVA address) QList VisualNavbar::sectionsForAddress(RVA address) { QList ret; - for (auto mappedSegment : mappedSegments) { - for (auto section : mappedSegment.sectionDescriptions) { - if ((section.vaddr <= address) && (address <= section.vaddr + section.vsize)) { - ret.append(section.name); - } + QList sections = Core()->getAllSections(); + for (const auto §ion : sections) { + if (address >= section.vaddr && address < section.vaddr + section.vsize) { + ret << section.name; } } return ret; diff --git a/src/widgets/VisualNavbar.h b/src/widgets/VisualNavbar.h index 88593241..d7dfcf6f 100644 --- a/src/widgets/VisualNavbar.h +++ b/src/widgets/VisualNavbar.h @@ -13,27 +13,13 @@ class VisualNavbar : public QToolBar { Q_OBJECT - struct xToAddress { + struct XToAddress { double x_start; double x_end; RVA address_from; RVA address_to; }; - struct MappedSegmentMetadata { - RVA address; - RVA size; - }; - - struct MappedSegment { - QList sectionDescriptions; - QList functions; - QList symbols; - QList strings; - RVA address_from; - RVA address_to; - }; - public: explicit VisualNavbar(MainWindow *main, QWidget *parent = nullptr); @@ -43,8 +29,6 @@ public slots: private slots: void fetchAndPaintData(); void fetchData(); - void updateMetadataAndPaint(); - void updateMetadata(); void fillData(); void drawCursor(); void on_seekChanged(RVA addr); @@ -54,30 +38,20 @@ private: QGraphicsScene *graphicsScene; QGraphicsRectItem *cursorGraphicsItem; MainWindow *main; - RVA totalMappedSize; - QList sections; - QList xToAddress; - QList mappedSegments; + BlockStatistics stats; + int statsWidth; + + QList xToAddress; // Used to check whether the width changed. If yes we need to re-initialize the scene (slow) int previousWidth = -1; - void drawMetadata(QList metadata, - RVA offset, - double x, - double width_per_byte, - double h, QColor color); - struct MappedSegment *mappedSegmentForAddress(RVA addr); RVA localXToAddress(double x); double addressToLocalX(RVA address); QList sectionsForAddress(RVA address); QString toolTipForAddress(RVA address); - static bool sortSectionLessThan(const SectionDescription §ion1, - const SectionDescription §ion2); - - void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; };