diff --git a/src/Cutter.cpp b/src/Cutter.cpp index 43831703..634a38cf 100644 --- a/src/Cutter.cpp +++ b/src/Cutter.cpp @@ -167,6 +167,10 @@ CutterCore::CutterCore(QObject *parent) : // Otherwise r2 may ask the user for input and Cutter would freeze setConfig("scr.interactive", false); + // Initialize graph node highlighter + bbHighlighter = new BasicBlockHighlighter(); + + // Initialize Async tasks manager asyncTaskManager = new AsyncTaskManager(this); } @@ -231,6 +235,7 @@ bool CutterCore::sdbSet(QString path, QString key, QString val) CutterCore::~CutterCore() { + delete bbHighlighter; r_core_free(this->core_); r_cons_free(); } @@ -2628,3 +2633,8 @@ QString CutterCore::ansiEscapeToHtml(const QString &text) free(html); return r; } + +BasicBlockHighlighter* CutterCore::getBBHighlighter() +{ + return bbHighlighter; +} diff --git a/src/Cutter.h b/src/Cutter.h index 6781814b..ae7f4fae 100644 --- a/src/Cutter.h +++ b/src/Cutter.h @@ -46,6 +46,7 @@ typedef ut64 RVA; class AsyncTaskManager; class CutterCore; #include "plugins/CutterPlugin.h" +#include "common/BasicBlockHighlighter.h" class RCoreLocked { @@ -728,6 +729,7 @@ public: RCoreLocked core() const; static QString ansiEscapeToHtml(const QString &text); + BasicBlockHighlighter *getBBHighlighter(); signals: void refreshAll(); @@ -783,6 +785,7 @@ private: QErrorMessage msgBox; bool emptyGraph = false; + BasicBlockHighlighter *bbHighlighter; }; diff --git a/src/Cutter.pro b/src/Cutter.pro index 3df480c0..8013cb93 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -298,7 +298,8 @@ SOURCES += \ dialogs/LoadNewTypesDialog.cpp \ widgets/SdbWidget.cpp \ common/PythonManager.cpp \ - plugins/PluginManager.cpp + plugins/PluginManager.cpp \ + common/BasicBlockHighlighter.cpp HEADERS += \ Cutter.h \ @@ -411,7 +412,8 @@ HEADERS += \ dialogs/LoadNewTypesDialog.h \ widgets/SdbWidget.h \ common/PythonManager.h \ - plugins/PluginManager.h + plugins/PluginManager.h \ + common/BasicBlockHighlighter.h FORMS += \ dialogs/AboutDialog.ui \ diff --git a/src/bindings/bindings.xml b/src/bindings/bindings.xml index cbd8fe44..d26c061c 100644 --- a/src/bindings/bindings.xml +++ b/src/bindings/bindings.xml @@ -7,6 +7,7 @@ + @@ -102,4 +103,4 @@ - \ No newline at end of file + diff --git a/src/common/BasicBlockHighlighter.cpp b/src/common/BasicBlockHighlighter.cpp new file mode 100644 index 00000000..e8565d12 --- /dev/null +++ b/src/common/BasicBlockHighlighter.cpp @@ -0,0 +1,48 @@ +#include "BasicBlockHighlighter.h" + +BasicBlockHighlighter::BasicBlockHighlighter() +{ +} + +BasicBlockHighlighter::~BasicBlockHighlighter() +{ + for (BasicBlockIt itr = bbMap.begin(); itr != bbMap.end(); itr++) { + delete itr->second; + } +} + +/*! + * \brief Highlight the basic block at address + */ +void BasicBlockHighlighter::highlight(RVA address, const QColor &color) +{ + BasicBlock *block = new BasicBlock; + block->address = address; + block->color = color; + bbMap[address] = block; +} + +/*! + * \brief Clear the basic block highlighting + */ +void BasicBlockHighlighter::clear(RVA address) +{ + bbMap.erase(address); +} + +/*! + * \brief Return a highlighted basic block + * + * If there is nothing to highlight at specified address, returns nullptr + */ +BasicBlock *BasicBlockHighlighter::getBasicBlock(RVA address) +{ + BasicBlockIt it; + + it = bbMap.find(address); + if (it != bbMap.end()) { + return it->second; + } + + return nullptr; +} diff --git a/src/common/BasicBlockHighlighter.h b/src/common/BasicBlockHighlighter.h new file mode 100644 index 00000000..53f44032 --- /dev/null +++ b/src/common/BasicBlockHighlighter.h @@ -0,0 +1,30 @@ +#ifndef BASICKBLOCKHIGHLIGHTER_H +#define BASICKBLOCKHIGHLIGHTER_H + +class BasicBlockHighlighter; + +#include "Cutter.h" +#include + +struct BasicBlock { + RVA address; + QColor color; +}; + +typedef std::map::iterator BasicBlockIt; + +class BasicBlockHighlighter +{ +public: + BasicBlockHighlighter(); + ~BasicBlockHighlighter(); + + void highlight(RVA address, const QColor &color); + void clear(RVA address); + BasicBlock *getBasicBlock(RVA address); + +private: + std::map bbMap; +}; + +#endif // BASICBLOCKHIGHLIGHTER_H diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 4d110f45..d6537d14 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -23,6 +23,7 @@ #include "common/CachedFontMetrics.h" #include "common/TempConfig.h" #include "common/SyntaxHighlighter.h" +#include "common/BasicBlockHighlighter.h" DisassemblerGraphView::DisassemblerGraphView(QWidget *parent) : GraphView(parent), @@ -429,8 +430,18 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block) p.setBrush(disassemblyBackgroundColor); } + // Draw basic block background p.drawRect(blockX, blockY, block.width, block.height); + auto bb = Core()->getBBHighlighter()->getBasicBlock(block.entry); + if (bb) { + QColor color(bb->color); + color.setAlphaF(0.5); + p.setBrush(color); + // Add basic block highlighting transparent color + p.drawRect(blockX, blockY, + block.width, block.height); + } // Draw different background for selected instruction if (selected_instruction != RVA_INVALID) { @@ -440,39 +451,16 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block) break; } auto selected = instr.addr == selected_instruction; - //auto traceCount = dbgfunctions->GetTraceRecordHitCount(instr.addr); - auto traceCount = 0; - if (selected && traceCount) { - p.fillRect(QRect(static_cast(blockX + charWidth), y, - static_cast(block.width - (10 + 2 * charWidth)), - int(instr.text.lines.size()) * charHeight), disassemblyTracedSelectionColor); - } else if (selected) { + if (selected) { p.fillRect(QRect(static_cast(blockX + charWidth), y, static_cast(block.width - (10 + 2 * charWidth)), int(instr.text.lines.size()) * charHeight), disassemblySelectionColor); - } else if (traceCount) { - // Color depending on how often a sequence of code is executed - int exponent = 1; - while (traceCount >>= 1) //log2(traceCount) - exponent++; - int colorDiff = (exponent * exponent) / 2; - - // If the user has a light trace background color, substract - if (disassemblyTracedColor.blue() > 160) - colorDiff *= -1; - - p.fillRect(QRect(static_cast(blockX + charWidth), y, - static_cast(block.width - (10 + 2 * charWidth)), - int(instr.text.lines.size()) * charHeight), - QColor(disassemblyTracedColor.red(), - disassemblyTracedColor.green(), - std::max(0, std::min(256, disassemblyTracedColor.blue() + colorDiff)))); } y += int(instr.text.lines.size()) * charHeight; } } - // highlight selected tokens + // Highlight selected tokens if (highlight_token != nullptr) { int y = static_cast(blockY + (2 * charWidth) + (db.header_text.lines.size() * charHeight)); int tokenWidth = mFontMetrics->width(highlight_token->content); @@ -508,7 +496,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block) } } - // highlight program counter + // Highlight program counter if (PCInBlock) { int y = static_cast(blockY + (2 * charWidth) + (db.header_text.lines.size() * charHeight)); for (const Instr &instr : db.instrs) { diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index dd566e2f..fc6e4112 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -192,8 +192,6 @@ private: QColor disassemblySelectedBackgroundColor; QColor disassemblySelectionColor; QColor PCSelectionColor; - QColor disassemblyTracedColor; - QColor disassemblyTracedSelectionColor; QColor jmpColor; QColor brtrueColor; QColor brfalseColor; diff --git a/src/widgets/OverviewView.cpp b/src/widgets/OverviewView.cpp index 024bf8e9..872140f7 100644 --- a/src/widgets/OverviewView.cpp +++ b/src/widgets/OverviewView.cpp @@ -52,6 +52,15 @@ void OverviewView::drawBlock(QPainter &p, GraphView::GraphBlock &block) p.setBrush(disassemblyBackgroundColor); p.drawRect(blockX, blockY, block.width, block.height); + // Draw basic block highlighting/tracing + auto bb = Core()->getBBHighlighter()->getBasicBlock(block.entry); + if (bb) { + QColor color(bb->color); + color.setAlphaF(0.5); + p.setBrush(color); + p.drawRect(block.x, block.y, + block.width, block.height); + } } void OverviewView::paintEvent(QPaintEvent *event)