diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index c2a5f4d3..30d6f091 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "Cutter.h" #include "utils/Colors.h" @@ -159,6 +160,11 @@ void DisassemblerGraphView::loadCurrentGraph() disassembly_blocks.clear(); blocks.clear(); + if (highlight_token) { + delete highlight_token; + highlight_token = nullptr; + } + bool emptyGraph = functions.isEmpty(); if (emptyGraph) { // If there's no function to print, just move to disassembly and add a message @@ -249,6 +255,7 @@ void DisassemblerGraphView::loadCurrentGraph() QTextDocument textDoc; textDoc.setHtml(disas); + i.plainText = textDoc.toPlainText(); RichTextPainter::List richText = RichTextPainter::fromTextDocument(textDoc); //Colors::colorizeAssembly(richText, textDoc.toPlainText(), 0); @@ -415,6 +422,29 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block) } } + // highlight selected tokens + if (highlight_token != nullptr) { + int y = block.y + (2 * charWidth) + (db.header_text.lines.size() * charHeight); + + for (Instr &instr : db.instrs) { + int pos = -1; + + while ((pos = instr.plainText.indexOf(highlight_token->content, pos + 1)) != -1) { + int tokenEnd = pos + highlight_token->content.length(); + + if ((pos > 0 && instr.plainText[pos - 1].isLetterOrNumber()) + || (tokenEnd < instr.plainText.length() && instr.plainText[tokenEnd].isLetterOrNumber())) { + continue; + } + + p.fillRect(QRect(block.x + charWidth * 3 + pos * charWidth, y, highlight_token->length * charWidth, + charHeight), disassemblySelectionColor.lighter(250)); + } + + y += int(instr.text.lines.size()) * charHeight; + } + } + // highlight program counter if (PCInBlock) { int y = block.y + (2 * charWidth) + (db.header_text.lines.size() * charHeight); @@ -691,17 +721,48 @@ void DisassemblerGraphView::seekPrev() } } +DisassemblerGraphView::Token * DisassemblerGraphView::getToken(Instr * instr, int x) +{ + int clickedCharPos = x / charWidth - 3; + + if (clickedCharPos > instr->plainText.length()) { + return nullptr; + } + + static const QRegularExpression tokenRegExp("\\b(?plainText); + + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + + if (match.capturedStart() <= clickedCharPos && match.capturedEnd() > clickedCharPos) { + Token * t = new Token; + t->start = match.capturedStart(); + t->length = match.capturedLength(); + t->content = match.captured(); + t->instr = instr; + + return t; + } + } + + return nullptr; +} + void DisassemblerGraphView::blockClicked(GraphView::GraphBlock &block, QMouseEvent *event, QPoint pos) { - RVA instr = getAddrForMouseEvent(block, &pos); - if (instr == RVA_INVALID) { + Instr *instr = getInstrForMouseEvent(block, &pos); + if (!instr) { return; } - seekLocal(instr); + highlight_token = getToken(instr, pos.x()); - mMenu->setOffset(instr); + RVA addr = instr->addr; + seekLocal(addr); + + mMenu->setOffset(addr); if (event->button() == Qt::RightButton) { mMenu->exec(event->globalPos()); } diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index d21604a9..249b4aa2 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -17,38 +17,6 @@ class DisassemblerGraphView : public GraphView { Q_OBJECT - - struct Token { - int start; //token[0] - int length; //token[1] - QString type; //token[2] - ut64 addr; //token[3] - QString name; //token[4] - }; - - struct HighlightToken { - QString type; //highlight_token[0] - ut64 addr; //highlight_token[1] - QString name; //highlight_token[2] - - bool equalsToken(const Token &token) - { - return this->type == token.type && - this->addr == token.addr && - this->name == token.name; - } - - static HighlightToken *fromToken(const Token &token) - { - //TODO: memory leaks - auto result = new HighlightToken(); - result->type = token.type; - result->addr = token.addr; - result->name = token.name; - return result; - } - }; - struct Text { std::vector lines; @@ -89,9 +57,18 @@ class DisassemblerGraphView : public GraphView ut64 size = 0; Text text; Text fullText; + QString plainText; std::vector opcode; //instruction bytes }; + struct Token { + int start; + int length; + QString type; + Instr * instr; + QString name; + QString content; + }; struct DisassemblyBlock { Text header_text; @@ -176,7 +153,7 @@ private: bool first_draw = true; bool transition_dont_seek = false; - HighlightToken *highlight_token; + Token *highlight_token; // Font data CachedFontMetrics *mFontMetrics; qreal charWidth; @@ -190,6 +167,7 @@ private: void initFont(); void prepareGraphNode(GraphBlock &block); + Token *getToken(Instr * instr, int x); RVA getAddrForMouseEvent(GraphBlock &block, QPoint *point); Instr *getInstrForMouseEvent(GraphBlock &block, QPoint *point); DisassemblyBlock *blockForAddress(RVA addr);