From 0c9687850027784b27b053e9d1f883fe0e66d831 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 19 Feb 2024 20:17:05 +0800 Subject: [PATCH 01/17] Update Rizin to the latest dev --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index fa455f8b..9719961b 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit fa455f8b5244ad0cebe2fa8aca1c71096f55dfa1 +Subproject commit 9719961b8217a97ec9327236519b0bc500a480c5 From 8574f0b0e42a1f0d12599548d9907a56dd236182 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 19 Feb 2024 20:36:28 +0800 Subject: [PATCH 02/17] Fix rz_core_analysis_bytes() API use --- src/core/Cutter.cpp | 21 ++++++--------------- src/core/RizinCpp.h | 6 ++++++ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 47fc607d..2a0db993 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -722,11 +722,10 @@ PRzAnalysisBytes CutterCore::getRzAnalysisBytesSingle(RVA addr) rz_io_read_at(core->io, addr, buf, sizeof(buf)); auto seek = seekTemp(addr); - auto vec = fromOwned(rz_core_analysis_bytes(core, addr, buf, sizeof(buf), 1)); + auto abiter = fromOwned(rz_core_analysis_bytes(core, addr, buf, sizeof(buf), 1)); + auto ab = + abiter ? reinterpret_cast(rz_iterator_next(abiter.get())) : nullptr; - auto ab = vec && rz_pvector_len(vec.get()) > 0 - ? reinterpret_cast(rz_pvector_pop_front(vec.get())) - : nullptr; return { ab, rz_analysis_bytes_free }; } @@ -1027,18 +1026,10 @@ RVA CutterCore::nextOpAddr(RVA startAddr, int count) { CORE_LOCK(); auto seek = seekTemp(startAddr); - auto vec = fromOwned(rz_core_analysis_bytes(core, core->offset, core->block, - (int)core->blocksize, count + 1)); + auto consumed = + rz_core_analysis_ops_size(core, core->offset, core->block, (int)core->blocksize, count); - RVA addr = startAddr + 1; - if (!vec) { - return addr; - } - auto ab = reinterpret_cast(rz_pvector_tail(vec.get())); - if (!(ab && ab->op)) { - return addr; - } - addr = ab->op->addr; + RVA addr = startAddr + consumed; return addr; } diff --git a/src/core/RizinCpp.h b/src/core/RizinCpp.h index 6399e145..65fd95b6 100644 --- a/src/core/RizinCpp.h +++ b/src/core/RizinCpp.h @@ -51,6 +51,12 @@ static inline auto fromOwned(RZ_OWN RzList *data) -> UniquePtrCP UniquePtrCP +{ + return { data, {} }; +} + // Rizin list iteration macros // deprecated, prefer using CutterPVector and CutterRzList instead #define CutterRzListForeach(list, it, type, x) \ From 1a52a7eea43e2d3d3c429b4826b39b3e31b9026d Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 19 Feb 2024 23:08:32 +0800 Subject: [PATCH 03/17] Fix compilation error of undefined TRUE --- src/widgets/GraphvizLayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/GraphvizLayout.cpp b/src/widgets/GraphvizLayout.cpp index f2a53b3c..eb1fe4e3 100644 --- a/src/widgets/GraphvizLayout.cpp +++ b/src/widgets/GraphvizLayout.cpp @@ -94,7 +94,7 @@ void GraphvizLayout::CalculateLayout(std::unordered_map &block std::unordered_map nodes; for (const auto &block : blocks) { - nodes[block.first] = agnode(g, nullptr, TRUE); + nodes[block.first] = agnode(g, nullptr, true); } std::vector strc; @@ -143,7 +143,7 @@ void GraphvizLayout::CalculateLayout(std::unordered_map &block if (v == nodes.end()) { continue; } - auto e = agedge(g, u, v->second, nullptr, TRUE); + auto e = agedge(g, u, v->second, nullptr, true); edges[{ blockIt.first, edge.target }] = e; if (loopEdges.find({ blockIt.first, edge.target }) != loopEdges.end()) { agxset(e, constraintAttr, STR("0")); From 372b45c8b9a8b90b9c025e2b47afa0090452d982 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sat, 24 Feb 2024 00:02:53 +0800 Subject: [PATCH 04/17] Update Rizin to the latest dev --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 9719961b..78d4043a 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 9719961b8217a97ec9327236519b0bc500a480c5 +Subproject commit 78d4043afb39a56fe91ea7ab03c83da613319cc3 From c20d2c61d67b0c0d4ceb23706c2ff6c8fb838fee Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sat, 24 Feb 2024 11:51:13 +0800 Subject: [PATCH 05/17] Bump version to v2.4.0 --- .appveyor.yml | 2 +- CMakeLists.txt | 2 +- docs/source/conf.py | 4 ++-- src/re.rizin.cutter.appdata.xml | 5 +++++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index ef25be60..849a98a6 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.2.0-git-{build}' +version: '2.4.0-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 771bddf1..4eefd16e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ if(NOT CUTTER_ENABLE_PYTHON) endif() set(CUTTER_VERSION_MAJOR 2) -set(CUTTER_VERSION_MINOR 2) +set(CUTTER_VERSION_MINOR 4) set(CUTTER_VERSION_PATCH 0) set(CUTTER_VERSION "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index 34af39b1..f86e443e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -24,9 +24,9 @@ copyright = '2020, The Cutter Developers' author = 'The Cutter Developers' # The short X.Y version -version = '2.2' +version = '2.4' # The full version, including a2lpha/beta/rc tags -release = '2.2.0' +release = '2.4.0' # -- General configuration --------------------------------------------------- diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index 9ef364ba..46efbef2 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,11 @@ xarkes + + + + + From 2106551d00348dc4117a842aeb8d9f8428d626ee Mon Sep 17 00:00:00 2001 From: wargio Date: Sat, 24 Feb 2024 19:47:29 +0800 Subject: [PATCH 06/17] Remove JSDec as decompiler and use rizin C api --- src/CutterApplication.cpp | 4 -- src/common/Decompiler.cpp | 99 ---------------------------- src/common/Decompiler.h | 16 ----- src/common/RizinTask.cpp | 2 +- src/core/Cutter.cpp | 44 ++++--------- src/core/Cutter.h | 6 +- src/menus/DisassemblyContextMenu.cpp | 2 +- src/widgets/GraphvizLayout.cpp | 4 +- 8 files changed, 21 insertions(+), 156 deletions(-) diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index 79a48b59..fc71ba58 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -120,10 +120,6 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc Config()->setOutputRedirectionEnabled(clOptions.outputRedirectionEnabled); - if (JSDecDecompiler::isAvailable()) { - Core()->registerDecompiler(new JSDecDecompiler(Core())); - } - #if CUTTER_RZGHIDRA_STATIC Core()->registerDecompiler(new RzGhidraDecompiler(Core())); #endif diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index 2d9478e5..2089a408 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -10,107 +10,8 @@ Decompiler::Decompiler(const QString &id, const QString &name, QObject *parent) { } -static char *jsonToStrdup(const CutterJson &str) -{ - const RzJson *j = str.lowLevelValue(); - if (!j || j->type != RZ_JSON_STRING) { - return NULL; - } - return rz_str_dup(j->str_value); -} - -static RzAnnotatedCode *parseJsonCode(CutterJson &json) -{ - char *raw_code = jsonToStrdup(json["code"]); - if (!raw_code) { - return NULL; - } - RzAnnotatedCode *code = rz_annotated_code_new(raw_code); - if (!code) { - return NULL; - } - for (const auto &jsonAnnotation : json["annotations"]) { - RzCodeAnnotation annotation = {}; - annotation.start = jsonAnnotation["start"].toUt64(); - annotation.end = jsonAnnotation["end"].toUt64(); - QString type = jsonAnnotation["type"].toString(); - if (type == "offset") { - annotation.type = RZ_CODE_ANNOTATION_TYPE_OFFSET; - annotation.offset.offset = jsonAnnotation["offset"].toString().toULongLong(); - } else if (type == "function_name") { - annotation.type = RZ_CODE_ANNOTATION_TYPE_FUNCTION_NAME; - annotation.reference.name = jsonToStrdup(jsonAnnotation["name"]); - annotation.reference.offset = jsonAnnotation["offset"].toString().toULongLong(); - } else if (type == "global_variable") { - annotation.type = RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE; - annotation.reference.offset = jsonAnnotation["offset"].toString().toULongLong(); - } else if (type == "constant_variable") { - annotation.type = RZ_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE; - annotation.reference.offset = jsonAnnotation["offset"].toString().toULongLong(); - } else if (type == "local_variable") { - annotation.type = RZ_CODE_ANNOTATION_TYPE_LOCAL_VARIABLE; - annotation.variable.name = jsonToStrdup(jsonAnnotation["name"]); - } else if (type == "function_parameter") { - annotation.type = RZ_CODE_ANNOTATION_TYPE_FUNCTION_PARAMETER; - annotation.variable.name = jsonToStrdup(jsonAnnotation["name"]); - } else if (type == "syntax_highlight") { - annotation.type = RZ_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT; - QString highlightType = jsonAnnotation["syntax_highlight"].toString(); - if (highlightType == "keyword") { - annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_KEYWORD; - } else if (highlightType == "comment") { - annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_COMMENT; - } else if (highlightType == "datatype") { - annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_DATATYPE; - } else if (highlightType == "function_name") { - annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME; - } else if (highlightType == "function_parameter") { - annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_PARAMETER; - } else if (highlightType == "local_variable") { - annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_LOCAL_VARIABLE; - } else if (highlightType == "constant_variable") { - annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE; - } else if (highlightType == "global_variable") { - annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_GLOBAL_VARIABLE; - } - } - rz_annotated_code_add_annotation(code, &annotation); - } - return code; -} - RzAnnotatedCode *Decompiler::makeWarning(QString warningMessage) { std::string temporary = warningMessage.toStdString(); return rz_annotated_code_new(strdup(temporary.c_str())); } - -JSDecDecompiler::JSDecDecompiler(QObject *parent) : Decompiler("jsdec", "jsdec", parent) -{ - task = nullptr; -} - -bool JSDecDecompiler::isAvailable() -{ - return Core()->getConfigVariableSpaces().contains("jsdec"); -} - -void JSDecDecompiler::decompileAt(RVA addr) -{ - if (task) { - return; - } - task = new RizinCmdTask("pddA @ " + QString::number(addr)); - connect(task, &RizinCmdTask::finished, this, [this]() { - CutterJson json = task->getResultJson(); - delete task; - task = nullptr; - if (!json.size()) { - emit finished(Decompiler::makeWarning(tr("Failed to parse JSON from jsdec"))); - return; - } - RzAnnotatedCode *code = parseJsonCode(json); - emit finished(code); - }); - task->startTask(); -} diff --git a/src/common/Decompiler.h b/src/common/Decompiler.h index c3468b1e..5cff67a8 100644 --- a/src/common/Decompiler.h +++ b/src/common/Decompiler.h @@ -37,20 +37,4 @@ signals: void finished(RzAnnotatedCode *codeDecompiled); }; -class JSDecDecompiler : public Decompiler -{ - Q_OBJECT - -private: - RizinCmdTask *task; - -public: - explicit JSDecDecompiler(QObject *parent = nullptr); - void decompileAt(RVA addr) override; - - bool isRunning() override { return task != nullptr; } - - static bool isAvailable(); -}; - #endif // DECOMPILER_H diff --git a/src/common/RizinTask.cpp b/src/common/RizinTask.cpp index 14433585..f3423ab9 100644 --- a/src/common/RizinTask.cpp +++ b/src/common/RizinTask.cpp @@ -62,7 +62,7 @@ CutterJson RizinCmdTask::getResultJson() } char *copy = static_cast(rz_mem_alloc(strlen(res) + 1)); strcpy(copy, res); - return Core()->parseJson(copy, nullptr); + return Core()->parseJson("task", copy, nullptr); } const char *RizinCmdTask::getResultRaw() diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 2a0db993..3b2eaa48 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -273,6 +273,7 @@ void CutterCore::loadCutterRC() } qInfo() << tr("Loading initialization file from ") << cutterRCFilePath; rz_core_cmd_file(core, cutterRCFilePath.toUtf8().constData()); + rz_cons_flush(); } } @@ -286,6 +287,7 @@ void CutterCore::loadDefaultCutterRC() } qInfo() << tr("Loading initialization file from ") << cutterRCFilePath; rz_core_cmd_file(core, cutterRCFilePath.toUtf8().constData()); + rz_cons_flush(); } QList CutterCore::sdbList(QString path) @@ -473,19 +475,7 @@ QString CutterCore::cmdRaw(const char *cmd) { QString res; CORE_LOCK(); - rz_cons_push(); - - // rz_core_cmd does not return the output of the command - rz_core_cmd(core, cmd, 0); - - // we grab the output straight from rz_cons - res = rz_cons_get_buffer(); - - // cleaning up - rz_cons_pop(); - rz_cons_echo(NULL); - - return res; + return rz_core_cmd_str(core, cmd); } CutterJson CutterCore::cmdj(const char *str) @@ -496,7 +486,7 @@ CutterJson CutterCore::cmdj(const char *str) res = rz_core_cmd_str(core, str); } - return parseJson(res, str); + return parseJson("cmdj", res, str); } QString CutterCore::cmdTask(const QString &str) @@ -507,9 +497,9 @@ QString CutterCore::cmdTask(const QString &str) return task.getResult(); } -CutterJson CutterCore::parseJson(char *res, const char *cmd) +CutterJson CutterCore::parseJson(const char *name, char *res, const char *cmd) { - if (!res) { + if (RZ_STR_ISEMPTY(res)) { return CutterJson(); } @@ -517,18 +507,11 @@ CutterJson CutterCore::parseJson(char *res, const char *cmd) if (!doc) { if (cmd) { - eprintf("Failed to parse JSON for command \"%s\"\n", cmd); + RZ_LOG_ERROR("%s: Failed to parse JSON for command \"%s\"\n%s\n", name, cmd, res); } else { - eprintf("Failed to parse JSON\n"); - } - const int MAX_JSON_DUMP_SIZE = 8 * 1024; - size_t originalSize = strlen(res); - if (originalSize > MAX_JSON_DUMP_SIZE) { - res[MAX_JSON_DUMP_SIZE] = 0; - eprintf("%zu bytes total: %s ...\n", originalSize, res); - } else { - eprintf("%s\n", res); + RZ_LOG_ERROR("%s: Failed to parse JSON %s\n", name, res); } + RZ_LOG_ERROR("%s: %s\n", name, res); } return CutterJson(doc, QSharedPointer::create(doc, res)); @@ -602,8 +585,6 @@ bool CutterCore::loadFile(QString path, ut64 baddr, ut64 mapaddr, int perms, int rz_bin_select_idx(core->bin, NULL, idx); } #endif - } else { - // Not loading RzBin info coz va = false } auto iod = core->io ? core->io->desc : NULL; @@ -611,7 +592,8 @@ bool CutterCore::loadFile(QString path, ut64 baddr, ut64 mapaddr, int perms, int core->file && iod && (core->file->fd == iod->fd) && iod->plugin && iod->plugin->isdbg; if (!debug && rz_flag_get(core->flags, "entry0")) { - rz_core_cmd0(core, "s entry0"); + ut64 addr = rz_num_math(core->num, "entry0"); + rz_core_seek_and_save(core, addr, true); } if (perms & RZ_PERM_W) { @@ -621,6 +603,7 @@ bool CutterCore::loadFile(QString path, ut64 baddr, ut64 mapaddr, int perms, int } } + rz_cons_flush(); fflush(stdout); return true; } @@ -1390,7 +1373,7 @@ CutterJson CutterCore::getSignatureInfo() if (!signature) { return {}; } - return parseJson(signature, nullptr); + return parseJson("signature", signature, nullptr); } bool CutterCore::existsFileInfo() @@ -4333,6 +4316,7 @@ void CutterCore::loadScript(const QString &scriptname) { CORE_LOCK(); rz_core_cmd_file(core, scriptname.toUtf8().constData()); + rz_cons_flush(); } triggerRefreshAll(); } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index ff2b4682..9634381b 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -183,10 +183,10 @@ public: QString getRizinVersionReadable(const char *program = nullptr); QString getVersionInformation(); - CutterJson parseJson(char *res, const char *cmd = nullptr); - CutterJson parseJson(char *res, const QString &cmd = QString()) + CutterJson parseJson(const char *name, char *res, const char *cmd = nullptr); + CutterJson parseJson(const char *name, char *res, const QString &cmd = QString()) { - return parseJson(res, cmd.isNull() ? nullptr : cmd.toLocal8Bit().constData()); + return parseJson(name, res, cmd.isNull() ? nullptr : cmd.toLocal8Bit().constData()); } QStringList autocomplete(const QString &cmd, RzLinePromptType promptType, size_t limit = 4096); diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 9879a16e..fbadfeca 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -520,7 +520,7 @@ void DisassemblyContextMenu::aboutToShowSlot() if (ab && ab->op) { const char *opexstr = RZ_STRBUF_SAFEGET(&ab->op->opex); - CutterJson operands = Core()->parseJson(strdup(opexstr), nullptr); + CutterJson operands = Core()->parseJson("opex", strdup(opexstr), nullptr); // Loop through both the operands of the instruction for (const CutterJson operand : operands) { diff --git a/src/widgets/GraphvizLayout.cpp b/src/widgets/GraphvizLayout.cpp index eb1fe4e3..e7770dc1 100644 --- a/src/widgets/GraphvizLayout.cpp +++ b/src/widgets/GraphvizLayout.cpp @@ -193,11 +193,11 @@ void GraphvizLayout::CalculateLayout(std::unordered_map &block if (it != edges.end()) { auto e = it->second; if (auto spl = ED_spl(e)) { - for (int i = 0; i < 1 && i < spl->size; i++) { + for (size_t i = 0; i < 1 && i < spl->size; i++) { auto bz = spl->list[i]; edge.polyline.clear(); edge.polyline.reserve(bz.size + 1); - for (int j = 0; j < bz.size; j++) { + for (size_t j = 0; j < bz.size; j++) { edge.polyline.push_back(QPointF(bz.list[j].x, bz.list[j].y)); } QPointF last(0, 0); From 70024929af52422877b1f5c63c212460b47d3a47 Mon Sep 17 00:00:00 2001 From: wargio Date: Sat, 24 Feb 2024 23:55:19 +0800 Subject: [PATCH 07/17] Build cutter native jsdec --- dist/CMakeLists.txt | 11 +++++++++-- dist/bundle_jsdec.ps1 | 24 +++++++++++++++++------- scripts/jsdec.sh | 16 ++++++++++------ 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index 2fe5b671..489bf8f1 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -24,7 +24,9 @@ if(WIN32) install(CODE " set(ENV{RZ_PREFIX} \"\${CMAKE_INSTALL_PREFIX}\") set(ENV{PATH} \"\${CMAKE_INSTALL_PREFIX};\$ENV{PATH}\") - execute_process(COMMAND powershell \"${CMAKE_CURRENT_SOURCE_DIR}/bundle_jsdec.ps1\" \"\${CMAKE_INSTALL_PREFIX}\" + execute_process(COMMAND powershell \"${CMAKE_CURRENT_SOURCE_DIR}/bundle_jsdec.ps1\" + \"\${CMAKE_INSTALL_PREFIX}\" + \"-DCUTTER_INSTALL_PLUGDIR=plugins/native\" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) @@ -124,9 +126,14 @@ endif() if(CUTTER_ENABLE_DEPENDENCY_DOWNLOADS AND (NOT WIN32)) if (CUTTER_PACKAGE_JSDEC) + if(APPLE) + set (JSDEC_PLUGIN_OPTIONS "-DCUTTER_INSTALL_PLUGDIR=plugins/native") + else() + set (JSDEC_PLUGIN_OPTIONS "") + endif() install(CODE " execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/jsdec.sh\" - --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} + \"\${CMAKE_INSTALL_PREFIX}\" \"${JSDEC_PLUGIN_OPTIONS}\" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) diff --git a/dist/bundle_jsdec.ps1 b/dist/bundle_jsdec.ps1 index 64466a7c..df7328be 100644 --- a/dist/bundle_jsdec.ps1 +++ b/dist/bundle_jsdec.ps1 @@ -2,16 +2,26 @@ $dist = $args[0] $python = Split-Path((Get-Command python.exe).Path) if (-not (Test-Path -Path 'jsdec' -PathType Container)) { - git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch "v0.7.0" + git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch "dev" } cd jsdec -& meson.exe --buildtype=release --prefix="$dist" build -ninja -C build install +$jsdecdir = (Get-Item .).FullName + +& meson.exe setup --buildtype=release -Dbuild_type=cutter "$jsdecdir\build_lib" +ninja -C "$jsdecdir\build_lib" + +# cmake is silly and expects .lib but meson generates the static lib as .a +Copy-Item "$jsdecdir\build_lib\libjsdec.a" -Destination "$jsdecdir\build_lib\jsdec.lib" + +mkdir build_plugin +cd build_plugin +cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DJSDEC_BUILD_DIR="$jsdecdir\build_lib" -DCMAKE_INSTALL_PREFIX="$dist" $cmake_opts "$jsdecdir\cutter-plugin" +ninja install + $ErrorActionPreference = 'Stop' -$pathdll = "$dist\lib\rizin\plugins\core_pdd.dll" +$pathdll = "$dist\share\rizin\cutter\plugins\native\jsdec_cutter.dll" if(![System.IO.File]::Exists($pathdll)) { - type build\meson-logs\meson-log.txt - ls "$dist\lib\rizin\plugins\" + echo "files: $dist\share\rizin\cutter\plugins\native\" + ls "$dist\share\rizin\cutter\plugins\native\" throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) } -Remove-Item -Recurse -Force "$dist\lib\rizin\plugins\core_pdd.lib" diff --git a/scripts/jsdec.sh b/scripts/jsdec.sh index c084133c..ed81a112 100755 --- a/scripts/jsdec.sh +++ b/scripts/jsdec.sh @@ -1,20 +1,24 @@ #!/bin/bash set -e +INSTALL_PREFIX="$1" +EXTRA_CMAKE_OPTS="$2" SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") cd "$SCRIPTPATH/.." if [ ! -d jsdec ]; then - git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch "v0.7.0" + git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch "dev" fi cd jsdec -if [ -d build ]; then - rm -rf build +if [ -d build_lib ]; then + rm -rf build_lib fi -meson --buildtype=release "$@" build -ninja -C build -ninja -C build install +meson setup --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" -Dbuild_type=cutter build_lib +ninja -C build_lib +mkdir build_plugin && cd build_plugin +cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DJSDEC_BUILD_DIR="../build_lib" -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" $EXTRA_CMAKE_OPTS ../cutter-plugin +ninja install From 6b660e7a481e87f73b995dee96788ef3ccd9c4f4 Mon Sep 17 00:00:00 2001 From: Karliss Date: Tue, 27 Feb 2024 00:14:01 +0200 Subject: [PATCH 08/17] Fix multiple crashes related to incorrect rz_iterator usage. RzAnalysisBytes are owned by the iterator, so returning analysis bytes while destroying iterator owning it is incorrect. --- src/core/Cutter.cpp | 12 +++++------- src/core/Cutter.h | 4 +--- src/core/RizinCpp.h | 32 ++++++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 3b2eaa48..3bce681a 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -698,18 +698,16 @@ void CutterCore::delFlag(const QString &name) emit flagsChanged(); } -PRzAnalysisBytes CutterCore::getRzAnalysisBytesSingle(RVA addr) +CutterRzIter CutterCore::getRzAnalysisBytesSingle(RVA addr) { CORE_LOCK(); ut8 buf[128]; rz_io_read_at(core->io, addr, buf, sizeof(buf)); - auto seek = seekTemp(addr); - auto abiter = fromOwned(rz_core_analysis_bytes(core, addr, buf, sizeof(buf), 1)); - auto ab = - abiter ? reinterpret_cast(rz_iterator_next(abiter.get())) : nullptr; - - return { ab, rz_analysis_bytes_free }; + // Warning! only safe to use with stack buffer, due to instruction count being 1 + auto result = + CutterRzIter(rz_core_analysis_bytes(core, addr, buf, sizeof(buf), 1)); + return result; } QString CutterCore::getInstructionBytes(RVA addr) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 9634381b..1ebf89f8 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -62,8 +62,6 @@ struct CUTTER_EXPORT RegisterRef QString name; }; -using PRzAnalysisBytes = std::unique_ptr; - class CUTTER_EXPORT CutterCore : public QObject { Q_OBJECT @@ -248,7 +246,7 @@ public: QString getGlobalVariableType(RVA offset); /* Edition functions */ - PRzAnalysisBytes getRzAnalysisBytesSingle(RVA addr); + CutterRzIter getRzAnalysisBytesSingle(RVA addr); QString getInstructionBytes(RVA addr); QString getInstructionOpcode(RVA addr); void editInstruction(RVA addr, const QString &inst, bool fillWithNops = false); diff --git a/src/core/RizinCpp.h b/src/core/RizinCpp.h index 65fd95b6..0e0e1620 100644 --- a/src/core/RizinCpp.h +++ b/src/core/RizinCpp.h @@ -51,12 +51,6 @@ static inline auto fromOwned(RZ_OWN RzList *data) -> UniquePtrCP UniquePtrCP -{ - return { data, {} }; -} - // Rizin list iteration macros // deprecated, prefer using CutterPVector and CutterRzList instead #define CutterRzListForeach(list, it, type, x) \ @@ -170,4 +164,30 @@ public: iterator end() const { return iterator(nullptr); } }; +template +class CutterRzIter +{ + UniquePtrC rzIter; + +public: + CutterRzIter(RzIterator *rzIter) : rzIter(rzIter) + { + // immediately attempt advancing by 1, otherwise it's hard to distinguish whether current + // element is null due to not having called next, or due to having run out of elements + if (rzIter) { + ++*this; + } + } + + CutterRzIter &operator++() + { + rz_iterator_next(rzIter.get()); + return *this; + } + operator bool() { return rzIter && rzIter->cur; } + T &operator*() { return *reinterpret_cast(rzIter->cur); } + T *get() { return reinterpret_cast(rzIter->cur); } + T *operator->() { return reinterpret_cast(rzIter->cur); } +}; + #endif // RIZINCPP_H From dbb49bbf98ea35ed87486a6b43c6599c4535eb7b Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Fri, 1 Mar 2024 19:28:06 +0800 Subject: [PATCH 09/17] Do not use removed rz_bin_get_info() API --- src/common/BugReporting.cpp | 3 ++- src/core/Cutter.cpp | 33 ++++++++++++++++--------------- src/core/Cutter.h | 2 +- src/dialogs/VersionInfoDialog.cpp | 6 +++++- src/widgets/Dashboard.cpp | 5 +++-- src/widgets/Dashboard.h | 2 +- 6 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/common/BugReporting.cpp b/src/common/BugReporting.cpp index 95da855f..13463d00 100644 --- a/src/common/BugReporting.cpp +++ b/src/common/BugReporting.cpp @@ -10,7 +10,8 @@ void openIssue() { RzCoreLocked core(Core()); RzBinFile *bf = rz_bin_cur(core->bin); - RzBinInfo *info = rz_bin_get_info(core->bin); + RzBinObject *bobj = rz_bin_cur_object(core->bin); + const RzBinInfo *info = bobj ? rz_bin_object_get_info(bobj) : nullptr; RzBinPlugin *plugin = rz_bin_file_cur_plugin(bf); QString url, osInfo, format, arch, type; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 3bce681a..6951e01a 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -517,7 +517,7 @@ CutterJson CutterCore::parseJson(const char *name, char *res, const char *cmd) return CutterJson(doc, QSharedPointer::create(doc, res)); } -QStringList CutterCore::autocomplete(const QString &cmd, RzLinePromptType promptType, size_t limit) +QStringList CutterCore::autocomplete(const QString &cmd, RzLinePromptType promptType) { RzLineBuffer buf; int c = snprintf(buf.data, sizeof(buf.data), "%s", cmd.toUtf8().constData()); @@ -526,18 +526,17 @@ QStringList CutterCore::autocomplete(const QString &cmd, RzLinePromptType prompt } buf.index = buf.length = std::min((int)(sizeof(buf.data) - 1), c); - RzLineCompletion completion; - rz_line_completion_init(&completion, limit); - rz_core_autocomplete(core(), &completion, &buf, promptType); + RzLineNSCompletionResult *compr = rz_core_autocomplete_rzshell(core(), &buf, promptType); QStringList r; - r.reserve(rz_pvector_len(&completion.args)); - for (size_t i = 0; i < rz_pvector_len(&completion.args); i++) { + auto optslen = rz_pvector_len(&compr->options); + r.reserve(optslen); + for (size_t i = 0; i < optslen; i++) { r.push_back(QString::fromUtf8( - reinterpret_cast(rz_pvector_at(&completion.args, i)))); + reinterpret_cast(rz_pvector_at(&compr->options, i)))); } + rz_line_ns_completion_result_free(compr); - rz_line_completion_fini(&completion); return r; } @@ -1377,7 +1376,11 @@ CutterJson CutterCore::getSignatureInfo() bool CutterCore::existsFileInfo() { CORE_LOCK(); - const RzBinInfo *info = rz_bin_get_info(core->bin); + RzBinObject *bobj = rz_bin_cur_object(core->bin); + if (!bobj) { + return false; + } + const RzBinInfo *info = rz_bin_object_get_info(bobj); if (!(info && info->rclass)) { return false; } @@ -3179,11 +3182,11 @@ QList CutterCore::getAllSymbols() } } - const RzList *entries = rz_bin_object_get_entries(bf->o); - if (entries) { + const RzPVector *entries = rz_bin_object_get_entries(bf->o); + if (symbols) { /* list entrypoints as symbols too */ int n = 0; - for (const auto &entry : CutterRzList(entries)) { + for (const auto &entry : CutterPVector(entries)) { SymbolDescription symbol; symbol.vaddr = entry->vaddr; symbol.name = QString("entry") + QString::number(n++); @@ -3496,10 +3499,8 @@ QList CutterCore::getAllEntrypoint() ut64 laddr = rz_bin_get_laddr(core->bin); QList qList; - const RzList *entries = rz_bin_object_get_entries(bf->o); - RzListIter *iter; - RzBinAddr *entry; - CutterRzListForeach (entries, iter, RzBinAddr, entry) { + const RzPVector *entries = rz_bin_object_get_entries(bf->o); + for (const auto &entry : CutterPVector(entries)) { if (entry->type != RZ_BIN_ENTRY_TYPE_PROGRAM) { continue; } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 1ebf89f8..1715c4da 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -187,7 +187,7 @@ public: return parseJson(name, res, cmd.isNull() ? nullptr : cmd.toLocal8Bit().constData()); } - QStringList autocomplete(const QString &cmd, RzLinePromptType promptType, size_t limit = 4096); + QStringList autocomplete(const QString &cmd, RzLinePromptType promptType); /* Functions methods */ void renameFunction(const RVA offset, const QString &newName); diff --git a/src/dialogs/VersionInfoDialog.cpp b/src/dialogs/VersionInfoDialog.cpp index dd43f23e..9cd5e03c 100644 --- a/src/dialogs/VersionInfoDialog.cpp +++ b/src/dialogs/VersionInfoDialog.cpp @@ -24,7 +24,11 @@ VersionInfoDialog::~VersionInfoDialog() {} void VersionInfoDialog::fillVersionInfo() { RzCoreLocked core(Core()); - const RzBinInfo *info = rz_bin_get_info(core->bin); + RzBinObject *bobj = rz_bin_cur_object(core->bin); + if (!bobj) { + return; + } + const RzBinInfo *info = rz_bin_object_get_info(bobj); if (!info || !info->rclass) { return; } diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 192aab30..29a4317f 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -52,7 +52,8 @@ void Dashboard::updateContents() } // Add file hashes, analysis info and libraries - RzBinInfo *binInfo = rz_bin_get_info(core->bin); + RzBinObject *bobj = rz_bin_cur_object(core->bin); + const RzBinInfo *binInfo = bobj ? rz_bin_object_get_info(bobj) : nullptr; setPlainText(ui->fileEdit, binInfo ? binInfo->file : ""); setPlainText(ui->formatEdit, binInfo ? binInfo->rclass : ""); @@ -211,7 +212,7 @@ void Dashboard::setPlainText(QLineEdit *textBox, const QString &text) * @brief Setting boolean values of binary information in dashboard * @param RzBinInfo */ -void Dashboard::setRzBinInfo(RzBinInfo *binInfo) +void Dashboard::setRzBinInfo(const RzBinInfo *binInfo) { setPlainText(ui->vaEdit, binInfo ? setBoolText(binInfo->has_va) : ""); setPlainText(ui->canaryEdit, binInfo ? setBoolText(binInfo->has_canary) : ""); diff --git a/src/widgets/Dashboard.h b/src/widgets/Dashboard.h index a7ee5c15..758249d5 100644 --- a/src/widgets/Dashboard.h +++ b/src/widgets/Dashboard.h @@ -33,7 +33,7 @@ private slots: private: std::unique_ptr ui; void setPlainText(QLineEdit *textBox, const QString &text); - void setRzBinInfo(RzBinInfo *binInfo); + void setRzBinInfo(const RzBinInfo *binInfo); const char *setBoolText(bool value); QWidget *hashesWidget = nullptr; From 171c0da04074525996a0f97ba83440ca7923a0b8 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Fri, 1 Mar 2024 20:53:37 +0800 Subject: [PATCH 10/17] Update Rizin to latest dev --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 78d4043a..4a0dca66 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 78d4043afb39a56fe91ea7ab03c83da613319cc3 +Subproject commit 4a0dca66131de65ca10679e42e3adb5d39735ffa From bffe193708ecb1ad3c24a31893f5cb26a8b0ee13 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sun, 3 Mar 2024 14:29:35 +0800 Subject: [PATCH 11/17] Update bundled Rizin to the 0.8.0 series --- cmake/BundledRizin.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 1c030690..1d6208b9 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -57,7 +57,7 @@ endif() # TODO: This version number should be fetched automatically # instead of being hardcoded. -set (Rizin_VERSION 0.7) +set (Rizin_VERSION 0.8) set (RZ_LIBS rz_core rz_config rz_cons rz_io rz_util rz_flag rz_asm rz_debug rz_hash rz_bin rz_lang rz_il rz_analysis rz_parse rz_bp rz_egg rz_reg From 1a09a5cbe781ba423f94e1f3b3528263cc8b610b Mon Sep 17 00:00:00 2001 From: John Helmert III Date: Sun, 10 Mar 2024 09:47:53 -0700 Subject: [PATCH 12/17] ProcessesWidget: make ColumnIndex a class member The same name with a differing definition clashes with ColumnIndex from ThreadsWidget, which violates C++ ODR (-Werror=odr). This brings ProcessesWidget in line with other widgets that define the column index enums within their respective classes. Signed-off-by: John Helmert III --- src/widgets/ProcessesWidget.cpp | 31 ++++++++++++++----------------- src/widgets/ProcessesWidget.h | 7 +++++++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/widgets/ProcessesWidget.cpp b/src/widgets/ProcessesWidget.cpp index 2a9477f8..0a45a98e 100644 --- a/src/widgets/ProcessesWidget.cpp +++ b/src/widgets/ProcessesWidget.cpp @@ -9,13 +9,6 @@ #define DEBUGGED_PID (-1) -enum ColumnIndex { - COLUMN_PID = 0, - COLUMN_UID, - COLUMN_STATUS, - COLUMN_PATH, -}; - ProcessesWidget::ProcessesWidget(MainWindow *main) : CutterDockWidget(main), ui(new Ui::ProcessesWidget) { @@ -23,10 +16,14 @@ ProcessesWidget::ProcessesWidget(MainWindow *main) // Setup processes model modelProcesses = new QStandardItemModel(1, 4, this); - modelProcesses->setHorizontalHeaderItem(COLUMN_PID, new QStandardItem(tr("PID"))); - modelProcesses->setHorizontalHeaderItem(COLUMN_UID, new QStandardItem(tr("UID"))); - modelProcesses->setHorizontalHeaderItem(COLUMN_STATUS, new QStandardItem(tr("Status"))); - modelProcesses->setHorizontalHeaderItem(COLUMN_PATH, new QStandardItem(tr("Path"))); + modelProcesses->setHorizontalHeaderItem(ProcessesWidget::COLUMN_PID, + new QStandardItem(tr("PID"))); + modelProcesses->setHorizontalHeaderItem(ProcessesWidget::COLUMN_UID, + new QStandardItem(tr("UID"))); + modelProcesses->setHorizontalHeaderItem(ProcessesWidget::COLUMN_STATUS, + new QStandardItem(tr("Status"))); + modelProcesses->setHorizontalHeaderItem(ProcessesWidget::COLUMN_PATH, + new QStandardItem(tr("Path"))); ui->viewProcesses->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); ui->viewProcesses->verticalHeader()->setVisible(false); ui->viewProcesses->setFont(Config()->getFont()); @@ -129,10 +126,10 @@ void ProcessesWidget::setProcessesGrid() rowStatus->setFont(font); rowPath->setFont(font); - modelProcesses->setItem(i, COLUMN_PID, rowPid); - modelProcesses->setItem(i, COLUMN_UID, rowUid); - modelProcesses->setItem(i, COLUMN_STATUS, rowStatus); - modelProcesses->setItem(i, COLUMN_PATH, rowPath); + modelProcesses->setItem(i, ProcessesWidget::COLUMN_PID, rowPid); + modelProcesses->setItem(i, ProcessesWidget::COLUMN_UID, rowUid); + modelProcesses->setItem(i, ProcessesWidget::COLUMN_STATUS, rowStatus); + modelProcesses->setItem(i, ProcessesWidget::COLUMN_PATH, rowPath); i++; } @@ -155,7 +152,7 @@ void ProcessesWidget::onActivated(const QModelIndex &index) if (!index.isValid()) return; - int pid = modelFilter->data(index.sibling(index.row(), COLUMN_PID)).toInt(); + int pid = modelFilter->data(index.sibling(index.row(), ProcessesWidget::COLUMN_PID)).toInt(); // Verify that the selected pid is still in the processes list since dp= will // attach to any given id. If it isn't found simply update the UI. for (const auto &value : Core()->getAllProcesses()) { @@ -185,7 +182,7 @@ ProcessesFilterModel::ProcessesFilterModel(QObject *parent) : QSortFilterProxyMo bool ProcessesFilterModel::filterAcceptsRow(int row, const QModelIndex &parent) const { // All columns are checked for a match - for (int i = COLUMN_PID; i <= COLUMN_PATH; ++i) { + for (int i = ProcessesWidget::COLUMN_PID; i <= ProcessesWidget::COLUMN_PATH; ++i) { QModelIndex index = sourceModel()->index(row, i, parent); if (qhelpers::filterStringContains(sourceModel()->data(index).toString(), this)) { return true; diff --git a/src/widgets/ProcessesWidget.h b/src/widgets/ProcessesWidget.h index fcc9db80..40f2f0f6 100644 --- a/src/widgets/ProcessesWidget.h +++ b/src/widgets/ProcessesWidget.h @@ -31,6 +31,13 @@ class ProcessesWidget : public CutterDockWidget Q_OBJECT public: + enum ColumnIndex { + COLUMN_PID = 0, + COLUMN_UID, + COLUMN_STATUS, + COLUMN_PATH, + }; + explicit ProcessesWidget(MainWindow *main); ~ProcessesWidget(); From 43950242aebd259c8f81a75d65aebb3cf9f1afde Mon Sep 17 00:00:00 2001 From: John Helmert III Date: Sun, 10 Mar 2024 09:47:53 -0700 Subject: [PATCH 13/17] ThreadsWidget: make ColumnIndex a class member This brings ThreadsWidget into alignment with ProcessesWidget and others which have column index enumerators as class members. This also avoids cluttering global scope with generic names, making it easier to avoid C++ ODR violations with differing definitions. Closes: #3316 Signed-off-by: John Helmert III --- src/widgets/ThreadsWidget.cpp | 24 ++++++++++-------------- src/widgets/ThreadsWidget.h | 6 ++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/widgets/ThreadsWidget.cpp b/src/widgets/ThreadsWidget.cpp index d9149108..8d474128 100644 --- a/src/widgets/ThreadsWidget.cpp +++ b/src/widgets/ThreadsWidget.cpp @@ -9,21 +9,17 @@ #define DEBUGGED_PID (-1) -enum ColumnIndex { - COLUMN_PID = 0, - COLUMN_STATUS, - COLUMN_PATH, -}; - ThreadsWidget::ThreadsWidget(MainWindow *main) : CutterDockWidget(main), ui(new Ui::ThreadsWidget) { ui->setupUi(this); // Setup threads model modelThreads = new QStandardItemModel(1, 3, this); - modelThreads->setHorizontalHeaderItem(COLUMN_PID, new QStandardItem(tr("PID"))); - modelThreads->setHorizontalHeaderItem(COLUMN_STATUS, new QStandardItem(tr("Status"))); - modelThreads->setHorizontalHeaderItem(COLUMN_PATH, new QStandardItem(tr("Path"))); + modelThreads->setHorizontalHeaderItem(ThreadsWidget::COLUMN_PID, new QStandardItem(tr("PID"))); + modelThreads->setHorizontalHeaderItem(ThreadsWidget::COLUMN_STATUS, + new QStandardItem(tr("Status"))); + modelThreads->setHorizontalHeaderItem(ThreadsWidget::COLUMN_PATH, + new QStandardItem(tr("Path"))); ui->viewThreads->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); ui->viewThreads->verticalHeader()->setVisible(false); ui->viewThreads->setFont(Config()->getFont()); @@ -120,9 +116,9 @@ void ThreadsWidget::setThreadsGrid() rowStatus->setFont(font); QStandardItem *rowPath = new QStandardItem(path); rowPath->setFont(font); - modelThreads->setItem(i, COLUMN_PID, rowPid); - modelThreads->setItem(i, COLUMN_STATUS, rowStatus); - modelThreads->setItem(i, COLUMN_PATH, rowPath); + modelThreads->setItem(i, ThreadsWidget::COLUMN_PID, rowPid); + modelThreads->setItem(i, ThreadsWidget::COLUMN_STATUS, rowStatus); + modelThreads->setItem(i, ThreadsWidget::COLUMN_PATH, rowPath); i++; } @@ -146,7 +142,7 @@ void ThreadsWidget::onActivated(const QModelIndex &index) if (!index.isValid()) return; - int tid = modelFilter->data(index.sibling(index.row(), COLUMN_PID)).toInt(); + int tid = modelFilter->data(index.sibling(index.row(), ThreadsWidget::COLUMN_PID)).toInt(); // Verify that the selected tid is still in the threads list since dpt= will // attach to any given id. If it isn't found simply update the UI. @@ -169,7 +165,7 @@ ThreadsFilterModel::ThreadsFilterModel(QObject *parent) : QSortFilterProxyModel( bool ThreadsFilterModel::filterAcceptsRow(int row, const QModelIndex &parent) const { // All columns are checked for a match - for (int i = COLUMN_PID; i <= COLUMN_PATH; ++i) { + for (int i = ThreadsWidget::COLUMN_PID; i <= ThreadsWidget::COLUMN_PATH; ++i) { QModelIndex index = sourceModel()->index(row, i, parent); if (qhelpers::filterStringContains(sourceModel()->data(index).toString(), this)) { return true; diff --git a/src/widgets/ThreadsWidget.h b/src/widgets/ThreadsWidget.h index 259c919d..fd452d1e 100644 --- a/src/widgets/ThreadsWidget.h +++ b/src/widgets/ThreadsWidget.h @@ -31,6 +31,12 @@ class ThreadsWidget : public CutterDockWidget Q_OBJECT public: + enum ColumnIndex { + COLUMN_PID = 0, + COLUMN_STATUS, + COLUMN_PATH, + }; + explicit ThreadsWidget(MainWindow *main); ~ThreadsWidget(); From f8c7df8260bea74dabe45a7b961da339c277bd38 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 19 Mar 2024 17:51:58 +0800 Subject: [PATCH 14/17] Update Rizin to the latest `dev` (#3319) --- cmake/BundledRizin.cmake | 7 +++---- rizin | 2 +- src/core/Cutter.cpp | 10 ++++------ src/widgets/DisassemblerGraphView.cpp | 2 +- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 1d6208b9..3e05b263 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -59,10 +59,9 @@ endif() # instead of being hardcoded. set (Rizin_VERSION 0.8) -set (RZ_LIBS rz_core rz_config rz_cons rz_io rz_util rz_flag rz_asm rz_debug - rz_hash rz_bin rz_lang rz_il rz_analysis rz_parse rz_bp rz_egg rz_reg - rz_search rz_syscall rz_socket rz_magic rz_crypto rz_type rz_diff rz_sign - rz_demangler) +set (RZ_LIBS rz_core rz_config rz_cons rz_io rz_util rz_flag rz_arch rz_debug + rz_hash rz_bin rz_lang rz_il rz_bp rz_egg rz_reg rz_search rz_syscall + rz_socket rz_magic rz_crypto rz_type rz_diff rz_sign rz_demangler) set (RZ_EXTRA_LIBS rz_main) set (RZ_BIN rz-bin rizin rz-diff rz-find rz-gg rz-hash rz-run rz-asm rz-ax) diff --git a/rizin b/rizin index 4a0dca66..94099b86 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 4a0dca66131de65ca10679e42e3adb5d39735ffa +Subproject commit 94099b860e6ce712e337e9ee29d258d51ae32962 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 6951e01a..0f646b81 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1295,7 +1295,7 @@ RVA CutterCore::getLastFunctionInstruction(RVA addr) if (!fcn) { return RVA_INVALID; } - RzAnalysisBlock *lastBB = (RzAnalysisBlock *)rz_list_last(fcn->bbs); + RzAnalysisBlock *lastBB = (RzAnalysisBlock *)rz_pvector_tail(fcn->bbs); return lastBB ? rz_analysis_block_get_op_addr(lastBB, lastBB->ninstr - 1) : RVA_INVALID; } @@ -1641,7 +1641,7 @@ QVector CutterCore::getHeapChunks(RVA arena_addr) rz_list_free(arenas); return chunks_vector; } - m_arena = ((RzArenaListItem *)rz_list_get_head_data(arenas))->addr; + m_arena = ((RzArenaListItem *)rz_list_first(arenas))->addr; rz_list_free(arenas); } else { m_arena = arena_addr; @@ -3061,7 +3061,7 @@ QList CutterCore::getAllFunctions() function.linearSize = rz_analysis_function_linear_size(fcn); function.nargs = rz_analysis_arg_count(fcn); function.nlocals = rz_analysis_var_local_count(fcn); - function.nbbs = rz_list_length(fcn->bbs); + function.nbbs = rz_pvector_len(fcn->bbs); function.calltype = fcn->cc ? QString::fromUtf8(fcn->cc) : QString(); function.name = fcn->name ? QString::fromUtf8(fcn->name) : QString(); function.edges = rz_analysis_function_count_edges(fcn, nullptr); @@ -4334,10 +4334,9 @@ QString CutterCore::getVersionInformation() const char *name; const char *(*callback)(); } vcs[] = { - { "rz_analysis", &rz_analysis_version }, + { "rz_arch", &rz_arch_version }, { "rz_lib", &rz_lib_version }, { "rz_egg", &rz_egg_version }, - { "rz_asm", &rz_asm_version }, { "rz_bin", &rz_bin_version }, { "rz_cons", &rz_cons_version }, { "rz_flag", &rz_flag_version }, @@ -4350,7 +4349,6 @@ QString CutterCore::getVersionInformation() #if !USE_LIB_MAGIC { "rz_magic", &rz_magic_version }, #endif - { "rz_parse", &rz_parse_version }, { "rz_reg", &rz_reg_version }, { "rz_sign", &rz_sign_version }, { "rz_search", &rz_search_version }, diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 82da0866..a220188f 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -225,7 +225,7 @@ void DisassemblerGraphView::loadCurrentGraph() return; } - for (const auto &bbi : CutterRzList(fcn->bbs)) { + for (const auto &bbi : CutterPVector(fcn->bbs)) { RVA bbiFail = bbi->fail; RVA bbiJump = bbi->jump; From 575013904100efdc71cbb9b614e4a1587f94ac7e Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 2 Apr 2024 20:55:16 +0800 Subject: [PATCH 15/17] Update Rizin to the latest dev --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 94099b86..3d93397d 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 94099b860e6ce712e337e9ee29d258d51ae32962 +Subproject commit 3d93397dd8b96ce1e8683a21ab86d94812f0b23f From bce9fe7732890934f750d9d91f4093983dbb5830 Mon Sep 17 00:00:00 2001 From: Ofek Date: Mon, 8 Apr 2024 23:00:51 +0300 Subject: [PATCH 16/17] Update GraphGridLayout Documentation (#3325) --- src/widgets/GraphGridLayout.cpp | 162 ++++++++++++++++---------------- 1 file changed, 83 insertions(+), 79 deletions(-) diff --git a/src/widgets/GraphGridLayout.cpp b/src/widgets/GraphGridLayout.cpp index 0cf7840d..51a5abca 100644 --- a/src/widgets/GraphGridLayout.cpp +++ b/src/widgets/GraphGridLayout.cpp @@ -14,96 +14,97 @@ Basic familiarity with graph algorithms is recommended. # Terms used: -- **Vertex**, **node**, **block** - read description of graph for definition. Within this text -vertex and node are used interchangeably with block due to code being written for visualizing basic +- **Vertex**, **node**, **block** - see the definition of graph. Within this text +vertex/node/block are used interchangeably due to the code being purposed for visualizing basic block control flow graph. -- **edge** - read description of graph for definition for precise definition. -- **DAG** - directed acyclic graph, graph using directed edges which doesn't have cycles. DAG may -contain loops if following them would require going in both directions of edges. Example 1->2 1->3 -3->2 is a DAG, 2->1 1->3 3->2 isn't a DAG. +- **edge** - see the definition of graph. +- **DAG** - directed acyclic graph, a graph using directed edges which doesn't have cycles. A DAG +may contain loops if following them would require going in both directions of edges. Example 1->2 +1->3 3->2 is a DAG, 2->1 1->3 3->2 isn't a DAG. - **DFS** - depth first search, a graph traversal algorithm -- **toposort** - topological sorting, process of ordering a DAG vertices that all edges go from -vertices earlier in the toposort order to vertices later in toposort order. There are multiple -algorithms for implementing toposort operation. Single DAG can have multiple valid topological +- **toposort** - topological sorting, the process of ordering a DAG vertices that results in all +edges going from vertices earlier in the toposort order to vertices later in toposort order. There +are multiple algorithms implementing toposort. A single DAG can have multiple valid topological orderings, a toposort algorithm can be designed to prioritize a specific one from all valid toposort orders. Example: for graph 1->4, 2->1, 2->3, 3->4 valid topological orders are [2,1,3,4] and [2,3,1,4]. -# High level structure of the algorithm -1. select subset of edges that form a DAG (remove cycles) -2. toposort the DAG -3. choose a subset of edges that form a tree and assign layers -4. assign node positions within grid using tree structure, child subtrees are placed side by side +# High level algorithm structure +1. Select a subset of edges that form a DAG (remove cycles) +2. Toposort the DAG +3. Choose a subset of edges that form a tree and assign layers +4. Assign node positions within grid using tree structure, child subtrees are placed side by side with parent on top -5. perform edge routing -6. calculate column and row pixel positions based on node sizes and amount edges between the rows -7. [optional] layout compacting +5. Perform edge routing +6. Calculate column and row pixel positions based on node sizes and amount edges between the rows +7. [optional] Layout compacting -Contrary to many other layered graph drawing algorithm this implementation doesn't perform node -reordering to minimize edge crossing. This simplifies implementation, and preserves original control -flow structure for conditional jumps ( true jump on one side, false jump on other). Due to most of -control flow being result of structured programming constructs like if/then/else and loops, -resulting layout is usually readable without node reordering within layers. +Contrary to many other layered graph-drawing algorithms this implementation doesn't perform node +reordering to minimize edge crossing. This simplifies the implementation, and preserves the original +control-flow structure for conditional jumps ( true jump on one side, false jump on other). Due to +most of the control flow resulting from structured programming constructs like if/then/else and +loops, the resulting layout is usually readable without node reordering within layers. -# Description of grid. -To simplify the layout algorithm initial steps assume that all nodes have the same size and edges -are zero width. After placing the nodes and routing the edges it is known which nodes are in in -which row and column, how many edges are between each pair of rows. Using this information positions -are converted from the grid cells to pixel coordinates. Routing 0 width edges between rows can also +# Grid +To simplify the layout algorithm, its initial steps assume that all nodes have the same size and +that edges are zero-width. After nodes placement and edges rounting, the row/column of nodes is +known as well as the amount of edges between each pair of rows. Using this information, positions +are converted from grid cells to pixel coordinates. Routing zero-width edges between rows can also be interpreted as every second row and column being reserved for edges. The row numbers in code are -using first interpretation. To allow better centering of nodes one above other each node is 2 +using the first interpretation. To allow better centering of nodes one above other, each node is 2 columns wide and 1 row high. \image html graph_grid.svg # 1-2 Cycle removal and toposort -Cycle removal and toposort are done at the same time during single DFS traversal. In case entrypoint -is part of a loop DFS started from entrypoint. This ensures that entrypoint is at the top of -resulting layout if possible. Resulting toposort order is used in many of the following layout steps -that require calculating some property of a vertex based on child property or the other way around. -Using toposort order such operations can be implemented iteration through array in either forward or -reverse direction. To prevent running out of stack memory when processing large graphs DFS is -implemented non-recursively. +Cycle removal and toposort are done in a single DFS traversal. In case the entrypoint +is part of a loop, the DFS starts from the entrypoint. This ensures that the entrypoint is at the +top of resulting layout, if possible. The resulting toposort order is used in many of the following +layout steps that require calculating some property of a vertex based on a child property or the +other way around. Using toposort order, such operations can be implemented by array iteration in +either forward/backward direction. To prevent running out of stack memory when processing large +graphs, DFS is implemented non-recursively. # Row assignment Rows are assigned in toposort order from top to bottom, with nodes row being max(predecessor.row)+1. -This ensures that loop edges are only ones going from deeper levels to previous layers. +This ensures that loop back-edges are the only edges going from lower to higher layers. -To further simply node placement a subset of edges is selected which forms a tree. This turns DAG -drawing problem into a tree drawing problem. For each node in level n following nodes which have -level exactly n+1 are greedily assigned as child nodes in tree. If a node already has parent -assigned then corresponding edge is not part of tree. +To further simply node placement, a subset of edges is selected which forms a tree. This turns a DAG +drawing problem into a tree drawing problem. For each node in level n the following nodes with +level exactly n+1 are greedily assigned as child nodes in the tree. If a node already has a parent +assigned then the corresponding edge is not part of the tree. -# Node position assignment +# Node placement Since the graph has been reduced to a tree, node placement is more or less putting subtrees side by -side with parent on top. There is some room for interpretation what exactly side by side means and -where exactly on top is. Drawing the graph either too dense or too big may make it less readable so -there are configuration options which allow choosing these things resulting in more or less dense -layout. +side with parent on top. There is some room for interpretation as to what exactly 'side by side' +means and where exactly 'on top' is: drawing the graph either too dense or too sparse may make it +less readable, so there are configuration options which allow choosing these things resulting in +more or less dense layout. -Once the subtrees are placed side by side. Parent node can be placed either in the middle of -horizontal bounds or in the middle of direct children. First option results in narrower layout and -more vertical columns. Second option results in nodes being more spread out which may help seeing -where each edge goes. +Once the subtrees are placed side by side, the parent node can be placed either in the middle of +the horizontal bounds or in the middle of its direct children. The first option results in narrower +layout and more vertical columns, while the second option results in more spread out layout which +may help seeing where each edge goes. -In more compact mode two subtrees are placed side by side taking into account their shape. In wider -mode bounding box of shorter subtree is used instead of exact shape. This gives slightly sparse -layout without it being too wide. +In compact mode two subtrees are placed side by side accounting for their shape. In wider +mode the bounding box of the shorter subtree is used instead of its exact shape. This gives slightly +sparser layout without being too wide. \image html graph_parent_placement.svg # Edge routing -Edge routing can be split into: main column selection, rough routing, segment offset calculation. +Edge routing can be split into: main column selection, rough routing, and segment offset +calculation. -Transition from source to target row is done using single vertical segment. This is called main -column. +Transition from source to target row is done using a single vertical segment. This segment is called +the 'main column'. -A sweep line is used for computing main columns: Blocks and edges are processed as events top to +Main columns are computed using a sweep line: blocks and edges are processed as events top to bottom based off their row (max(start row, end row) for edges). Blocked columns are tracked in a tree structure which allows searching nearest column with at least last N rows empty. The column of the starting block is favored for the main column, otherwise the target block's column is chosen @@ -114,10 +115,9 @@ true or false branch. In case of upward edges it is allowed to choose a column o is slightly further than nearest empty to reduce the chance of producing tilted figure 8 shaped crossing between two blocks. -Rough routing creates the path of edge using up to 5 segments using grid coordinates. -Due to nodes being placed in a grid. Horizontal segments of edges can't intersect with any nodes. +Due to nodes being placed in a grid, horizontal segments of edges can't intersect with any nodes. The path for edges is chosen so that it consists of at most 5 segments, typically resulting in -sideways U shape or square Z shape. +sideways U shape or square Z shape: - short vertical segment from node to horizontal line - move to empty column - vertical segment between starting row and end row @@ -134,45 +134,49 @@ ensures that two segments don't overlap. Segment offsets within each column are with some heuristics for assignment order to reduce amount of edge crossings and result in more visually pleasing output for a typical CFG graph. Each segment gets assigned an offset that is maximum of previously assigned offsets overlapping with current segment + segment spacing. -Assignment order is chosen based on: -* direction of previous and last segment - helps reducing crossings and place the segments between + +Assignment order is based on: +- direction of previous and last segment - helps reducing crossings and place the segments between nodes -* segment length - reduces crossing when segment endpoints have the same structure as valid +- segment length - reduces crossing when segment endpoints have the same structure as valid parentheses expression -* edge length - establishes some kind of order when single node is connected to many edges, +- edge length - establishes some kind of order when single node is connected to many edges, typically a block with switch statement or block after switch statement. # Layout compacting -Doing the layout within a grid causes minimal spacing to be limited by widest and tallest block -within each column and row. One common case is block with function entrypoint being wider due to -function name causing wide horizontal space between branching blocks. Another case is rows in two +Doing the layout on a grid limits the minimal spacing to the widest block within a column and +tallest block within a row. One common case is a function-entry block being wider due to the +function name, causing wide horizontal space between branching blocks. Another case is rows in two parallel columns being aligned. \image html layout_compacting.svg -Both problems are mitigated by squishing graph. Compressing in each of the two direction is done +Both problems are mitigated by squishing the graph. Compressing in each of the two direction is done separately. The process is defined as liner program. Each variable represents a position of edge segment or node in the direction being optimized. -Following constraints are used +The following constraints are used: - Keep the order with nearest segments. -- If the node has two outgoing edges, one to the node on left side and other to the right, keep them -on the corresponding side of node's center. -- For all edges keep the node which is above above. This helps when vertical block spacing is set -bigger than double edge spacing and edge shadows relationship between two blocks. +- If a node has two outgoing edges, one to the left and one to the right, keep them +on the corresponding side of the node's center. - Equality constraint to keep relative position between nodes and and segments directly connected to them. -- Equality constraint to keep the node centered when control flow merges -In the vertical direction objective function minimizes y positions of nodes and lengths of vertical -segments. In the horizontal direction objective function minimizes lengths of horizontal segments. +- For all blocks connected by forward edge, keep the vertical distance at least as big as configured +block vertical spacing. This helps when vertical block-spacing is set bigger than double edge +spacing and an edge shadows relationship between two blocks. +- Equality constraint to keep a node centered when control flow merges. -In the resulting linear program all constraints beside x_i >= 0 consist of exactly two variables: +In the vertical direction the objective function minimizes y positions of nodes and lengths of +vertical segments. In the horizontal direction the objective function minimizes the lengths of +horizontal segments. + +In the resulting linear program all constraints besides x_i >= 0 consist of exactly two variables: either x_i - x_j <= c_k or x_i = x_j + c_k. -Since it isn't necessary get perfect solution and to avoid worst case performance current -implementation isn't using a general purpose linear programming solver. Each variable is changed -until constraint is reached and afterwards variables are grouped and changed together. +Since a perfect solution isn't necessary and to avoid worst case performance, the current +implementation isn't using a general purpose linear solver. Instead, each variable is modified +until a constraint is satisfied and afterwards variables are grouped and modified together. */ From de46cb109b85ad8da6ecfad36545b4df70ae2d33 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:22:09 +0800 Subject: [PATCH 17/17] disable openssl for libyara on linux/mac builds and use tagged version (#3332) * disable openssl for libyara on linux/mac builds and use tagged version * Bump rizin version --- dist/bundle_rz_libyara.ps1 | 2 +- rizin | 2 +- scripts/rz-libyara.sh | 4 ++-- src/core/Cutter.cpp | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dist/bundle_rz_libyara.ps1 b/dist/bundle_rz_libyara.ps1 index 984913d6..2f3dafaa 100644 --- a/dist/bundle_rz_libyara.ps1 +++ b/dist/bundle_rz_libyara.ps1 @@ -3,7 +3,7 @@ $cmake_opts = $args[1] $python = Split-Path((Get-Command python.exe).Path) if (-not (Test-Path -Path 'rz_libyara' -PathType Container)) { - git clone https://github.com/rizinorg/rz-libyara.git --depth 1 rz_libyara + git clone https://github.com/rizinorg/rz-libyara.git --depth 1 --branch main rz_libyara git -C rz_libyara submodule init git -C rz_libyara submodule update } diff --git a/rizin b/rizin index 3d93397d..34f1a9e7 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 3d93397dd8b96ce1e8683a21ab86d94812f0b23f +Subproject commit 34f1a9e7b40e289cdf8e7f03c145bdbd5d41dc89 diff --git a/scripts/rz-libyara.sh b/scripts/rz-libyara.sh index 5fdb303c..8941f4b4 100755 --- a/scripts/rz-libyara.sh +++ b/scripts/rz-libyara.sh @@ -8,14 +8,14 @@ EXTRA_CMAKE_OPTS="$2" cd "$SCRIPTPATH/.." if [[ ! -d rz_libyara ]]; then - git clone https://github.com/rizinorg/rz-libyara.git --depth 1 rz_libyara + git clone https://github.com/rizinorg/rz-libyara.git --depth 1 --branch main rz_libyara git -C rz_libyara submodule init git -C rz_libyara submodule update fi cd rz_libyara -meson --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" --prefix="$INSTALL_PREFIX" -Duse_sys_yara=disabled build +meson --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" --prefix="$INSTALL_PREFIX" -Denable_openssl=false -Duse_sys_yara=disabled build ninja -C build install cd cutter-plugin diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 0f646b81..b5271ca7 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3418,13 +3418,13 @@ QList CutterCore::getAllSections() section.size = sect->size; section.perm = rz_str_rwx_i(sect->perm); if (sect->size > 0) { - HtPP *digests = rz_core_bin_create_digests(core, sect->paddr, sect->size, hashnames); + HtSS *digests = rz_core_bin_create_digests(core, sect->paddr, sect->size, hashnames); if (!digests) { continue; } - const char *entropy = (const char *)ht_pp_find(digests, "entropy", NULL); + const char *entropy = (const char *)ht_ss_find(digests, "entropy", NULL); section.entropy = rz_str_get(entropy); - ht_pp_free(digests); + ht_ss_free(digests); } sections << section;