Skip to content

Commit

Permalink
Refactored Decompiler Widget and R2Dec Plugin to use RAnnotatedCode (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
NirmalManoj committed Jun 8, 2020
1 parent 1e9b828 commit 8759d4d
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 102 deletions.
74 changes: 19 additions & 55 deletions src/common/Decompiler.cpp
Expand Up @@ -5,49 +5,18 @@
#include <QJsonObject>
#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)
: QObject(parent),
id(id),
name(name)
{
}

RAnnotatedCode *Decompiler::makeWarning(QString warningMessage){
std::string temporary = warningMessage.toStdString();
return r_annotated_code_new(strdup(temporary.c_str()));
}

R2DecDecompiler::R2DecDecompiler(QObject *parent)
: Decompiler("r2dec", "r2dec", parent)
{
Expand All @@ -64,26 +33,22 @@ void R2DecDecompiler::decompileAt(RVA addr)
if (task) {
return;
}

task = new R2Task("pddj @ " + QString::number(addr));
connect(task, &R2Task::finished, this, [this]() {
AnnotatedCode code = {};
QString s;

QJsonObject json = task->getResultJson().object();
delete task;
task = nullptr;
if (json.isEmpty()) {
code.code = tr("Failed to parse JSON from r2dec");
emit finished(code);
emit finished(Decompiler::makeWarning(tr("Failed to parse JSON from r2dec")));
return;
}

RAnnotatedCode *code = r_annotated_code_new(nullptr);
QString codeString = "";
for (const auto &line : json["log"].toArray()) {
if (!line.isString()) {
continue;
}
code.code.append(line.toString() + "\n");
codeString.append(line.toString() + "\n");
}

auto linesArray = json["lines"].toArray();
Expand All @@ -92,25 +57,24 @@ void R2DecDecompiler::decompileAt(RVA addr)
if (lineObject.isEmpty()) {
continue;
}
CodeAnnotation annotation = {};
annotation.type = CodeAnnotation::Type::Offset;
annotation.start = code.code.length();
code.code.append(lineObject["str"].toString() + "\n");
annotation.end = code.code.length();
RCodeAnnotation *annotationi = new RCodeAnnotation;
annotationi->start = codeString.length();
codeString.append(lineObject["str"].toString() + "\n");
annotationi->end = codeString.length();
bool ok;
annotation.offset.offset = lineObject["offset"].toVariant().toULongLong(&ok);
if (ok) {
code.annotations.push_back(annotation);
}
annotationi->type = R_CODE_ANNOTATION_TYPE_OFFSET;
annotationi->offset.offset = lineObject["offset"].toVariant().toULongLong(&ok);
r_annotated_code_add_annotation(code, annotationi);
}

for (const auto &line : json["errors"].toArray()) {
if (!line.isString()) {
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);
});
task->startTask();
Expand Down
38 changes: 4 additions & 34 deletions src/common/Decompiler.h
Expand Up @@ -3,43 +3,11 @@

#include "CutterCommon.h"
#include "R2Task.h"
#include <r_util/r_annotated_code.h>

#include <QString>
#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()
*/
Expand All @@ -55,6 +23,8 @@ class Decompiler: public QObject
Decompiler(const QString &id, const QString &name, QObject *parent = nullptr);
virtual ~Decompiler() = default;

static RAnnotatedCode *makeWarning(QString warningMessage);

QString getId() const { return id; }
QString getName() const { return name; }
virtual bool isRunning() { return false; }
Expand All @@ -64,7 +34,7 @@ class Decompiler: public QObject
virtual void cancel() {}

signals:
void finished(AnnotatedCode code);
void finished(RAnnotatedCode *codeDecompiled);
};

class R2DecDecompiler: public Decompiler
Expand Down
60 changes: 50 additions & 10 deletions src/widgets/DecompilerWidget.cpp
Expand Up @@ -18,7 +18,8 @@
DecompilerWidget::DecompilerWidget(MainWindow *main) :
MemoryDockWidget(MemoryWidgetType::Decompiler, 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);

Expand Down Expand Up @@ -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)
{
if (!refreshDeferrer->attemptRefresh(nullptr)) {
Expand Down Expand Up @@ -183,7 +223,7 @@ void DecompilerWidget::refreshDecompiler()

QTextCursor DecompilerWidget::getCursorForAddress(RVA addr)
{
size_t pos = code.PositionForOffset(addr);
size_t pos = positionForOffset(*code, addr);
if (pos == SIZE_MAX || pos == 0) {
return QTextCursor();
}
Expand All @@ -193,19 +233,20 @@ QTextCursor DecompilerWidget::getCursorForAddress(RVA addr)
return cursor;
}

void DecompilerWidget::decompilationFinished(AnnotatedCode code)
void DecompilerWidget::decompilationFinished(RAnnotatedCode *codeDecompiled)
{
ui->progressLabel->setVisible(false);
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
updateRefreshButton();

this->code = code;
if (code.code.isEmpty()) {
this->code.reset(codeDecompiled);
QString codeString = QString::fromUtf8(this->code->code);
if (codeString.isEmpty()) {
ui->textEdit->setPlainText(tr("Cannot decompile at this address (Not a function?)"));
return;
} else {
connectCursorPositionChanged(true);
ui->textEdit->setPlainText(code.code);
ui->textEdit->setPlainText(codeString);
connectCursorPositionChanged(false);
updateCursorPosition();
highlightPC();
Expand Down Expand Up @@ -244,7 +285,7 @@ void DecompilerWidget::cursorPositionChanged()
}

size_t pos = ui->textEdit->textCursor().position();
RVA offset = code.OffsetForPosition(pos);
RVA offset = offsetForPosition(*code, pos);
if (offset != RVA_INVALID && offset != Core()->getOffset()) {
seekFromCursor = true;
Core()->seek(offset);
Expand Down Expand Up @@ -274,7 +315,7 @@ void DecompilerWidget::seekChanged()
void DecompilerWidget::updateCursorPosition()
{
RVA offset = Core()->getOffset();
size_t pos = code.PositionForOffset(offset);
size_t pos = positionForOffset(*code, offset);
if (pos == SIZE_MAX) {
return;
}
Expand Down Expand Up @@ -334,7 +375,7 @@ void DecompilerWidget::showDisasContextMenu(const QPoint &pt)
void DecompilerWidget::seekToReference()
{
size_t pos = ui->textEdit->textCursor().position();
RVA offset = code.OffsetForPosition(pos);
RVA offset = offsetForPosition(*code, pos);
seekable->seekToReference(offset);
}

Expand All @@ -352,7 +393,6 @@ bool DecompilerWidget::eventFilter(QObject *obj, QEvent *event)
return MemoryDockWidget::eventFilter(obj, event);
}


void DecompilerWidget::highlightPC()
{
RVA PCAddress = Core()->getProgramCounterValue();
Expand Down
6 changes: 3 additions & 3 deletions src/widgets/DecompilerWidget.h
Expand Up @@ -38,7 +38,7 @@ private slots:
void decompilerSelected();
void cursorPositionChanged();
void seekChanged();
void decompilationFinished(AnnotatedCode code);
void decompilationFinished(RAnnotatedCode *code);

private:
std::unique_ptr<Ui::DecompilerWidget> ui;
Expand All @@ -56,8 +56,7 @@ private slots:
bool decompilerWasBusy;

RVA decompiledFunctionAddr;
AnnotatedCode code;

std::unique_ptr<RAnnotatedCode, void (*)(RAnnotatedCode*)> code;
bool seekFromCursor = false;

Decompiler *getCurrentDecompiler();
Expand Down Expand Up @@ -99,6 +98,7 @@ private slots:
* It will also run when a breakpoint is added, removed or modified.
*/
void highlightBreakpoints();

};

#endif // DECOMPILERWIDGET_H

0 comments on commit 8759d4d

Please sign in to comment.