diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index c35b8cf7..6ce33d15 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -5,42 +5,6 @@ #include #include - -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), @@ -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) : Decompiler("r2dec", "r2dec", parent) { @@ -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(); @@ -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(); diff --git a/src/common/Decompiler.h b/src/common/Decompiler.h index cd88d4ec..031edefd 100644 --- a/src/common/Decompiler.h +++ b/src/common/Decompiler.h @@ -3,43 +3,11 @@ #include "CutterCommon.h" #include "R2Task.h" +#include #include #include -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 annotations; - - ut64 OffsetForPosition(size_t pos) const; - size_t PositionForOffset(ut64 offset) const; -}; - /** * 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); virtual ~Decompiler() = default; + static RAnnotatedCode *makeWarning(QString warningMessage); + QString getId() const { return id; } QString getName() const { return name; } virtual bool isRunning() { return false; } @@ -64,7 +34,7 @@ public: virtual void cancel() {} signals: - void finished(AnnotatedCode code); + void finished(RAnnotatedCode *codeDecompiled); }; class R2DecDecompiler: public Decompiler diff --git a/src/widgets/DecompilerWidget.cpp b/src/widgets/DecompilerWidget.cpp index 39482d3d..0140b913 100644 --- a/src/widgets/DecompilerWidget.cpp +++ b/src/widgets/DecompilerWidget.cpp @@ -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); @@ -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)) { @@ -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(); } @@ -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(); @@ -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); @@ -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; } @@ -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); } @@ -352,7 +393,6 @@ bool DecompilerWidget::eventFilter(QObject *obj, QEvent *event) return MemoryDockWidget::eventFilter(obj, event); } - void DecompilerWidget::highlightPC() { RVA PCAddress = Core()->getProgramCounterValue(); diff --git a/src/widgets/DecompilerWidget.h b/src/widgets/DecompilerWidget.h index 11c1a1dc..5b66b253 100644 --- a/src/widgets/DecompilerWidget.h +++ b/src/widgets/DecompilerWidget.h @@ -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; @@ -56,8 +56,7 @@ private: bool decompilerWasBusy; RVA decompiledFunctionAddr; - AnnotatedCode code; - + std::unique_ptr code; bool seekFromCursor = false; Decompiler *getCurrentDecompiler(); @@ -99,6 +98,7 @@ private: * It will also run when a breakpoint is added, removed or modified. */ void highlightBreakpoints(); + }; #endif // DECOMPILERWIDGET_H