Refactored Decompiler Widget and R2Dec Plugin to use RAnnotatedCode (#2227)

This commit is contained in:
NIRMAL MANOJ C 2020-06-09 02:59:26 +05:30 committed by karliss
parent 498d2076c8
commit 255ffe1208
4 changed files with 76 additions and 102 deletions

View File

@ -5,42 +5,6 @@
#include <QJsonObject> #include <QJsonObject>
#include <QJsonArray> #include <QJsonArray>
ut64 AnnotatedCode::OffsetForPosition(size_t pos) const
{
size_t closestPos = SIZE_MAX;
ut64 closestOffset = UT64_MAX;
for (const auto &annotation : annotations) {
if (annotation.type != CodeAnnotation::Type::Offset || annotation.start > pos || annotation.end <= pos) {
continue;
}
if (closestPos != SIZE_MAX && closestPos >= annotation.start) {
continue;
}
closestPos = annotation.start;
closestOffset = annotation.offset.offset;
}
return closestOffset;
}
size_t AnnotatedCode::PositionForOffset(ut64 offset) const
{
size_t closestPos = SIZE_MAX;
ut64 closestOffset = UT64_MAX;
for (const auto &annotation : annotations) {
if (annotation.type != CodeAnnotation::Type::Offset || annotation.offset.offset > offset) {
continue;
}
if (closestOffset != UT64_MAX && closestOffset >= annotation.offset.offset) {
continue;
}
closestPos = annotation.start;
closestOffset = annotation.offset.offset;
}
return closestPos;
}
Decompiler::Decompiler(const QString &id, const QString &name, QObject *parent) Decompiler::Decompiler(const QString &id, const QString &name, QObject *parent)
: QObject(parent), : QObject(parent),
id(id), id(id),
@ -48,6 +12,11 @@ Decompiler::Decompiler(const QString &id, const QString &name, QObject *parent)
{ {
} }
RAnnotatedCode *Decompiler::makeWarning(QString warningMessage){
std::string temporary = warningMessage.toStdString();
return r_annotated_code_new(strdup(temporary.c_str()));
}
R2DecDecompiler::R2DecDecompiler(QObject *parent) R2DecDecompiler::R2DecDecompiler(QObject *parent)
: Decompiler("r2dec", "r2dec", parent) : Decompiler("r2dec", "r2dec", parent)
{ {
@ -64,26 +33,22 @@ void R2DecDecompiler::decompileAt(RVA addr)
if (task) { if (task) {
return; return;
} }
task = new R2Task("pddj @ " + QString::number(addr)); task = new R2Task("pddj @ " + QString::number(addr));
connect(task, &R2Task::finished, this, [this]() { connect(task, &R2Task::finished, this, [this]() {
AnnotatedCode code = {};
QString s;
QJsonObject json = task->getResultJson().object(); QJsonObject json = task->getResultJson().object();
delete task; delete task;
task = nullptr; task = nullptr;
if (json.isEmpty()) { if (json.isEmpty()) {
code.code = tr("Failed to parse JSON from r2dec"); emit finished(Decompiler::makeWarning(tr("Failed to parse JSON from r2dec")));
emit finished(code);
return; return;
} }
RAnnotatedCode *code = r_annotated_code_new(nullptr);
QString codeString = "";
for (const auto &line : json["log"].toArray()) { for (const auto &line : json["log"].toArray()) {
if (!line.isString()) { if (!line.isString()) {
continue; continue;
} }
code.code.append(line.toString() + "\n"); codeString.append(line.toString() + "\n");
} }
auto linesArray = json["lines"].toArray(); auto linesArray = json["lines"].toArray();
@ -92,25 +57,24 @@ void R2DecDecompiler::decompileAt(RVA addr)
if (lineObject.isEmpty()) { if (lineObject.isEmpty()) {
continue; continue;
} }
CodeAnnotation annotation = {}; RCodeAnnotation *annotationi = new RCodeAnnotation;
annotation.type = CodeAnnotation::Type::Offset; annotationi->start = codeString.length();
annotation.start = code.code.length(); codeString.append(lineObject["str"].toString() + "\n");
code.code.append(lineObject["str"].toString() + "\n"); annotationi->end = codeString.length();
annotation.end = code.code.length();
bool ok; bool ok;
annotation.offset.offset = lineObject["offset"].toVariant().toULongLong(&ok); annotationi->type = R_CODE_ANNOTATION_TYPE_OFFSET;
if (ok) { annotationi->offset.offset = lineObject["offset"].toVariant().toULongLong(&ok);
code.annotations.push_back(annotation); r_annotated_code_add_annotation(code, annotationi);
}
} }
for (const auto &line : json["errors"].toArray()) { for (const auto &line : json["errors"].toArray()) {
if (!line.isString()) { if (!line.isString()) {
continue; continue;
} }
code.code.append(line.toString() + "\n"); codeString.append(line.toString() + "\n");
} }
std::string tmp = codeString.toStdString();
code->code = strdup(tmp.c_str());
emit finished(code); emit finished(code);
}); });
task->startTask(); task->startTask();

View File

@ -3,43 +3,11 @@
#include "CutterCommon.h" #include "CutterCommon.h"
#include "R2Task.h" #include "R2Task.h"
#include <r_util/r_annotated_code.h>
#include <QString> #include <QString>
#include <QObject> #include <QObject>
struct CodeAnnotation
{
size_t start;
size_t end;
enum class Type { Offset };
Type type;
union
{
struct
{
ut64 offset;
} offset;
};
};
/**
* Describes the result of a Decompilation Process with optional metadata
*/
struct AnnotatedCode
{
/**
* The entire decompiled code
*/
QString code;
QList<CodeAnnotation> annotations;
ut64 OffsetForPosition(size_t pos) const;
size_t PositionForOffset(ut64 offset) const;
};
/** /**
* Implements a decompiler that can be registered using CutterCore::registerDecompiler() * Implements a decompiler that can be registered using CutterCore::registerDecompiler()
*/ */
@ -55,6 +23,8 @@ public:
Decompiler(const QString &id, const QString &name, QObject *parent = nullptr); Decompiler(const QString &id, const QString &name, QObject *parent = nullptr);
virtual ~Decompiler() = default; virtual ~Decompiler() = default;
static RAnnotatedCode *makeWarning(QString warningMessage);
QString getId() const { return id; } QString getId() const { return id; }
QString getName() const { return name; } QString getName() const { return name; }
virtual bool isRunning() { return false; } virtual bool isRunning() { return false; }
@ -64,7 +34,7 @@ public:
virtual void cancel() {} virtual void cancel() {}
signals: signals:
void finished(AnnotatedCode code); void finished(RAnnotatedCode *codeDecompiled);
}; };
class R2DecDecompiler: public Decompiler class R2DecDecompiler: public Decompiler

View File

@ -18,7 +18,8 @@
DecompilerWidget::DecompilerWidget(MainWindow *main) : DecompilerWidget::DecompilerWidget(MainWindow *main) :
MemoryDockWidget(MemoryWidgetType::Decompiler, main), MemoryDockWidget(MemoryWidgetType::Decompiler, main),
mCtxMenu(new DisassemblyContextMenu(this, main)), mCtxMenu(new DisassemblyContextMenu(this, main)),
ui(new Ui::DecompilerWidget) ui(new Ui::DecompilerWidget),
code(Decompiler::makeWarning(tr("Choose an offset and refresh to get decompiled code")), &r_annotated_code_free)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -139,6 +140,45 @@ void DecompilerWidget::updateRefreshButton()
} }
} }
static ut64 offsetForPosition(RAnnotatedCode &codeDecompiled, size_t pos)
{
size_t closestPos = SIZE_MAX;
ut64 closestOffset = UT64_MAX;
void *annotationi;
r_vector_foreach(&codeDecompiled.annotations, annotationi) {
RCodeAnnotation *annotation = (RCodeAnnotation *)annotationi;
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET || annotation->start > pos
|| annotation->end <= pos) {
continue;
}
if (closestPos != SIZE_MAX && closestPos >= annotation->start) {
continue;
}
closestPos = annotation->start;
closestOffset = annotation->offset.offset;
}
return closestOffset;
}
static size_t positionForOffset(RAnnotatedCode &codeDecompiled, ut64 offset)
{
size_t closestPos = SIZE_MAX;
ut64 closestOffset = UT64_MAX;
void *annotationi;
r_vector_foreach(&codeDecompiled.annotations, annotationi) {
RCodeAnnotation *annotation = (RCodeAnnotation *)annotationi;
if (annotation->type != R_CODE_ANNOTATION_TYPE_OFFSET || annotation->offset.offset > offset) {
continue;
}
if (closestOffset != UT64_MAX && closestOffset >= annotation->offset.offset) {
continue;
}
closestPos = annotation->start;
closestOffset = annotation->offset.offset;
}
return closestPos;
}
void DecompilerWidget::doRefresh(RVA addr) void DecompilerWidget::doRefresh(RVA addr)
{ {
if (!refreshDeferrer->attemptRefresh(nullptr)) { if (!refreshDeferrer->attemptRefresh(nullptr)) {
@ -183,7 +223,7 @@ void DecompilerWidget::refreshDecompiler()
QTextCursor DecompilerWidget::getCursorForAddress(RVA addr) QTextCursor DecompilerWidget::getCursorForAddress(RVA addr)
{ {
size_t pos = code.PositionForOffset(addr); size_t pos = positionForOffset(*code, addr);
if (pos == SIZE_MAX || pos == 0) { if (pos == SIZE_MAX || pos == 0) {
return QTextCursor(); return QTextCursor();
} }
@ -193,19 +233,20 @@ QTextCursor DecompilerWidget::getCursorForAddress(RVA addr)
return cursor; return cursor;
} }
void DecompilerWidget::decompilationFinished(AnnotatedCode code) void DecompilerWidget::decompilationFinished(RAnnotatedCode *codeDecompiled)
{ {
ui->progressLabel->setVisible(false); ui->progressLabel->setVisible(false);
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled); ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
updateRefreshButton(); updateRefreshButton();
this->code = code; this->code.reset(codeDecompiled);
if (code.code.isEmpty()) { QString codeString = QString::fromUtf8(this->code->code);
if (codeString.isEmpty()) {
ui->textEdit->setPlainText(tr("Cannot decompile at this address (Not a function?)")); ui->textEdit->setPlainText(tr("Cannot decompile at this address (Not a function?)"));
return; return;
} else { } else {
connectCursorPositionChanged(true); connectCursorPositionChanged(true);
ui->textEdit->setPlainText(code.code); ui->textEdit->setPlainText(codeString);
connectCursorPositionChanged(false); connectCursorPositionChanged(false);
updateCursorPosition(); updateCursorPosition();
highlightPC(); highlightPC();
@ -244,7 +285,7 @@ void DecompilerWidget::cursorPositionChanged()
} }
size_t pos = ui->textEdit->textCursor().position(); size_t pos = ui->textEdit->textCursor().position();
RVA offset = code.OffsetForPosition(pos); RVA offset = offsetForPosition(*code, pos);
if (offset != RVA_INVALID && offset != Core()->getOffset()) { if (offset != RVA_INVALID && offset != Core()->getOffset()) {
seekFromCursor = true; seekFromCursor = true;
Core()->seek(offset); Core()->seek(offset);
@ -274,7 +315,7 @@ void DecompilerWidget::seekChanged()
void DecompilerWidget::updateCursorPosition() void DecompilerWidget::updateCursorPosition()
{ {
RVA offset = Core()->getOffset(); RVA offset = Core()->getOffset();
size_t pos = code.PositionForOffset(offset); size_t pos = positionForOffset(*code, offset);
if (pos == SIZE_MAX) { if (pos == SIZE_MAX) {
return; return;
} }
@ -334,7 +375,7 @@ void DecompilerWidget::showDisasContextMenu(const QPoint &pt)
void DecompilerWidget::seekToReference() void DecompilerWidget::seekToReference()
{ {
size_t pos = ui->textEdit->textCursor().position(); size_t pos = ui->textEdit->textCursor().position();
RVA offset = code.OffsetForPosition(pos); RVA offset = offsetForPosition(*code, pos);
seekable->seekToReference(offset); seekable->seekToReference(offset);
} }
@ -352,7 +393,6 @@ bool DecompilerWidget::eventFilter(QObject *obj, QEvent *event)
return MemoryDockWidget::eventFilter(obj, event); return MemoryDockWidget::eventFilter(obj, event);
} }
void DecompilerWidget::highlightPC() void DecompilerWidget::highlightPC()
{ {
RVA PCAddress = Core()->getProgramCounterValue(); RVA PCAddress = Core()->getProgramCounterValue();

View File

@ -38,7 +38,7 @@ private slots:
void decompilerSelected(); void decompilerSelected();
void cursorPositionChanged(); void cursorPositionChanged();
void seekChanged(); void seekChanged();
void decompilationFinished(AnnotatedCode code); void decompilationFinished(RAnnotatedCode *code);
private: private:
std::unique_ptr<Ui::DecompilerWidget> ui; std::unique_ptr<Ui::DecompilerWidget> ui;
@ -56,8 +56,7 @@ private:
bool decompilerWasBusy; bool decompilerWasBusy;
RVA decompiledFunctionAddr; RVA decompiledFunctionAddr;
AnnotatedCode code; std::unique_ptr<RAnnotatedCode, void (*)(RAnnotatedCode*)> code;
bool seekFromCursor = false; bool seekFromCursor = false;
Decompiler *getCurrentDecompiler(); Decompiler *getCurrentDecompiler();
@ -99,6 +98,7 @@ private:
* It will also run when a breakpoint is added, removed or modified. * It will also run when a breakpoint is added, removed or modified.
*/ */
void highlightBreakpoints(); void highlightBreakpoints();
}; };
#endif // DECOMPILERWIDGET_H #endif // DECOMPILERWIDGET_H