From 5bf513c45b7e63ddbaf117e9e3eda7c7a195e975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 18 Dec 2020 10:47:50 +0100 Subject: [PATCH] Add RizinFunctionTask and common base class with RizinCmdTask (#2520) --- src/common/Decompiler.cpp | 4 +- src/common/Decompiler.h | 2 +- src/common/DecompilerHighlighter.cpp | 2 + src/common/RizinTask.cpp | 76 ++++++++++++++++++---------- src/common/RizinTask.h | 44 ++++++++++++---- src/core/Cutter.cpp | 15 +++--- src/core/Cutter.h | 13 +++-- src/widgets/GraphHorizontalAdapter.h | 2 + 8 files changed, 106 insertions(+), 52 deletions(-) diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index 7f6cf72e..56c6e8ff 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -33,8 +33,8 @@ void R2DecDecompiler::decompileAt(RVA addr) if (task) { return; } - task = new RizinTask("pddj @ " + QString::number(addr)); - connect(task, &RizinTask::finished, this, [this]() { + task = new RizinCmdTask("pddj @ " + QString::number(addr)); + connect(task, &RizinCmdTask::finished, this, [this]() { QJsonObject json = task->getResultJson().object(); delete task; task = nullptr; diff --git a/src/common/Decompiler.h b/src/common/Decompiler.h index b2ddf0ea..2fefd65d 100644 --- a/src/common/Decompiler.h +++ b/src/common/Decompiler.h @@ -42,7 +42,7 @@ class R2DecDecompiler: public Decompiler Q_OBJECT private: - RizinTask *task; + RizinCmdTask *task; public: explicit R2DecDecompiler(QObject *parent = nullptr); diff --git a/src/common/DecompilerHighlighter.cpp b/src/common/DecompilerHighlighter.cpp index 9c9028a2..f09cfe41 100644 --- a/src/common/DecompilerHighlighter.cpp +++ b/src/common/DecompilerHighlighter.cpp @@ -2,6 +2,8 @@ #include "DecompilerHighlighter.h" #include "common/Configuration.h" +#include + DecompilerHighlighter::DecompilerHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) { diff --git a/src/common/RizinTask.cpp b/src/common/RizinTask.cpp index 82579650..d48cfaf8 100644 --- a/src/common/RizinTask.cpp +++ b/src/common/RizinTask.cpp @@ -2,29 +2,11 @@ #include "RizinTask.h" #include -RizinTask::RizinTask(const QString &cmd, bool transient) -{ - task = rz_core_cmd_task_new(Core()->core(), - cmd.toLocal8Bit().constData(), - static_cast(&RizinTask::taskFinishedCallback), - this); - task->transient = transient; - rz_core_task_incref(task); -} - RizinTask::~RizinTask() { - rz_core_task_decref(task); -} - -void RizinTask::taskFinishedCallback(const char *, void *user) -{ - reinterpret_cast(user)->taskFinished(); -} - -void RizinTask::taskFinished() -{ - emit finished(); + if (task) { + rz_core_task_decref(task); + } } void RizinTask::startTask() @@ -42,25 +24,67 @@ void RizinTask::joinTask() rz_core_task_join(&Core()->core_->tasks, nullptr, task->id); } -QString RizinTask::getResult() +void RizinTask::taskFinished() +{ + emit finished(); +} + +// RizinCmdTask + +RizinCmdTask::RizinCmdTask(const QString &cmd, bool transient) +{ + task = rz_core_cmd_task_new(Core()->core(), + cmd.toLocal8Bit().constData(), + static_cast(&RizinCmdTask::taskFinishedCallback), + this); + task->transient = transient; + rz_core_task_incref(task); +} + +void RizinCmdTask::taskFinishedCallback(const char *, void *user) +{ + reinterpret_cast(user)->taskFinished(); +} + +QString RizinCmdTask::getResult() { const char *res = rz_core_cmd_task_get_result(task); - if(!res) { + if (!res) { return nullptr; } return QString::fromUtf8(res); } -QJsonDocument RizinTask::getResultJson() +QJsonDocument RizinCmdTask::getResultJson() { const char *res = rz_core_cmd_task_get_result(task); - if(!res) { + if (!res) { return QJsonDocument(); } return Core()->parseJson(res, nullptr); } -const char *RizinTask::getResultRaw() +const char *RizinCmdTask::getResultRaw() { return rz_core_cmd_task_get_result(task); } + +// RizinFunctionTask + +RizinFunctionTask::RizinFunctionTask(std::function fcn, bool transient) + : fcn(fcn), res(nullptr) +{ + task = rz_core_function_task_new(Core()->core(), + static_cast(&RizinFunctionTask::runner), + this); + task->transient = transient; + rz_core_task_incref(task); +} + +void *RizinFunctionTask::runner(RzCore *core, void *user) +{ + RizinFunctionTask *task = reinterpret_cast(user); + task->res = task->fcn(core); + task->taskFinished(); + return nullptr; +} diff --git a/src/common/RizinTask.h b/src/common/RizinTask.h index 31f4fb42..84cbaf90 100644 --- a/src/common/RizinTask.h +++ b/src/common/RizinTask.h @@ -4,32 +4,58 @@ #include "core/Cutter.h" -class RizinTask: public QObject +class CUTTER_EXPORT RizinTask: public QObject { Q_OBJECT -private: +protected: RzCoreTask *task; - static void taskFinishedCallback(const char *, void *user); + RizinTask() {} void taskFinished(); public: using Ptr = QSharedPointer; - explicit RizinTask(const QString &cmd, bool transient = true); - ~RizinTask(); + virtual ~RizinTask(); void startTask(); void breakTask(); void joinTask(); - QString getResult(); - QJsonDocument getResultJson(); - const char *getResultRaw(); - signals: void finished(); }; +class CUTTER_EXPORT RizinCmdTask: public RizinTask +{ + Q_OBJECT + +private: + static void taskFinishedCallback(const char *, void *user); + +public: + explicit RizinCmdTask(const QString &cmd, bool transient = true); + + QString getResult(); + QJsonDocument getResultJson(); + const char *getResultRaw(); +}; + +class CUTTER_EXPORT RizinFunctionTask: public RizinTask +{ + Q_OBJECT + +private: + std::function fcn; + void *res; + + static void *runner(RzCore *core, void *user); + +public: + explicit RizinFunctionTask(std::function fcn, bool transient = true); + + void *getResult() { return res; } +}; + #endif // RZTASK_H diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 475fa8d3..0860404c 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -15,6 +15,7 @@ #include "common/Configuration.h" #include "common/AsyncTask.h" #include "common/RizinTask.h" +#include "dialogs/RizinTaskDialog.h" #include "common/Json.h" #include "core/Cutter.h" #include "Decompiler.h" @@ -394,7 +395,7 @@ bool CutterCore::isDebugTaskInProgress() return false; } -bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer &task) +bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer &task) { asyncCmd(command, task); @@ -402,7 +403,7 @@ bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer &ta return false; } - connect(task.data(), &RizinTask::finished, task.data(), [this, task] () { + connect(task.data(), &RizinCmdTask::finished, task.data(), [this, task] () { QString res = task.data()->getResult(); if (res.contains(QStringLiteral("[ESIL] Stopped execution in an invalid instruction"))) { @@ -413,7 +414,7 @@ bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer &ta return true; } -bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) +bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) { if (!task.isNull()) { return false; @@ -423,8 +424,8 @@ bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) RVA offset = core->offset; - task = QSharedPointer(new RizinTask(str, true)); - connect(task.data(), &RizinTask::finished, task.data(), [this, offset, task] () { + task = QSharedPointer(new RizinCmdTask(str, true)); + connect(task.data(), &RizinCmdTask::finished, task.data(), [this, offset, task] () { CORE_LOCK(); if (offset != core->offset) { @@ -494,7 +495,7 @@ QJsonDocument CutterCore::cmdjAt(const char *str, RVA address) QString CutterCore::cmdTask(const QString &str) { - RizinTask task(str); + RizinCmdTask task(str); task.startTask(); task.joinTask(); return task.getResult(); @@ -502,7 +503,7 @@ QString CutterCore::cmdTask(const QString &str) QJsonDocument CutterCore::cmdjTask(const QString &str) { - RizinTask task(str); + RizinCmdTask task(str); task.startTask(); task.joinTask(); return parseJson(task.getResultRaw(), str); diff --git a/src/core/Cutter.h b/src/core/Cutter.h index e717ae3f..5adcad96 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -21,12 +21,11 @@ class BasicInstructionHighlighter; class CutterCore; class Decompiler; class RizinTask; +class RizinCmdTask; class RizinTaskDialog; #include "common/BasicBlockHighlighter.h" -#include "common/RizinTask.h" #include "common/Helpers.h" -#include "dialogs/RizinTaskDialog.h" #include @@ -75,8 +74,8 @@ public: * Once you have setup connections you can start the task with task->startTask() * If you want to seek to an address, you should use CutterCore::seek. */ - bool asyncCmd(const char *str, QSharedPointer &task); - bool asyncCmd(const QString &str, QSharedPointer &task) { return asyncCmd(str.toUtf8().constData(), task); } + bool asyncCmd(const char *str, QSharedPointer &task); + bool asyncCmd(const QString &str, QSharedPointer &task) { return asyncCmd(str.toUtf8().constData(), task); } /** * @brief Execute a Rizin command \a cmd. By nature, the API @@ -132,8 +131,8 @@ public: * Once you have setup connections you can start the task with task->startTask() * If you want to seek to an address, you should use CutterCore::seek. */ - bool asyncCmdEsil(const char *command, QSharedPointer &task); - bool asyncCmdEsil(const QString &command, QSharedPointer &task) { return asyncCmdEsil(command.toUtf8().constData(), task); } + bool asyncCmdEsil(const char *command, QSharedPointer &task); + bool asyncCmdEsil(const QString &command, QSharedPointer &task) { return asyncCmdEsil(command.toUtf8().constData(), task); } QString getVersionInformation(); QJsonDocument parseJson(const char *res, const char *cmd = nullptr); @@ -725,7 +724,7 @@ private: bool iocache = false; BasicInstructionHighlighter biHighlighter; - QSharedPointer debugTask; + QSharedPointer debugTask; RizinTaskDialog *debugTaskDialog; QVector getCutterRCFilePaths() const; diff --git a/src/widgets/GraphHorizontalAdapter.h b/src/widgets/GraphHorizontalAdapter.h index f17b181b..3f27b98d 100644 --- a/src/widgets/GraphHorizontalAdapter.h +++ b/src/widgets/GraphHorizontalAdapter.h @@ -4,6 +4,8 @@ #include "core/Cutter.h" #include "GraphLayout.h" +#include + /** * @brief Adapter for converting vertical graph layout into horizontal one. */