Graph highlighting (#624)

* Add saving instruction plaintext
* Add graph highlighting
* Remove HighlightToken
This commit is contained in:
Adam Zambrzycki 2018-08-16 16:05:48 +02:00 committed by xarkes
parent bb3ff2dc54
commit 336c20a955
2 changed files with 76 additions and 37 deletions

View File

@ -11,6 +11,7 @@
#include <QFileDialog>
#include <QFile>
#include <QVBoxLayout>
#include <QRegularExpression>
#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(?<!\\.)([^\\s]+)\\b(?!\\.)");
QRegularExpressionMatchIterator i = tokenRegExp.globalMatch(instr->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());
}

View File

@ -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<RichTextPainter::List> lines;
@ -89,9 +57,18 @@ class DisassemblerGraphView : public GraphView
ut64 size = 0;
Text text;
Text fullText;
QString plainText;
std::vector<unsigned char> 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);