diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 41effa61..f3a706bf 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -124,6 +124,7 @@ HexWidget::HexWidget(QWidget *parent) : startAddress = 0ULL; cursor.address = 0ULL; data.reset(new MemoryData()); + oldData.reset(new MemoryData()); fetchData(); updateCursorMeta(); @@ -206,6 +207,27 @@ void HexWidget::setItemGroupSize(int size) viewport()->update(); } +/** + * @brief Checks if Item at the address changed compared to the last read data. + * @param address Address of Item to be compared. + * @return True if Item is different, False if Item is equal or last read didn't contain the address. + * @see HexWidget#readItem + * + * Checks if current Item at the address changed compared to the last read data. + * It is assumed that the current read data buffer contains the address. + */ +bool HexWidget::isItemDifferentAt(uint64_t address) { + if (address >= oldData->minIndex() && address < oldData->maxIndex()) { + uint64_t itemOffset = address - startAddress; + QVariant curItem = readItem(itemOffset); + data.swap(oldData); + QVariant oldItem = readItem(itemOffset); + data.swap(oldData); + return (oldItem != curItem); + } + return false; +} + void HexWidget::updateCounts() { actionHexPairs->setEnabled(rowSizeBytes > 1 && itemByteLen == 1 @@ -335,6 +357,7 @@ void HexWidget::updateColors() printableColor = Config()->getColor("ai.write"); defColor = Config()->getColor("btext"); addrColor = Config()->getColor("func_var_addr"); + diffColor = Config()->getColor("graph.diff.unmatch"); updateCursorMeta(); viewport()->update(); @@ -465,13 +488,13 @@ void HexWidget::wheelEvent(QWheelEvent *event) startAddress = 0; } else if (delta > 0 && data->maxIndex() < static_cast(bytesPerScreen())) { startAddress = 0; - } else if (delta > 0 - && (data->maxIndex() - startAddress) <= static_cast(bytesPerScreen() + delta - 1)) { - startAddress = (data->maxIndex() - bytesPerScreen()) + 1; } else { startAddress += delta; } fetchData(); + if ((data->maxIndex() - startAddress) <= static_cast(bytesPerScreen() + delta - 1)) { + startAddress = (data->maxIndex() - bytesPerScreen()) + 1; + } if (cursor.address >= startAddress && cursor.address <= lastVisibleAddr()) { /* Don't enable cursor blinking if selection isn't empty */ cursorEnabled = selection.isEmpty(); @@ -756,6 +779,9 @@ void HexWidget::drawItemArea(QPainter &painter) if (selection.contains(itemAddr) && !cursorOnAscii) { itemColor = palette().highlightedText().color(); } + if (isItemDifferentAt(itemAddr)) { + itemColor.setRgb(diffColor.rgb()); + } painter.setPen(itemColor); painter.drawText(itemRect, Qt::AlignVCenter, itemString); itemRect.translate(itemWidth(), 0); @@ -789,8 +815,12 @@ void HexWidget::drawAsciiArea(QPainter &painter) charRect.moveLeft(asciiArea.left()); for (int j = 0; j < itemRowByteLen() && address <= data->maxIndex(); ++j, ++address) { ascii = renderAscii(address - startAddress, &color); - if (selection.contains(address) && cursorOnAscii) + if (selection.contains(address) && cursorOnAscii) { color = palette().highlightedText().color(); + } + if (isItemDifferentAt(address)) { + color.setRgb(diffColor.rgb()); + } painter.setPen(color); /* Dots look ugly. Use fillRect() instead of drawText(). */ if (ascii == '.') { @@ -985,10 +1015,6 @@ void HexWidget::setCursorAddr(BasicCursor addr, bool select) /* Align start address */ addressValue -= (addressValue % itemRowByteLen()); - if (addressValue > (data->maxIndex() - bytesPerScreen()) + 1) { - addressValue = (data->maxIndex() - bytesPerScreen()) + 1; - } - /* FIXME: handling Page Up/Down */ if (addressValue == startAddress + bytesPerScreen()) { startAddress += itemRowByteLen(); @@ -997,6 +1023,10 @@ void HexWidget::setCursorAddr(BasicCursor addr, bool select) } fetchData(); + + if (startAddress > (data->maxIndex() - bytesPerScreen()) + 1) { + startAddress = (data->maxIndex() - bytesPerScreen()) + 1; + } } updateCursorMeta(); @@ -1192,6 +1222,7 @@ QChar HexWidget::renderAscii(int offset, QColor *color) void HexWidget::fetchData() { + data.swap(oldData); data->fetch(startAddress, bytesPerScreen()); } diff --git a/src/widgets/HexWidget.h b/src/widgets/HexWidget.h index 60651dc0..ebb561c8 100644 --- a/src/widgets/HexWidget.h +++ b/src/widgets/HexWidget.h @@ -75,6 +75,7 @@ public: virtual void fetch(uint64_t addr, int len) = 0; virtual const void *dataPtr(uint64_t addr) = 0; virtual uint64_t maxIndex() = 0; + virtual uint64_t minIndex() = 0; }; class BufferData : public AbstractData @@ -121,14 +122,20 @@ public: void fetch(uint64_t address, int length) override { // FIXME: reuse data if possible - uint64_t alignedAddr = address & ~(4096ULL - 1); + const uint64_t blockSize = 0x1000ULL; + uint64_t alignedAddr = address & ~(blockSize - 1); int offset = address - alignedAddr; - int len = (offset + length + (4096 - 1)) & ~(4096 - 1); + int len = (offset + length + (blockSize - 1)) & ~(blockSize - 1); m_firstBlockAddr = alignedAddr; + m_lastValidAddr = length ? alignedAddr + len - 1 : 0; + if (m_lastValidAddr < m_firstBlockAddr) { + m_lastValidAddr = -1; + len = m_lastValidAddr - m_firstBlockAddr + 1; + } m_blocks.clear(); uint64_t addr = alignedAddr; - for (int i = 0; i < len / 4096; ++i, addr += 4096) { - m_blocks.append(Core()->ioRead(addr, 4096)); + for (int i = 0; i < len / blockSize; ++i, addr += blockSize) { + m_blocks.append(Core()->ioRead(addr, blockSize)); } } @@ -142,12 +149,18 @@ public: virtual uint64_t maxIndex() override { - return UINT64_MAX; + return m_lastValidAddr; + } + + virtual uint64_t minIndex() override + { + return m_firstBlockAddr; } private: QVector m_blocks; - uint64_t m_firstBlockAddr; + uint64_t m_firstBlockAddr = 0; + uint64_t m_lastValidAddr = 0; }; class HexSelection @@ -298,6 +311,7 @@ private: void setCursorAddr(BasicCursor addr, bool select = false); void updateCursorMeta(); void setCursorOnAscii(bool ascii); + bool isItemDifferentAt(uint64_t address); const QColor itemColor(uint8_t byte); QVariant readItem(int offset, QColor *color = nullptr); QString renderItem(int offset, QColor *color = nullptr); @@ -446,6 +460,7 @@ private: QColor backgroundColor; QColor defColor; QColor addrColor; + QColor diffColor; QColor b0x00Color; QColor b0x7fColor; QColor b0xffColor; @@ -469,6 +484,7 @@ private: QAction *actionCopyAddress; QAction *actionSelectRange; + std::unique_ptr oldData; std::unique_ptr data; }; diff --git a/src/widgets/HexdumpWidget.cpp b/src/widgets/HexdumpWidget.cpp index cab6895c..dcde3e74 100644 --- a/src/widgets/HexdumpWidget.cpp +++ b/src/widgets/HexdumpWidget.cpp @@ -80,6 +80,9 @@ HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) : connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated())); connect(Core(), &CutterCore::refreshAll, this, [this]() { refresh(); }); + connect(Core(), &CutterCore::instructionChanged, this, [this]() { refresh(); }); + connect(Core(), &CutterCore::stackChanged, this, [this]() { refresh(); }); + connect(Core(), &CutterCore::registersChanged, this, [this]() { refresh(); }); connect(seekable, &CutterSeekable::seekableSeekChanged, this, &HexdumpWidget::onSeekChanged); connect(ui->hexTextView, &HexWidget::positionChanged, this, [this](RVA addr) {