From 7dfc289660b6639a60bbed15bb3adb87bba925cd Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sun, 26 Dec 2021 16:58:05 +0800 Subject: [PATCH 01/94] Update version to 2.0.5 and rizin stable (before 0.3.2) (#2864) --- .appveyor.yml | 2 +- CMakeLists.txt | 2 +- docs/source/conf.py | 2 +- rizin | 2 +- src/re.rizin.cutter.appdata.xml | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 9d0bf2f5..4f0866ae 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.0.4-git-{build}' +version: '2.0.5-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c878fd8..bbbba86b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() set(CUTTER_VERSION_MAJOR 2) set(CUTTER_VERSION_MINOR 0) -set(CUTTER_VERSION_PATCH 4) +set(CUTTER_VERSION_PATCH 5) set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index f366fc03..ba34c0fb 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ author = 'The Cutter Developers' # The short X.Y version version = '2.0' # The full version, including a2lpha/beta/rc tags -release = '2.0.4' +release = '2.0.5' # -- General configuration --------------------------------------------------- diff --git a/rizin b/rizin index 6ef55aa6..9ed8ffd2 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 6ef55aa63a563864774f4777dcd1a69933b62a72 +Subproject commit 9ed8ffd29a64782903b7008311c1061ea1636d75 diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index cfec367e..a622e5cd 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,7 @@ xarkes + From 7d50b80d445dc1ded84ba112f0234d38d9ab4863 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 29 Dec 2021 14:22:22 +0800 Subject: [PATCH 02/94] Bump Rizin version to v0.3.2 --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 9ed8ffd2..507fdbd0 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 9ed8ffd29a64782903b7008311c1061ea1636d75 +Subproject commit 507fdbd07891f7ea4b58769f0231a0753cf87af9 From 829f4091c5656e1fc3029731f6d23df775e58cb2 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Fri, 7 Jan 2022 21:42:53 +0800 Subject: [PATCH 03/94] Update Rizin to 0.3.3 (#2870) --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 507fdbd0..c09ff312 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 507fdbd07891f7ea4b58769f0231a0753cf87af9 +Subproject commit c09ff31205f18f478234249fc76b101ebb101663 From f5a7a79ee8efc04514189565b1d319c7a39bf0de Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 11 Jan 2022 02:16:51 +0800 Subject: [PATCH 04/94] Bump Rizin version to v0.3.4 (#2876) --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index c09ff312..2373c538 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit c09ff31205f18f478234249fc76b101ebb101663 +Subproject commit 2373c53880e017be86afed5454bca5b5017b920e From 98411b4dbfa84bdf7a5bde58da8f39193ca55c09 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Wed, 22 Dec 2021 09:57:58 +0100 Subject: [PATCH 05/94] Update Rizin to dev and use CMake config files (#2855) API usage has been adjusted. There are now also cmake config files directly installed by Rizin itself, so we don't need to keep a custom FindRizin.cmake file in Cutter. This remove that file and just uses `find_package(Rizin COMPONENTS Core)`, which will use the cmake files installed on the system. --- CMakeLists.txt | 4 +- cmake/BundledRizin.cmake | 4 +- cmake/FindRizin.cmake | 117 ------------------------------ dist/CMakeLists.txt | 8 +- dist/MacOSSetupBundle.cmake.in | 1 - dist/bundle_jsdec.ps1 | 4 +- scripts/jsdec.sh | 4 +- src/common/ColorThemeWorker.cpp | 9 ++- src/common/Configuration.cpp | 2 +- src/core/Cutter.cpp | 25 ++++--- src/dialogs/BreakpointsDialog.cpp | 12 +-- src/widgets/BreakpointWidget.cpp | 6 +- 12 files changed, 40 insertions(+), 156 deletions(-) delete mode 100644 cmake/FindRizin.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index bbbba86b..92b49af4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,8 +48,8 @@ if(CUTTER_USE_BUNDLED_RIZIN) include(BundledRizin) set(RIZIN_TARGET Rizin) else() - find_package(Rizin REQUIRED) - set(RIZIN_TARGET Rizin::librz) + find_package(Rizin COMPONENTS Core REQUIRED) + set(RIZIN_TARGET Rizin::Core) endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index a042f807..ba6813e3 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -47,8 +47,8 @@ else() endif() 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_io 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_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) set (RZ_EXTRA_LIBS rz_main) set (RZ_BIN rz-agent rz-bin rizin rz-diff rz-find rz-gg rz-hash rz-run rz-asm rz-ax) diff --git a/cmake/FindRizin.cmake b/cmake/FindRizin.cmake deleted file mode 100644 index 924e112a..00000000 --- a/cmake/FindRizin.cmake +++ /dev/null @@ -1,117 +0,0 @@ -# - Find Rizin (librz) -# -# This module provides the following imported targets, if found: -# -# Rizin::librz -# -# This will define the following variables: -# (but don't use them if you don't know what you are doing, use Rizin::librz) -# -# Rizin_FOUND - True if librz has been found. -# Rizin_INCLUDE_DIRS - librz include directory -# Rizin_LIBRARIES - List of libraries when using librz. -# Rizin_LIBRARY_DIRS - librz library directories -# -# If librz was found using find_library and not pkg-config, the following variables will also be set: -# Rizin_LIBRARY_ - Path to library rz_ - -if(WIN32) - find_path(Rizin_INCLUDE_DIRS - NAMES rz_core.h rz_bin.h rz_util.h - HINTS - "$ENV{HOME}/bin/prefix/rizin/include/librz" - /usr/local/include/libr - /usr/include/librz) - find_path(SDB_INCLUDE_DIR - NAMES sdb.h sdbht.h sdb_version.h - HINTS - "$ENV{HOME}/bin/prefix/rizin/include/librz/sdb" - /usr/local/include/librz/sdb - /usr/include/librz/sdb) - - list(APPEND Rizin_INCLUDE_DIRS ${SDB_INCLUDE_DIR}) - - set(Rizin_LIBRARY_NAMES - core - config - cons - io - util - flag - asm - debug - hash - bin - lang - io - analysis - parse - bp - egg - reg - search - syscall - socket - magic - crypto - type) - - set(Rizin_LIBRARIES "") - set(Rizin_LIBRARIES_VARS "") - foreach(libname ${Rizin_LIBRARY_NAMES}) - find_library(Rizin_LIBRARY_${libname} - rz_${libname} - HINTS - "$ENV{HOME}/bin/prefix/rizin/lib" - /usr/local/lib - /usr/lib) - - list(APPEND Rizin_LIBRARIES ${Rizin_LIBRARY_${libname}}) - list(APPEND Rizin_LIBRARIES_VARS "Rizin_LIBRARY_${libname}") - endforeach() - - set(Rizin_LIBRARY_DIRS "") - - add_library(Rizin::librz UNKNOWN IMPORTED) - set_target_properties(Rizin::librz PROPERTIES - IMPORTED_LOCATION "${Rizin_LIBRARY_core}" - IMPORTED_LINK_INTERFACE_LIBRARIES "${Rizin_LIBRARIES}" - INTERFACE_LINK_DIRECTORIES "${Rizin_LIBRARY_DIRS}" - INTERFACE_INCLUDE_DIRECTORIES "${Rizin_INCLUDE_DIRS}") - set(Rizin_TARGET Rizin::librz) -else() - # support installation locations used by rizin scripts like sys/user.sh and sys/install.sh - if(CUTTER_USE_ADDITIONAL_RIZIN_PATHS) - set(Rizin_CMAKE_PREFIX_PATH_TEMP ${CMAKE_PREFIX_PATH}) - list(APPEND CMAKE_PREFIX_PATH "$ENV{HOME}/bin/prefix/rizin") # sys/user.sh - list(APPEND CMAKE_PREFIX_PATH "/usr/local") # sys/install.sh - endif() - - find_package(PkgConfig REQUIRED) - if(CMAKE_VERSION VERSION_LESS "3.6") - pkg_search_module(Rizin REQUIRED rz_core) - else() - pkg_search_module(Rizin IMPORTED_TARGET REQUIRED rz_core) - endif() - - # reset CMAKE_PREFIX_PATH - if(CUTTER_USE_ADDITIONAL_RIZIN_PATHS) - set(CMAKE_PREFIX_PATH ${Rizin_CMAKE_PREFIX_PATH_TEMP}) - endif() - - if((TARGET PkgConfig::Rizin) AND (NOT CMAKE_VERSION VERSION_LESS "3.11.0")) - set_target_properties(PkgConfig::Rizin PROPERTIES IMPORTED_GLOBAL ON) - add_library(Rizin::librz ALIAS PkgConfig::Rizin) - set(Rizin_TARGET Rizin::librz) - elseif(Rizin_FOUND) - add_library(Rizin::librz INTERFACE IMPORTED) - set_target_properties(Rizin::librz PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${Rizin_INCLUDE_DIRS}") - set_target_properties(Rizin::librz PROPERTIES - INTERFACE_LINK_LIBRARIES "${Rizin_LIBRARIES}") - set(Rizin_TARGET Rizin::librz) - endif() -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Rizin REQUIRED_VARS Rizin_TARGET Rizin_LIBRARIES Rizin_INCLUDE_DIRS) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index 5dec4c46..cf57cc66 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -84,9 +84,7 @@ if(APPLE) if (CUTTER_PACKAGE_JSDEC AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) install(CODE " - execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/jsdec.sh\" --prefix=\${CMAKE_INSTALL_PREFIX} - \"-Drizin_incdir=\${CMAKE_INSTALL_PREFIX}/include/librz\" - \"-Drizin_libdir=\${CMAKE_INSTALL_PREFIX}/lib\" + execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/jsdec.sh\" --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) @@ -109,9 +107,9 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) # installed Cutter. ExternalProject_Add(rz-ghidra GIT_REPOSITORY https://github.com/rizinorg/rz-ghidra - GIT_TAG v0.3.0 + #GIT_TAG v0.3.0 #GIT_TAG c7a50a2e7c0a95cd52b167c9ee0fa1805223f08e - #GIT_TAG dev + GIT_TAG dev #GIT_SHALLOW ON # disable this line when using commit hash CONFIGURE_COMMAND "" BUILD_COMMAND "" diff --git a/dist/MacOSSetupBundle.cmake.in b/dist/MacOSSetupBundle.cmake.in index 3666bae7..88bd6fd8 100644 --- a/dist/MacOSSetupBundle.cmake.in +++ b/dist/MacOSSetupBundle.cmake.in @@ -25,7 +25,6 @@ file(COPY "${INFO_PLIST_PATH}" DESTINATION "${BUNDLE_PATH}/Contents") # replace absolute path from build directory in rizin pkgconfig files with relative ones file(GLOB RZ_PCFILES "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig/rz_*.pc") -list(APPEND RZ_PCFILES "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig/librz.pc") foreach (_pcfile ${RZ_PCFILES}) file(READ "${_pcfile}" _text) string(REGEX REPLACE "^prefix=[^\n]*\n" "prefix=\${pcfiledir}/../..\n" _text "${_text}") diff --git a/dist/bundle_jsdec.ps1 b/dist/bundle_jsdec.ps1 index fe3ded97..762d7b11 100644 --- a/dist/bundle_jsdec.ps1 +++ b/dist/bundle_jsdec.ps1 @@ -2,10 +2,10 @@ $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.3.1 + git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch master } cd jsdec -& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS -Djsc_folder=".." -Drizin_plugdir=lib\plugins --prefix=$dist --libdir=lib\plugins --datadir=lib\plugins p build +& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS -Djsc_folder=".." --prefix=$dist p build ninja -C build install $ErrorActionPreference = 'Stop' $pathdll = "$dist\lib\plugins\core_pdd.dll" diff --git a/scripts/jsdec.sh b/scripts/jsdec.sh index 571ecb80..caee0759 100755 --- a/scripts/jsdec.sh +++ b/scripts/jsdec.sh @@ -7,13 +7,13 @@ SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") cd "$SCRIPTPATH/.." if [[ ! -d jsdec ]]; then - git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.1 + git clone https://github.com/rizinorg/jsdec.git --depth 2 --branch master fi cd jsdec rm -rf build mkdir build && cd build -meson --buildtype=release -Drizin_plugdir=share/rizin/plugins -Djsc_folder="../" --libdir=share/rizin/plugins --datadir=share/rizin/plugins "$@" ../p +meson --buildtype=release -Djsc_folder="../" "$@" ../p ninja ninja install diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index 34851920..a7ca2bc8 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "common/Configuration.h" @@ -29,7 +30,7 @@ const QStringList ColorThemeWorker::rizinUnusedOptions = { ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) { - char *szThemes = rz_str_home(RZ_HOME_THEMES); + char *szThemes = rz_path_home_prefix(RZ_THEMES); customRzThemesLocationPath = szThemes; rz_mem_free(szThemes); if (!QDir(customRzThemesLocationPath).exists()) { @@ -37,7 +38,7 @@ ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) } QDir currDir { - QStringLiteral("%1%2%3").arg(rz_sys_prefix(nullptr)).arg(RZ_SYS_DIR).arg(RZ_THEMES) + QStringLiteral("%1%2%3").arg(rz_path_prefix(nullptr)).arg(RZ_SYS_DIR).arg(RZ_THEMES) }; if (currDir.exists()) { standardRzThemesLocationPath = currDir.absolutePath(); @@ -132,9 +133,9 @@ QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const if (themeName != curr) { RzCoreLocked core(Core()); - rz_core_load_theme(core, themeName.toUtf8().constData()); + rz_core_theme_load(core, themeName.toUtf8().constData()); theme = Core()->cmdj("ecj").object().toVariantMap(); - rz_core_load_theme(core, curr.toUtf8().constData()); + rz_core_theme_load(core, curr.toUtf8().constData()); } else { theme = Core()->cmdj("ecj").object().toVariantMap(); } diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 3c309e83..5bb7a7ef 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -530,7 +530,7 @@ void Configuration::setColorTheme(const QString &theme) Core()->cmdRaw("ecd"); s.setValue("theme", "default"); } else { - rz_core_load_theme(Core()->core(), theme.toUtf8().constData()); + rz_core_theme_load(Core()->core(), theme.toUtf8().constData()); s.setValue("theme", theme); } diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 92cf4acb..fbcff262 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -187,7 +187,7 @@ void CutterCore::initialize(bool loadPlugins) #if defined(CUTTER_ENABLE_PACKAGING) && defined(Q_OS_WIN) auto prefixBytes = prefix.absolutePath().toUtf8(); - rz_sys_prefix(prefixBytes.constData()); + rz_path_prefix(prefixBytes.constData()); #endif rz_cons_new(); // initialize console @@ -225,7 +225,7 @@ void CutterCore::initialize(bool loadPlugins) setConfig("cfg.plugins", 0); } if (getConfigi("cfg.plugins")) { - rz_core_loadlibs(this->core_, RZ_CORE_LOADLIBS_ALL, nullptr); + rz_core_loadlibs(this->core_, RZ_CORE_LOADLIBS_ALL); } // IMPLICIT rz_bin_iobind (core_->bin, core_->io); @@ -2416,7 +2416,7 @@ void CutterCore::addBreakpoint(const BreakpointDescription &config) RzBreakpointItem *breakpoint = nullptr; int watchpoint_prot = 0; if (config.hw) { - watchpoint_prot = config.permission & ~(RZ_BP_PROT_EXEC); + watchpoint_prot = config.permission & ~(RZ_PERM_X); } auto address = config.addr; @@ -3003,7 +3003,7 @@ QList CutterCore::getAllComments(const QString &filterType) CORE_LOCK(); QList ret; - QJsonArray commentsArray = cmdj("CCj").array(); + QJsonArray commentsArray = cmdj("CClj").array(); for (const QJsonValue &value : commentsArray) { QJsonObject commentObject = value.toObject(); @@ -3153,13 +3153,16 @@ QList CutterCore::getAllSections() section.paddr = sect->paddr; section.size = sect->size; section.perm = rz_str_rwx_i(sect->perm); - HtPP *digests = rz_core_bin_section_digests(core, sect, hashnames); - if (!digests) { - continue; + if (sect->size > 0) { + HtPP *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); + section.entropy = rz_str_get(entropy); + ht_pp_free(digests); } - const char *entropy = (const char *)ht_pp_find(digests, "entropy", NULL); - section.entropy = rz_str_get(entropy); - ht_pp_free(digests); + section.entropy = ""; sections << section; } @@ -3834,7 +3837,7 @@ QString CutterCore::listFlagsAsStringAt(RVA addr) QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut) { - auto r = cmdj(QString("fdj @") + QString::number(offset)).object(); + auto r = cmdj(QString("fdj @ ") + QString::number(offset)).object(); QString name = r.value("name").toString(); if (flagOffsetOut) { auto offsetValue = r.value("offset"); diff --git a/src/dialogs/BreakpointsDialog.cpp b/src/dialogs/BreakpointsDialog.cpp index 75c5f8b4..c4c3108a 100644 --- a/src/dialogs/BreakpointsDialog.cpp +++ b/src/dialogs/BreakpointsDialog.cpp @@ -86,9 +86,9 @@ BreakpointsDialog::BreakpointsDialog(const BreakpointDescription &breakpoint, QW ui->breakpointCondition->setEditText(breakpoint.condition); if (breakpoint.hw) { ui->radioHardware->setChecked(true); - ui->hwRead->setChecked(breakpoint.permission & RZ_BP_PROT_READ); - ui->hwWrite->setChecked(breakpoint.permission & RZ_BP_PROT_WRITE); - ui->hwExecute->setChecked(breakpoint.permission & RZ_BP_PROT_EXEC); + ui->hwRead->setChecked(breakpoint.permission & RZ_PERM_R); + ui->hwWrite->setChecked(breakpoint.permission & RZ_PERM_W); + ui->hwExecute->setChecked(breakpoint.permission & RZ_PERM_X); ui->breakpointSize->setCurrentText(QString::number(breakpoint.size)); } else { ui->radioSoftware->setChecked(true); @@ -204,13 +204,13 @@ int BreakpointsDialog::getHwPermissions() { int result = 0; if (ui->hwRead->isChecked()) { - result |= RZ_BP_PROT_READ; + result |= RZ_PERM_R; } if (ui->hwWrite->isChecked()) { - result |= RZ_BP_PROT_WRITE; + result |= RZ_PERM_W; } if (ui->hwExecute->isChecked()) { - result |= RZ_BP_PROT_EXEC; + result |= RZ_PERM_X; } return result; } diff --git a/src/widgets/BreakpointWidget.cpp b/src/widgets/BreakpointWidget.cpp index ceb5636d..967e13a8 100644 --- a/src/widgets/BreakpointWidget.cpp +++ b/src/widgets/BreakpointWidget.cpp @@ -32,13 +32,13 @@ int BreakpointModel::columnCount(const QModelIndex &) const static QString formatHwBreakpoint(int permission) { char data[] = "rwx"; - if ((permission & (RZ_BP_PROT_READ | RZ_BP_PROT_ACCESS)) == 0) { + if ((permission & (RZ_PERM_R | RZ_PERM_RW)) == 0) { data[0] = '-'; } - if ((permission & (RZ_BP_PROT_WRITE | RZ_BP_PROT_ACCESS)) == 0) { + if ((permission & (RZ_PERM_W | RZ_PERM_RW)) == 0) { data[1] = '-'; } - if ((permission & RZ_BP_PROT_EXEC) == 0) { + if ((permission & RZ_PERM_X) == 0) { data[2] = '-'; } return data; From 138078a6f4de1dcdb9e36508a35a8517822a581c Mon Sep 17 00:00:00 2001 From: nirkog Date: Sat, 8 Jan 2022 13:07:20 +0200 Subject: [PATCH 06/94] Added support for ctrl+Enter submission in open shellcode tab (#2851) * Added support for ctrl+Enter submission in shellcode tab in the new file dialog --- src/dialogs/NewFileDialog.cpp | 32 ++++++++++++++++++++++++++++++++ src/dialogs/NewFileDialog.h | 2 ++ 2 files changed, 34 insertions(+) diff --git a/src/dialogs/NewFileDialog.cpp b/src/dialogs/NewFileDialog.cpp index a45aa75c..cde5fc85 100644 --- a/src/dialogs/NewFileDialog.cpp +++ b/src/dialogs/NewFileDialog.cpp @@ -75,6 +75,9 @@ NewFileDialog::NewFileDialog(MainWindow *main) /* Set focus on the TextInput */ ui->newFileEdit->setFocus(); + /* Install an event filter for shellcode text edit to enable ctrl+return event */ + ui->shellcodeText->installEventFilter(this); + updateLoadProjectButton(); } @@ -366,3 +369,32 @@ void NewFileDialog::on_tabWidget_currentChanged(int index) { Config()->setNewFileLastClicked(index); } + +bool NewFileDialog::eventFilter(QObject * /*obj*/, QEvent *event) +{ + QString shellcode = ui->shellcodeText->toPlainText(); + QString extractedCode = ""; + static const QRegularExpression rx("([0-9a-f]{2})", QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatchIterator i = rx.globalMatch(shellcode); + int size = 0; + + if (event->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast(event); + + // Confirm comment by pressing Ctrl/Cmd+Return + if ((keyEvent->modifiers() & Qt::ControlModifier) + && ((keyEvent->key() == Qt::Key_Enter) || (keyEvent->key() == Qt::Key_Return))) { + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + extractedCode.append(match.captured(1)); + } + size = extractedCode.size() / 2; + if (size > 0) { + loadShellcode(extractedCode, size); + } + return true; + } + } + + return false; +} diff --git a/src/dialogs/NewFileDialog.h b/src/dialogs/NewFileDialog.h index 197f0508..eb5cb542 100644 --- a/src/dialogs/NewFileDialog.h +++ b/src/dialogs/NewFileDialog.h @@ -69,6 +69,8 @@ private: void loadProject(const QString &project); void loadShellcode(const QString &shellcode, const int size); + bool eventFilter(QObject *obj, QEvent *event); + static const int MaxRecentFiles = 5; }; From 5c4ba4891d5fbca6cd1aa7cf4a27c065d179798f Mon Sep 17 00:00:00 2001 From: nirkog Date: Sat, 8 Jan 2022 15:53:27 +0200 Subject: [PATCH 07/94] Add double click to seek to global var in decompiler (#2871) --- src/widgets/DecompilerWidget.cpp | 32 +++++++++++++++++++++++++++++--- src/widgets/DecompilerWidget.h | 12 ++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/widgets/DecompilerWidget.cpp b/src/widgets/DecompilerWidget.cpp index e45c8c8a..a6dd58af 100644 --- a/src/widgets/DecompilerWidget.cpp +++ b/src/widgets/DecompilerWidget.cpp @@ -115,6 +115,28 @@ Decompiler *DecompilerWidget::getCurrentDecompiler() return Core()->getDecompilerById(ui->decompilerComboBox->currentData().toString()); } +ut64 DecompilerWidget::findReference(size_t pos) +{ + size_t closestPos = SIZE_MAX; + ut64 closestOffset = RVA_INVALID; + void *iter; + rz_vector_foreach(&code->annotations, iter) + { + RzCodeAnnotation *annotation = (RzCodeAnnotation *)iter; + + if (!(annotation->type == RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE) + || annotation->start > pos || annotation->end <= pos) { + continue; + } + if (closestPos != SIZE_MAX && closestPos >= annotation->start) { + continue; + } + closestPos = annotation->start; + closestOffset = annotation->reference.offset; + } + return closestOffset; +} + ut64 DecompilerWidget::offsetForPosition(size_t pos) { size_t closestPos = SIZE_MAX; @@ -123,7 +145,8 @@ ut64 DecompilerWidget::offsetForPosition(size_t pos) rz_vector_foreach(&code->annotations, iter) { RzCodeAnnotation *annotation = (RzCodeAnnotation *)iter; - if (annotation->type != RZ_CODE_ANNOTATION_TYPE_OFFSET || annotation->start > pos + + if (!(annotation->type == RZ_CODE_ANNOTATION_TYPE_OFFSET) || annotation->start > pos || annotation->end <= pos) { continue; } @@ -479,8 +502,11 @@ void DecompilerWidget::showDecompilerContextMenu(const QPoint &pt) void DecompilerWidget::seekToReference() { size_t pos = ui->textEdit->textCursor().position(); - RVA offset = offsetForPosition(pos); - seekable->seekToReference(offset); + RVA offset = findReference(pos); + if (offset != RVA_INVALID) { + seekable->seek(offset); + } + seekable->seekToReference(offsetForPosition(pos)); } bool DecompilerWidget::eventFilter(QObject *obj, QEvent *event) diff --git a/src/widgets/DecompilerWidget.h b/src/widgets/DecompilerWidget.h index 22d0abf7..015525af 100644 --- a/src/widgets/DecompilerWidget.h +++ b/src/widgets/DecompilerWidget.h @@ -198,6 +198,18 @@ private: * @param endPos - Position of the end of the range(inclusive). */ void gatherBreakpointInfo(RzAnnotatedCode &codeDecompiled, size_t startPos, size_t endPos); + /** + * @brief Finds the global variable reference that's closes to the specified position in the + * decompiled code. Same as offsetForPosition but for global references only + * + * @note If no global reference annotations are found at the given position, an RVA_INVALID is + * returned + * + * @param pos - Position in the decompiled code + * @return Address of the referenced global for the specified position, or RVA_INVALID if none + * is found + */ + ut64 findReference(size_t pos); /** * @brief Finds the offset that's closest to the specified position in the decompiled code. * From 893baea83299ae347a998ae364912ac4fb3ab975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 8 Jan 2022 17:16:41 +0100 Subject: [PATCH 08/94] Fix pdj call in nextOpAddr for disasm scrolling (#2874) --- src/core/Cutter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index fbcff262..87d52b15 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -991,7 +991,7 @@ RVA CutterCore::nextOpAddr(RVA startAddr, int count) CORE_LOCK(); QJsonArray array = - Core()->cmdj("pdj " + QString::number(count + 1) + "@" + QString::number(startAddr)) + Core()->cmdj("pdj " + QString::number(count + 1) + " @ " + QString::number(startAddr)) .array(); if (array.isEmpty()) { return startAddr + 1; From 297b9bb192381c2fb98826d1549dc14cc9531e9c Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sat, 15 Jan 2022 21:02:01 +0100 Subject: [PATCH 09/94] Enable support for building rz-libswift on cutter (#2841) --- .github/workflows/ccpp.yml | 3 +++ CMakeLists.txt | 1 + dist/CMakeLists.txt | 23 +++++++++++++++++++++++ dist/bundle_rz_libswift.ps1 | 16 ++++++++++++++++ scripts/rz-libswift.sh | 19 +++++++++++++++++++ src/menus/DecompilerContextMenu.cpp | 2 +- 6 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 dist/bundle_rz_libswift.ps1 create mode 100755 scripts/rz-libswift.sh diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 789e1def..e567c6b9 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -121,6 +121,7 @@ jobs: -DCUTTER_ENABLE_PACKAGING=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ + -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ -DCMAKE_INSTALL_PREFIX=appdir/usr \ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ .. @@ -187,6 +188,7 @@ jobs: -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ -DCUTTER_PACKAGE_JSDEC=ON \ + -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ -DCPACK_PACKAGE_FILE_NAME="$PACKAGE_NAME" \ -DCMAKE_FRAMEWORK_PATH="$BREAKPAD_FRAMEWORK_DIR" \ -DCPACK_BUNDLE_APPLE_CERT_APP="-" \ @@ -224,6 +226,7 @@ jobs: -DCUTTER_ENABLE_PACKAGING=ON ^ -DCUTTER_PACKAGE_DEPENDENCIES=ON ^ -DCUTTER_PACKAGE_RZ_GHIDRA=ON ^ + -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON ^ -DCUTTER_PACKAGE_JSDEC=ON ^ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON ^ -DCUTTER_ENABLE_CRASH_REPORTS=ON ^ diff --git a/CMakeLists.txt b/CMakeLists.txt index 92b49af4..9c0f30b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option(CUTTER_ENABLE_DEPENDENCY_DOWNLOADS "Enable downloading of dependencies. S option(CUTTER_ENABLE_PACKAGING "Enable building platform-specific packages for distributing" OFF) option(CUTTER_PACKAGE_DEPENDENCIES "During install step include the third party dependencies." OFF) option(CUTTER_PACKAGE_RZ_GHIDRA "Compile and install rz-ghidra during install step." OFF) +option(CUTTER_PACKAGE_RZ_LIBSWIFT, "Compile and install rz-libswift demangler during the install step." OFF) option(CUTTER_PACKAGE_JSDEC "Compile and install jsdec during install step." OFF) OPTION(CUTTER_QT6 "Use QT6" OFF) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index cf57cc66..6ce64463 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -32,6 +32,18 @@ if(WIN32) endif() ") endif() + if (CUTTER_PACKAGE_RZ_LIBSWIFT AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + 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_rz_libswift.ps1\" \"\${CMAKE_INSTALL_PREFIX}\" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz-libswift\") + endif() + ") + endif() endif() ################################################ @@ -93,6 +105,17 @@ if(APPLE) ") endif() + if (CUTTER_PACKAGE_RZ_LIBSWIFT AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + install(CODE " + execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-libswift.sh\" --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz-libswift\") + endif() + ") + endif() + endif() ################################################ diff --git a/dist/bundle_rz_libswift.ps1 b/dist/bundle_rz_libswift.ps1 new file mode 100644 index 00000000..12928c93 --- /dev/null +++ b/dist/bundle_rz_libswift.ps1 @@ -0,0 +1,16 @@ +$dist = $args[0] +$python = Split-Path((Get-Command python.exe).Path) + +if (-not (Test-Path -Path 'libswift' -PathType Container)) { + git clone https://github.com/rizinorg/rz-libswift.git --depth 1 libswift +} +cd libswift +& meson.exe --buildtype=release --prefix=$dist build +ninja -C build install +$pathdll = "$dist/lib/plugins/swift.dll" +if(![System.IO.File]::Exists($pathdll)) { + type build/meson-logs/meson-log.txt + ls "$dist/lib/plugins/" + throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) +} +Remove-Item -Recurse -Force $dist/lib/plugins/libswift.lib diff --git a/scripts/rz-libswift.sh b/scripts/rz-libswift.sh new file mode 100755 index 00000000..0772cb4c --- /dev/null +++ b/scripts/rz-libswift.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -e + +SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") + +cd "$SCRIPTPATH/.." + +if [[ ! -d libswift ]]; then + git clone https://github.com/rizinorg/rz-libswift.git --depth 1 libswift +fi + +cd libswift +rm -rf build || sleep 0 +mkdir build && cd build +meson --buildtype=release "$@" .. +ninja +ninja install + diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index e0e1baff..d36cf0b7 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -564,7 +564,7 @@ void DecompilerContextMenu::updateTargetMenuActions() RzCoreLocked core = Core()->core(); if (isReference()) { QString name; - QMenu *menu; + QMenu *menu = nullptr; if (annotationHere->type == RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE || annotationHere->type == RZ_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE) { menu = mainWindow->createShowInMenu(this, annotationHere->reference.offset, From 453974da35f3fd6dd68e95526c989cc5d3e34c1b Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:39:56 +0100 Subject: [PATCH 10/94] Add signature widget for flirts (#2881) * Added flirt view and removed zignature one * Added menu for apply signature from file and create new sig/pat files * Updated rizin to dev branch --- .../menus/information-windows-menu.rst | 6 +- src/CMakeLists.txt | 8 +- src/core/Cutter.cpp | 83 +++++--- src/core/Cutter.h | 6 +- src/core/CutterDescriptions.h | 20 +- src/core/MainWindow.cpp | 50 ++++- src/core/MainWindow.h | 8 +- src/core/MainWindow.ui | 13 ++ src/menus/FlirtContextMenu.cpp | 62 ++++++ src/menus/FlirtContextMenu.h | 40 ++++ src/widgets/FlirtWidget.cpp | 188 ++++++++++++++++++ src/widgets/FlirtWidget.h | 88 ++++++++ .../{ZignaturesWidget.ui => FlirtWidget.ui} | 8 +- src/widgets/ZignaturesWidget.cpp | 152 -------------- src/widgets/ZignaturesWidget.h | 78 -------- 15 files changed, 529 insertions(+), 281 deletions(-) create mode 100644 src/menus/FlirtContextMenu.cpp create mode 100644 src/menus/FlirtContextMenu.h create mode 100644 src/widgets/FlirtWidget.cpp create mode 100644 src/widgets/FlirtWidget.h rename src/widgets/{ZignaturesWidget.ui => FlirtWidget.ui} (90%) delete mode 100644 src/widgets/ZignaturesWidget.cpp delete mode 100644 src/widgets/ZignaturesWidget.h diff --git a/docs/source/user-docs/menus/information-windows-menu.rst b/docs/source/user-docs/menus/information-windows-menu.rst index 070fdfc6..ee35bbff 100644 --- a/docs/source/user-docs/menus/information-windows-menu.rst +++ b/docs/source/user-docs/menus/information-windows-menu.rst @@ -89,8 +89,8 @@ Show VTables **Steps:** Windows -> Info... -> VTables -Show Zignatures +Show Signatures ---------------------------------------- -**Description:** Cutter has its own format of signatures, called Zignatures. This widget lists all the loaded Zignatures. +**Description:** Cutter supports the creation and the utilization of signatures. This widget lists all the signatures available to cutter. -**Steps:** Windows -> Info... -> Zignatures \ No newline at end of file +**Steps:** Windows -> Info... -> Signatures \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8aae0d5d..eb556529 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ set(SOURCES widgets/SymbolsWidget.cpp menus/DisassemblyContextMenu.cpp menus/DecompilerContextMenu.cpp + menus/FlirtContextMenu.cpp widgets/DisassemblyWidget.cpp widgets/HexdumpWidget.cpp common/Configuration.cpp @@ -73,7 +74,7 @@ set(SOURCES common/JsonTreeItem.cpp common/JsonModel.cpp dialogs/VersionInfoDialog.cpp - widgets/ZignaturesWidget.cpp + widgets/FlirtWidget.cpp common/AsyncTask.cpp dialogs/AsyncTaskDialog.cpp widgets/StackWidget.cpp @@ -190,6 +191,7 @@ set(HEADER_FILES widgets/SymbolsWidget.h menus/DisassemblyContextMenu.h menus/DecompilerContextMenu.h + menus/FlirtContextMenu.h widgets/DisassemblyWidget.h widgets/HexdumpWidget.h common/Configuration.h @@ -221,7 +223,7 @@ set(HEADER_FILES common/JsonTreeItem.h common/JsonModel.h dialogs/VersionInfoDialog.h - widgets/ZignaturesWidget.h + widgets/FlirtWidget.h common/AsyncTask.h dialogs/AsyncTaskDialog.h widgets/StackWidget.h @@ -341,7 +343,7 @@ set(UI_FILES widgets/SearchWidget.ui dialogs/RizinPluginsDialog.ui dialogs/VersionInfoDialog.ui - widgets/ZignaturesWidget.ui + widgets/FlirtWidget.ui dialogs/AsyncTaskDialog.ui dialogs/RizinTaskDialog.ui widgets/StackWidget.ui diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 87d52b15..adf0d0e9 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1016,6 +1016,40 @@ RVA CutterCore::getOffset() return core_->offset; } +void CutterCore::applySignature(const QString &filepath) +{ + CORE_LOCK(); + int old_cnt, new_cnt; + const char *arch = rz_config_get(core->config, "asm.arch"); + ut8 expected_arch = rz_core_flirt_arch_from_name(arch); + if (expected_arch == RZ_FLIRT_SIG_ARCH_ANY && filepath.endsWith(".sig", Qt::CaseInsensitive)) { + QMessageBox::warning( + nullptr, tr("Signatures"), + tr("Cannot apply signature because the requested arch is not supported by .sig " + "files\n")); + return; + } + old_cnt = rz_flag_count(core->flags, "flirt"); + rz_sign_flirt_apply(core->analysis, filepath.toStdString().c_str(), expected_arch); + new_cnt = rz_flag_count(core->flags, "flirt"); + QMessageBox::information(nullptr, tr("Signatures"), + tr("Found %1 signatures!").arg(new_cnt - old_cnt)); +} + +void CutterCore::createSignature(const QString &filepath) +{ + CORE_LOCK(); + ut32 n_modules = 0; + if (!rz_core_flirt_create_file(core, filepath.toStdString().c_str(), &n_modules)) { + QMessageBox::warning( + nullptr, tr("Signatures"), + tr("Cannot create signature file (check the console for more details).\n")); + return; + } + QMessageBox::information(nullptr, tr("Signatures"), + tr("Written %1 signatures to %2").arg(n_modules).arg(filepath)); +} + ut64 CutterCore::math(const QString &expr) { CORE_LOCK(); @@ -2967,35 +3001,34 @@ QList CutterCore::getAllHeaders() return ret; } -QList CutterCore::getAllZignatures() +QList CutterCore::getSignaturesDB() { CORE_LOCK(); - QList zignatures; - - QJsonArray zignaturesArray = cmdj("zj").array(); - - for (const QJsonValue &value : zignaturesArray) { - QJsonObject zignatureObject = value.toObject(); - - ZignatureDescription zignature; - - zignature.name = zignatureObject[RJsonKey::name].toString(); - zignature.bytes = zignatureObject[RJsonKey::bytes].toString(); - zignature.offset = zignatureObject[RJsonKey::offset].toVariant().toULongLong(); - for (const QJsonValue &ref : zignatureObject[RJsonKey::refs].toArray()) { - zignature.refs << ref.toString(); - } - - QJsonObject graphObject = zignatureObject[RJsonKey::graph].toObject(); - zignature.cc = graphObject[RJsonKey::cc].toVariant().toULongLong(); - zignature.nbbs = graphObject[RJsonKey::nbbs].toVariant().toULongLong(); - zignature.edges = graphObject[RJsonKey::edges].toVariant().toULongLong(); - zignature.ebbs = graphObject[RJsonKey::ebbs].toVariant().toULongLong(); - - zignatures << zignature; + QList sigdb; + const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path"); + if (RZ_STR_ISEMPTY(sigdb_path)) { + return sigdb; } - return zignatures; + RzList *list = rz_sign_sigdb_load_database(sigdb_path, true); + void *ptr = NULL; + RzListIter *iter = NULL; + + rz_list_foreach(list, iter, ptr) + { + RzSigDBEntry *sig = static_cast(ptr); + FlirtDescription flirt; + flirt.bin_name = sig->bin_name; + flirt.arch_name = sig->arch_name; + flirt.base_name = sig->base_name; + flirt.short_path = sig->short_path; + flirt.file_path = sig->file_path; + flirt.details = sig->details; + flirt.n_modules = QString::number(sig->n_modules); + flirt.arch_bits = QString::number(sig->arch_bits); + sigdb << flirt; + } + return sigdb; } QList CutterCore::getAllComments(const QString &filterType) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index fbd73b6e..8671b73a 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -316,6 +316,10 @@ public: RVA prevOpAddr(RVA startAddr, int count); RVA nextOpAddr(RVA startAddr, int count); + /* SigDB / Flirt functions */ + void applySignature(const QString &filepath); + void createSignature(const QString &filepath); + /* Math functions */ ut64 math(const QString &expr); ut64 num(const QString &expr); @@ -553,7 +557,7 @@ public: QList getAllExports(); QList getAllSymbols(); QList getAllHeaders(); - QList getAllZignatures(); + QList getSignaturesDB(); QList getAllComments(const QString &filterType); QList getAllRelocs(); QList getAllStrings(); diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index 941be488..e28894ee 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -60,16 +60,16 @@ struct HeaderDescription QString name; }; -struct ZignatureDescription +struct FlirtDescription { - QString name; - QString bytes; - RVA cc; - RVA nbbs; - RVA edges; - RVA ebbs; - RVA offset; - QStringList refs; + QString bin_name; + QString arch_name; + QString arch_bits; + QString base_name; + QString short_path; + QString file_path; + QString details; + QString n_modules; }; struct TypeDescription @@ -413,7 +413,7 @@ Q_DECLARE_METATYPE(ResourcesDescription) Q_DECLARE_METATYPE(VTableDescription) Q_DECLARE_METATYPE(TypeDescription) Q_DECLARE_METATYPE(HeaderDescription) -Q_DECLARE_METATYPE(ZignatureDescription) +Q_DECLARE_METATYPE(FlirtDescription) Q_DECLARE_METATYPE(SearchDescription) Q_DECLARE_METATYPE(SectionDescription) Q_DECLARE_METATYPE(SegmentDescription) diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 7d254031..6e796a8c 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -55,7 +55,7 @@ #include "widgets/ResourcesWidget.h" #include "widgets/VTablesWidget.h" #include "widgets/HeadersWidget.h" -#include "widgets/ZignaturesWidget.h" +#include "widgets/FlirtWidget.h" #include "widgets/DebugActions.h" #include "widgets/MemoryMapWidget.h" #include "widgets/BreakpointWidget.h" @@ -399,7 +399,7 @@ void MainWindow::initDocks() segmentsDock = new SegmentsWidget(this), symbolsDock = new SymbolsWidget(this), vTablesDock = new VTablesWidget(this), - zignaturesDock = new ZignaturesWidget(this), + flirtDock = new FlirtWidget(this), rzGraphDock = new RizinGraphWidget(this), callGraphDock = new CallGraphWidget(this, false), globalCallGraphDock = new CallGraphWidget(this, true), @@ -896,7 +896,7 @@ void MainWindow::restoreDocks() tabifyDockWidget(dashboardDock, typesDock); tabifyDockWidget(dashboardDock, searchDock); tabifyDockWidget(dashboardDock, headersDock); - tabifyDockWidget(dashboardDock, zignaturesDock); + tabifyDockWidget(dashboardDock, flirtDock); tabifyDockWidget(dashboardDock, symbolsDock); tabifyDockWidget(dashboardDock, classesDock); tabifyDockWidget(dashboardDock, resourcesDock); @@ -1741,6 +1741,50 @@ void MainWindow::on_actionExport_as_code_triggered() fileOut << Core()->cmd(cmd + " $s @ 0"); } +void MainWindow::on_actionApplySigFromFile_triggered() +{ + QStringList filters; + filters << tr("Signature File (*.sig)"); + filters << tr("Pattern File (*.pat)"); + + QFileDialog dialog(this); + dialog.setWindowTitle(tr("Apply Signature From File")); + dialog.setNameFilters(filters); + + if (!dialog.exec()) { + return; + } + + const QString &sigfile = QDir::toNativeSeparators(dialog.selectedFiles().first()); + + if (!sigfile.isEmpty()) { + core->applySignature(sigfile); + this->refreshAll(); + } +} + +void MainWindow::on_actionCreateNewSig_triggered() +{ + QStringList filters; + filters << tr("Signature File (*.sig)"); + filters << tr("Pattern File (*.pat)"); + + QFileDialog dialog(this, tr("Create New Signature File")); + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setNameFilters(filters); + dialog.selectFile(""); + dialog.setDefaultSuffix("sig"); + if (!dialog.exec()) + return; + + const QString &sigfile = QDir::toNativeSeparators(dialog.selectedFiles().first()); + + if (!sigfile.isEmpty()) { + core->createSignature(sigfile); + } +} + void MainWindow::on_actionGrouped_dock_dragging_triggered(bool checked) { #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index 312350cd..dd878062 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -44,7 +44,7 @@ class ResourcesWidget; class VTablesWidget; class TypesWidget; class HeadersWidget; -class ZignaturesWidget; +class FlirtWidget; class SearchWidget; class QDockWidget; class DisassemblyWidget; @@ -190,6 +190,10 @@ private slots: void on_actionExport_as_code_triggered(); + void on_actionApplySigFromFile_triggered(); + + void on_actionCreateNewSig_triggered(); + void on_actionGrouped_dock_dragging_triggered(bool checked); void updateTasksIndicator(); @@ -243,7 +247,7 @@ private: SdbWidget *sdbDock = nullptr; SectionsWidget *sectionsDock = nullptr; SegmentsWidget *segmentsDock = nullptr; - ZignaturesWidget *zignaturesDock = nullptr; + FlirtWidget *flirtDock = nullptr; ConsoleWidget *consoleDock = nullptr; ClassesWidget *classesDock = nullptr; ResourcesWidget *resourcesDock = nullptr; diff --git a/src/core/MainWindow.ui b/src/core/MainWindow.ui index dc9e4f1e..2af046cc 100644 --- a/src/core/MainWindow.ui +++ b/src/core/MainWindow.ui @@ -77,6 +77,9 @@ + + + @@ -740,6 +743,16 @@ Export as code + + + Apply Signature From File + + + + + Create New Signature File + + Add Hexdump diff --git a/src/menus/FlirtContextMenu.cpp b/src/menus/FlirtContextMenu.cpp new file mode 100644 index 00000000..cd573af0 --- /dev/null +++ b/src/menus/FlirtContextMenu.cpp @@ -0,0 +1,62 @@ +#include "FlirtContextMenu.h" +#include "MainWindow.h" + +#include +#include +#include +#include +#include +#include + +FlirtContextMenu::FlirtContextMenu(QWidget *parent, MainWindow *mainWindow) + : QMenu(parent), mainWindow(mainWindow) +{ + actionCopyLine = new QAction(tr("Copy Line"), this); + actionApplySignature = new QAction(tr("Apply Signature File"), this); + + connect(actionCopyLine, &QAction::triggered, this, &FlirtContextMenu::onActionCopyLine); + connect(actionApplySignature, &QAction::triggered, this, + &FlirtContextMenu::onActionApplySignature); + + addAction(actionCopyLine); + addSeparator(); + addAction(actionApplySignature); + + setHasTarget(false); +} + +FlirtContextMenu::~FlirtContextMenu() {} + +void FlirtContextMenu::setTarget(const FlirtDescription &flirt) +{ + this->entry = flirt; + setHasTarget(true); +} + +void FlirtContextMenu::clearTarget() +{ + setHasTarget(false); +} + +void FlirtContextMenu::onActionCopyLine() +{ + auto clipboard = QApplication::clipboard(); + QString text = entry.bin_name + "\t" + entry.arch_name + "\t" + entry.arch_bits + "\t" + + entry.n_modules + "\t" + entry.base_name + "\t" + entry.details; + clipboard->setText(text); +} + +void FlirtContextMenu::onActionApplySignature() +{ + if (this->hasTarget) { + Core()->applySignature(entry.file_path); + } +} + +void FlirtContextMenu::setHasTarget(bool hasTarget) +{ + this->hasTarget = hasTarget; + for (const auto &action : this->actions()) { + action->setEnabled(hasTarget); + } +} diff --git a/src/menus/FlirtContextMenu.h b/src/menus/FlirtContextMenu.h new file mode 100644 index 00000000..6cf12cae --- /dev/null +++ b/src/menus/FlirtContextMenu.h @@ -0,0 +1,40 @@ +#ifndef FLIRT_CONTEXTMENU_H +#define FLIRT_CONTEXTMENU_H + +#include "core/Cutter.h" +#include +#include + +class MainWindow; + +class CUTTER_EXPORT FlirtContextMenu : public QMenu +{ + Q_OBJECT + +public: + FlirtContextMenu(QWidget *parent, MainWindow *mainWindow); + ~FlirtContextMenu(); + +public slots: + void setTarget(const FlirtDescription &flirt); + void clearTarget(); + +private: + void onActionCopyLine(); + void onActionApplySignature(); + + QMenu *pluginMenu; + QAction *pluginMenuAction; + MainWindow *mainWindow; + + bool hasTarget = false; + +protected: + void setHasTarget(bool hasTarget); + QAction *actionApplySignature; + QAction *actionCopyLine; + QAction *actionShowContents; + + FlirtDescription entry; +}; +#endif // FlirtCONTEXTMENU_H diff --git a/src/widgets/FlirtWidget.cpp b/src/widgets/FlirtWidget.cpp new file mode 100644 index 00000000..61d43d87 --- /dev/null +++ b/src/widgets/FlirtWidget.cpp @@ -0,0 +1,188 @@ +#include "FlirtWidget.h" +#include "ui_FlirtWidget.h" +#include "core/MainWindow.h" +#include "common/Helpers.h" + +FlirtModel::FlirtModel(QList *sigdb, QObject *parent) + : QAbstractListModel(parent), sigdb(sigdb) +{ +} + +int FlirtModel::rowCount(const QModelIndex &) const +{ + return sigdb->count(); +} + +int FlirtModel::columnCount(const QModelIndex &) const +{ + return FlirtModel::ColumnCount; +} + +QVariant FlirtModel::data(const QModelIndex &index, int role) const +{ + if (index.row() >= sigdb->count()) + return QVariant(); + + const FlirtDescription &entry = sigdb->at(index.row()); + + switch (role) { + case Qt::DisplayRole: + switch (index.column()) { + case BinTypeColumn: + return entry.bin_name; + case ArchNameColumn: + return entry.arch_name; + case ArchBitsColumn: + return entry.arch_bits; + case NumModulesColumn: + return entry.n_modules; + case NameColumn: + return entry.base_name; + case DetailsColumn: + return entry.details; + default: + return QVariant(); + } + + case FlirtDescriptionRole: + return QVariant::fromValue(entry); + + case Qt::ToolTipRole: { + return entry.short_path; + } + + default: + return QVariant(); + } +} + +QVariant FlirtModel::headerData(int section, Qt::Orientation, int role) const +{ + switch (role) { + case Qt::DisplayRole: + switch (section) { + case BinTypeColumn: + return tr("Bin"); + case ArchNameColumn: + return tr("Arch"); + case ArchBitsColumn: + return tr("Bits"); + case NumModulesColumn: + return tr("# Funcs"); + case NameColumn: + return tr("Name"); + case DetailsColumn: + return tr("Details"); + default: + return QVariant(); + } + default: + return QVariant(); + } +} + +FlirtProxyModel::FlirtProxyModel(FlirtModel *sourceModel, QObject *parent) + : QSortFilterProxyModel(parent) +{ + setSourceModel(sourceModel); +} + +bool FlirtProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +{ + QModelIndex index = sourceModel()->index(row, 0, parent); + FlirtDescription entry = index.data(FlirtModel::FlirtDescriptionRole).value(); + return qhelpers::filterStringContains(entry.base_name, this); +} + +bool FlirtProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + FlirtDescription leftEntry = + left.data(FlirtModel::FlirtDescriptionRole).value(); + FlirtDescription rightEntry = + right.data(FlirtModel::FlirtDescriptionRole).value(); + + switch (left.column()) { + case FlirtModel::BinTypeColumn: + return leftEntry.bin_name < rightEntry.bin_name; + case FlirtModel::ArchNameColumn: + return leftEntry.arch_name < rightEntry.arch_name; + case FlirtModel::ArchBitsColumn: + return leftEntry.arch_bits < rightEntry.arch_bits; + case FlirtModel::NumModulesColumn: + return leftEntry.n_modules < rightEntry.n_modules; + case FlirtModel::NameColumn: + return leftEntry.base_name < rightEntry.base_name; + case FlirtModel::DetailsColumn: + return leftEntry.details < rightEntry.details; + default: + break; + } + + return leftEntry.bin_name < rightEntry.bin_name; +} + +FlirtWidget::FlirtWidget(MainWindow *main) + : CutterDockWidget(main), + ui(new Ui::FlirtWidget), + blockMenu(new FlirtContextMenu(this, mainWindow)) +{ + ui->setupUi(this); + + model = new FlirtModel(&sigdb, this); + proxyModel = new FlirtProxyModel(model, this); + ui->flirtTreeView->setModel(proxyModel); + ui->flirtTreeView->sortByColumn(FlirtModel::BinTypeColumn, Qt::AscendingOrder); + + setScrollMode(); + + this->connect(this, &QWidget::customContextMenuRequested, this, + &FlirtWidget::showItemContextMenu); + this->setContextMenuPolicy(Qt::CustomContextMenu); + + this->connect(ui->flirtTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, + &FlirtWidget::onSelectedItemChanged); + connect(Core(), &CutterCore::refreshAll, this, &FlirtWidget::refreshFlirt); + + this->addActions(this->blockMenu->actions()); +} + +FlirtWidget::~FlirtWidget() {} + +void FlirtWidget::refreshFlirt() +{ + model->beginResetModel(); + sigdb = Core()->getSignaturesDB(); + model->endResetModel(); + + ui->flirtTreeView->resizeColumnToContents(0); + ui->flirtTreeView->resizeColumnToContents(1); + ui->flirtTreeView->resizeColumnToContents(2); + ui->flirtTreeView->resizeColumnToContents(3); + ui->flirtTreeView->resizeColumnToContents(4); + ui->flirtTreeView->resizeColumnToContents(5); +} + +void FlirtWidget::setScrollMode() +{ + qhelpers::setVerticalScrollMode(ui->flirtTreeView); +} + +void FlirtWidget::onSelectedItemChanged(const QModelIndex &index) +{ + if (index.isValid()) { + const FlirtDescription &entry = sigdb.at(index.row()); + blockMenu->setTarget(entry); + } else { + blockMenu->clearTarget(); + } +} + +void FlirtWidget::showItemContextMenu(const QPoint &pt) +{ + auto index = ui->flirtTreeView->currentIndex(); + if (index.isValid()) { + const FlirtDescription &entry = sigdb.at(index.row()); + blockMenu->setTarget(entry); + blockMenu->exec(this->mapToGlobal(pt)); + } +} \ No newline at end of file diff --git a/src/widgets/FlirtWidget.h b/src/widgets/FlirtWidget.h new file mode 100644 index 00000000..937e91f5 --- /dev/null +++ b/src/widgets/FlirtWidget.h @@ -0,0 +1,88 @@ +#ifndef FLIRT_WIDGET_H +#define FLIRT_WIDGET_H + +#include + +#include "core/Cutter.h" +#include "CutterDockWidget.h" +#include "menus/FlirtContextMenu.h" + +#include +#include + +class MainWindow; +class QTreeWidget; +class QTreeWidgetItem; +class FlirtWidget; + +namespace Ui { +class FlirtWidget; +} + +class FlirtModel : public QAbstractListModel +{ + Q_OBJECT + + friend FlirtWidget; + +public: + enum Column { + BinTypeColumn = 0, + ArchNameColumn, + ArchBitsColumn, + NumModulesColumn, + NameColumn, + DetailsColumn, + ColumnCount + }; + enum Role { FlirtDescriptionRole = Qt::UserRole }; + + FlirtModel(QList *sigdb, QObject *parent = 0); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + +private: + QList *sigdb; +}; + +class FlirtProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + FlirtProxyModel(FlirtModel *sourceModel, QObject *parent = nullptr); + +protected: + bool filterAcceptsRow(int row, const QModelIndex &parent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; +}; + +class FlirtWidget : public CutterDockWidget +{ + Q_OBJECT + +public: + explicit FlirtWidget(MainWindow *main); + ~FlirtWidget(); + +private slots: + void refreshFlirt(); + void onSelectedItemChanged(const QModelIndex &index); + void showItemContextMenu(const QPoint &pt); + +private: + std::unique_ptr ui; + + FlirtModel *model; + FlirtProxyModel *proxyModel; + QList sigdb; + FlirtContextMenu *blockMenu; + + void setScrollMode(); +}; + +#endif // FLIRT_WIDGET_H diff --git a/src/widgets/ZignaturesWidget.ui b/src/widgets/FlirtWidget.ui similarity index 90% rename from src/widgets/ZignaturesWidget.ui rename to src/widgets/FlirtWidget.ui index 4db82885..19b922e1 100644 --- a/src/widgets/ZignaturesWidget.ui +++ b/src/widgets/FlirtWidget.ui @@ -1,7 +1,7 @@ - ZignaturesWidget - + FlirtWidget + 0 @@ -11,7 +11,7 @@ - Zignatures + Signatures @@ -28,7 +28,7 @@ 0 - + CutterTreeView::item { diff --git a/src/widgets/ZignaturesWidget.cpp b/src/widgets/ZignaturesWidget.cpp deleted file mode 100644 index 222a4d09..00000000 --- a/src/widgets/ZignaturesWidget.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "ZignaturesWidget.h" -#include "ui_ZignaturesWidget.h" -#include "core/MainWindow.h" -#include "common/Helpers.h" - -ZignaturesModel::ZignaturesModel(QList *zignatures, QObject *parent) - : QAbstractListModel(parent), zignatures(zignatures) -{ -} - -int ZignaturesModel::rowCount(const QModelIndex &) const -{ - return zignatures->count(); -} - -int ZignaturesModel::columnCount(const QModelIndex &) const -{ - return ZignaturesModel::ColumnCount; -} - -QVariant ZignaturesModel::data(const QModelIndex &index, int role) const -{ - if (index.row() >= zignatures->count()) - return QVariant(); - - const ZignatureDescription &zignature = zignatures->at(index.row()); - - switch (role) { - case Qt::DisplayRole: - switch (index.column()) { - case OffsetColumn: - return RzAddressString(zignature.offset); - case NameColumn: - return zignature.name; - case ValueColumn: - return zignature.bytes; - default: - return QVariant(); - } - - case ZignatureDescriptionRole: - return QVariant::fromValue(zignature); - - case Qt::ToolTipRole: { - QString tmp = QString("Graph:\n\n Cyclomatic complexity: " + RzSizeString(zignature.cc) - + "\n Nodes / basicblocks: " + RzSizeString(zignature.nbbs) - + "\n Edges: " + RzSizeString(zignature.edges) - + "\n Ebbs: " + RzSizeString(zignature.ebbs) + "\n\nRefs:\n"); - for (const QString &ref : zignature.refs) { - tmp.append("\n " + ref); - } - return tmp; - } - - default: - return QVariant(); - } -} - -QVariant ZignaturesModel::headerData(int section, Qt::Orientation, int role) const -{ - switch (role) { - case Qt::DisplayRole: - switch (section) { - case OffsetColumn: - return tr("Offset"); - case NameColumn: - return tr("Name"); - case ValueColumn: - return tr("Bytes"); - default: - return QVariant(); - } - default: - return QVariant(); - } -} - -ZignaturesProxyModel::ZignaturesProxyModel(ZignaturesModel *sourceModel, QObject *parent) - : QSortFilterProxyModel(parent) -{ - setSourceModel(sourceModel); -} - -bool ZignaturesProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const -{ - QModelIndex index = sourceModel()->index(row, 0, parent); - ZignatureDescription item = - index.data(ZignaturesModel::ZignatureDescriptionRole).value(); - return qhelpers::filterStringContains(item.name, this); -} - -bool ZignaturesProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - ZignatureDescription leftZignature = - left.data(ZignaturesModel::ZignatureDescriptionRole).value(); - ZignatureDescription rightZignature = - right.data(ZignaturesModel::ZignatureDescriptionRole).value(); - - switch (left.column()) { - case ZignaturesModel::OffsetColumn: - return leftZignature.offset < rightZignature.offset; - case ZignaturesModel::NameColumn: - return leftZignature.name < rightZignature.name; - case ZignaturesModel::ValueColumn: - return leftZignature.bytes < rightZignature.bytes; - default: - break; - } - - return leftZignature.offset < rightZignature.offset; -} - -ZignaturesWidget::ZignaturesWidget(MainWindow *main) - : CutterDockWidget(main), ui(new Ui::ZignaturesWidget) -{ - ui->setupUi(this); - - zignaturesModel = new ZignaturesModel(&zignatures, this); - zignaturesProxyModel = new ZignaturesProxyModel(zignaturesModel, this); - ui->zignaturesTreeView->setModel(zignaturesProxyModel); - ui->zignaturesTreeView->sortByColumn(ZignaturesModel::OffsetColumn, Qt::AscendingOrder); - - setScrollMode(); - - connect(Core(), &CutterCore::refreshAll, this, &ZignaturesWidget::refreshZignatures); -} - -ZignaturesWidget::~ZignaturesWidget() {} - -void ZignaturesWidget::refreshZignatures() -{ - zignaturesModel->beginResetModel(); - zignatures = Core()->getAllZignatures(); - zignaturesModel->endResetModel(); - - ui->zignaturesTreeView->resizeColumnToContents(0); - ui->zignaturesTreeView->resizeColumnToContents(1); - ui->zignaturesTreeView->resizeColumnToContents(2); -} - -void ZignaturesWidget::setScrollMode() -{ - qhelpers::setVerticalScrollMode(ui->zignaturesTreeView); -} - -void ZignaturesWidget::on_zignaturesTreeView_doubleClicked(const QModelIndex &index) -{ - ZignatureDescription item = - index.data(ZignaturesModel::ZignatureDescriptionRole).value(); - Core()->seekAndShow(item.offset); -} diff --git a/src/widgets/ZignaturesWidget.h b/src/widgets/ZignaturesWidget.h deleted file mode 100644 index 88a6d945..00000000 --- a/src/widgets/ZignaturesWidget.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef ZIGNATURESWIDGET_H -#define ZIGNATURESWIDGET_H - -#include - -#include "core/Cutter.h" -#include "CutterDockWidget.h" - -#include -#include - -class MainWindow; -class QTreeWidget; -class QTreeWidgetItem; -class ZignaturesWidget; - -namespace Ui { -class ZignaturesWidget; -} - -class ZignaturesModel : public QAbstractListModel -{ - Q_OBJECT - - friend ZignaturesWidget; - -public: - enum Column { OffsetColumn = 0, NameColumn, ValueColumn, ColumnCount }; - enum Role { ZignatureDescriptionRole = Qt::UserRole }; - - ZignaturesModel(QList *zignatures, QObject *parent = 0); - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - -private: - QList *zignatures; -}; - -class ZignaturesProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT - -public: - ZignaturesProxyModel(ZignaturesModel *sourceModel, QObject *parent = nullptr); - -protected: - bool filterAcceptsRow(int row, const QModelIndex &parent) const override; - bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; -}; - -class ZignaturesWidget : public CutterDockWidget -{ - Q_OBJECT - -public: - explicit ZignaturesWidget(MainWindow *main); - ~ZignaturesWidget(); - -private slots: - void on_zignaturesTreeView_doubleClicked(const QModelIndex &index); - - void refreshZignatures(); - -private: - std::unique_ptr ui; - - ZignaturesModel *zignaturesModel; - ZignaturesProxyModel *zignaturesProxyModel; - QList zignatures; - - void setScrollMode(); -}; - -#endif // ZIGNATURESWIDGET_H From 4f627e9bff9c9c57678e6c8fa7b6b014e94e0ca7 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Fri, 21 Jan 2022 18:48:10 +0100 Subject: [PATCH 11/94] Return error when applying a signature fails. (#2882) * Updated rizin commit to 8282cee287abdbf8664a0b2540bad2b5ea5b819d * Fix messages based on fail/success result while applying a sig/pat file --- src/core/Cutter.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index adf0d0e9..261ca99a 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1023,17 +1023,22 @@ void CutterCore::applySignature(const QString &filepath) const char *arch = rz_config_get(core->config, "asm.arch"); ut8 expected_arch = rz_core_flirt_arch_from_name(arch); if (expected_arch == RZ_FLIRT_SIG_ARCH_ANY && filepath.endsWith(".sig", Qt::CaseInsensitive)) { - QMessageBox::warning( - nullptr, tr("Signatures"), - tr("Cannot apply signature because the requested arch is not supported by .sig " - "files\n")); + QMessageBox::warning(nullptr, tr("Signatures"), + tr("Cannot apply signature file because the requested arch is not " + "supported by .sig " + "files")); return; } old_cnt = rz_flag_count(core->flags, "flirt"); - rz_sign_flirt_apply(core->analysis, filepath.toStdString().c_str(), expected_arch); - new_cnt = rz_flag_count(core->flags, "flirt"); - QMessageBox::information(nullptr, tr("Signatures"), - tr("Found %1 signatures!").arg(new_cnt - old_cnt)); + if (rz_sign_flirt_apply(core->analysis, filepath.toStdString().c_str(), expected_arch)) { + new_cnt = rz_flag_count(core->flags, "flirt"); + QMessageBox::information(nullptr, tr("Signatures"), + tr("Found %1 matching signatures!").arg(new_cnt - old_cnt)); + return; + } + QMessageBox::warning( + nullptr, tr("Signatures"), + tr("Failed to apply signature file!\nPlease check the console for more details.")); } void CutterCore::createSignature(const QString &filepath) @@ -1043,11 +1048,11 @@ void CutterCore::createSignature(const QString &filepath) if (!rz_core_flirt_create_file(core, filepath.toStdString().c_str(), &n_modules)) { QMessageBox::warning( nullptr, tr("Signatures"), - tr("Cannot create signature file (check the console for more details).\n")); + tr("Cannot create signature file (check the console for more details).")); return; } QMessageBox::information(nullptr, tr("Signatures"), - tr("Written %1 signatures to %2").arg(n_modules).arg(filepath)); + tr("Written %1 signatures to %2.").arg(n_modules).arg(filepath)); } ut64 CutterCore::math(const QString &expr) From cabe3ffb3e35f3da26460562c15142a9a5e46e99 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Wed, 26 Jan 2022 15:53:05 +0200 Subject: [PATCH 12/94] Fix crash on Windows when starting from a console (#2885) Fixes #2877 --- src/Main.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index 0e665061..89101b11 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -22,14 +22,19 @@ static void connectToConsole() return; } - // Avoid reconfiguring stderr/stdout if one of them is already connected to a stream. + // Avoid reconfiguring stdin/stderr/stdout if one of them is already connected to a stream. // This can happen when running with stdout/stderr redirected to a file. - if (0 > fileno(stdout)) { - // Overwrite FD 1 and 2 for the benefit of any code that uses the FDs + if (0 > fileno(stdin)) { + // Overwrite FD 0, FD 1 and 2 for the benefit of any code that uses the FDs // directly. This is safe because the CRT allocates FDs 0, 1 and // 2 at startup even if they don't have valid underlying Windows // handles. This means we won't be overwriting an FD created by // _open() after startup. + _close(0); + + freopen("CONIN$", "r+", stdin); + } + if (0 > fileno(stdout)) { _close(1); if (freopen("CONOUT$", "a+", stdout)) { From 35408be46f65f863607385b12efa7daf0699d931 Mon Sep 17 00:00:00 2001 From: billow Date: Thu, 27 Jan 2022 17:06:20 +0800 Subject: [PATCH 13/94] Convert rizin commands to C apis (#2861) * "fr" renameFlag * "f-" delFlag * "f" addFlag * "fsj" getAllFlagspaces * "fj" getAllFlags * "afn" renameFunction * "af-" delFunction * "af" createFunctionAt * "eco" * "ecd" --- src/common/Configuration.cpp | 2 +- src/common/SettingsUpgrade.cpp | 8 +- src/core/Cutter.cpp | 135 +++++++++++++++------------ src/core/Cutter.h | 11 ++- src/dialogs/EditVariablesDialog.cpp | 2 +- src/menus/DisassemblyContextMenu.cpp | 2 +- src/widgets/FunctionsWidget.cpp | 5 +- 7 files changed, 95 insertions(+), 70 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 5bb7a7ef..87a97b92 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -527,7 +527,7 @@ const QColor Configuration::getColor(const QString &name) const void Configuration::setColorTheme(const QString &theme) { if (theme == "default") { - Core()->cmdRaw("ecd"); + rz_cons_pal_init(Core()->core()->cons->context); s.setValue("theme", "default"); } else { rz_core_theme_load(Core()->core(), theme.toUtf8().constData()); diff --git a/src/common/SettingsUpgrade.cpp b/src/common/SettingsUpgrade.cpp index 33b5bff9..9ff48999 100644 --- a/src/common/SettingsUpgrade.cpp +++ b/src/common/SettingsUpgrade.cpp @@ -183,8 +183,11 @@ static void removeObsoleteOptionsFromCustomThemes() { const QStringList options = Core()->cmdj("ecj").object().keys() << ColorThemeWorker::cutterSpecificOptions; - for (auto theme : Core()->cmdList("eco*")) { - theme = theme.trimmed(); + RzList *themes_list = rz_core_theme_list(Core()->core()); + RzListIter *th_iter; + const char *th; + CutterRzListForeach (themes_list, th_iter, const char, th) { + auto theme = QString(th).trimmed(); if (!ThemeWorker().isCustomTheme(theme)) { continue; } @@ -197,6 +200,7 @@ static void removeObsoleteOptionsFromCustomThemes() } ThemeWorker().save(QJsonDocument(updatedTheme), theme); } + rz_list_free(themes_list); } void Cutter::migrateThemes() diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 261ca99a..21a07c57 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -687,19 +687,25 @@ bool CutterCore::mapFile(QString path, RVA mapaddr) void CutterCore::renameFunction(const RVA offset, const QString &newName) { - cmdRaw("afn " + newName + " " + RzAddressString(offset)); + CORE_LOCK(); + rz_core_analysis_function_rename(core, offset, newName.toStdString().c_str()); emit functionRenamed(offset, newName); } void CutterCore::delFunction(RVA addr) { - cmdRaw("af- " + RzAddressString(addr)); + CORE_LOCK(); + rz_core_analysis_undefine(core, addr); emit functionsChanged(); } void CutterCore::renameFlag(QString old_name, QString new_name) { - cmdRaw("fr " + old_name + " " + new_name); + CORE_LOCK(); + RzFlagItem *flag = rz_flag_get(core->flags, old_name.toStdString().c_str()); + if (!flag) + return; + rz_flag_rename(core->flags, flag, new_name.toStdString().c_str()); emit flagsChanged(); } @@ -717,13 +723,15 @@ void CutterCore::renameFunctionVariable(QString newName, QString oldName, RVA fu void CutterCore::delFlag(RVA addr) { - cmdRawAt("f-", addr); + CORE_LOCK(); + rz_flag_unset_off(core->flags, addr); emit flagsChanged(); } void CutterCore::delFlag(const QString &name) { - cmdRaw("f-" + name); + CORE_LOCK(); + rz_flag_unset_name(core->flags, name.toStdString().c_str()); emit flagsChanged(); } @@ -797,34 +805,34 @@ void CutterCore::setAsString(RVA addr, int size, StringTypeFormats type) return; } - QString command; - + RzStrEnc encoding; switch (type) { case StringTypeFormats::None: { - command = "Cs"; + encoding = RZ_STRING_ENC_GUESS; break; } case StringTypeFormats::ASCII_LATIN1: { - command = "Csa"; + encoding = RZ_STRING_ENC_8BIT; break; } case StringTypeFormats::UTF8: { - command = "Cs8"; + encoding = RZ_STRING_ENC_UTF8; break; } default: return; } + CORE_LOCK(); seekAndShow(addr); - - cmdRawAt(QString("%1 %2").arg(command).arg(size), addr); + rz_core_meta_string_add(core, addr, size, encoding, nullptr); emit instructionChanged(addr); } void CutterCore::removeString(RVA addr) { - cmdRawAt("Cs-", addr); + CORE_LOCK(); + rz_meta_del(core->analysis, RZ_META_TYPE_STRING, addr, 1); emit instructionChanged(addr); } @@ -833,21 +841,33 @@ QString CutterCore::getString(RVA addr) return cmdRawAt("ps", addr); } +QString CutterCore::getMetaString(RVA addr) +{ + return cmdRawAt("Cs.", addr); +} + void CutterCore::setToData(RVA addr, int size, int repeat) { if (size <= 0 || repeat <= 0) { return; } - cmdRawAt("Cd-", addr); - cmdRawAt(QString("Cd %1 %2").arg(size).arg(repeat), addr); + + CORE_LOCK(); + rz_meta_del(core->analysis, RZ_META_TYPE_DATA, addr, 1); + RVA address = addr; + auto name = QString(size).toStdString(); + for (int i = 0; i < repeat; ++i, address += size) { + rz_meta_set(core->analysis, RZ_META_TYPE_DATA, address, size, name.c_str()); + } emit instructionChanged(addr); } int CutterCore::sizeofDataMeta(RVA addr) { - bool ok; - int size = cmdRawAt("Cd.", addr).toInt(&ok); - return (ok ? size : 0); + ut64 size; + CORE_LOCK(); + rz_meta_get_at(core->analysis, addr, RZ_META_TYPE_DATA, &size); + return (int)size; } void CutterCore::setComment(RVA addr, const QString &cmt) @@ -1302,20 +1322,22 @@ void CutterCore::cmdEsil(const char *command) } } -QString CutterCore::createFunctionAt(RVA addr) +void CutterCore::createFunctionAt(RVA addr) { - QString ret = cmdRaw(QString("af %1").arg(addr)); - emit functionsChanged(); - return ret; + createFunctionAt(addr, ""); } -QString CutterCore::createFunctionAt(RVA addr, QString name) +void CutterCore::createFunctionAt(RVA addr, QString name) { - static const QRegularExpression regExp("[^a-zA-Z0-9_.]"); - name.remove(regExp); - QString ret = cmdRawAt(QString("af %1").arg(name), addr); + if (!name.isEmpty() && !name.isNull()) { + static const QRegularExpression regExp("[^a-zA-Z0-9_.]"); + name.remove(regExp); + } + + CORE_LOCK(); + bool analyze_recursively = rz_config_get_i(core->config, "analysis.calls"); + rz_core_analysis_function_add(core, name.toStdString().c_str(), addr, analyze_recursively); emit functionsChanged(); - return ret; } QJsonDocument CutterCore::getRegistersInfo() @@ -3118,45 +3140,37 @@ QList CutterCore::parseStringsJson(const QJsonDocument &doc) QList CutterCore::getAllFlagspaces() { CORE_LOCK(); - QList ret; - - QJsonArray flagspacesArray = cmdj("fsj").array(); - for (const QJsonValue &value : flagspacesArray) { - QJsonObject flagspaceObject = value.toObject(); - + QList flagspaces; + RzSpaceIter it; + RzSpace *space; + rz_flag_space_foreach(core->flags, it, space) + { FlagspaceDescription flagspace; - - flagspace.name = flagspaceObject[RJsonKey::name].toString(); - - ret << flagspace; + flagspace.name = space->name; + flagspaces << flagspace; } - return ret; + return flagspaces; } QList CutterCore::getAllFlags(QString flagspace) { CORE_LOCK(); - QList ret; - - if (!flagspace.isEmpty()) - cmdRaw("fs " + flagspace); - else - cmdRaw("fs *"); - - QJsonArray flagsArray = cmdj("fj").array(); - for (const QJsonValue &value : flagsArray) { - QJsonObject flagObject = value.toObject(); - - FlagDescription flag; - - flag.offset = flagObject[RJsonKey::offset].toVariant().toULongLong(); - flag.size = flagObject[RJsonKey::size].toVariant().toULongLong(); - flag.name = flagObject[RJsonKey::name].toString(); - flag.realname = flagObject[RJsonKey::realname].toString(); - - ret << flag; - } - return ret; + QList flags; + std::string name = flagspace.isEmpty() || flagspace.isNull() ? "*" : flagspace.toStdString(); + RzSpace *space = rz_flag_space_get(core->flags, name.c_str()); + rz_flag_foreach_space( + core->flags, space, + [](RzFlagItem *item, void *user) { + FlagDescription flag; + flag.offset = item->offset; + flag.size = item->size; + flag.name = item->name; + flag.realname = item->name; + reinterpret_cast *>(user)->append(flag); + return true; + }, + &flags); + return flags; } QList CutterCore::getAllSections() @@ -3856,7 +3870,8 @@ QList CutterCore::getXRefs(RVA addr, bool to, bool whole_functi void CutterCore::addFlag(RVA offset, QString name, RVA size) { name = sanitizeStringForCommand(name); - cmdRawAt(QString("f %1 %2").arg(name).arg(size), offset); + CORE_LOCK(); + rz_flag_set(core->flags, name.toStdString().c_str(), offset, size); emit flagsChanged(); } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 8671b73a..d8b7a0a1 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -198,8 +198,8 @@ public: RVA getLastFunctionInstruction(RVA addr); QString cmdFunctionAt(QString addr); QString cmdFunctionAt(RVA addr); - QString createFunctionAt(RVA addr); - QString createFunctionAt(RVA addr, QString name); + void createFunctionAt(RVA addr); + void createFunctionAt(RVA addr, QString name); QStringList getDisassemblyPreview(RVA address, int num_of_lines); /* Flags */ @@ -242,6 +242,13 @@ public: * \param addr The address of the array where the string will be applied */ void removeString(RVA addr); + /** + * @brief Gets string at address + * That function correspond the 'Cs.' command + * \param addr The address of the string + * @return string at requested address + */ + QString getMetaString(RVA addr); /** * @brief Gets string at address * That function calls the 'ps' command diff --git a/src/dialogs/EditVariablesDialog.cpp b/src/dialogs/EditVariablesDialog.cpp index 5525048f..6954814a 100644 --- a/src/dialogs/EditVariablesDialog.cpp +++ b/src/dialogs/EditVariablesDialog.cpp @@ -73,7 +73,7 @@ void EditVariablesDialog::applyFields() if (!v_type || error_msg) { return; } - rz_analysis_var_set_type(v, v_type); + rz_analysis_var_set_type(v, v_type, true); // TODO Remove all those replace once rizin command parser is fixed QString newName = ui->nameEdit->text() diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 420d15bc..2c7b8ba8 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -533,7 +533,7 @@ void DisassemblyContextMenu::aboutToShowSlot() actionAnalyzeFunction.setVisible(true); // Show the option to remove a defined string only if a string is defined in this address - QString stringDefinition = Core()->cmdRawAt("Cs.", offset); + QString stringDefinition = Core()->getMetaString(offset); actionSetAsStringRemove.setVisible(!stringDefinition.isEmpty()); QString comment = Core()->getCommentAt(offset); diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index 760a7487..c494e5a0 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -599,10 +599,9 @@ void FunctionsWidget::onActionFunctionsRenameTriggered() void FunctionsWidget::onActionFunctionsUndefineTriggered() { const auto selection = ui->treeView->selectionModel()->selection().indexes(); - std::vector offsets; - offsets.reserve(selection.size()); + QSet offsets; for (const auto &index : selection) { - offsets.push_back(functionProxyModel->address(index)); + offsets.insert(functionProxyModel->address(index)); } for (RVA offset : offsets) { Core()->delFunction(offset); From f7e6f9466d38f8170a6348ae37302ba688d42b7e Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sat, 5 Feb 2022 08:51:36 +0200 Subject: [PATCH 14/94] Enable console redirection on Windows without starting from a console (#2888) --- src/Main.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index 89101b11..b0cef4a0 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -12,15 +12,11 @@ /** * @brief Attempt to connect to a parent console and configure outputs. - * - * @note Doesn't do anything if the exe wasn't executed from a console. */ #ifdef Q_OS_WIN static void connectToConsole() { - if (!AttachConsole(ATTACH_PARENT_PROCESS)) { - return; - } + BOOL attached = AttachConsole(ATTACH_PARENT_PROCESS); // Avoid reconfiguring stdin/stderr/stdout if one of them is already connected to a stream. // This can happen when running with stdout/stderr redirected to a file. @@ -32,12 +28,12 @@ static void connectToConsole() // _open() after startup. _close(0); - freopen("CONIN$", "r+", stdin); + freopen(attached ? "CONIN$" : "NUL", "r+", stdin); } if (0 > fileno(stdout)) { _close(1); - if (freopen("CONOUT$", "a+", stdout)) { + if (freopen(attached ? "CONOUT$" : "NUL", "a+", stdout)) { // Avoid buffering stdout/stderr since IOLBF is replaced by IOFBF in Win32. setvbuf(stdout, nullptr, _IONBF, 0); } @@ -45,7 +41,7 @@ static void connectToConsole() if (0 > fileno(stderr)) { _close(2); - if (freopen("CONOUT$", "a+", stderr)) { + if (freopen(attached ? "CONOUT$" : "NUL", "a+", stderr)) { setvbuf(stderr, nullptr, _IONBF, 0); } } From 22cb8e7594415d18bbcfcd74a3ad23ee327cfdd6 Mon Sep 17 00:00:00 2001 From: Petros S Date: Sat, 5 Feb 2022 08:55:10 +0200 Subject: [PATCH 15/94] Move more common disassembly-previewing functionality to namaspace (#2849) --- src/common/DisassemblyPreview.cpp | 15 +++++-- src/common/DisassemblyPreview.h | 7 +++ src/widgets/DisassemblerGraphView.cpp | 10 ----- src/widgets/DisassemblerGraphView.h | 1 - src/widgets/DisassemblyWidget.cpp | 64 ++++----------------------- src/widgets/DisassemblyWidget.h | 1 - src/widgets/FunctionsWidget.cpp | 8 +--- 7 files changed, 28 insertions(+), 78 deletions(-) diff --git a/src/common/DisassemblyPreview.cpp b/src/common/DisassemblyPreview.cpp index df6fb58b..e80e6eaa 100644 --- a/src/common/DisassemblyPreview.cpp +++ b/src/common/DisassemblyPreview.cpp @@ -35,9 +35,6 @@ QString DisassemblyPreview::getToolTipStyleSheet() bool DisassemblyPreview::showDisasPreview(QWidget *parent, const QPoint &pointOfEvent, const RVA offsetFrom) { - QProcessEnvironment env; - QPoint point = pointOfEvent; - QList refs = Core()->getXRefs(offsetFrom, false, false); if (refs.length()) { if (refs.length() > 1) { @@ -75,10 +72,20 @@ bool DisassemblyPreview::showDisasPreview(QWidget *parent, const QPoint &pointOf .arg(qMax(8, fnt.pointSize() - 1)) .arg(disasmPreview.join("
")); - QToolTip::showText(point, tooltip, parent, QRect {}, 3500); + QToolTip::showText(pointOfEvent, tooltip, parent, QRect {}, 3500); return true; } } } return false; } + +RVA DisassemblyPreview::readDisassemblyOffset(QTextCursor tc) +{ + auto userData = getUserData(tc.block()); + if (!userData) { + return RVA_INVALID; + } + + return userData->line.offset; +} diff --git a/src/common/DisassemblyPreview.h b/src/common/DisassemblyPreview.h index 656b818e..81e67ee8 100644 --- a/src/common/DisassemblyPreview.h +++ b/src/common/DisassemblyPreview.h @@ -31,8 +31,15 @@ QString getToolTipStyleSheet(); /*! * @brief Show a QToolTip that previews the disassembly that is pointed to + * It works for GraphWidget and DisassemblyWidget * @return True if the tooltip is shown */ bool showDisasPreview(QWidget *parent, const QPoint &pointOfEvent, const RVA offsetFrom); + +/*! + * @brief Reads the offset for the cursor position + * @return The disassembly offset of the hovered asm text + */ +RVA readDisassemblyOffset(QTextCursor tc); } #endif diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 7f434ff6..e4bb05b8 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -997,13 +997,3 @@ bool DisassemblerGraphView::Instr::contains(ut64 addr) const { return this->addr <= addr && (addr - this->addr) < size; } - -RVA DisassemblerGraphView::readDisassemblyOffset(QTextCursor tc) -{ - auto userData = getUserData(tc.block()); - if (!userData) { - return RVA_INVALID; - } - - return userData->line.offset; -} diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index 07bfc9ed..c5f10bb1 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -178,7 +178,6 @@ private: DisassemblyBlock *blockForAddress(RVA addr); void seekLocal(RVA addr, bool update_viewport = true); void seekInstruction(bool previous_instr); - RVA readDisassemblyOffset(QTextCursor tc); CutterSeekable *seekable = nullptr; QList shortcuts; diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 97c83e64..be8c9bc9 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -371,7 +371,7 @@ void DisassemblyWidget::highlightCurrentLine() highlightSelection.cursor = cursor; highlightSelection.cursor.movePosition(QTextCursor::Start); while (true) { - RVA lineOffset = readDisassemblyOffset(highlightSelection.cursor); + RVA lineOffset = DisassemblyPreview::readDisassemblyOffset(highlightSelection.cursor); if (lineOffset == seekable->getOffset()) { highlightSelection.format.setBackground(highlightColor); highlightSelection.format.setProperty(QTextFormat::FullWidthSelection, true); @@ -406,7 +406,7 @@ void DisassemblyWidget::highlightPCLine() highlightSelection.cursor.movePosition(QTextCursor::Start); if (PCAddr != RVA_INVALID) { while (true) { - RVA lineOffset = readDisassemblyOffset(highlightSelection.cursor); + RVA lineOffset = DisassemblyPreview::readDisassemblyOffset(highlightSelection.cursor); if (lineOffset == PCAddr) { highlightSelection.format.setBackground(highlightPCColor); highlightSelection.format.setProperty(QTextFormat::FullWidthSelection, true); @@ -439,17 +439,7 @@ void DisassemblyWidget::showDisasContextMenu(const QPoint &pt) RVA DisassemblyWidget::readCurrentDisassemblyOffset() { QTextCursor tc = mDisasTextEdit->textCursor(); - return readDisassemblyOffset(tc); -} - -RVA DisassemblyWidget::readDisassemblyOffset(QTextCursor tc) -{ - auto userData = getUserData(tc.block()); - if (!userData) { - return RVA_INVALID; - } - - return userData->line.offset; + return DisassemblyPreview::readDisassemblyOffset(tc); } void DisassemblyWidget::updateCursorPosition() @@ -476,7 +466,7 @@ void DisassemblyWidget::updateCursorPosition() cursor.movePosition(QTextCursor::Start); while (true) { - RVA lineOffset = readDisassemblyOffset(cursor); + RVA lineOffset = DisassemblyPreview::readDisassemblyOffset(cursor); if (lineOffset == offset) { if (cursorLineOffset > 0) { cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, @@ -537,7 +527,7 @@ void DisassemblyWidget::cursorPositionChanged() cursorCharOffset = c.positionInBlock(); while (c.blockNumber() > 0) { c.movePosition(QTextCursor::PreviousBlock); - if (readDisassemblyOffset(c) != offset) { + if (DisassemblyPreview::readDisassemblyOffset(c) != offset) { break; } cursorLineOffset++; @@ -623,7 +613,7 @@ void DisassemblyWidget::moveCursorRelative(bool up, bool page) void DisassemblyWidget::jumpToOffsetUnderCursor(const QTextCursor &cursor) { - RVA offset = readDisassemblyOffset(cursor); + RVA offset = DisassemblyPreview::readDisassemblyOffset(cursor); seekable->seekToReference(offset); } @@ -645,47 +635,9 @@ bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event) auto cursorForWord = mDisasTextEdit->cursorForPosition(helpEvent->pos()); cursorForWord.select(QTextCursor::WordUnderCursor); - RVA offsetFrom = readDisassemblyOffset(cursorForWord); - RVA offsetTo = RVA_INVALID; + RVA offsetFrom = DisassemblyPreview::readDisassemblyOffset(cursorForWord); - QList refs = Core()->getXRefs(offsetFrom, false, false); - - if (refs.length()) { - if (refs.length() > 1) { - qWarning() << tr("More than one (%1) references here. Weird behaviour expected.") - .arg(refs.length()); - } - offsetTo = refs.at(0).to; // This is the offset we want to preview - - if (Q_UNLIKELY(offsetFrom != refs.at(0).from)) { - qWarning() << tr("offsetFrom (%1) differs from refs.at(0).from (%(2))") - .arg(offsetFrom) - .arg(refs.at(0).from); - } - - // Only if the offset we point *to* is different from the one the cursor is currently - // on *and* the former is a valid offset, we are allowed to get a preview of offsetTo - if (offsetTo != offsetFrom && offsetTo != RVA_INVALID) { - QStringList disasmPreview = Core()->getDisassemblyPreview(offsetTo, 10); - - // Last check to make sure the returned preview isn't an empty text (QStringList) - if (!disasmPreview.isEmpty()) { - const QFont &fnt = Config()->getFont(); - QFontMetrics fm { fnt }; - - QString tooltip = - QString("
Disassembly Preview:
%3
") - .arg(fnt.family()) - .arg(qMax(6, fnt.pointSize() - 1)) - .arg(disasmPreview.join("
")); - QToolTip::showText(helpEvent->globalPos(), tooltip, this, QRect(), 3500); - } - } - } - - return true; + return DisassemblyPreview::showDisasPreview(this, helpEvent->globalPos(), offsetFrom); } return MemoryDockWidget::eventFilter(obj, event); diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 7657401d..1ab16216 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -83,7 +83,6 @@ private: RefreshDeferrer *disasmRefresh; RVA readCurrentDisassemblyOffset(); - RVA readDisassemblyOffset(QTextCursor tc); bool eventFilter(QObject *obj, QEvent *event) override; void keyPressEvent(QKeyEvent *event) override; QString getWindowTitle() const override; diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index c494e5a0..47c93aed 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -2,6 +2,7 @@ #include "ui_ListDockWidget.h" #include "core/MainWindow.h" +#include "common/DisassemblyPreview.h" #include "common/Helpers.h" #include "common/FunctionsTask.h" #include "common/TempConfig.h" @@ -634,10 +635,5 @@ void FunctionsWidget::onActionVerticalToggled(bool enable) */ void FunctionsWidget::setTooltipStylesheet() { - setStyleSheet(QString("QToolTip { border-width: 1px; max-width: %1px;" - "opacity: 230; background-color: %2;" - "color: %3; border-color: %3;}") - .arg(kMaxTooltipWidth) - .arg(Config()->getColor("gui.tooltip.background").name()) - .arg(Config()->getColor("gui.tooltip.foreground").name())); + setStyleSheet(DisassemblyPreview::getToolTipStyleSheet()); } From cff49fa2a2ad78cbd8b2d32d0b60c6424f3f3e95 Mon Sep 17 00:00:00 2001 From: Theofilos Pechlivanis <49034471+theopechli@users.noreply.github.com> Date: Sat, 5 Feb 2022 09:00:08 +0200 Subject: [PATCH 16/94] Save and load the layout of the Functions widget (#2844) --- src/common/Configuration.cpp | 46 +++++++++++++++++++++------------ src/common/Configuration.h | 13 ++++++++++ src/widgets/FunctionsWidget.cpp | 8 +++++- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 87a97b92..cc8690b4 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -21,17 +21,16 @@ * and for light - only light ones. */ const QHash Configuration::relevantThemes = { - { "ayu", DarkFlag }, { "basic", DarkFlag }, { "behelit", DarkFlag }, - { "bold", DarkFlag }, { "bright", DarkFlag }, { "consonance", DarkFlag }, - { "darkda", DarkFlag }, { "defragger", DarkFlag }, { "focus", DarkFlag }, - { "gentoo", DarkFlag }, { "lima", DarkFlag }, { "monokai", DarkFlag }, - { "ogray", DarkFlag }, { "onedark", DarkFlag }, { "pink", DarkFlag }, - { "rasta", DarkFlag }, { "sepia", DarkFlag }, { "smyck", DarkFlag }, - { "solarized", DarkFlag }, { "twilight", DarkFlag }, { "white2", DarkFlag }, - { "xvilka", DarkFlag }, { "zenburn", DarkFlag }, - { "cga", LightFlag }, { "cutter", LightFlag }, { "dark", LightFlag }, - { "gb", LightFlag }, { "matrix", LightFlag }, { "tango", LightFlag }, - { "white", LightFlag } + { "ayu", DarkFlag }, { "basic", DarkFlag }, { "behelit", DarkFlag }, + { "bold", DarkFlag }, { "bright", DarkFlag }, { "consonance", DarkFlag }, + { "darkda", DarkFlag }, { "defragger", DarkFlag }, { "focus", DarkFlag }, + { "gentoo", DarkFlag }, { "lima", DarkFlag }, { "monokai", DarkFlag }, + { "ogray", DarkFlag }, { "onedark", DarkFlag }, { "pink", DarkFlag }, + { "rasta", DarkFlag }, { "sepia", DarkFlag }, { "smyck", DarkFlag }, + { "solarized", DarkFlag }, { "twilight", DarkFlag }, { "white2", DarkFlag }, + { "xvilka", DarkFlag }, { "zenburn", DarkFlag }, { "cga", LightFlag }, + { "cutter", LightFlag }, { "dark", LightFlag }, { "gb", LightFlag }, + { "matrix", LightFlag }, { "tango", LightFlag }, { "white", LightFlag } }; static const QString DEFAULT_LIGHT_COLOR_THEME = "cutter"; static const QString DEFAULT_DARK_COLOR_THEME = "ayu"; @@ -251,8 +250,8 @@ bool Configuration::setLocaleByName(const QString &language) QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); for (auto &it : allLocales) { - if (QString::compare(it.nativeLanguageName(), language, Qt::CaseInsensitive) == 0 || - it.name() == language) { + if (QString::compare(it.nativeLanguageName(), language, Qt::CaseInsensitive) == 0 + || it.name() == language) { setLocale(it); return true; } @@ -289,7 +288,8 @@ void Configuration::loadNativeStylesheet() QTextStream ts(&f); QString stylesheet = ts.readAll(); #ifdef Q_OS_MACOS - QFile mf(nativeWindowIsDark() ? ":native/native-macos-dark.qss" : ":native/native-macos-light.qss"); + QFile mf(nativeWindowIsDark() ? ":native/native-macos-dark.qss" + : ":native/native-macos-light.qss"); if (mf.exists()) { mf.open(QFile::ReadOnly | QFile::Text); QTextStream mts(&mf); @@ -667,11 +667,13 @@ QStringList Configuration::getAvailableTranslations() for (auto i : fileNames) { QString localeName = i.mid(sizeof("cutter_") - 1, 2); // TODO:#2321 don't asume 2 characters - // language code is sometimes 3 characters, and there could also be language_COUNTRY. Qt supports that. + // language code is sometimes 3 characters, and there could also be language_COUNTRY. Qt + // supports that. QLocale locale(localeName); if (locale.language() != QLocale::C) { currLanguageName = locale.nativeLanguageName(); - if (currLanguageName.isEmpty()) { // Qt doesn't have native language name for some languages + if (currLanguageName + .isEmpty()) { // Qt doesn't have native language name for some languages currLanguageName = QLocale::languageToString(locale.language()); } if (!currLanguageName.isEmpty()) { @@ -774,7 +776,7 @@ bool Configuration::getOutputRedirectionEnabled() const return outputRedirectEnabled; } -void Configuration::setPreviewValue( bool checked ) +void Configuration::setPreviewValue(bool checked) { s.setValue("asm.preview", checked); } @@ -821,3 +823,13 @@ void Configuration::addRecentProject(QString file) files.prepend(file); setRecentProjects(files); } + +QString Configuration::getFunctionsWidgetLayout() +{ + return s.value("functionsWidgetLayout").toString(); +} + +void Configuration::setFunctionsWidgetLayout(const QString &layout) +{ + s.setValue("functionsWidgetLayout", layout); +} diff --git a/src/common/Configuration.h b/src/common/Configuration.h index 3343e271..b6324705 100644 --- a/src/common/Configuration.h +++ b/src/common/Configuration.h @@ -228,6 +228,19 @@ public: void setRecentProjects(const QStringList &list); void addRecentProject(QString file); + // Functions Widget Layout + + /** + * @brief Get the layout of the Functions widget. + * @return The layout. + */ + QString getFunctionsWidgetLayout(); + + /** + * @brief Set the layout of the Functions widget + * @param layout The layout of the Functions widget, either horizontal or vertical. + */ + void setFunctionsWidgetLayout(const QString &layout); public slots: void refreshFont(); signals: diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index 47c93aed..f77bae3d 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -526,7 +526,11 @@ FunctionsWidget::FunctionsWidget(MainWindow *main) addActions(itemConextMenu->actions()); // Use a custom context menu on the dock title bar - actionHorizontal.setChecked(true); + if (Config()->getFunctionsWidgetLayout() == "horizontal") { + actionHorizontal.setChecked(true); + } else { + actionVertical.setChecked(true); + } this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &QWidget::customContextMenuRequested, this, &FunctionsWidget::showTitleContextMenu); @@ -617,6 +621,7 @@ void FunctionsWidget::showTitleContextMenu(const QPoint &pt) void FunctionsWidget::onActionHorizontalToggled(bool enable) { if (enable) { + Config()->setFunctionsWidgetLayout("horizontal"); functionModel->setNested(false); ui->treeView->setIndentation(8); } @@ -625,6 +630,7 @@ void FunctionsWidget::onActionHorizontalToggled(bool enable) void FunctionsWidget::onActionVerticalToggled(bool enable) { if (enable) { + Config()->setFunctionsWidgetLayout("vertical"); functionModel->setNested(true); ui->treeView->setIndentation(20); } From a4bc803eea7eb05fb150e5ff80ef761982b18d5d Mon Sep 17 00:00:00 2001 From: Yossi Zap Date: Tue, 8 Feb 2022 23:22:55 +0200 Subject: [PATCH 17/94] Add missing rz_demangler.dll to windows packaging --- cmake/BundledRizin.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index ba6813e3..10f582b4 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -48,7 +48,8 @@ endif() 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_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-agent rz-bin rizin rz-diff rz-find rz-gg rz-hash rz-run rz-asm rz-ax) From c95a5d59a5c4043f711bdbc2c80a09ad4f30ad71 Mon Sep 17 00:00:00 2001 From: Yossi Zap Date: Wed, 9 Feb 2022 16:04:04 +0200 Subject: [PATCH 18/94] Bypass meson Popen_safe_legacy() error --- .github/workflows/ccpp.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index e567c6b9..39b07cbe 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -70,6 +70,7 @@ jobs: brew install pkg-config - name: py dependencies run: | + python3 -m pip install -U pip==21.3.1 pip install meson - name: Prepare package id shell: bash From ddaa02c0f838da7bf843585aa5df7a6666f326db Mon Sep 17 00:00:00 2001 From: yossizap Date: Sat, 19 Feb 2022 15:34:08 +0000 Subject: [PATCH 19/94] Remove additional 0x prefix in the registers widget (#2896) --- src/widgets/RegistersWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/RegistersWidget.cpp b/src/widgets/RegistersWidget.cpp index b6354fd3..ad9482e1 100644 --- a/src/widgets/RegistersWidget.cpp +++ b/src/widgets/RegistersWidget.cpp @@ -51,7 +51,7 @@ void RegistersWidget::setRegisterGrid() registerLen = registerRefs.size(); for (auto ® : registerRefs) { - regValue = "0x" + reg.value; + regValue = reg.value; // check if we already filled this grid space with label/value if (!registerLayout->itemAtPosition(i, col)) { registerLabel = new QLabel; From 518014ee195b346481663a77e4069f2dc120395e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 14 Mar 2022 17:04:49 +0900 Subject: [PATCH 20/94] Use rizin instead of Qt to parse JSON (#2902) Qt truncates integers to 52-bit, corrupting e.g. memory addresses. Use rizin's JSON parser, which can parse integers whose size is up to 64 bits. --- .../code/development-guidelines.rst | 2 +- src/CMakeLists.txt | 2 + src/common/BugReporting.cpp | 10 +- src/common/ColorThemeWorker.cpp | 31 +- src/common/ColorThemeWorker.h | 1 + src/common/Decompiler.cpp | 21 +- src/common/IOModesController.cpp | 5 +- src/common/RizinTask.cpp | 8 +- src/common/RizinTask.h | 2 +- src/common/SettingsUpgrade.cpp | 2 +- src/core/Cutter.cpp | 519 +++++++----------- src/core/Cutter.h | 64 ++- src/core/CutterJson.cpp | 28 + src/core/CutterJson.h | 119 ++++ src/dialogs/VersionInfoDialog.cpp | 61 +- src/menus/DisassemblyContextMenu.cpp | 45 +- src/widgets/BacktraceWidget.cpp | 10 +- src/widgets/CallGraph.cpp | 10 +- src/widgets/ColorThemeListView.h | 1 + src/widgets/Dashboard.cpp | 45 +- src/widgets/Dashboard.h | 3 +- src/widgets/DisassemblerGraphView.cpp | 54 +- src/widgets/FunctionsWidget.cpp | 2 +- src/widgets/ProcessesWidget.cpp | 15 +- src/widgets/RegisterRefsWidget.cpp | 9 +- src/widgets/RizinGraphWidget.cpp | 13 +- src/widgets/StackWidget.cpp | 10 +- src/widgets/ThreadsWidget.cpp | 11 +- 28 files changed, 575 insertions(+), 528 deletions(-) create mode 100644 src/core/CutterJson.cpp create mode 100644 src/core/CutterJson.h diff --git a/docs/source/contributing/code/development-guidelines.rst b/docs/source/contributing/code/development-guidelines.rst index 948d134f..25560bfe 100644 --- a/docs/source/contributing/code/development-guidelines.rst +++ b/docs/source/contributing/code/development-guidelines.rst @@ -47,7 +47,7 @@ Example: .. code:: cpp - QJsonArray array = Core()->cmdj("pdj 1 @ main").array(); + CutterJson array = Core()->cmdj("pdj 1 @ main"); Seek the Current File ~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb556529..4601cb96 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CutterConfig.h.in" set(SOURCES Main.cpp core/Cutter.cpp + core/CutterJson.cpp dialogs/EditStringDialog.cpp dialogs/WriteCommandsDialogs.cpp widgets/DisassemblerGraphView.cpp @@ -153,6 +154,7 @@ set(HEADER_FILES core/Cutter.h core/CutterCommon.h core/CutterDescriptions.h + core/CutterJson.h dialogs/EditStringDialog.h dialogs/WriteCommandsDialogs.h widgets/DisassemblerGraphView.h diff --git a/src/common/BugReporting.cpp b/src/common/BugReporting.cpp index f2242900..7d5ec919 100644 --- a/src/common/BugReporting.cpp +++ b/src/common/BugReporting.cpp @@ -12,13 +12,13 @@ void openIssue() // Pull in info needed for git issue osInfo = QSysInfo::productType() + " " + (QSysInfo::productVersion() == "unknown" ? "" : QSysInfo::productVersion()); - QJsonDocument docu = Core()->getFileInfo(); - QJsonObject coreObj = docu.object()["core"].toObject(); - QJsonObject binObj = docu.object()["bin"].toObject(); - if (!binObj.QJsonObject::isEmpty()) { + CutterJson docu = Core()->getFileInfo(); + CutterJson coreObj = docu["core"]; + CutterJson binObj = docu["bin"]; + if (binObj.size()) { format = coreObj["format"].toString(); arch = binObj["arch"].toString(); - if (!binObj["type"].isUndefined()) { + if (binObj["type"].valid()) { type = coreObj["type"].toString(); } else { type = "N/A"; diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index a7ca2bc8..aabc0c1f 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -128,22 +128,34 @@ bool ColorThemeWorker::isThemeExist(const QString &name) const QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const { int r, g, b, a; + CutterJson rzTheme; QVariantMap theme; QString curr = Config()->getColorTheme(); if (themeName != curr) { RzCoreLocked core(Core()); rz_core_theme_load(core, themeName.toUtf8().constData()); - theme = Core()->cmdj("ecj").object().toVariantMap(); + rzTheme = Core()->cmdj("ecj"); rz_core_theme_load(core, curr.toUtf8().constData()); } else { - theme = Core()->cmdj("ecj").object().toVariantMap(); + rzTheme = Core()->cmdj("ecj"); } - for (auto it = theme.begin(); it != theme.end(); it++) { - auto arr = it.value().toList(); - QColor(arr[0].toInt(), arr[1].toInt(), arr[2].toInt()).getRgb(&r, &g, &b, &a); - theme[it.key()] = QJsonArray({ r, g, b, a }); + for (CutterJson value : rzTheme) { + QJsonArray arr; + int count = 0; + for (CutterJson element : value) { + arr.append(element.toSt64()); + count++; + if (count >= 3) { + break; + } + } + while (count < 3) { + arr.append(0); + } + arr.append(255); + theme[value.key()] = arr; } ColorFlags colorFlags = ColorFlags::DarkFlag; @@ -278,9 +290,8 @@ bool ColorThemeWorker::isFileTheme(const QString &filePath, bool *ok) const } const QString colors = "black|red|white|green|magenta|yellow|cyan|blue|gray|none"; - QString options = (Core()->cmdj("ecj").object().keys() << cutterSpecificOptions) - .join('|') - .replace(".", "\\."); + QString options = + (Core()->cmdj("ecj").keys() << cutterSpecificOptions).join('|').replace(".", "\\."); QString pattern = QString("((ec\\s+(%1)\\s+(((rgb:|#)[0-9a-fA-F]{3,8})|(%2))))\\s*") .arg(options) @@ -315,7 +326,7 @@ QStringList ColorThemeWorker::customThemes() const const QStringList &ColorThemeWorker::getRizinSpecificOptions() { if (rizinSpecificOptions.isEmpty()) { - rizinSpecificOptions = Core()->cmdj("ecj").object().keys(); + rizinSpecificOptions = Core()->cmdj("ecj").keys(); } return rizinSpecificOptions; } diff --git a/src/common/ColorThemeWorker.h b/src/common/ColorThemeWorker.h index 7c228804..3d67826f 100644 --- a/src/common/ColorThemeWorker.h +++ b/src/common/ColorThemeWorker.h @@ -5,6 +5,7 @@ #include #include #include "Cutter.h" +#include #include #define ThemeWorker() (ColorThemeWorker::instance()) diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index 569a7d68..94892075 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -33,40 +33,37 @@ void JSDecDecompiler::decompileAt(RVA addr) } task = new RizinCmdTask("pddj @ " + QString::number(addr)); connect(task, &RizinCmdTask::finished, this, [this]() { - QJsonObject json = task->getResultJson().object(); + CutterJson json = task->getResultJson(); delete task; task = nullptr; - if (json.isEmpty()) { + if (!json.size()) { emit finished(Decompiler::makeWarning(tr("Failed to parse JSON from jsdec"))); return; } RzAnnotatedCode *code = rz_annotated_code_new(nullptr); QString codeString = ""; - for (const auto &line : json["log"].toArray()) { - if (!line.isString()) { + for (auto line : json["log"]) { + if (line.type() != RZ_JSON_STRING) { continue; } codeString.append(line.toString() + "\n"); } - auto linesArray = json["lines"].toArray(); - for (const auto &line : linesArray) { - QJsonObject lineObject = line.toObject(); - if (lineObject.isEmpty()) { + for (auto lineObject : json["lines"]) { + if (!lineObject.size()) { continue; } RzCodeAnnotation annotationi = {}; annotationi.start = codeString.length(); codeString.append(lineObject["str"].toString() + "\n"); annotationi.end = codeString.length(); - bool ok; annotationi.type = RZ_CODE_ANNOTATION_TYPE_OFFSET; - annotationi.offset.offset = lineObject["offset"].toVariant().toULongLong(&ok); + annotationi.offset.offset = lineObject["offset"].toUt64(); rz_annotated_code_add_annotation(code, &annotationi); } - for (const auto &line : json["errors"].toArray()) { - if (!line.isString()) { + for (auto line : json["errors"]) { + if (line.type() != RZ_JSON_STRING) { continue; } codeString.append(line.toString() + "\n"); diff --git a/src/common/IOModesController.cpp b/src/common/IOModesController.cpp index e7a11aaf..4fa29502 100644 --- a/src/common/IOModesController.cpp +++ b/src/common/IOModesController.cpp @@ -78,11 +78,10 @@ bool IOModesController::prepareForWriting() bool IOModesController::allChangesComitted() { // Get a list of available write changes - QJsonArray changes = Core()->cmdj("wcj").array(); + CutterJson changes = Core()->cmdj("wcj"); // Check if there is a change which isn't written to the file - for (const QJsonValue &value : changes) { - QJsonObject changeObject = value.toObject(); + for (CutterJson changeObject : changes) { if (!changeObject["written"].toBool()) { return false; } diff --git a/src/common/RizinTask.cpp b/src/common/RizinTask.cpp index 48cb0901..14433585 100644 --- a/src/common/RizinTask.cpp +++ b/src/common/RizinTask.cpp @@ -54,13 +54,15 @@ QString RizinCmdTask::getResult() return QString::fromUtf8(res); } -QJsonDocument RizinCmdTask::getResultJson() +CutterJson RizinCmdTask::getResultJson() { const char *res = rz_core_cmd_task_get_result(task); if (!res) { - return QJsonDocument(); + return CutterJson(); } - return Core()->parseJson(res, nullptr); + char *copy = static_cast(rz_mem_alloc(strlen(res) + 1)); + strcpy(copy, res); + return Core()->parseJson(copy, nullptr); } const char *RizinCmdTask::getResultRaw() diff --git a/src/common/RizinTask.h b/src/common/RizinTask.h index e07e1fb3..e0972bc4 100644 --- a/src/common/RizinTask.h +++ b/src/common/RizinTask.h @@ -38,7 +38,7 @@ public: explicit RizinCmdTask(const QString &cmd, bool transient = true); QString getResult(); - QJsonDocument getResultJson(); + CutterJson getResultJson(); const char *getResultRaw(); }; diff --git a/src/common/SettingsUpgrade.cpp b/src/common/SettingsUpgrade.cpp index 9ff48999..4ef57e59 100644 --- a/src/common/SettingsUpgrade.cpp +++ b/src/common/SettingsUpgrade.cpp @@ -181,7 +181,7 @@ void Cutter::initializeSettings() static void removeObsoleteOptionsFromCustomThemes() { - const QStringList options = Core()->cmdj("ecj").object().keys() + const QStringList options = Core()->cmdj("ecj").keys() << ColorThemeWorker::cutterSpecificOptions; RzList *themes_list = rz_core_theme_list(Core()->core()); RzListIter *th_iter; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 21a07c57..bb0b661a 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -481,7 +481,7 @@ QString CutterCore::cmdRaw(const char *cmd) return res; } -QJsonDocument CutterCore::cmdj(const char *str) +CutterJson CutterCore::cmdj(const char *str) { char *res; { @@ -489,15 +489,12 @@ QJsonDocument CutterCore::cmdj(const char *str) res = rz_core_cmd_str(core, str); } - QJsonDocument doc = parseJson(res, str); - rz_mem_free(res); - - return doc; + return parseJson(res, str); } -QJsonDocument CutterCore::cmdjAt(const char *str, RVA address) +CutterJson CutterCore::cmdjAt(const char *str, RVA address) { - QJsonDocument res; + CutterJson res; RVA oldOffset = getOffset(); seekSilent(address); @@ -515,49 +512,42 @@ QString CutterCore::cmdTask(const QString &str) return task.getResult(); } -QJsonDocument CutterCore::cmdjTask(const QString &str) +CutterJson CutterCore::cmdjTask(const QString &str) { RizinCmdTask task(str); task.startTask(); task.joinTask(); - return parseJson(task.getResultRaw(), str); + const char *res = task.getResultRaw(); + char *copy = static_cast(rz_mem_alloc(strlen(res) + 1)); + strcpy(copy, res); + return parseJson(copy, str); } -QJsonDocument CutterCore::parseJson(const char *res, const char *cmd) +CutterJson CutterCore::parseJson(char *res, const char *cmd) { - QByteArray json(res); - - if (json.isEmpty()) { - return QJsonDocument(); + if (!res) { + return CutterJson(); } - QJsonParseError jsonError; - QJsonDocument doc = QJsonDocument::fromJson(json, &jsonError); + RzJson *doc = rz_json_parse(res); - if (jsonError.error != QJsonParseError::NoError) { - // don't call trimmed() before knowing that parsing failed to avoid copying huge jsons all - // the time - if (json.trimmed().isEmpty()) { - return doc; - } + if (!doc) { if (cmd) { - eprintf("Failed to parse JSON for command \"%s\": %s\n", cmd, - jsonError.errorString().toLocal8Bit().constData()); + eprintf("Failed to parse JSON for command \"%s\"\n", cmd); } else { - eprintf("Failed to parse JSON: %s\n", - jsonError.errorString().toLocal8Bit().constData()); + eprintf("Failed to parse JSON\n"); } const int MAX_JSON_DUMP_SIZE = 8 * 1024; - if (json.length() > MAX_JSON_DUMP_SIZE) { - int originalSize = json.length(); - json.resize(MAX_JSON_DUMP_SIZE); - eprintf("%d bytes total: %s ...\n", originalSize, json.constData()); + 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", json.constData()); + eprintf("%s\n", res); } } - return doc; + return CutterJson(doc, QSharedPointer::create(doc, res)); } QStringList CutterCore::autocomplete(const QString &cmd, RzLinePromptType promptType, size_t limit) @@ -675,8 +665,7 @@ bool CutterCore::mapFile(QString path, RVA mapaddr) { CORE_LOCK(); RVA addr = mapaddr != RVA_INVALID ? mapaddr : 0; - ut64 baddr = - Core()->getFileInfo().object()["bin"].toObject()["baddr"].toVariant().toULongLong(); + ut64 baddr = Core()->getFileInfo()["bin"]["baddr"].toUt64(); if (rz_core_file_open(core, path.toUtf8().constData(), RZ_PERM_RX, addr)) { rz_core_bin_load(core, path.toUtf8().constData(), baddr); } else { @@ -737,20 +726,12 @@ void CutterCore::delFlag(const QString &name) QString CutterCore::getInstructionBytes(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)) - .array() - .first() - .toObject()[RJsonKey::bytes] - .toString(); + return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::bytes].toString(); } QString CutterCore::getInstructionOpcode(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)) - .array() - .first() - .toObject()[RJsonKey::opcode] - .toString(); + return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::opcode].toString(); } void CutterCore::editInstruction(RVA addr, const QString &inst) @@ -1010,21 +991,19 @@ RVA CutterCore::nextOpAddr(RVA startAddr, int count) { CORE_LOCK(); - QJsonArray array = - Core()->cmdj("pdj " + QString::number(count + 1) + " @ " + QString::number(startAddr)) - .array(); - if (array.isEmpty()) { + CutterJson array = + Core()->cmdj("pdj " + QString::number(count + 1) + " @ " + QString::number(startAddr)); + if (!array.size()) { return startAddr + 1; } - QJsonValue instValue = array.last(); - if (!instValue.isObject()) { + CutterJson instValue = array.last(); + if (instValue.type() != RZ_JSON_OBJECT) { return startAddr + 1; } - bool ok; - RVA offset = instValue.toObject()[RJsonKey::offset].toVariant().toULongLong(&ok); - if (!ok) { + RVA offset = instValue[RJsonKey::offset].toRVA(); + if (offset == RVA_INVALID) { return startAddr + 1; } @@ -1340,27 +1319,14 @@ void CutterCore::createFunctionAt(RVA addr, QString name) emit functionsChanged(); } -QJsonDocument CutterCore::getRegistersInfo() +CutterJson CutterCore::getRegistersInfo() { return cmdj("aeafj"); } RVA CutterCore::getOffsetJump(RVA addr) { - bool ok; - RVA value = cmdj("aoj @" + QString::number(addr)) - .array() - .first() - .toObject() - .value(RJsonKey::jump) - .toVariant() - .toULongLong(&ok); - - if (!ok) { - return RVA_INVALID; - } - - return value; + return cmdj("aoj @" + QString::number(addr)).first().toRVA(); } QList CutterCore::getDecompilers() @@ -1388,17 +1354,17 @@ bool CutterCore::registerDecompiler(Decompiler *decompiler) return true; } -QJsonDocument CutterCore::getFileInfo() +CutterJson CutterCore::getFileInfo() { return cmdj("ij"); } -QJsonDocument CutterCore::getFileVersionInfo() +CutterJson CutterCore::getFileVersionInfo() { return cmdj("iVj"); } -QJsonDocument CutterCore::getSignatureInfo() +CutterJson CutterCore::getSignatureInfo() { return cmdj("iCj"); } @@ -1413,41 +1379,43 @@ static inline const QString appendVar(QString &dst, const QString val, const QSt return val; } -RefDescription CutterCore::formatRefDesc(QJsonObject refItem) +RefDescription CutterCore::formatRefDesc(const AddrRefs &refItem) { RefDescription desc; - // Ignore empty refs and refs that only contain addr - if (refItem.size() <= 1) { + if (refItem.addr == RVA_INVALID) { return desc; } - QString str = refItem["string"].toVariant().toString(); + QString str = refItem.string; if (!str.isEmpty()) { desc.ref = str; desc.refColor = ConfigColor("comment"); } else { + QSharedPointer cursor(&refItem); QString type, string; - do { + while (true) { desc.ref += " ->"; - appendVar(desc.ref, refItem["reg"].toVariant().toString(), " @", ""); - appendVar(desc.ref, refItem["mapname"].toVariant().toString(), " (", ")"); - appendVar(desc.ref, refItem["section"].toVariant().toString(), " (", ")"); - appendVar(desc.ref, refItem["func"].toVariant().toString(), " ", ""); - type = appendVar(desc.ref, refItem["type"].toVariant().toString(), " ", ""); - appendVar(desc.ref, refItem["perms"].toVariant().toString(), " ", ""); - appendVar(desc.ref, refItem["asm"].toVariant().toString(), " \"", "\""); - string = appendVar(desc.ref, refItem["string"].toVariant().toString(), " ", ""); + appendVar(desc.ref, cursor->reg, " @", ""); + appendVar(desc.ref, cursor->mapname, " (", ")"); + appendVar(desc.ref, cursor->section, " (", ")"); + appendVar(desc.ref, cursor->fcn, " ", ""); + type = appendVar(desc.ref, cursor->type, " ", ""); + appendVar(desc.ref, cursor->perms, " ", ""); + appendVar(desc.ref, cursor->asm_op, " \"", "\""); + string = appendVar(desc.ref, cursor->string, " ", ""); if (!string.isNull()) { // There is no point in adding ascii and addr info after a string break; } - if (!refItem["value"].isNull()) { - appendVar(desc.ref, RzAddressString(refItem["value"].toVariant().toULongLong()), - " ", ""); + if (cursor->has_value) { + appendVar(desc.ref, RzAddressString(cursor->value), " ", ""); } - refItem = refItem["ref"].toObject(); - } while (!refItem.empty()); + if (!cursor->ref) { + break; + } + cursor = cursor->ref; + } // Set the ref's color according to the last item type if (type == "ascii" || !string.isEmpty()) { @@ -1464,29 +1432,28 @@ RefDescription CutterCore::formatRefDesc(QJsonObject refItem) return desc; } -QList CutterCore::getRegisterRefs(int depth) +QList CutterCore::getRegisterRefs(int depth) { - QList ret; + QList ret; if (!currentlyDebugging) { return ret; } - QJsonObject registers = cmdj("drj").object(); - - for (const QString &key : registers.keys()) { - QJsonObject reg; - reg["value"] = registers.value(key); - reg["ref"] = getAddrRefs(registers.value(key).toVariant().toULongLong(), depth); - reg["name"] = key; + CutterJson registers = cmdj("drj"); + for (CutterJson value : registers) { + RegisterRef reg; + reg.value = value.toUt64(); + reg.ref = getAddrRefs(reg.value, depth); + reg.name = value.key(); ret.append(reg); } return ret; } -QList CutterCore::getStack(int size, int depth) +QList CutterCore::getStack(int size, int depth) { - QList stack; + QList stack; if (!currentlyDebugging) { return stack; } @@ -1510,11 +1477,12 @@ QList CutterCore::getStack(int size, int depth) return stack; } -QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) +AddrRefs CutterCore::getAddrRefs(RVA addr, int depth) { - QJsonObject json; + AddrRefs refs; if (depth < 1 || addr == UT64_MAX) { - return json; + refs.addr = RVA_INVALID; + return refs; } CORE_LOCK(); @@ -1522,19 +1490,19 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) QByteArray buf = QByteArray(); ut64 type = rz_core_analysis_address(core, addr); - json["addr"] = QString::number(addr); + refs.addr = addr; // Search for the section the addr is in, avoid duplication for heap/stack with type if (!(type & RZ_ANALYSIS_ADDR_TYPE_HEAP || type & RZ_ANALYSIS_ADDR_TYPE_STACK)) { // Attempt to find the address within a map RzDebugMap *map = rz_debug_map_get(core->dbg, addr); if (map && map->name && map->name[0]) { - json["mapname"] = map->name; + refs.mapname = map->name; } RzBinSection *sect = rz_bin_get_section_at(rz_bin_cur_object(core->bin), addr, true); if (sect && sect->name[0]) { - json["section"] = sect->name; + refs.section = sect->name; } } @@ -1543,30 +1511,30 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) if (fi) { RzRegItem *r = rz_reg_get(core->dbg->reg, fi->name, -1); if (r) { - json["reg"] = r->name; + refs.reg = r->name; } } // Attempt to find the address within a function RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, addr, 0); if (fcn) { - json["fcn"] = fcn->name; + refs.fcn = fcn->name; } // Update type and permission information if (type != 0) { if (type & RZ_ANALYSIS_ADDR_TYPE_HEAP) { - json["type"] = "heap"; + refs.type = "heap"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_STACK) { - json["type"] = "stack"; + refs.type = "stack"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_PROGRAM) { - json["type"] = "program"; + refs.type = "program"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_LIBRARY) { - json["type"] = "library"; + refs.type = "library"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_ASCII) { - json["type"] = "ascii"; + refs.type = "ascii"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_SEQUENCE) { - json["type"] = "sequence"; + refs.type = "sequence"; } QString perms = ""; @@ -1584,11 +1552,11 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) rz_io_read_at(core->io, addr, (unsigned char *)buf.data(), buf.size()); rz_asm_set_pc(core->rasm, addr); rz_asm_disassemble(core->rasm, &op, (unsigned char *)buf.data(), buf.size()); - json["asm"] = rz_asm_op_get_asm(&op); + refs.asm_op = rz_asm_op_get_asm(&op); } if (!perms.isEmpty()) { - json["perms"] = perms; + refs.perms = perms; } } @@ -1601,14 +1569,15 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) ut64 n = (bits == 64) ? *n64 : *n32; // The value of the next address will serve as an indication that there's more to // telescope if we have reached the depth limit - json["value"] = QString::number(n); + refs.value = n; + refs.has_value = true; if (depth && n != addr && !(type & RZ_ANALYSIS_ADDR_TYPE_EXEC)) { // Make sure we aren't telescoping the same address - QJsonObject ref = getAddrRefs(n, depth - 1); - if (!ref.empty() && !ref["type"].isNull()) { + AddrRefs ref = getAddrRefs(n, depth - 1); + if (!ref.type.isNull()) { // If the dereference of the current pointer is an ascii character we // might have a string in this address - if (ref["type"].toString().contains("ascii")) { + if (ref.type.contains("ascii")) { buf.resize(128); rz_io_read_at(core->io, addr, (unsigned char *)buf.data(), buf.size()); QString strVal = QString(buf); @@ -1616,16 +1585,16 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) if (strVal.size() == buf.size()) { strVal += "..."; } - json["string"] = strVal; + refs.string = strVal; } - json["ref"] = ref; + refs.ref = QSharedPointer::create(ref); } } } - return json; + return refs; } -QJsonDocument CutterCore::getProcessThreads(int pid) +CutterJson CutterCore::getProcessThreads(int pid) { if (-1 == pid) { // Return threads list of the currently debugged PID @@ -1765,7 +1734,7 @@ bool CutterCore::writeHeapChunk(RzHeapChunkSimple *chunk_simple) return rz_heap_write_chunk(core, chunk_simple); } -QJsonDocument CutterCore::getChildProcesses(int pid) +CutterJson CutterCore::getChildProcesses(int pid) { // Return the currently debugged process and it's children if (-1 == pid) { @@ -1775,7 +1744,7 @@ QJsonDocument CutterCore::getChildProcesses(int pid) return cmdj("dpj " + QString::number(pid)); } -QJsonDocument CutterCore::getRegisterValues() +CutterJson CutterCore::getRegisterValues() { return cmdj("drj"); } @@ -1783,11 +1752,10 @@ QJsonDocument CutterCore::getRegisterValues() QList CutterCore::getVariables(RVA at) { QList ret; - QJsonObject varsObject = cmdj(QString("afvj @ %1").arg(at)).object(); + CutterJson varsObject = cmdj(QString("afvj @ %1").arg(at)); - auto addVars = [&](VariableDescription::RefType refType, const QJsonArray &array) { - for (const QJsonValue &varValue : array) { - QJsonObject varObject = varValue.toObject(); + auto addVars = [&](VariableDescription::RefType refType, const CutterJson &array) { + for (CutterJson varObject : array) { VariableDescription desc; desc.refType = refType; desc.name = varObject["name"].toString(); @@ -1796,21 +1764,19 @@ QList CutterCore::getVariables(RVA at) } }; - addVars(VariableDescription::RefType::SP, varsObject["sp"].toArray()); - addVars(VariableDescription::RefType::BP, varsObject["bp"].toArray()); - addVars(VariableDescription::RefType::Reg, varsObject["reg"].toArray()); + addVars(VariableDescription::RefType::SP, varsObject["sp"]); + addVars(VariableDescription::RefType::BP, varsObject["bp"]); + addVars(VariableDescription::RefType::Reg, varsObject["reg"]); return ret; } QVector CutterCore::getRegisterRefValues() { - QJsonArray registerRefArray = cmdj("drrj").array(); + CutterJson registerRefArray = cmdj("drrj"); QVector result; - for (const QJsonValue value : registerRefArray) { - QJsonObject regRefObject = value.toObject(); - + for (CutterJson regRefObject : registerRefArray) { RegisterRefValueDescription desc; desc.name = regRefObject[RJsonKey::reg].toString(); desc.value = regRefObject[RJsonKey::value].toString(); @@ -2371,11 +2337,8 @@ void CutterCore::stepBackDebug() QStringList CutterCore::getDebugPlugins() { QStringList plugins; - QJsonArray pluginArray = cmdj("dLj").array(); - - for (const QJsonValue &value : pluginArray) { - QJsonObject pluginObject = value.toObject(); + for (CutterJson pluginObject : cmdj("dLj")) { QString plugin = pluginObject[RJsonKey::name].toString(); plugins << plugin; @@ -2647,7 +2610,7 @@ bool CutterCore::isBreakpoint(const QList &breakpoints, RVA addr) return breakpoints.contains(addr); } -QJsonDocument CutterCore::getBacktrace() +CutterJson CutterCore::getBacktrace() { return cmdj("dbtj"); } @@ -2655,15 +2618,12 @@ QJsonDocument CutterCore::getBacktrace() QList CutterCore::getAllProcesses() { QList ret; - QJsonArray processArray = cmdj("dplj").array(); - - for (const QJsonValue &value : processArray) { - QJsonObject procObject = value.toObject(); + for (CutterJson procObject : cmdj("dplj")) { ProcessDescription proc; - proc.pid = procObject[RJsonKey::pid].toInt(); - proc.uid = procObject[RJsonKey::uid].toInt(); + proc.pid = procObject[RJsonKey::pid].toSt64(); + proc.uid = procObject[RJsonKey::uid].toSt64(); proc.status = procObject[RJsonKey::status].toString(); proc.path = procObject[RJsonKey::path].toString(); @@ -2676,17 +2636,14 @@ QList CutterCore::getAllProcesses() QList CutterCore::getMemoryMap() { QList ret; - QJsonArray memoryMapArray = cmdj("dmj").array(); - - for (const QJsonValue &value : memoryMapArray) { - QJsonObject memMapObject = value.toObject(); + for (CutterJson memMapObject : cmdj("dmj")) { MemoryMapDescription memMap; memMap.name = memMapObject[RJsonKey::name].toString(); memMap.fileName = memMapObject[RJsonKey::file].toString(); - memMap.addrStart = memMapObject[RJsonKey::addr].toVariant().toULongLong(); - memMap.addrEnd = memMapObject[RJsonKey::addr_end].toVariant().toULongLong(); + memMap.addrStart = memMapObject[RJsonKey::addr].toRVA(); + memMap.addrEnd = memMapObject[RJsonKey::addr_end].toRVA(); memMap.type = memMapObject[RJsonKey::type].toString(); memMap.permission = memMapObject[RJsonKey::perm].toString(); @@ -2925,15 +2882,11 @@ QList CutterCore::getAllImports() CORE_LOCK(); QList ret; - QJsonArray importsArray = cmdj("iij").array(); - - for (const QJsonValue &value : importsArray) { - QJsonObject importObject = value.toObject(); - + for (CutterJson importObject : cmdj("iij")) { ImportDescription import; - import.plt = importObject[RJsonKey::plt].toVariant().toULongLong(); - import.ordinal = importObject[RJsonKey::ordinal].toInt(); + import.plt = importObject[RJsonKey::plt].toRVA(); + import.ordinal = importObject[RJsonKey::ordinal].toSt64(); import.bind = importObject[RJsonKey::bind].toString(); import.type = importObject[RJsonKey::type].toString(); import.libname = importObject[RJsonKey::libname].toString(); @@ -2950,16 +2903,12 @@ QList CutterCore::getAllExports() CORE_LOCK(); QList ret; - QJsonArray exportsArray = cmdj("iEj").array(); - - for (const QJsonValue &value : exportsArray) { - QJsonObject exportObject = value.toObject(); - + for (CutterJson exportObject : cmdj("iEj")) { ExportDescription exp; - exp.vaddr = exportObject[RJsonKey::vaddr].toVariant().toULongLong(); - exp.paddr = exportObject[RJsonKey::paddr].toVariant().toULongLong(); - exp.size = exportObject[RJsonKey::size].toVariant().toULongLong(); + exp.vaddr = exportObject[RJsonKey::vaddr].toRVA(); + exp.paddr = exportObject[RJsonKey::paddr].toRVA(); + exp.size = exportObject[RJsonKey::size].toRVA(); exp.type = exportObject[RJsonKey::type].toString(); exp.name = exportObject[RJsonKey::name].toString(); exp.flag_name = exportObject[RJsonKey::flagname].toString(); @@ -3010,15 +2959,11 @@ QList CutterCore::getAllHeaders() CORE_LOCK(); QList ret; - QJsonArray headersArray = cmdj("ihj").array(); - - for (const QJsonValue &value : headersArray) { - QJsonObject headerObject = value.toObject(); - + for (CutterJson headerObject : cmdj("ihj")) { HeaderDescription header; - header.vaddr = headerObject[RJsonKey::vaddr].toVariant().toULongLong(); - header.paddr = headerObject[RJsonKey::paddr].toVariant().toULongLong(); + header.vaddr = headerObject[RJsonKey::vaddr].toRVA(); + header.paddr = headerObject[RJsonKey::paddr].toRVA(); header.value = headerObject[RJsonKey::comment].toString(); header.name = headerObject[RJsonKey::name].toString(); @@ -3063,16 +3008,13 @@ QList CutterCore::getAllComments(const QString &filterType) CORE_LOCK(); QList ret; - QJsonArray commentsArray = cmdj("CClj").array(); - for (const QJsonValue &value : commentsArray) { - QJsonObject commentObject = value.toObject(); - + for (CutterJson commentObject : cmdj("CClj")) { QString type = commentObject[RJsonKey::type].toString(); if (type != filterType) continue; CommentDescription comment; - comment.offset = commentObject[RJsonKey::offset].toVariant().toULongLong(); + comment.offset = commentObject[RJsonKey::offset].toRVA(); comment.name = commentObject[RJsonKey::name].toString(); ret << comment; @@ -3114,22 +3056,19 @@ QList CutterCore::getAllStrings() return parseStringsJson(cmdjTask("izzj")); } -QList CutterCore::parseStringsJson(const QJsonDocument &doc) +QList CutterCore::parseStringsJson(const CutterJson &doc) { QList ret; - QJsonArray stringsArray = doc.array(); - for (const QJsonValue &value : stringsArray) { - QJsonObject stringObject = value.toObject(); - + for (CutterJson value : doc) { StringDescription string; - string.string = stringObject[RJsonKey::string].toString(); - string.vaddr = stringObject[RJsonKey::vaddr].toVariant().toULongLong(); - string.type = stringObject[RJsonKey::type].toString(); - string.size = stringObject[RJsonKey::size].toVariant().toUInt(); - string.length = stringObject[RJsonKey::length].toVariant().toUInt(); - string.section = stringObject[RJsonKey::section].toString(); + string.string = value[RJsonKey::string].toString(); + string.vaddr = value[RJsonKey::vaddr].toRVA(); + string.type = value[RJsonKey::type].toString(); + string.size = value[RJsonKey::size].toUt64(); + string.length = value[RJsonKey::length].toUt64(); + string.section = value[RJsonKey::section].toString(); ret << string; } @@ -3249,21 +3188,17 @@ QList CutterCore::getAllSegments() CORE_LOCK(); QList ret; - QJsonArray segments = cmdj("iSSj").array(); - - for (const QJsonValue &value : segments) { - QJsonObject segmentObject = value.toObject(); - + for (CutterJson segmentObject : cmdj("iSSj")) { QString name = segmentObject[RJsonKey::name].toString(); if (name.isEmpty()) continue; SegmentDescription segment; segment.name = name; - segment.vaddr = segmentObject[RJsonKey::vaddr].toVariant().toULongLong(); - segment.paddr = segmentObject[RJsonKey::paddr].toVariant().toULongLong(); - segment.size = segmentObject[RJsonKey::size].toVariant().toULongLong(); - segment.vsize = segmentObject[RJsonKey::vsize].toVariant().toULongLong(); + segment.vaddr = segmentObject[RJsonKey::vaddr].toRVA(); + segment.paddr = segmentObject[RJsonKey::paddr].toRVA(); + segment.size = segmentObject[RJsonKey::size].toRVA(); + segment.vsize = segmentObject[RJsonKey::vsize].toRVA(); segment.perm = segmentObject[RJsonKey::perm].toString(); ret << segment; @@ -3276,17 +3211,14 @@ QList CutterCore::getAllEntrypoint() CORE_LOCK(); QList ret; - QJsonArray entrypointsArray = cmdj("iej").array(); - for (const QJsonValue &value : entrypointsArray) { - QJsonObject entrypointObject = value.toObject(); - + for (CutterJson entrypointObject : cmdj("iej")) { EntrypointDescription entrypoint; - entrypoint.vaddr = entrypointObject[RJsonKey::vaddr].toVariant().toULongLong(); - entrypoint.paddr = entrypointObject[RJsonKey::paddr].toVariant().toULongLong(); - entrypoint.baddr = entrypointObject[RJsonKey::baddr].toVariant().toULongLong(); - entrypoint.laddr = entrypointObject[RJsonKey::laddr].toVariant().toULongLong(); - entrypoint.haddr = entrypointObject[RJsonKey::haddr].toVariant().toULongLong(); + entrypoint.vaddr = entrypointObject[RJsonKey::vaddr].toRVA(); + entrypoint.paddr = entrypointObject[RJsonKey::paddr].toRVA(); + entrypoint.baddr = entrypointObject[RJsonKey::baddr].toRVA(); + entrypoint.laddr = entrypointObject[RJsonKey::laddr].toRVA(); + entrypoint.haddr = entrypointObject[RJsonKey::haddr].toRVA(); entrypoint.type = entrypointObject[RJsonKey::type].toString(); ret << entrypoint; @@ -3299,34 +3231,27 @@ QList CutterCore::getAllClassesFromBin() CORE_LOCK(); QList ret; - QJsonArray classesArray = cmdj("icj").array(); - for (const QJsonValue &value : classesArray) { - QJsonObject classObject = value.toObject(); - + for (CutterJson classObject : cmdj("icj")) { BinClassDescription cls; cls.name = classObject[RJsonKey::classname].toString(); - cls.addr = classObject[RJsonKey::addr].toVariant().toULongLong(); - cls.index = classObject[RJsonKey::index].toVariant().toULongLong(); - - for (const QJsonValue &value2 : classObject[RJsonKey::methods].toArray()) { - QJsonObject methObject = value2.toObject(); + cls.addr = classObject[RJsonKey::addr].toRVA(); + cls.index = classObject[RJsonKey::index].toUt64(); + for (CutterJson methObject : classObject[RJsonKey::methods]) { BinClassMethodDescription meth; meth.name = methObject[RJsonKey::name].toString(); - meth.addr = methObject[RJsonKey::addr].toVariant().toULongLong(); + meth.addr = methObject[RJsonKey::addr].toRVA(); cls.methods << meth; } - for (const QJsonValue &value2 : classObject[RJsonKey::fields].toArray()) { - QJsonObject fieldObject = value2.toObject(); - + for (CutterJson fieldObject : classObject[RJsonKey::fields]) { BinClassFieldDescription field; field.name = fieldObject[RJsonKey::name].toString(); - field.addr = fieldObject[RJsonKey::addr].toVariant().toULongLong(); + field.addr = fieldObject[RJsonKey::addr].toRVA(); cls.fields << field; } @@ -3345,10 +3270,7 @@ QList CutterCore::getAllClassesFromFlags() QList ret; QMap classesCache; - QJsonArray flagsArray = cmdj("fj@F:classes").array(); - for (const QJsonValue &value : flagsArray) { - QJsonObject flagObject = value.toObject(); - + for (const CutterJson flagObject : cmdj("fj@F:classes")) { QString flagName = flagObject[RJsonKey::name].toString(); QRegularExpressionMatch match = classFlagRegExp.match(flagName); @@ -3365,7 +3287,7 @@ QList CutterCore::getAllClassesFromFlags() desc = it.value(); } desc->name = match.captured(1); - desc->addr = flagObject[RJsonKey::offset].toVariant().toULongLong(); + desc->addr = flagObject[RJsonKey::offset].toRVA(); desc->index = RVA_INVALID; continue; } @@ -3390,7 +3312,7 @@ QList CutterCore::getAllClassesFromFlags() BinClassMethodDescription meth; meth.name = match.captured(2); - meth.addr = flagObject[RJsonKey::offset].toVariant().toULongLong(); + meth.addr = flagObject[RJsonKey::offset].toRVA(); classDesc->methods << meth; continue; } @@ -3559,17 +3481,14 @@ QList CutterCore::getAllResources() CORE_LOCK(); QList resources; - QJsonArray resourcesArray = cmdj("iRj").array(); - for (const QJsonValue &value : resourcesArray) { - QJsonObject resourceObject = value.toObject(); - + for (CutterJson resourceObject : cmdj("iRj")) { ResourcesDescription res; res.name = resourceObject[RJsonKey::name].toString(); - res.vaddr = resourceObject[RJsonKey::vaddr].toVariant().toULongLong(); - res.index = resourceObject[RJsonKey::index].toVariant().toULongLong(); + res.vaddr = resourceObject[RJsonKey::vaddr].toRVA(); + res.index = resourceObject[RJsonKey::index].toUt64(); res.type = resourceObject[RJsonKey::type].toString(); - res.size = resourceObject[RJsonKey::size].toVariant().toULongLong(); + res.size = resourceObject[RJsonKey::size].toUt64(); res.lang = resourceObject[RJsonKey::lang].toString(); resources << res; @@ -3582,21 +3501,15 @@ QList CutterCore::getAllVTables() CORE_LOCK(); QList vtables; - QJsonArray vTablesArray = cmdj("avj").array(); - for (const QJsonValue &vTableValue : vTablesArray) { - QJsonObject vTableObject = vTableValue.toObject(); - + for (CutterJson vTableObject : cmdj("avj")) { VTableDescription res; - res.addr = vTableObject[RJsonKey::offset].toVariant().toULongLong(); - QJsonArray methodArray = vTableObject[RJsonKey::methods].toArray(); - - for (const QJsonValue &methodValue : methodArray) { - QJsonObject methodObject = methodValue.toObject(); + res.addr = vTableObject[RJsonKey::offset].toRVA(); + for (CutterJson methodObject : vTableObject[RJsonKey::methods]) { BinClassMethodDescription method; - method.addr = methodObject[RJsonKey::offset].toVariant().toULongLong(); + method.addr = methodObject[RJsonKey::offset].toRVA(); method.name = methodObject[RJsonKey::name].toString(); res.methods << method; @@ -3693,43 +3606,33 @@ QList CutterCore::getAllSearch(QString searchFor, QString spa CORE_LOCK(); QList searchRef; - QJsonArray searchArray; + CutterJson searchArray; { TempConfig cfg; cfg.set("search.in", in); - searchArray = cmdj(QString("%1 %2").arg(space, searchFor)).array(); + searchArray = cmdj(QString("%1 %2").arg(space, searchFor)); } if (space == "/Rj") { - for (const QJsonValue &value : searchArray) { - QJsonObject searchObject = value.toObject(); - + for (CutterJson searchObject : searchArray) { SearchDescription exp; exp.code.clear(); - for (const QJsonValue &value2 : searchObject[RJsonKey::opcodes].toArray()) { - QJsonObject gadget = value2.toObject(); + for (CutterJson gadget : searchObject[RJsonKey::opcodes]) { exp.code += gadget[RJsonKey::opcode].toString() + "; "; } - exp.offset = searchObject[RJsonKey::opcodes] - .toArray() - .first() - .toObject()[RJsonKey::offset] - .toVariant() - .toULongLong(); - exp.size = searchObject[RJsonKey::size].toVariant().toULongLong(); + exp.offset = searchObject[RJsonKey::opcodes].first()[RJsonKey::offset].toRVA(); + exp.size = searchObject[RJsonKey::size].toUt64(); searchRef << exp; } } else { - for (const QJsonValue &value : searchArray) { - QJsonObject searchObject = value.toObject(); - + for (CutterJson searchObject : searchArray) { SearchDescription exp; - exp.offset = searchObject[RJsonKey::offset].toVariant().toULongLong(); - exp.size = searchObject[RJsonKey::len].toVariant().toULongLong(); + exp.offset = searchObject[RJsonKey::offset].toRVA(); + exp.size = searchObject[RJsonKey::len].toUt64(); exp.code = searchObject[RJsonKey::code].toString(); exp.data = searchObject[RJsonKey::data].toString(); @@ -3747,35 +3650,31 @@ BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount) return blockStats; } - QJsonObject statsObj; + CutterJson statsObj; // User TempConfig here to set the search boundaries to all sections. This makes sure // that the Visual Navbar will show all the relevant addresses. { TempConfig tempConfig; tempConfig.set("search.in", "bin.sections"); - statsObj = cmdj("p-j " + QString::number(blocksCount)).object(); + statsObj = cmdj("p-j " + QString::number(blocksCount)); } - blockStats.from = statsObj[RJsonKey::from].toVariant().toULongLong(); - blockStats.to = statsObj[RJsonKey::to].toVariant().toULongLong(); - blockStats.blocksize = statsObj[RJsonKey::blocksize].toVariant().toULongLong(); - - QJsonArray blocksArray = statsObj[RJsonKey::blocks].toArray(); - - for (const QJsonValue &value : blocksArray) { - QJsonObject blockObj = value.toObject(); + blockStats.from = statsObj[RJsonKey::from].toRVA(); + blockStats.to = statsObj[RJsonKey::to].toRVA(); + blockStats.blocksize = statsObj[RJsonKey::blocksize].toRVA(); + for (CutterJson blockObj : statsObj[RJsonKey::blocks]) { BlockDescription block; - block.addr = blockObj[RJsonKey::offset].toVariant().toULongLong(); - block.size = blockObj[RJsonKey::size].toVariant().toULongLong(); - block.flags = blockObj[RJsonKey::flags].toInt(0); - block.functions = blockObj[RJsonKey::functions].toInt(0); - block.inFunctions = blockObj[RJsonKey::in_functions].toInt(0); - block.comments = blockObj[RJsonKey::comments].toInt(0); - block.symbols = blockObj[RJsonKey::symbols].toInt(0); - block.strings = blockObj[RJsonKey::strings].toInt(0); + block.addr = blockObj[RJsonKey::offset].toRVA(); + block.size = blockObj[RJsonKey::size].toRVA(); + block.flags = blockObj[RJsonKey::flags].toSt64(); + block.functions = blockObj[RJsonKey::functions].toSt64(); + block.inFunctions = blockObj[RJsonKey::in_functions].toSt64(); + block.comments = blockObj[RJsonKey::comments].toSt64(); + block.symbols = blockObj[RJsonKey::symbols].toSt64(); + block.strings = blockObj[RJsonKey::strings].toSt64(); block.rwx = 0; QString rwxStr = blockObj[RJsonKey::rwx].toString(); @@ -3801,20 +3700,12 @@ QList CutterCore::getXRefsForVariable(QString variableName, boo RVA offset) { QList xrefList = QList(); - QJsonArray xrefsArray; - if (findWrites) { - xrefsArray = cmdjAt("afvWj", offset).array(); - } else { - xrefsArray = cmdjAt("afvRj", offset).array(); - } - for (const QJsonValue &value : xrefsArray) { - QJsonObject xrefObject = value.toObject(); + for (CutterJson xrefObject : cmdjAt(findWrites ? "afvWj" : "afvRj", offset)) { QString name = xrefObject[RJsonKey::name].toString(); if (name == variableName) { - QJsonArray addressArray = xrefObject[RJsonKey::addrs].toArray(); - for (const QJsonValue &address : addressArray) { + for (CutterJson address : xrefObject[RJsonKey::addrs]) { XrefDescription xref; - RVA addr = address.toVariant().toULongLong(); + RVA addr = address.toRVA(); xref.from = addr; xref.to = addr; if (findWrites) { @@ -3890,11 +3781,11 @@ QString CutterCore::listFlagsAsStringAt(RVA addr) QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut) { - auto r = cmdj(QString("fdj @ ") + QString::number(offset)).object(); - QString name = r.value("name").toString(); + auto r = cmdj(QString("fdj @ ") + QString::number(offset)); + QString name = r["name"].toString(); if (flagOffsetOut) { - auto offsetValue = r.value("offset"); - *flagOffsetOut = offsetValue.isUndefined() ? offset : offsetValue.toVariant().toULongLong(); + auto offsetValue = r["offset"]; + *flagOffsetOut = offsetValue.valid() ? offsetValue.toRVA() : offset; } return name; } @@ -3965,18 +3856,15 @@ void CutterCore::loadPDB(const QString &file) QList CutterCore::disassembleLines(RVA offset, int lines) { - QJsonArray array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") - + QString::number(offset)) - .array(); + CutterJson array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") + + QString::number(offset)); QList r; - for (const QJsonValueRef &value : array) { - QJsonObject object = value.toObject(); + for (CutterJson object : array) { DisassemblyLine line; - line.offset = object[RJsonKey::offset].toVariant().toULongLong(); + line.offset = object[RJsonKey::offset].toRVA(); line.text = ansiEscapeToHtml(object[RJsonKey::text].toString()); - const auto &arrow = object[RJsonKey::arrow]; - line.arrow = arrow.isNull() ? RVA_INVALID : arrow.toVariant().toULongLong(); + line.arrow = object[RJsonKey::arrow].toRVA(); r << line; } @@ -4094,8 +3982,7 @@ QString CutterCore::getVersionInformation() QList CutterCore::getColorThemes() { QList r; - QJsonDocument themes = cmdj("ecoj"); - for (const QJsonValue &s : themes.array()) { + for (CutterJson s : cmdj("ecoj")) { r << s.toString(); } return r; @@ -4181,13 +4068,13 @@ void CutterCore::setWriteMode(bool enabled) bool CutterCore::isWriteModeEnabled() { - using namespace std; - QJsonArray ans = cmdj("oj").array(); - return find_if(begin(ans), end(ans), - [](const QJsonValue &v) { return v.toObject().value("raised").toBool(); }) - ->toObject() - .value("writable") - .toBool(); + for (CutterJson v : cmdj("oj")) { + if (v["raised"].toBool()) { + return v["writable"].toBool(); + } + } + + return false; } /** diff --git a/src/core/Cutter.h b/src/core/Cutter.h index d8b7a0a1..c1e21e50 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -3,15 +3,16 @@ #include "core/CutterCommon.h" #include "core/CutterDescriptions.h" +#include "core/CutterJson.h" #include "common/BasicInstructionHighlighter.h" #include #include #include #include +#include #include #include -#include #include #include #include @@ -34,6 +35,29 @@ class RizinTaskDialog; class RzCoreLocked; +struct CUTTER_EXPORT AddrRefs +{ + RVA addr; + QString mapname; + QString section; + QString reg; + QString fcn; + QString type; + QString asm_op; + QString perms; + ut64 value; + bool has_value; + QString string; + QSharedPointer ref; +}; + +struct CUTTER_EXPORT RegisterRef +{ + ut64 value; + AddrRefs ref; + QString name; +}; + class CUTTER_EXPORT CutterCore : public QObject { Q_OBJECT @@ -124,16 +148,16 @@ public: seekSilent(oldOffset); } - QJsonDocument cmdj(const char *str); - QJsonDocument cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } - QJsonDocument cmdjAt(const char *str, RVA address); + CutterJson cmdj(const char *str); + CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } + CutterJson cmdjAt(const char *str, RVA address); QStringList cmdList(const char *str) { return cmd(str).split(QLatin1Char('\n'), CUTTER_QT_SKIP_EMPTY_PARTS); } QStringList cmdList(const QString &str) { return cmdList(str.toUtf8().constData()); } QString cmdTask(const QString &str); - QJsonDocument cmdjTask(const QString &str); + CutterJson cmdjTask(const QString &str); /** * @brief send a command to Rizin and check for ESIL errors * @param command the command you want to execute @@ -159,8 +183,8 @@ public: QString getRizinVersionReadable(); QString getVersionInformation(); - QJsonDocument parseJson(const char *res, const char *cmd = nullptr); - QJsonDocument parseJson(const char *res, const QString &cmd = QString()) + CutterJson parseJson(char *res, const char *cmd = nullptr); + CutterJson parseJson(char *res, const QString &cmd = QString()) { return parseJson(res, cmd.isNull() ? nullptr : cmd.toLocal8Bit().constData()); } @@ -376,8 +400,8 @@ public: bool sdbSet(QString path, QString key, QString val); /* Debug */ - QJsonDocument getRegistersInfo(); - QJsonDocument getRegisterValues(); + CutterJson getRegistersInfo(); + CutterJson getRegisterValues(); QString getRegisterName(QString registerRole); RVA getProgramCounterValue(); void setRegister(QString regName, QString regValue); @@ -391,32 +415,32 @@ public: * @param size number of bytes to scan * @param depth telescoping depth */ - QList getStack(int size = 0x100, int depth = 6); + QList getStack(int size = 0x100, int depth = 6); /** * @brief Recursively dereferences pointers starting at the specified address * up to a given depth * @param addr telescoping addr * @param depth telescoping depth */ - QJsonObject getAddrRefs(RVA addr, int depth); + AddrRefs getAddrRefs(RVA addr, int depth); /** * @brief return a RefDescription with a formatted ref string and configured colors * @param ref the "ref" JSON node from getAddrRefs */ - RefDescription formatRefDesc(QJsonObject ref); + RefDescription formatRefDesc(const AddrRefs &ref); /** * @brief Get a list of a given process's threads * @param pid The pid of the process, -1 for the currently debugged process * @return JSON object result of dptj */ - QJsonDocument getProcessThreads(int pid); + CutterJson getProcessThreads(int pid); /** * @brief Get a list of a given process's child processes * @param pid The pid of the process, -1 for the currently debugged process * @return JSON object result of dptj */ - QJsonDocument getChildProcesses(int pid); - QJsonDocument getBacktrace(); + CutterJson getChildProcesses(int pid); + CutterJson getBacktrace(); /** * @brief Get a list of heap chunks * Uses RZ_API rz_heap_chunks_list to get vector of chunks @@ -532,9 +556,9 @@ public: bool registerDecompiler(Decompiler *decompiler); RVA getOffsetJump(RVA addr); - QJsonDocument getFileInfo(); - QJsonDocument getSignatureInfo(); - QJsonDocument getFileVersionInfo(); + CutterJson getFileInfo(); + CutterJson getSignatureInfo(); + CutterJson getFileVersionInfo(); QStringList getStats(); void setGraphEmpty(bool empty); bool isGraphEmpty(); @@ -631,7 +655,7 @@ public: * @brief returns a list of reg values and their telescoped references * @param depth telescoping depth */ - QList getRegisterRefs(int depth = 6); + QList getRegisterRefs(int depth = 6); QVector getRegisterRefValues(); QList getVariables(RVA at); /** @@ -649,7 +673,7 @@ public: QList getXRefs(RVA addr, bool to, bool whole_function, const QString &filterType = QString()); - QList parseStringsJson(const QJsonDocument &doc); + QList parseStringsJson(const CutterJson &doc); void handleREvent(int type, void *data); diff --git a/src/core/CutterJson.cpp b/src/core/CutterJson.cpp new file mode 100644 index 00000000..dc6667c0 --- /dev/null +++ b/src/core/CutterJson.cpp @@ -0,0 +1,28 @@ +#include "core/CutterJson.h" + +CutterJson CutterJson::last() const +{ + if (!has_children()) { + return CutterJson(); + } + + const RzJson *last = value->children.first; + while (last->next) { + last = last->next; + } + + return CutterJson(last, owner); +} + +QStringList CutterJson::keys() const +{ + QStringList list; + + if (value && value->type == RZ_JSON_OBJECT) { + for (const RzJson *child = value->children.first; child; child = child->next) { + list.append(child->key); + } + } + + return list; +} diff --git a/src/core/CutterJson.h b/src/core/CutterJson.h new file mode 100644 index 00000000..042ca84b --- /dev/null +++ b/src/core/CutterJson.h @@ -0,0 +1,119 @@ +#ifndef CUTTER_JSON_H +#define CUTTER_JSON_H + +#include "core/CutterCommon.h" + +#include +#include +#include +#include + +class CutterJsonOwner; + +class CUTTER_EXPORT CutterJson +{ +public: + class iterator + { + public: + iterator(const RzJson *value, QSharedPointer owner) + : value(value), owner(owner) + { + } + + CutterJson operator*() const { return CutterJson(value, owner); } + + bool operator!=(const iterator &other) const { return value != other.value; } + + iterator &operator++() + { + value = value->next; + return *this; + } + + private: + const RzJson *value; + QSharedPointer owner; + }; + + CutterJson() : value(nullptr), owner(nullptr) {} + + CutterJson(const RzJson *value, QSharedPointer owner) + : value(value), owner(owner) + { + } + + CutterJson first() const + { + return CutterJson(has_children() ? value->children.first : nullptr, owner); + } + + CutterJson last() const; + + CutterJson operator[](const QString &key) const + { + QByteArray utf8 = key.toUtf8(); + return (*this)[utf8.data()]; + } + + CutterJson operator[](const char *key) const + { + return CutterJson( + value && value->type == RZ_JSON_OBJECT ? rz_json_get(value, key) : nullptr, owner); + } + + iterator begin() const + { + return iterator(has_children() ? value->children.first : nullptr, owner); + } + + iterator end() const { return iterator(nullptr, nullptr); } + + bool toBool() const { return value && value->type == RZ_JSON_BOOLEAN && value->num.u_value; } + QString toJson() const { return rz_json_as_string(value); } + st64 toSt64() const { return value && value->type == RZ_JSON_INTEGER ? value->num.s_value : 0; } + ut64 toUt64() const { return value && value->type == RZ_JSON_INTEGER ? value->num.u_value : 0; } + + RVA toRVA() const + { + return value && value->type == RZ_JSON_INTEGER ? value->num.u_value : RVA_INVALID; + } + + QString toString() const + { + return value && value->type == RZ_JSON_STRING ? QString(value->str_value) : QString(); + } + + QString key() const { return value ? value->key : QString(); } + QStringList keys() const; + size_t size() const { return has_children() ? value->children.count : 0; } + RzJsonType type() const { return value ? value->type : RZ_JSON_NULL; } + bool valid() const { return value ? true : false; } + +private: + bool has_children() const + { + return value && (value->type == RZ_JSON_OBJECT || value->type == RZ_JSON_ARRAY); + } + + const RzJson *value; + QSharedPointer owner; +}; + +class CUTTER_EXPORT CutterJsonOwner +{ +public: + CutterJsonOwner(RzJson *value, char *text) : value(value), text(text) {} + + virtual ~CutterJsonOwner() + { + rz_json_free(value); + rz_mem_free(text); + } + +private: + RzJson *value; + char *text; +}; + +#endif // CUTTER_JSON_H diff --git a/src/dialogs/VersionInfoDialog.cpp b/src/dialogs/VersionInfoDialog.cpp index 9d166bb4..7e67d594 100644 --- a/src/dialogs/VersionInfoDialog.cpp +++ b/src/dialogs/VersionInfoDialog.cpp @@ -24,12 +24,12 @@ VersionInfoDialog::~VersionInfoDialog() {} void VersionInfoDialog::fillVersionInfo() { - QJsonDocument doc = Core()->getFileVersionInfo(); + CutterJson doc = Core()->getFileVersionInfo(); // Case ELF - if (doc.object().contains("verneed")) { - QJsonObject verneed = doc.object()["verneed"].toArray().first().toObject(); - QJsonObject versym = doc.object()["versym"].toArray().first().toObject(); + if (doc["verneed"].valid()) { + CutterJson verneed = doc["verneed"].first(); + CutterJson versym = doc["versym"].first(); // Set labels ui->leftLabel->setText("Version symbols"); @@ -43,17 +43,17 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *addrItemL = new QTreeWidgetItem(); addrItemL->setText(0, "Address:"); - addrItemL->setText(1, RzAddressString(versym["address"].toDouble())); + addrItemL->setText(1, RzAddressString(versym["address"].toRVA())); ui->leftTreeWidget->addTopLevelItem(addrItemL); QTreeWidgetItem *offItemL = new QTreeWidgetItem(); offItemL->setText(0, "Offset:"); - offItemL->setText(1, RzAddressString(versym["offset"].toDouble())); + offItemL->setText(1, RzAddressString(versym["offset"].toRVA())); ui->leftTreeWidget->addTopLevelItem(offItemL); QTreeWidgetItem *linkItemL = new QTreeWidgetItem(); linkItemL->setText(0, "Link:"); - linkItemL->setText(1, QString::number(versym["link"].toDouble())); + linkItemL->setText(1, QString::number(versym["link"].toRVA())); ui->leftTreeWidget->addTopLevelItem(linkItemL); QTreeWidgetItem *linkNameItemL = new QTreeWidgetItem(); @@ -63,10 +63,9 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *entriesItemL = new QTreeWidgetItem(); entriesItemL->setText(0, "Entries:"); - for (QJsonValue val : versym["entries"].toArray()) { - QJsonObject obj = val.toObject(); + for (CutterJson obj : versym["entries"]) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, RzAddressString(obj["idx"].toDouble())); + tempItem->setText(0, RzAddressString(obj["idx"].toRVA())); tempItem->setText(1, obj["value"].toString()); entriesItemL->addChild(tempItem); } @@ -83,17 +82,17 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *addrItemR = new QTreeWidgetItem(); addrItemR->setText(0, "Address:"); - addrItemR->setText(1, RzAddressString(verneed["address"].toDouble())); + addrItemR->setText(1, RzAddressString(verneed["address"].toRVA())); ui->rightTreeWidget->addTopLevelItem(addrItemR); QTreeWidgetItem *offItemR = new QTreeWidgetItem(); offItemR->setText(0, "Offset:"); - offItemR->setText(1, RzAddressString(verneed["offset"].toDouble())); + offItemR->setText(1, RzAddressString(verneed["offset"].toRVA())); ui->rightTreeWidget->addTopLevelItem(offItemR); QTreeWidgetItem *linkItemR = new QTreeWidgetItem(); linkItemR->setText(0, "Link:"); - linkItemR->setText(1, QString::number(verneed["link"].toDouble())); + linkItemR->setText(1, QString::number(verneed["link"].toSt64())); ui->rightTreeWidget->addTopLevelItem(linkItemR); QTreeWidgetItem *linkNameItemR = new QTreeWidgetItem(); @@ -103,24 +102,22 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *entriesItemR = new QTreeWidgetItem(); entriesItemR->setText(0, "Entries:"); - for (QJsonValue parentVal : verneed["entries"].toArray()) { - QJsonObject parentObj = parentVal.toObject(); + for (CutterJson parentObj : verneed["entries"]) { QTreeWidgetItem *parentItem = new QTreeWidgetItem(); QString parentString; - parentItem->setText(0, RzAddressString(parentObj["idx"].toDouble())); - parentString.append("Version: " + QString::number(parentObj["vn_version"].toDouble()) + parentItem->setText(0, RzAddressString(parentObj["idx"].toRVA())); + parentString.append("Version: " + QString::number(parentObj["vn_version"].toSt64()) + "\t"); parentString.append("File: " + parentObj["file_name"].toString()); parentItem->setText(1, parentString); - for (QJsonValue childVal : parentObj["vernaux"].toArray()) { - QJsonObject childObj = childVal.toObject(); + for (CutterJson childObj : parentObj["vernaux"]) { QTreeWidgetItem *childItem = new QTreeWidgetItem(); QString childString; - childItem->setText(0, RzAddressString(childObj["idx"].toDouble())); + childItem->setText(0, RzAddressString(childObj["idx"].toRVA())); childString.append("Name: " + childObj["name"].toString() + "\t"); childString.append("Flags: " + childObj["flags"].toString() + "\t"); - childString.append("Version: " + QString::number(childObj["version"].toDouble())); + childString.append("Version: " + QString::number(childObj["version"].toSt64())); childItem->setText(1, childString); parentItem->addChild(childItem); } @@ -134,22 +131,22 @@ void VersionInfoDialog::fillVersionInfo() } // Case PE - else if (doc.object().contains("VS_FIXEDFILEINFO")) { - QJsonObject vs = doc.object()["VS_FIXEDFILEINFO"].toObject(); - QJsonObject strings = doc.object()["StringTable"].toObject(); + else if (doc["VS_FIXEDFILEINFO"].valid()) { + CutterJson vs = doc["VS_FIXEDFILEINFO"]; + CutterJson strings = doc["StringTable"]; // Set labels ui->leftLabel->setText("VS Fixed file info"); ui->rightLabel->setText("String table"); // Left tree - for (QString key : vs.keys()) { + for (CutterJson property : vs) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, key); - if (vs[key].isDouble()) - tempItem->setText(1, RzHexString(vs[key].toDouble())); + tempItem->setText(0, property.key()); + if (property.type() == RZ_JSON_INTEGER) + tempItem->setText(1, RzHexString(property.toRVA())); else - tempItem->setText(1, vs[key].toString()); + tempItem->setText(1, property.toString()); ui->leftTreeWidget->addTopLevelItem(tempItem); // Adjust columns to content @@ -157,10 +154,10 @@ void VersionInfoDialog::fillVersionInfo() } // Right tree - for (QString key : strings.keys()) { + for (CutterJson property : strings) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, key); - tempItem->setText(1, strings[key].toString()); + tempItem->setText(0, property.key()); + tempItem->setText(1, property.toString()); ui->rightTreeWidget->addTopLevelItem(tempItem); // Adjust columns to content diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 2c7b8ba8..c2065c9d 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -314,15 +314,15 @@ void DisassemblyContextMenu::addDebugMenu() QVector DisassemblyContextMenu::getThingUsedHere(RVA offset) { QVector result; - const QJsonArray array = Core()->cmdj("anj @ " + QString::number(offset)).array(); + const CutterJson array = Core()->cmdj("anj @ " + QString::number(offset)); result.reserve(array.size()); for (const auto &thing : array) { - auto obj = thing.toObject(); - RVA offset = obj["offset"].toVariant().toULongLong(); + auto obj = thing; + RVA offset = obj["offset"].toRVA(); QString name; // If real names display is enabled, show flag's real name instead of full flag name - if (Config()->getConfigBool("asm.flags.real") && obj.contains("realname")) { + if (Config()->getConfigBool("asm.flags.real") && obj["realname"].valid()) { name = obj["realname"].toString(); } else { name = obj["name"].toString(); @@ -482,29 +482,24 @@ void DisassemblyContextMenu::setupRenaming() void DisassemblyContextMenu::aboutToShowSlot() { // check if set immediate base menu makes sense - QJsonObject instObject = - Core()->cmdj("aoj @ " + QString::number(offset)).array().first().toObject(); - auto keys = instObject.keys(); - bool immBase = keys.contains("val") || keys.contains("ptr"); + CutterJson instObject = Core()->cmdj("aoj @ " + QString::number(offset)).first(); + bool immBase = instObject["val"].valid() || instObject["ptr"].valid(); setBaseMenu->menuAction()->setVisible(immBase); setBitsMenu->menuAction()->setVisible(true); // Create structure offset menu if it makes sense QString memBaseReg; // Base register - QVariant memDisp; // Displacement - if (instObject.contains("opex") && instObject["opex"].toObject().contains("operands")) { - // Loop through both the operands of the instruction - for (const QJsonValue value : instObject["opex"].toObject()["operands"].toArray()) { - QJsonObject operand = value.toObject(); - if (operand.contains("type") && operand["type"].toString() == "mem" - && operand.contains("base") && !operand["base"].toString().contains("bp") - && operand.contains("disp") && operand["disp"].toVariant().toLongLong() > 0) { + st64 memDisp; // Displacement - // The current operand is the one which has an immediate displacement - memBaseReg = operand["base"].toString(); - memDisp = operand["disp"].toVariant(); - break; - } + // Loop through both the operands of the instruction + for (const CutterJson operand : instObject["opex"]["operands"]) { + if (operand["type"].toString() == "mem" && !operand["base"].toString().contains("bp") + && operand["disp"].toSt64() > 0) { + + // The current operand is the one which has an immediate displacement + memBaseReg = operand["base"].toString(); + memDisp = operand["disp"].toSt64(); + break; } } if (memBaseReg.isEmpty()) { @@ -517,7 +512,7 @@ void DisassemblyContextMenu::aboutToShowSlot() // Get the possible offsets using the "ahts" command // TODO: add ahtj command to Rizin and then use it here - QStringList ret = Core()->cmdList("ahts " + memDisp.toString()); + QStringList ret = Core()->cmdList("ahts " + QString::number(memDisp)); for (const QString &val : ret) { if (val.isEmpty()) { continue; @@ -714,12 +709,12 @@ void DisassemblyContextMenu::showReverseJmpQuery() { QString type; - QJsonArray array = Core()->cmdj("pdj 1 @ " + RzAddressString(offset)).array(); - if (array.isEmpty()) { + CutterJson array = Core()->cmdj("pdj 1 @ " + RzAddressString(offset)); + if (!array.size()) { return; } - type = array.first().toObject()["type"].toString(); + type = array.first()["type"].toString(); if (type == "cjmp") { actionJmpReverse.setVisible(true); } else { diff --git a/src/widgets/BacktraceWidget.cpp b/src/widgets/BacktraceWidget.cpp index 793813d7..433a1b1e 100644 --- a/src/widgets/BacktraceWidget.cpp +++ b/src/widgets/BacktraceWidget.cpp @@ -44,13 +44,11 @@ void BacktraceWidget::updateContents() void BacktraceWidget::setBacktraceGrid() { - QJsonArray backtraceValues = Core()->getBacktrace().array(); int i = 0; - for (const QJsonValue &value : backtraceValues) { - QJsonObject backtraceItem = value.toObject(); - QString progCounter = RzAddressString(backtraceItem["pc"].toVariant().toULongLong()); - QString stackPointer = RzAddressString(backtraceItem["sp"].toVariant().toULongLong()); - int frameSize = backtraceItem["frame_size"].toVariant().toInt(); + for (CutterJson backtraceItem : Core()->getBacktrace()) { + QString progCounter = RzAddressString(backtraceItem["pc"].toRVA()); + QString stackPointer = RzAddressString(backtraceItem["sp"].toRVA()); + st64 frameSize = backtraceItem["frame_size"].toSt64(); QString funcName = backtraceItem["fname"].toString(); QString desc = backtraceItem["desc"].toString(); diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index 2bd16b73..c66a862e 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -77,8 +77,7 @@ void CallGraphView::loadCurrentGraph() blockContent.clear(); blocks.clear(); - QJsonDocument functionsDoc = Core()->cmdj(global ? "agCj" : QString("agcj @ %1").arg(address)); - auto nodes = functionsDoc.array(); + CutterJson nodes = Core()->cmdj(global ? "agCj" : QString("agcj @ %1").arg(address)); QHash idMapping; @@ -91,11 +90,10 @@ void CallGraphView::loadCurrentGraph() return itemId; }; - for (const QJsonValueRef &value : nodes) { - QJsonObject block = value.toObject(); - QString name = block["name"].toVariant().toString(); + for (CutterJson block : nodes) { + QString name = block["name"].toString(); - auto edges = block["imports"].toArray(); + auto edges = block["imports"]; GraphLayout::GraphBlock layoutBlock; layoutBlock.entry = getId(name); for (auto edge : edges) { diff --git a/src/widgets/ColorThemeListView.h b/src/widgets/ColorThemeListView.h index a1eb5103..8525312d 100644 --- a/src/widgets/ColorThemeListView.h +++ b/src/widgets/ColorThemeListView.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index c641b8b0..4f49739a 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -32,16 +32,16 @@ Dashboard::~Dashboard() {} void Dashboard::updateContents() { - QJsonDocument docu = Core()->getFileInfo(); - QJsonObject item = docu.object()["core"].toObject(); - QJsonObject item2 = docu.object()["bin"].toObject(); + CutterJson docu = Core()->getFileInfo(); + CutterJson item = docu["core"]; + CutterJson item2 = docu["bin"]; setPlainText(this->ui->fileEdit, item["file"].toString()); setPlainText(this->ui->formatEdit, item["format"].toString()); setPlainText(this->ui->modeEdit, item["mode"].toString()); setPlainText(this->ui->typeEdit, item["type"].toString()); - setPlainText(this->ui->sizeEdit, qhelpers::formatBytecount(item["size"].toDouble())); - setPlainText(this->ui->fdEdit, QString::number(item["fd"].toDouble())); + setPlainText(this->ui->sizeEdit, qhelpers::formatBytecount(item["size"].toUt64())); + setPlainText(this->ui->fdEdit, QString::number(item["fd"].toUt64())); setPlainText(this->ui->archEdit, item2["arch"].toString()); setPlainText(this->ui->langEdit, item2["lang"].toString().toUpper()); @@ -52,7 +52,7 @@ void Dashboard::updateContents() setPlainText(this->ui->endianEdit, item2["endian"].toString()); setPlainText(this->ui->compilationDateEdit, item2["compiled"].toString()); setPlainText(this->ui->compilerEdit, item2["compiler"].toString()); - setPlainText(this->ui->bitsEdit, QString::number(item2["bits"].toDouble())); + setPlainText(this->ui->bitsEdit, QString::number(item2["bits"].toUt64())); if (!item2["relro"].toString().isEmpty()) { QString relro = item2["relro"].toString().section(QLatin1Char(' '), 0, 0); @@ -62,7 +62,7 @@ void Dashboard::updateContents() setPlainText(this->ui->relroEdit, "N/A"); } - setPlainText(this->ui->baddrEdit, RzAddressString(item2["baddr"].toVariant().toULongLong())); + setPlainText(this->ui->baddrEdit, RzAddressString(item2["baddr"].toRVA())); // set booleans setBool(this->ui->vaEdit, item2, "va"); @@ -110,16 +110,16 @@ void Dashboard::updateContents() hashesLayout->addRow(new QLabel(label), hashLineEdit); } - QJsonObject analinfo = Core()->cmdj("aaij").object(); - setPlainText(ui->functionsLineEdit, QString::number(analinfo["fcns"].toInt())); - setPlainText(ui->xRefsLineEdit, QString::number(analinfo["xrefs"].toInt())); - setPlainText(ui->callsLineEdit, QString::number(analinfo["calls"].toInt())); - setPlainText(ui->stringsLineEdit, QString::number(analinfo["strings"].toInt())); - setPlainText(ui->symbolsLineEdit, QString::number(analinfo["symbols"].toInt())); - setPlainText(ui->importsLineEdit, QString::number(analinfo["imports"].toInt())); - setPlainText(ui->coverageLineEdit, QString::number(analinfo["covrage"].toInt()) + " bytes"); - setPlainText(ui->codeSizeLineEdit, QString::number(analinfo["codesz"].toInt()) + " bytes"); - setPlainText(ui->percentageLineEdit, QString::number(analinfo["percent"].toInt()) + "%"); + CutterJson analinfo = Core()->cmdj("aaij"); + setPlainText(ui->functionsLineEdit, QString::number(analinfo["fcns"].toSt64())); + setPlainText(ui->xRefsLineEdit, QString::number(analinfo["xrefs"].toSt64())); + setPlainText(ui->callsLineEdit, QString::number(analinfo["calls"].toSt64())); + setPlainText(ui->stringsLineEdit, QString::number(analinfo["strings"].toSt64())); + setPlainText(ui->symbolsLineEdit, QString::number(analinfo["symbols"].toSt64())); + setPlainText(ui->importsLineEdit, QString::number(analinfo["imports"].toSt64())); + setPlainText(ui->coverageLineEdit, QString::number(analinfo["covrage"].toSt64()) + " bytes"); + setPlainText(ui->codeSizeLineEdit, QString::number(analinfo["codesz"].toSt64()) + " bytes"); + setPlainText(ui->percentageLineEdit, QString::number(analinfo["percent"].toSt64()) + "%"); QStringList libs = Core()->cmdList("il"); if (!libs.isEmpty()) { @@ -155,10 +155,10 @@ void Dashboard::updateContents() QStringList stats = Core()->getStats(); // Check if signature info and version info available - if (Core()->getSignatureInfo().isEmpty()) { + if (!Core()->getSignatureInfo().size()) { ui->certificateButton->setEnabled(false); } - if (Core()->getFileVersionInfo().isEmpty()) { + if (!Core()->getFileVersionInfo().size()) { ui->versioninfoButton->setEnabled(false); } } @@ -173,8 +173,7 @@ void Dashboard::on_certificateButton_clicked() viewDialog = new QDialog(this); view = new CutterTreeView(viewDialog); model = new JsonModel(); - QJsonDocument qjsonCertificatesDoc = Core()->getSignatureInfo(); - qstrCertificates = qjsonCertificatesDoc.toJson(QJsonDocument::Compact); + qstrCertificates = Core()->getSignatureInfo().toJson(); } if (!viewDialog->isVisible()) { std::string strCertificates = qstrCertificates.toUtf8().constData(); @@ -230,9 +229,9 @@ void Dashboard::setPlainText(QLineEdit *textBox, const QString &text) * @param textBox * @param isTrue */ -void Dashboard::setBool(QLineEdit *textBox, const QJsonObject &jsonObject, const QString &key) +void Dashboard::setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key) { - if (jsonObject.contains(key)) { + if (jsonObject[key].valid()) { if (jsonObject[key].toBool()) { setPlainText(textBox, tr("True")); } else { diff --git a/src/widgets/Dashboard.h b/src/widgets/Dashboard.h index 45e578f6..61a2c677 100644 --- a/src/widgets/Dashboard.h +++ b/src/widgets/Dashboard.h @@ -3,6 +3,7 @@ #include #include +#include "core/Cutter.h" #include "CutterDockWidget.h" QT_BEGIN_NAMESPACE @@ -32,7 +33,7 @@ private slots: private: std::unique_ptr ui; void setPlainText(QLineEdit *textBox, const QString &text); - void setBool(QLineEdit *textBox, const QJsonObject &jsonObject, const QString &key); + void setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key); QWidget *hashesWidget = nullptr; }; diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index e4bb05b8..09dacdd2 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -182,12 +182,11 @@ void DisassemblerGraphView::loadCurrentGraph() .set("asm.lines", false) .set("asm.lines.fcn", false); - QJsonArray functions; + CutterJson functions; RzAnalysisFunction *fcn = Core()->functionIn(seekable->getOffset()); if (fcn) { currentFcnAddr = fcn->addr; - QJsonDocument functionsDoc = Core()->cmdj("agJ " + RzAddressString(fcn->addr)); - functions = functionsDoc.array(); + functions = Core()->cmdj("agJ " + RzAddressString(fcn->addr)); } disassembly_blocks.clear(); @@ -198,7 +197,7 @@ void DisassemblerGraphView::loadCurrentGraph() highlight_token = nullptr; } - emptyGraph = functions.isEmpty(); + emptyGraph = !functions.size(); if (emptyGraph) { // If there's no function to print, just add a message if (!emptyText) { @@ -215,8 +214,7 @@ void DisassemblerGraphView::loadCurrentGraph() // Refresh global "empty graph" variable so other widget know there is nothing to show here Core()->setGraphEmpty(emptyGraph); - QJsonValue funcRef = functions.first(); - QJsonObject func = funcRef.toObject(); + CutterJson func = functions.first(); windowTitle = tr("Graph"); QString funcName = func["name"].toString().trimmed(); @@ -227,15 +225,14 @@ void DisassemblerGraphView::loadCurrentGraph() } emit nameChanged(windowTitle); - RVA entry = func["offset"].toVariant().toULongLong(); + RVA entry = func["offset"].toRVA(); setEntry(entry); - for (const QJsonValueRef &value : func["blocks"].toArray()) { - QJsonObject block = value.toObject(); - RVA block_entry = block["offset"].toVariant().toULongLong(); - RVA block_size = block["size"].toVariant().toULongLong(); - RVA block_fail = block["fail"].toVariant().toULongLong(); - RVA block_jump = block["jump"].toVariant().toULongLong(); + for (CutterJson block : func["blocks"]) { + RVA block_entry = block["offset"].toRVA(); + RVA block_size = block["size"].toRVA(); + RVA block_fail = block["fail"].toRVA(); + RVA block_jump = block["jump"].toRVA(); DisassemblyBlock db; GraphBlock gb; @@ -259,30 +256,29 @@ void DisassemblerGraphView::loadCurrentGraph() gb.edges.emplace_back(block_jump); } - QJsonObject switchOp = block["switchop"].toObject(); - if (!switchOp.isEmpty()) { - QJsonArray caseArray = switchOp["cases"].toArray(); - for (QJsonValue caseOpValue : caseArray) { - QJsonObject caseOp = caseOpValue.toObject(); - bool ok; - RVA caseJump = caseOp["jump"].toVariant().toULongLong(&ok); - if (!ok) { + CutterJson switchOp = block["switchop"]; + if (switchOp.size()) { + for (CutterJson caseOp : switchOp["cases"]) { + RVA caseJump = caseOp["jump"].toRVA(); + if (caseJump == RVA_INVALID) { continue; } gb.edges.emplace_back(caseJump); } } - QJsonArray opArray = block["ops"].toArray(); - for (int opIndex = 0; opIndex < opArray.size(); opIndex++) { - QJsonObject op = opArray[opIndex].toObject(); + CutterJson opArray = block["ops"]; + CutterJson::iterator iterator = opArray.begin(); + while (iterator != opArray.end()) { + CutterJson op = *iterator; Instr i; - i.addr = op["offset"].toVariant().toULongLong(); + i.addr = op["offset"].toUt64(); - if (opIndex < opArray.size() - 1) { + ++iterator; + + if (iterator != opArray.end()) { // get instruction size from distance to next instruction ... - RVA nextOffset = - opArray[opIndex + 1].toObject()["offset"].toVariant().toULongLong(); + RVA nextOffset = (*iterator)["offset"].toRVA(); i.size = nextOffset - i.addr; } else { // or to the end of the block. @@ -314,7 +310,7 @@ void DisassemblerGraphView::loadCurrentGraph() } cleanupEdges(blocks); - if (!func["blocks"].toArray().isEmpty()) { + if (func["blocks"].size()) { computeGraphPlacement(); } } diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index f77bae3d..ab92ecd9 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -562,7 +562,7 @@ void FunctionsWidget::refreshTree() importAddresses.insert(import.plt); } - mainAdress = (ut64)Core()->cmdj("iMj").object()["vaddr"].toInt(); + mainAdress = (ut64)Core()->cmdj("iMj")["vaddr"].toUt64(); functionModel->updateCurrentIndex(); functionModel->endResetModel(); diff --git a/src/widgets/ProcessesWidget.cpp b/src/widgets/ProcessesWidget.cpp index 28a1e335..b8e12435 100644 --- a/src/widgets/ProcessesWidget.cpp +++ b/src/widgets/ProcessesWidget.cpp @@ -106,14 +106,12 @@ QString ProcessesWidget::translateStatus(QString status) void ProcessesWidget::setProcessesGrid() { - QJsonArray processesValues = Core()->getChildProcesses(DEBUGGED_PID).array(); int i = 0; QFont font; - for (const QJsonValue &value : processesValues) { - QJsonObject processesItem = value.toObject(); - int pid = processesItem["pid"].toVariant().toInt(); - int uid = processesItem["uid"].toVariant().toInt(); + for (CutterJson processesItem : Core()->getChildProcesses(DEBUGGED_PID)) { + st64 pid = processesItem["pid"].toSt64(); + st64 uid = processesItem["uid"].toSt64(); QString status = translateStatus(processesItem["status"].toString()); QString path = processesItem["path"].toString(); bool current = processesItem["current"].toBool(); @@ -162,10 +160,9 @@ void ProcessesWidget::onActivated(const QModelIndex &index) // 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. - QJsonArray processesValues = Core()->getChildProcesses(DEBUGGED_PID).array(); - for (QJsonValue value : processesValues) { - QString status = value.toObject()["status"].toString(); - if (pid == value.toObject()["pid"].toInt()) { + for (CutterJson value : Core()->getChildProcesses(DEBUGGED_PID)) { + QString status = value["status"].toString(); + if (pid == value["pid"].toSt64()) { if (QString(QChar(RZ_DBG_PROC_ZOMBIE)) == status || QString(QChar(RZ_DBG_PROC_DEAD)) == status) { QMessageBox msgBox; diff --git a/src/widgets/RegisterRefsWidget.cpp b/src/widgets/RegisterRefsWidget.cpp index adfd67af..d0cfb4dd 100644 --- a/src/widgets/RegisterRefsWidget.cpp +++ b/src/widgets/RegisterRefsWidget.cpp @@ -184,14 +184,13 @@ void RegisterRefsWidget::refreshRegisterRef() registerRefModel->beginResetModel(); - QList regRefs = Core()->getRegisterRefs(); registerRefs.clear(); - for (const QJsonObject ® : regRefs) { + for (const RegisterRef ® : Core()->getRegisterRefs()) { RegisterRefDescription desc; - desc.value = RzAddressString(reg["value"].toVariant().toULongLong()); - desc.reg = reg["name"].toVariant().toString(); - desc.refDesc = Core()->formatRefDesc(reg["ref"].toObject()); + desc.value = RzAddressString(reg.value); + desc.reg = reg.name; + desc.refDesc = Core()->formatRefDesc(reg.ref); registerRefs.push_back(desc); } diff --git a/src/widgets/RizinGraphWidget.cpp b/src/widgets/RizinGraphWidget.cpp index a0b88e15..346cf012 100644 --- a/src/widgets/RizinGraphWidget.cpp +++ b/src/widgets/RizinGraphWidget.cpp @@ -96,12 +96,11 @@ void GenericRizinGraphView::loadCurrentGraph() return; } - QJsonDocument functionsDoc = Core()->cmdj(QString("%1j").arg(graphCommand)); - auto nodes = functionsDoc.object()["nodes"].toArray(); + CutterJson functionsDoc = Core()->cmdj(QString("%1j").arg(graphCommand)); + auto nodes = functionsDoc["nodes"]; - for (const QJsonValueRef &value : nodes) { - QJsonObject block = value.toObject(); - uint64_t id = block["id"].toVariant().toULongLong(); + for (CutterJson block : nodes) { + uint64_t id = block["id"].toUt64(); QString content; QString title = block["title"].toString(); @@ -112,11 +111,11 @@ void GenericRizinGraphView::loadCurrentGraph() content = title + body; } - auto edges = block["out_nodes"].toArray(); + auto edges = block["out_nodes"]; GraphLayout::GraphBlock layoutBlock; layoutBlock.entry = id; for (auto edge : edges) { - auto targetId = edge.toVariant().toULongLong(); + auto targetId = edge.toUt64(); layoutBlock.edges.emplace_back(targetId); } diff --git a/src/widgets/StackWidget.cpp b/src/widgets/StackWidget.cpp index fd68db29..d673f8b1 100644 --- a/src/widgets/StackWidget.cpp +++ b/src/widgets/StackWidget.cpp @@ -145,16 +145,16 @@ StackModel::StackModel(QObject *parent) : QAbstractTableModel(parent) {} void StackModel::reload() { - QList stackItems = Core()->getStack(); + QList stackItems = Core()->getStack(); beginResetModel(); values.clear(); - for (const QJsonObject &stackItem : stackItems) { + for (const AddrRefs &stackItem : stackItems) { Item item; - item.offset = stackItem["addr"].toVariant().toULongLong(); - item.value = RzAddressString(stackItem["value"].toVariant().toULongLong()); - item.refDesc = Core()->formatRefDesc(stackItem["ref"].toObject()); + item.offset = stackItem.addr; + item.value = RzAddressString(stackItem.value); + item.refDesc = Core()->formatRefDesc(*stackItem.ref); values.push_back(item); } diff --git a/src/widgets/ThreadsWidget.cpp b/src/widgets/ThreadsWidget.cpp index b650e7a6..6cdde089 100644 --- a/src/widgets/ThreadsWidget.cpp +++ b/src/widgets/ThreadsWidget.cpp @@ -104,13 +104,11 @@ QString ThreadsWidget::translateStatus(QString status) void ThreadsWidget::setThreadsGrid() { - QJsonArray threadsValues = Core()->getProcessThreads(DEBUGGED_PID).array(); int i = 0; QFont font; - for (const QJsonValue &value : threadsValues) { - QJsonObject threadsItem = value.toObject(); - int pid = threadsItem["pid"].toVariant().toInt(); + for (CutterJson threadsItem : Core()->getProcessThreads(DEBUGGED_PID)) { + st64 pid = threadsItem["pid"].toSt64(); QString status = translateStatus(threadsItem["status"].toString()); QString path = threadsItem["path"].toString(); bool current = threadsItem["current"].toBool(); @@ -152,9 +150,8 @@ void ThreadsWidget::onActivated(const QModelIndex &index) // 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. - QJsonArray threadsValues = Core()->getProcessThreads(DEBUGGED_PID).array(); - for (QJsonValue value : threadsValues) { - if (tid == value.toObject()["pid"].toInt()) { + for (CutterJson value : Core()->getProcessThreads(DEBUGGED_PID)) { + if (tid == value["pid"].toSt64()) { Core()->setCurrentDebugThread(tid); break; } From b0c2dea7728c972ea4e81f90a2c683c86c815a40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 14 Mar 2022 10:09:35 +0100 Subject: [PATCH 21/94] Remove unused stats query (#2903) The views showing this info have been removed in the past, so it was unused. This also fixes some errors with latest rizin where zero-argument f does not exist anymore (it's now fl). --- src/core/Cutter.cpp | 26 -------------------------- src/core/Cutter.h | 1 - src/widgets/Dashboard.cpp | 3 --- 3 files changed, 30 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index bb0b661a..d5db389b 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2653,32 +2653,6 @@ QList CutterCore::getMemoryMap() return ret; } -QStringList CutterCore::getStats() -{ - QStringList stats; - cmdRaw("fs functions"); - - // The cmd coomand is frequently used in this function because - // cmdRaw would not work with grep - stats << cmd("f~?").trimmed(); - - QString imps = cmd("ii~?").trimmed(); - stats << imps; - - cmdRaw("fs symbols"); - stats << cmd("f~?").trimmed(); - cmdRaw("fs strings"); - stats << cmd("f~?").trimmed(); - cmdRaw("fs relocs"); - stats << cmd("f~?").trimmed(); - cmdRaw("fs sections"); - stats << cmd("f~?").trimmed(); - cmdRaw("fs *"); - stats << cmd("f~?").trimmed(); - - return stats; -} - void CutterCore::setGraphEmpty(bool empty) { emptyGraph = empty; diff --git a/src/core/Cutter.h b/src/core/Cutter.h index c1e21e50..249da7ce 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -559,7 +559,6 @@ public: CutterJson getFileInfo(); CutterJson getSignatureInfo(); CutterJson getFileVersionInfo(); - QStringList getStats(); void setGraphEmpty(bool empty); bool isGraphEmpty(); diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 4f49739a..c0d0cf87 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -151,9 +151,6 @@ void Dashboard::updateContents() QSpacerItem *spacer = new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding); ui->verticalLayout_2->addSpacerItem(spacer); - // Get stats for the graphs - QStringList stats = Core()->getStats(); - // Check if signature info and version info available if (!Core()->getSignatureInfo().size()) { ui->certificateButton->setEnabled(false); From f26f04b5fec94f9c7a88c6aa99ead5d6e68d24cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 14 Mar 2022 09:49:52 +0100 Subject: [PATCH 22/94] Replace usage of wcj by C API --- src/common/IOModesController.cpp | 10 +++------- src/core/CutterCommon.h | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/common/IOModesController.cpp b/src/common/IOModesController.cpp index 4fa29502..88378c10 100644 --- a/src/common/IOModesController.cpp +++ b/src/common/IOModesController.cpp @@ -77,16 +77,12 @@ bool IOModesController::prepareForWriting() bool IOModesController::allChangesComitted() { - // Get a list of available write changes - CutterJson changes = Core()->cmdj("wcj"); - - // Check if there is a change which isn't written to the file - for (CutterJson changeObject : changes) { - if (!changeObject["written"].toBool()) { + RzCoreLocked core(Core()); + for (auto c : CutterPVector(&core->io->cache)) { + if (!c->written) { return false; } } - return true; } diff --git a/src/core/CutterCommon.h b/src/core/CutterCommon.h index 3cbc1941..6d6f7e7a 100644 --- a/src/core/CutterCommon.h +++ b/src/core/CutterCommon.h @@ -25,6 +25,32 @@ (char *)it != (char *)(vec)->a + ((vec)->len * (vec)->elem_size); \ it = (type *)((char *)it + (vec)->elem_size)) +template class CutterPVector +{ +private: + const RzPVector * const vec; + +public: + class iterator : public std::iterator + { + private: + T **p; + + public: + iterator(T **p) : p(p) {} + iterator(const iterator &o) : p(o.p) {} + iterator &operator++() { p++; return *this; } + iterator operator++(int) { iterator tmp(*this); operator++(); return tmp; } + bool operator==(const iterator &rhs) const {return p == rhs.p;} + bool operator!=(const iterator &rhs) const {return p != rhs.p;} + T *operator*() { return *p; } + }; + + CutterPVector(const RzPVector *vec) : vec(vec) {} + iterator begin() const { return iterator(reinterpret_cast(vec->v.a)); } + iterator end() const { return iterator(reinterpret_cast(vec->v.a) + vec->v.len); } +}; + // Global information for Cutter #define APPNAME "Cutter" From 9d2404b486ae89a109335d0cfadfa1b1fd390503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 14 Mar 2022 10:01:48 +0100 Subject: [PATCH 23/94] Rewrite isWriteModeEnabled() with API This also introduces a slight behavioral change: Previously, only the core file with the "raised" io desc was checked, which is RzIO.desc. But that member is deprecated for good reasons, so now we just check if there is any core file whose primary fd has write enabled. --- src/core/Cutter.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index d5db389b..b0731590 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -4042,12 +4042,18 @@ void CutterCore::setWriteMode(bool enabled) bool CutterCore::isWriteModeEnabled() { - for (CutterJson v : cmdj("oj")) { - if (v["raised"].toBool()) { - return v["writable"].toBool(); + CORE_LOCK(); + RzListIter *it; + RzCoreFile *cf; + CutterRzListForeach (core->files, it, RzCoreFile, cf) { + RzIODesc *desc = rz_io_desc_get(core->io, cf->fd); + if (!desc) { + continue; + } + if (desc->perm & RZ_PERM_W) { + return true; } } - return false; } From b884fe5f74ddb5c856c8d35ff42716aa548b0710 Mon Sep 17 00:00:00 2001 From: yossizap Date: Tue, 15 Mar 2022 10:58:09 +0000 Subject: [PATCH 24/94] Update rizin submodule (#2900) This is also a partial fix for #2897 --- src/core/Cutter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index b0731590..43edba36 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -737,7 +737,7 @@ QString CutterCore::getInstructionOpcode(RVA addr) void CutterCore::editInstruction(RVA addr, const QString &inst) { CORE_LOCK(); - rz_core_write_assembly(core, addr, inst.trimmed().toStdString().c_str(), false, false); + rz_core_write_assembly(core, addr, inst.trimmed().toStdString().c_str()); emit instructionChanged(addr); } From 7119017eae3089efaa27bc10952539c1ad60181f Mon Sep 17 00:00:00 2001 From: alexthesys Date: Thu, 2 Dec 2021 12:35:10 +0300 Subject: [PATCH 25/94] Hexeditor: add option to write hex bytes --- src/widgets/HexWidget.cpp | 41 ++++++++++++++++++++++++++++++++++++++- src/widgets/HexWidget.h | 1 + 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 784528a9..a3e0ae46 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -147,7 +147,11 @@ HexWidget::HexWidget(QWidget *parent) connect(actionWrite64, &QAction::triggered, this, &HexWidget::w_write64); actionsWriteString.append(actionWrite64); - actionsWriteOther.reserve(4); + actionsWriteOther.reserve(5); + QAction *actionWriteBytes = new QAction(tr("Write hex bytes"), this); + connect(actionWriteBytes, &QAction::triggered, this, &HexWidget::w_writeBytes); + actionsWriteOther.append(actionWriteBytes); + QAction *actionWriteZeros = new QAction(tr("Write zeros"), this); connect(actionWriteZeros, &QAction::triggered, this, &HexWidget::w_writeZeros); actionsWriteOther.append(actionWriteZeros); @@ -730,6 +734,41 @@ void HexWidget::w_increaseDecrease() refresh(); } +void HexWidget::w_writeBytes() +{ + if (!ioModesController.prepareForWriting()) { + return; + } + bool ok = false; + + int size = INT_MAX; + if (!selection.isEmpty() && selection.size() <= INT_MAX) { + size = static_cast(selection.size()); + } + + QInputDialog d; + d.setInputMode(QInputDialog::InputMode::TextInput); + QByteArray bytes = d.getText(this, tr("Write hex bytes"), tr("Hex byte string:"), + QLineEdit::Normal, "", &ok) + .toUtf8(); + const int offset = bytes.startsWith("\\x") ? 2 : 0; + const int incr = offset + 2; + const int bytes_size = qMin(bytes.size() / incr, size); + if (ok && bytes_size) { + uint8_t *buf = (uint8_t *)malloc(static_cast(bytes_size)); + if (!buf) { + return; + } + for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { + buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); + } + RzCoreLocked core(Core()); + rz_core_write_at(core, getLocationAddress(), buf, bytes_size); + free(buf); + refresh(); + } +} + void HexWidget::w_writeZeros() { if (!ioModesController.prepareForWriting()) { diff --git a/src/widgets/HexWidget.h b/src/widgets/HexWidget.h index 1489ef85..5a6a15f0 100644 --- a/src/widgets/HexWidget.h +++ b/src/widgets/HexWidget.h @@ -315,6 +315,7 @@ private slots: // Write command slots void w_writeString(); void w_increaseDecrease(); + void w_writeBytes(); void w_writeZeros(); void w_write64(); void w_writeRandom(); From 21ab0e2a9ef66a9215279af1372c021010eb13ff Mon Sep 17 00:00:00 2001 From: alexthesys Date: Tue, 7 Dec 2021 11:57:05 +0300 Subject: [PATCH 26/94] Convert if-block to early return --- src/widgets/HexWidget.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index a3e0ae46..334176be 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -754,19 +754,20 @@ void HexWidget::w_writeBytes() const int offset = bytes.startsWith("\\x") ? 2 : 0; const int incr = offset + 2; const int bytes_size = qMin(bytes.size() / incr, size); - if (ok && bytes_size) { - uint8_t *buf = (uint8_t *)malloc(static_cast(bytes_size)); - if (!buf) { - return; - } - for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { - buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); - } - RzCoreLocked core(Core()); - rz_core_write_at(core, getLocationAddress(), buf, bytes_size); - free(buf); - refresh(); + if (!ok || !bytes_size) { + return; } + uint8_t *buf = (uint8_t *)malloc(static_cast(bytes_size)); + if (!buf) { + return; + } + for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { + buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); + } + RzCoreLocked core(Core()); + rz_core_write_at(core, getLocationAddress(), buf, bytes_size); + free(buf); + refresh(); } void HexWidget::w_writeZeros() From 8ace08b6e00865852f4a7546f371fb103c848e55 Mon Sep 17 00:00:00 2001 From: SR_team Date: Mon, 28 Mar 2022 15:12:09 +0300 Subject: [PATCH 27/94] Update includes compat with KF5.92 on some distributions (#2912) With KF5.92 headers KSyntaxHighlighting/{header}.h copied to KSyntaxHighlighting/ksyntaxhighlighting/{header}.h. Headers KSyntaxHighlighting/{Header} now include ksyntaxhighlighting/{header}.h instead of {header}.h. Than on some distros like ArchLinux headers KSyntaxHighlighting/{header}.h removed, because it copies of KSyntaxHighlighting/ksyntaxhighlighting/{header}.h and because KSyntaxHighlighting/{Header} now include ksyntaxhighlighting/{header}.h. --- src/common/Configuration.cpp | 6 +++--- src/common/SyntaxHighlighter.cpp | 2 +- src/common/SyntaxHighlighter.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index cc8690b4..0a73eb34 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -7,9 +7,9 @@ #include #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING -# include -# include -# include +# include +# include +# include #endif #include "common/ColorThemeWorker.h" diff --git a/src/common/SyntaxHighlighter.cpp b/src/common/SyntaxHighlighter.cpp index 64a2038e..b15afc63 100644 --- a/src/common/SyntaxHighlighter.cpp +++ b/src/common/SyntaxHighlighter.cpp @@ -5,7 +5,7 @@ # include "Configuration.h" -# include +# include SyntaxHighlighter::SyntaxHighlighter(QTextDocument *document) : KSyntaxHighlighting::SyntaxHighlighter(document) diff --git a/src/common/SyntaxHighlighter.h b/src/common/SyntaxHighlighter.h index b9e88970..7846c227 100644 --- a/src/common/SyntaxHighlighter.h +++ b/src/common/SyntaxHighlighter.h @@ -10,7 +10,7 @@ #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING -# include +# include class SyntaxHighlighter : public KSyntaxHighlighting::SyntaxHighlighter { From 76c1ab894e27b4132e71764a9712001dbcc83ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 28 Mar 2022 19:21:25 +0200 Subject: [PATCH 28/94] Add missing overrides to SectionsModel --- src/widgets/SectionsWidget.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/widgets/SectionsWidget.h b/src/widgets/SectionsWidget.h index 9a7e9638..8fcdafcf 100644 --- a/src/widgets/SectionsWidget.h +++ b/src/widgets/SectionsWidget.h @@ -51,11 +51,11 @@ public: SectionsModel(QList *sections, QObject *parent = nullptr); - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex &index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; RVA address(const QModelIndex &index) const override; QString name(const QModelIndex &index) const override; From b6288ecbf6f50fbfc78972f1d129874609a3330c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 28 Mar 2022 19:32:33 +0200 Subject: [PATCH 29/94] Fix a strange comparison --- src/widgets/HexWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 334176be..39d9d2e2 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -726,7 +726,7 @@ void HexWidget::w_increaseDecrease() } int64_t value = (int64_t)d.getValue(); uint8_t sz = d.getNBytes(); - if (!d.getMode() == IncrementDecrementDialog::Increase) { + if (d.getMode() == IncrementDecrementDialog::Decrease) { value *= -1; } RzCoreLocked core(Core()); From 0dc4e94647858b2357cb7f893f710f1b8a7809a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 28 Mar 2022 20:19:58 +0200 Subject: [PATCH 30/94] Remove unnessecary str in setToData() (Fix #2901) --- src/core/Cutter.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 43edba36..85924471 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -834,11 +834,9 @@ void CutterCore::setToData(RVA addr, int size, int repeat) } CORE_LOCK(); - rz_meta_del(core->analysis, RZ_META_TYPE_DATA, addr, 1); RVA address = addr; - auto name = QString(size).toStdString(); for (int i = 0; i < repeat; ++i, address += size) { - rz_meta_set(core->analysis, RZ_META_TYPE_DATA, address, size, name.c_str()); + rz_meta_set(core->analysis, RZ_META_TYPE_DATA, address, size, nullptr); } emit instructionChanged(addr); } From d65ad504caac26893067d8b5507c6dcd14e91e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 28 Mar 2022 20:43:47 +0200 Subject: [PATCH 31/94] Rewrite getVariables with API This also avoids annoying "ERROR: No function found in ..." beging printed by afvj when right-clicking anywhere outside a function. The heuristics in functionIn() also have been adjusted to prefer the function that has its entrypoint at the given addr, if there is any. --- src/core/Cutter.cpp | 54 ++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 85924471..5c9ba1d0 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1221,10 +1221,13 @@ QString CutterCore::disassembleSingleInstruction(RVA addr) RzAnalysisFunction *CutterCore::functionIn(ut64 addr) { CORE_LOCK(); + RzAnalysisFunction *fcn = rz_analysis_get_function_at(core->analysis, addr); + if (fcn) { + return fcn; + } RzList *fcns = rz_analysis_get_functions_in(core->analysis, addr); - RzAnalysisFunction *fcn = !rz_list_empty(fcns) - ? reinterpret_cast(rz_list_first(fcns)) - : nullptr; + fcn = !rz_list_empty(fcns) ? reinterpret_cast(rz_list_first(fcns)) + : nullptr; rz_list_free(fcns); return fcn; } @@ -1750,22 +1753,37 @@ CutterJson CutterCore::getRegisterValues() QList CutterCore::getVariables(RVA at) { QList ret; - CutterJson varsObject = cmdj(QString("afvj @ %1").arg(at)); - - auto addVars = [&](VariableDescription::RefType refType, const CutterJson &array) { - for (CutterJson varObject : array) { - VariableDescription desc; - desc.refType = refType; - desc.name = varObject["name"].toString(); - desc.type = varObject["type"].toString(); - ret << desc; + CORE_LOCK(); + RzAnalysisFunction *fcn = functionIn(at); + if (!fcn) { + return ret; + } + for (auto var : CutterPVector(&fcn->vars)) { + VariableDescription desc; + switch (var->kind) { + case RZ_ANALYSIS_VAR_KIND_BPV: + desc.refType = VariableDescription::RefType::BP; + break; + case RZ_ANALYSIS_VAR_KIND_SPV: + desc.refType = VariableDescription::RefType::SP; + break; + case RZ_ANALYSIS_VAR_KIND_REG: + default: + desc.refType = VariableDescription::RefType::Reg; + break; } - }; - - addVars(VariableDescription::RefType::SP, varsObject["sp"]); - addVars(VariableDescription::RefType::BP, varsObject["bp"]); - addVars(VariableDescription::RefType::Reg, varsObject["reg"]); - + if (!var->name || !var->type) { + continue; + } + desc.name = QString::fromUtf8(var->name); + char *tn = rz_type_as_string(core->analysis->typedb, var->type); + if (!tn) { + continue; + } + desc.type = QString::fromUtf8(tn); + rz_mem_free(tn); + ret.push_back(desc); + } return ret; } From 085f5024b917e1e5e80ede1909f830e0900b256a Mon Sep 17 00:00:00 2001 From: Nirmal Manoj Date: Mon, 4 Oct 2021 18:07:49 +0530 Subject: [PATCH 32/94] Use RzAnnotatedCode from JSDec (pddA) --- src/common/Decompiler.cpp | 102 ++++++++++++++++++++++++++------------ src/core/CutterJson.h | 1 + 2 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index 94892075..7653f1d2 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -10,6 +10,75 @@ 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_new(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(); @@ -31,7 +100,7 @@ void JSDecDecompiler::decompileAt(RVA addr) if (task) { return; } - task = new RizinCmdTask("pddj @ " + QString::number(addr)); + task = new RizinCmdTask("pddA @ " + QString::number(addr)); connect(task, &RizinCmdTask::finished, this, [this]() { CutterJson json = task->getResultJson(); delete task; @@ -40,36 +109,7 @@ void JSDecDecompiler::decompileAt(RVA addr) emit finished(Decompiler::makeWarning(tr("Failed to parse JSON from jsdec"))); return; } - RzAnnotatedCode *code = rz_annotated_code_new(nullptr); - QString codeString = ""; - for (auto line : json["log"]) { - if (line.type() != RZ_JSON_STRING) { - continue; - } - codeString.append(line.toString() + "\n"); - } - - for (auto lineObject : json["lines"]) { - if (!lineObject.size()) { - continue; - } - RzCodeAnnotation annotationi = {}; - annotationi.start = codeString.length(); - codeString.append(lineObject["str"].toString() + "\n"); - annotationi.end = codeString.length(); - annotationi.type = RZ_CODE_ANNOTATION_TYPE_OFFSET; - annotationi.offset.offset = lineObject["offset"].toUt64(); - rz_annotated_code_add_annotation(code, &annotationi); - } - - for (auto line : json["errors"]) { - if (line.type() != RZ_JSON_STRING) { - continue; - } - codeString.append(line.toString() + "\n"); - } - std::string tmp = codeString.toStdString(); - code->code = strdup(tmp.c_str()); + RzAnnotatedCode *code = parseJsonCode(json); emit finished(code); }); task->startTask(); diff --git a/src/core/CutterJson.h b/src/core/CutterJson.h index 042ca84b..e8dd9819 100644 --- a/src/core/CutterJson.h +++ b/src/core/CutterJson.h @@ -89,6 +89,7 @@ public: size_t size() const { return has_children() ? value->children.count : 0; } RzJsonType type() const { return value ? value->type : RZ_JSON_NULL; } bool valid() const { return value ? true : false; } + const RzJson *lowLevelValue() const { return value; } private: bool has_children() const From 3e168fb76a839e946e12ca57d09eb11a48f1f8f3 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 30 Mar 2022 10:41:37 +0200 Subject: [PATCH 33/94] Fixed formatting (#2917) --- src/dialogs/preferences/AsmOptionsWidget.cpp | 2 +- src/dialogs/preferences/GraphOptionsWidget.cpp | 2 +- src/menus/FlirtContextMenu.h | 3 +-- src/widgets/DecompilerWidget.cpp | 1 - src/widgets/HeapDockWidget.h | 2 +- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/dialogs/preferences/AsmOptionsWidget.cpp b/src/dialogs/preferences/AsmOptionsWidget.cpp index 7004b4b4..08abec50 100644 --- a/src/dialogs/preferences/AsmOptionsWidget.cpp +++ b/src/dialogs/preferences/AsmOptionsWidget.cpp @@ -242,7 +242,7 @@ void AsmOptionsWidget::on_varsubCheckBox_toggled(bool checked) triggerAsmOptionsChanged(); } -void AsmOptionsWidget::on_previewCheckBox_toggled( bool checked ) +void AsmOptionsWidget::on_previewCheckBox_toggled(bool checked) { Config()->setPreviewValue(checked); triggerAsmOptionsChanged(); diff --git a/src/dialogs/preferences/GraphOptionsWidget.cpp b/src/dialogs/preferences/GraphOptionsWidget.cpp index 7a896174..13bb0922 100644 --- a/src/dialogs/preferences/GraphOptionsWidget.cpp +++ b/src/dialogs/preferences/GraphOptionsWidget.cpp @@ -85,7 +85,7 @@ void GraphOptionsWidget::on_graphOffsetCheckBox_toggled(bool checked) triggerOptionsChanged(); } -void GraphOptionsWidget::on_graphPreviewCheckBox_toggled( bool checked ) +void GraphOptionsWidget::on_graphPreviewCheckBox_toggled(bool checked) { Config()->setGraphPreview(checked); triggerOptionsChanged(); diff --git a/src/menus/FlirtContextMenu.h b/src/menus/FlirtContextMenu.h index 6cf12cae..ec57c7e0 100644 --- a/src/menus/FlirtContextMenu.h +++ b/src/menus/FlirtContextMenu.h @@ -33,8 +33,7 @@ protected: void setHasTarget(bool hasTarget); QAction *actionApplySignature; QAction *actionCopyLine; - QAction *actionShowContents; FlirtDescription entry; }; -#endif // FlirtCONTEXTMENU_H +#endif // FLIRT_CONTEXTMENU_H diff --git a/src/widgets/DecompilerWidget.cpp b/src/widgets/DecompilerWidget.cpp index a6dd58af..9414f118 100644 --- a/src/widgets/DecompilerWidget.cpp +++ b/src/widgets/DecompilerWidget.cpp @@ -551,7 +551,6 @@ void DecompilerWidget::highlightBreakpoints() for (RVA &bp : functionBreakpoints) { if (bp == RVA_INVALID) { continue; - ; } cursor = getCursorForAddress(bp); if (!cursor.isNull()) { diff --git a/src/widgets/HeapDockWidget.h b/src/widgets/HeapDockWidget.h index 4e507c39..a8a324cb 100644 --- a/src/widgets/HeapDockWidget.h +++ b/src/widgets/HeapDockWidget.h @@ -22,7 +22,7 @@ private: enum Allocator { Glibc = 0, AllocatorCount }; Ui::HeapDockWidget *ui; MainWindow *main; - QWidget* currentHeapWidget = nullptr; + QWidget *currentHeapWidget = nullptr; }; #endif // HEAPDOCKWIDGET_H From 6629d579c68ca4e0313b1c5e45bcad7763460374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 30 Mar 2022 10:57:10 +0200 Subject: [PATCH 34/94] Update windows CI to 2019 --- .github/workflows/ccpp.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 39b07cbe..64a3f7f6 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -19,13 +19,13 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, ubuntu-18.04, macos-latest, windows-2016] + os: [ubuntu-20.04, ubuntu-18.04, macos-latest, windows-2019] python-version: [3.7.x] system-deps: [false] cc-override: [default] cxx-override: [default] include: - - os: windows-2016 + - os: windows-2019 package: true - os: ubuntu-18.04 # ensure that Cutter can be built at least in basic config on Ubuntu 18.04 using sytem libraries python-version: 3.6.x @@ -213,7 +213,7 @@ jobs: set ARCH=x64 set CUTTER_DEPS=%CD%\cutter-deps set PATH=%CD%\cutter-deps\qt\bin;%PATH% - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 call scripts\prepare_breakpad.bat cd mkdir build From ae2ad5d50cc19b57a30243b1396cd3937b317dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 31 Mar 2022 12:49:37 +0200 Subject: [PATCH 35/94] Extend cmake config files with deps, version, etc. (#2916) This improves how the installed CutterConfig.cmake can be used for native plugin development: * Transitive dependencies are resolved automatically * Version file is included * Cutter_USER_PLUGINDIR is set to a path that plugins can use as a default install destination src/plugins/sample-cpp/CMakeLists.txt is an example for how to use it. Rizin was also updated to prevent an error with multiple `find_package()` calls. --- CMakeLists.txt | 8 +++--- cmake/BundledRizin.cmake | 3 ++- cmake/CutterConfig.cmake | 1 - cmake/CutterConfig.cmake.in | 22 +++++++++++++++ cmake/CutterInstallDirs.cmake | 2 +- src/CMakeLists.txt | 27 ++++++++++++------- src/Main.cpp | 2 ++ src/core/MainWindow.h | 2 +- src/plugins/sample-cpp/CMakeLists.txt | 13 +++++++++ src/plugins/sample-cpp/CutterSamplePlugin.cpp | 16 +++++++---- src/plugins/sample-cpp/CutterSamplePlugin.h | 8 +++--- src/plugins/sample-cpp/CutterSamplePlugin.pro | 10 ------- src/widgets/ConsoleWidget.cpp | 1 + 13 files changed, 78 insertions(+), 37 deletions(-) delete mode 100644 cmake/CutterConfig.cmake create mode 100644 cmake/CutterConfig.cmake.in create mode 100644 src/plugins/sample-cpp/CMakeLists.txt delete mode 100644 src/plugins/sample-cpp/CutterSamplePlugin.pro diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c0f30b5..991368ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,16 +57,14 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) +set(QT_COMPONENTS Core Widgets Gui Svg Network) if (CUTTER_QT6) set(QT_PREFIX Qt6) + list(APPEND QT_COMPONENTS Core5Compat SvgWidgets OpenGLWidgets) else() set(QT_PREFIX Qt5) endif() - -find_package(${QT_PREFIX} REQUIRED COMPONENTS Core Widgets Gui Svg Network) -if (CUTTER_QT6) - find_package(${QT_PREFIX} REQUIRED COMPONENTS Core5Compat SvgWidgets OpenGLWidgets) -endif() +find_package(${QT_PREFIX} REQUIRED COMPONENTS ${QT_COMPONENTS}) if(CUTTER_ENABLE_PYTHON) find_package(PythonInterp REQUIRED) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 10f582b4..4dcf4301 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -57,7 +57,8 @@ target_link_libraries(Rizin INTERFACE ${RZ_LIBS}) target_include_directories(Rizin INTERFACE "$" - "$") + "$" + "$") install(TARGETS Rizin EXPORT CutterTargets) if (WIN32) diff --git a/cmake/CutterConfig.cmake b/cmake/CutterConfig.cmake deleted file mode 100644 index 926efecf..00000000 --- a/cmake/CutterConfig.cmake +++ /dev/null @@ -1 +0,0 @@ -include("${CMAKE_CURRENT_LIST_DIR}/CutterTargets.cmake") \ No newline at end of file diff --git a/cmake/CutterConfig.cmake.in b/cmake/CutterConfig.cmake.in new file mode 100644 index 00000000..cfab9542 --- /dev/null +++ b/cmake/CutterConfig.cmake.in @@ -0,0 +1,22 @@ +@PACKAGE_INIT@ + +set(Cutter_RIZIN_BUNDLED @CUTTER_USE_BUNDLED_RIZIN@) + +include(CMakeFindDependencyMacro) +find_dependency(@QT_PREFIX@ COMPONENTS @QT_COMPONENTS@) +find_dependency(Rizin COMPONENTS Core) + +# Make a best guess for a user location from where plugins can be loaded. +# This can be used in Cutter plugins like +# set(CUTTER_INSTALL_PLUGDIR "${Cutter_USER_PLUGINDIR}" CACHE STRING "Directory to install Cutter plugin into") +# see https://doc.qt.io/qt-5/qstandardpaths.html under AppDataLocation +if(APPLE) + set(Cutter_USER_PLUGINDIR "$ENV{HOME}/Library/Application Support/rizin/cutter/plugins/native") +elseif(WIN32) + file(TO_CMAKE_PATH "$ENV{APPDATA}" Cutter_USER_PLUGINDIR) + set(Cutter_USER_PLUGINDIR "${Cutter_USER_PLUGINDIR}/rizin/cutter/plugins/native") +else() + set(Cutter_USER_PLUGINDIR "$ENV{HOME}/.local/share/rizin/cutter/plugins/native") +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/CutterTargets.cmake") diff --git a/cmake/CutterInstallDirs.cmake b/cmake/CutterInstallDirs.cmake index f7133abc..31873c69 100644 --- a/cmake/CutterInstallDirs.cmake +++ b/cmake/CutterInstallDirs.cmake @@ -20,4 +20,4 @@ else() include(GNUInstallDirs) set(CUTTER_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}/${CUTTER_DIR_NAME}" CACHE PATH "Resource installation directory") endif() -set(ConfigPackageLocation "${CMAKE_INSTALL_LIBDIR}/Cutter" CACHE PATH "Cmake file install location") +set(CUTTER_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/Cutter" CACHE PATH "CMake file install location") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4601cb96..4fb5d4d4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -558,17 +558,26 @@ install(TARGETS Cutter EXPORT CutterTargets RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION "." # needs to be tested - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Devel -) + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Devel) install(EXPORT CutterTargets NAMESPACE Cutter:: - DESTINATION "${ConfigPackageLocation}" + DESTINATION "${CUTTER_INSTALL_CONFIGDIR}" COMPONENT Devel) +include(CMakePackageConfigHelpers) +configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/CutterConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/CutterConfig.cmake" + INSTALL_DESTINATION "${CUTTER_INSTALL_CONFIGDIR}" + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/CutterConfigVersion.cmake" + VERSION "${CUTTER_VERSION_FULL}" + COMPATIBILITY AnyNewerVersion) install(FILES - ../cmake/CutterConfig.cmake - DESTINATION ${ConfigPackageLocation} - COMPONENT Devel -) + "${CMAKE_CURRENT_BINARY_DIR}/CutterConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/CutterConfigVersion.cmake" + DESTINATION ${CUTTER_INSTALL_CONFIGDIR} + COMPONENT Devel) foreach(_file ${HEADER_FILES}) # Can't use target PUBLIC_HEADER option for installing due to multiple directories get_filename_component(_header_dir "${_file}" DIRECTORY) @@ -576,8 +585,8 @@ foreach(_file ${HEADER_FILES}) endforeach() if(UNIX AND NOT APPLE) - install (FILES "img/cutter.svg" - DESTINATION "share/icons/hicolor/scalable/apps/") + install(FILES "img/cutter.svg" + DESTINATION "share/icons/hicolor/scalable/apps/") install(FILES "re.rizin.cutter.desktop" DESTINATION "share/applications" COMPONENT Devel) diff --git a/src/Main.cpp b/src/Main.cpp index b0cef4a0..8cb4347f 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -14,6 +14,8 @@ * @brief Attempt to connect to a parent console and configure outputs. */ #ifdef Q_OS_WIN +#include + static void connectToConsole() { BOOL attached = AttachConsole(ATTACH_PARENT_PROCESS); diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index dd878062..ce1bdceb 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -60,7 +60,7 @@ namespace Ui { class MainWindow; } -class MainWindow : public QMainWindow +class CUTTER_EXPORT MainWindow : public QMainWindow { Q_OBJECT diff --git a/src/plugins/sample-cpp/CMakeLists.txt b/src/plugins/sample-cpp/CMakeLists.txt new file mode 100644 index 00000000..93e140f5 --- /dev/null +++ b/src/plugins/sample-cpp/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.12) +project(cutter-sample-plugin) + +find_package(Cutter REQUIRED) +set(CUTTER_INSTALL_PLUGDIR "${Cutter_USER_PLUGINDIR}" CACHE STRING "Directory to install Cutter plugin into") + +set(CMAKE_AUTOMOC ON) + +add_library(sample_plugin MODULE + CutterSamplePlugin.h + CutterSamplePlugin.cpp) +target_link_libraries(sample_plugin PRIVATE Cutter::Cutter) +install(TARGETS sample_plugin DESTINATION "${CUTTER_INSTALL_PLUGDIR}") diff --git a/src/plugins/sample-cpp/CutterSamplePlugin.cpp b/src/plugins/sample-cpp/CutterSamplePlugin.cpp index 98c95f70..bb2264b3 100644 --- a/src/plugins/sample-cpp/CutterSamplePlugin.cpp +++ b/src/plugins/sample-cpp/CutterSamplePlugin.cpp @@ -4,9 +4,10 @@ #include #include "CutterSamplePlugin.h" -#include "common/TempConfig.h" -#include "common/Configuration.h" -#include "MainWindow.h" + +#include +#include +#include void CutterSamplePlugin::setupPlugin() {} @@ -56,9 +57,14 @@ void CutterSamplePluginWidget::on_seekChanged(RVA addr) void CutterSamplePluginWidget::on_buttonClicked() { - QString fortune = Core()->cmd("fo").replace("\n", ""); + RzCoreLocked core(Core()); + char *fortune = rz_core_fortune_get_random(core); + if (!fortune) { + return; + } // cmdRaw can be used to execute single raw commands // this is especially good for user-controlled input - QString res = Core()->cmdRaw("?E " + fortune); + QString res = Core()->cmdRaw("?E " + QString::fromUtf8(fortune)); text->setText(res); + rz_mem_free(fortune); } diff --git a/src/plugins/sample-cpp/CutterSamplePlugin.h b/src/plugins/sample-cpp/CutterSamplePlugin.h index 45cbaedb..d0497a0c 100644 --- a/src/plugins/sample-cpp/CutterSamplePlugin.h +++ b/src/plugins/sample-cpp/CutterSamplePlugin.h @@ -1,9 +1,9 @@ #ifndef CUTTERSAMPLEPLUGIN_H #define CUTTERSAMPLEPLUGIN_H -#include -#include -#include "CutterPlugin.h" +#include + +#include class CutterSamplePlugin : public QObject, CutterPlugin { @@ -26,7 +26,7 @@ class CutterSamplePluginWidget : public CutterDockWidget Q_OBJECT public: - explicit CutterSamplePluginWidget(MainWindow *main, QAction *action); + explicit CutterSamplePluginWidget(MainWindow *main); private: QLabel *text; diff --git a/src/plugins/sample-cpp/CutterSamplePlugin.pro b/src/plugins/sample-cpp/CutterSamplePlugin.pro deleted file mode 100644 index c65aca87..00000000 --- a/src/plugins/sample-cpp/CutterSamplePlugin.pro +++ /dev/null @@ -1,10 +0,0 @@ -HEADERS += ../CutterSamplePlugin.h ../CutterPlugin.h -INCLUDEPATH += ../ ../../ ../../core ../../widgets -SOURCES += CutterSamplePlugin.cpp - -QMAKE_CXXFLAGS += $$system("pkg-config --cflags rz_core") - -TEMPLATE = lib -CONFIG += plugin -QT += widgets -TARGET = PluginSample diff --git a/src/widgets/ConsoleWidget.cpp b/src/widgets/ConsoleWidget.cpp index db378068..de0e6892 100644 --- a/src/widgets/ConsoleWidget.cpp +++ b/src/widgets/ConsoleWidget.cpp @@ -17,6 +17,7 @@ #include "WidgetShortcuts.h" #ifdef Q_OS_WIN +# include # include # define dup2 _dup2 # define dup _dup From f8744d12c228d91342cc55d0986df7ac86290818 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Thu, 31 Mar 2022 19:34:34 +0200 Subject: [PATCH 36/94] =?UTF-8?q?=E2=80=98memDisp=E2=80=99=20may=20be=20us?= =?UTF-8?q?ed=20uninitialized=20(#2920)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/menus/DisassemblyContextMenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index c2065c9d..15e23f8c 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -489,7 +489,7 @@ void DisassemblyContextMenu::aboutToShowSlot() // Create structure offset menu if it makes sense QString memBaseReg; // Base register - st64 memDisp; // Displacement + st64 memDisp = 0; // Displacement // Loop through both the operands of the instruction for (const CutterJson operand : instObject["opex"]["operands"]) { From 46ea1569d24a75e03fb129ec468811e5faa55989 Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 2 Apr 2022 15:44:42 +0800 Subject: [PATCH 37/94] Convert various debug code to C API (#2913) --- src/common/AnalysisTask.cpp | 4 +- src/core/Cutter.cpp | 213 +++++++++++++++++++-------- src/core/Cutter.h | 39 +++-- src/core/CutterDescriptions.h | 4 +- src/dialogs/EditVariablesDialog.cpp | 3 +- src/menus/DecompilerContextMenu.cpp | 2 +- src/menus/DisassemblyContextMenu.cpp | 2 +- src/widgets/DebugActions.cpp | 2 +- src/widgets/ProcessesWidget.cpp | 36 +++-- src/widgets/ProcessesWidget.h | 2 +- src/widgets/ThreadsWidget.cpp | 18 +-- src/widgets/ThreadsWidget.h | 2 +- 12 files changed, 215 insertions(+), 112 deletions(-) diff --git a/src/common/AnalysisTask.cpp b/src/common/AnalysisTask.cpp index 75e90395..dc4a5094 100644 --- a/src/common/AnalysisTask.cpp +++ b/src/common/AnalysisTask.cpp @@ -79,14 +79,14 @@ void AnalysisTask::runTask() if (!options.shellcode.isNull() && options.shellcode.size() / 2 > 0) { log(tr("Loading shellcode...")); - Core()->cmdRaw("wx " + options.shellcode); + rz_core_write_hexpair(core, core->offset, options.shellcode.toStdString().c_str()); } if (options.endian != InitialOptions::Endianness::Auto) { Core()->setEndianness(options.endian == InitialOptions::Endianness::Big); } - Core()->cmdRaw("fs *"); + rz_flag_space_set(core->flags, "*"); if (!options.script.isNull()) { log(tr("Executing script...")); diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 5c9ba1d0..4721ab4f 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -408,7 +408,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); @@ -417,7 +417,7 @@ bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer } connect(task.data(), &RizinCmdTask::finished, task.data(), [this, task]() { - QString res = task.data()->getResult(); + QString res = qobject_cast(task.data())->getResult(); if (res.contains(QStringLiteral("[ESIL] Stopped execution in an invalid instruction"))) { msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can " @@ -428,7 +428,7 @@ bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer return true; } -bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) +bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) { if (!task.isNull()) { return false; @@ -438,8 +438,28 @@ bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) RVA offset = core->offset; - task = QSharedPointer(new RizinCmdTask(str, true)); - connect(task.data(), &RizinCmdTask::finished, task.data(), [this, offset, task]() { + task = QSharedPointer(new RizinCmdTask(str, true)); + connect(task.data(), &RizinTask::finished, task.data(), [this, offset, task]() { + CORE_LOCK(); + + if (offset != core->offset) { + updateSeek(); + } + }); + + return true; +} + +bool CutterCore::asyncTask(std::function fcn, QSharedPointer &task) +{ + if (!task.isNull()) { + return false; + } + + CORE_LOCK(); + RVA offset = core->offset; + task = QSharedPointer(new RizinFunctionTask(std::move(fcn), true)); + connect(task.data(), &RizinTask::finished, task.data(), [this, offset, task]() { CORE_LOCK(); if (offset != core->offset) { @@ -819,12 +839,23 @@ void CutterCore::removeString(RVA addr) QString CutterCore::getString(RVA addr) { - return cmdRawAt("ps", addr); + CORE_LOCK(); + char *s = (char *)returnAtSeek( + [&]() { + RzStrStringifyOpt opt = { 0 }; + opt.buffer = core->block; + opt.length = core->blocksize; + opt.encoding = rz_str_guess_encoding_from_buffer(core->block, core->blocksize); + return rz_str_stringify_raw_buffer(&opt, NULL); + }, + addr); + return fromOwnedCharPtr(s); } QString CutterCore::getMetaString(RVA addr) { - return cmdRawAt("Cs.", addr); + CORE_LOCK(); + return rz_meta_get_string(core->analysis, RZ_META_TYPE_STRING, addr); } void CutterCore::setToData(RVA addr, int size, int repeat) @@ -1595,16 +1626,6 @@ AddrRefs CutterCore::getAddrRefs(RVA addr, int depth) return refs; } -CutterJson CutterCore::getProcessThreads(int pid) -{ - if (-1 == pid) { - // Return threads list of the currently debugged PID - return cmdj("dptj"); - } else { - return cmdj("dptj " + QString::number(pid)); - } -} - QVector CutterCore::getHeapChunks(RVA arena_addr) { CORE_LOCK(); @@ -1735,16 +1756,6 @@ bool CutterCore::writeHeapChunk(RzHeapChunkSimple *chunk_simple) return rz_heap_write_chunk(core, chunk_simple); } -CutterJson CutterCore::getChildProcesses(int pid) -{ - // Return the currently debugged process and it's children - if (-1 == pid) { - return cmdj("dpj"); - } - // Return the given pid and it's child processes - return cmdj("dpj " + QString::number(pid)); -} - CutterJson CutterCore::getRegisterValues() { return cmdj("drj"); @@ -1831,7 +1842,12 @@ void CutterCore::setRegister(QString regName, QString regValue) void CutterCore::setCurrentDebugThread(int tid) { - if (!asyncCmd("dpt=" + QString::number(tid), debugTask)) { + if (!asyncTask( + [=](RzCore *core) { + rz_debug_select(core->dbg, core->dbg->pid, tid); + return (void *)NULL; + }, + debugTask)) { return; } @@ -1851,7 +1867,14 @@ void CutterCore::setCurrentDebugThread(int tid) void CutterCore::setCurrentDebugProcess(int pid) { - if (!currentlyDebugging || !asyncCmd("dp=" + QString::number(pid), debugTask)) { + if (!currentlyDebugging + || !asyncTask( + [=](RzCore *core) { + rz_debug_select(core->dbg, pid, core->dbg->tid); + core->dbg->main_pid = pid; + return (void *)NULL; + }, + debugTask)) { return; } @@ -1877,7 +1900,12 @@ void CutterCore::startDebug() } currentlyOpenFile = getConfig("file.path"); - if (!asyncCmd("ood", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_file_reopen_debug(core, ""); + return (void *)NULL; + }, + debugTask)) { return; } @@ -1961,7 +1989,15 @@ void CutterCore::attachRemote(const QString &uri) } // connect to a debugger with the given plugin - asyncCmd("e cfg.debug=true; oodf " + uri, debugTask); + if (!asyncTask( + [&](RzCore *core) { + setConfig("cfg.debug", true); + rz_core_file_reopen_remote_debug(core, uri.toStdString().c_str(), 0); + return (void *)NULL; + }, + debugTask)) { + return; + } emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this, uri]() { @@ -2124,7 +2160,12 @@ void CutterCore::continueDebug() return; } } else { - if (!asyncCmd("dc", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_debug_continue(core->dbg); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2151,7 +2192,12 @@ void CutterCore::continueBackDebug() return; } } else { - if (!asyncCmd("dcb", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_debug_continue_back(core->dbg); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2167,22 +2213,26 @@ void CutterCore::continueBackDebug() debugTask->startTask(); } -void CutterCore::continueUntilDebug(QString offset) +void CutterCore::continueUntilDebug(ut64 offset) { if (!currentlyDebugging) { return; } if (currentlyEmulating) { - if (!asyncCmdEsil("aecu " + offset, debugTask)) { + if (!asyncCmdEsil("aecu " + QString::number(offset), debugTask)) { return; } } else { - if (!asyncCmd("dcu " + offset, debugTask)) { + if (!asyncTask( + [=](RzCore *core) { + rz_core_debug_continue_until(core, offset, offset); + return (void *)NULL; + }, + debugTask)) { return; } } - emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { debugTask.clear(); @@ -2190,7 +2240,6 @@ void CutterCore::continueUntilDebug(QString offset) emit refreshCodeViews(); emit debugTaskStateChanged(); }); - debugTask->startTask(); } @@ -2205,7 +2254,12 @@ void CutterCore::continueUntilCall() return; } } else { - if (!asyncCmd("dcc", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_debug_step_one(core, 0); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2259,7 +2313,12 @@ void CutterCore::stepDebug() return; } } else { - if (!asyncCmd("ds", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_debug_step_one(core, 1); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2383,7 +2442,13 @@ void CutterCore::startTraceSession() return; } } else { - if (!asyncCmd("dts+", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + core->dbg->session = rz_debug_session_new(); + rz_debug_add_checkpoint(core->dbg); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2419,7 +2484,13 @@ void CutterCore::stopTraceSession() return; } } else { - if (!asyncCmd("dts-", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_debug_session_free(core->dbg->session); + core->dbg->session = NULL; + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2517,25 +2588,29 @@ void CutterCore::updateBreakpoint(int index, const BreakpointDescription &config void CutterCore::delBreakpoint(RVA addr) { - cmdRaw("db- " + RzAddressString(addr)); + CORE_LOCK(); + rz_bp_del(core->dbg->bp, addr); emit breakpointsChanged(addr); } void CutterCore::delAllBreakpoints() { - cmdRaw("db-*"); + CORE_LOCK(); + rz_bp_del_all(core->dbg->bp); emit refreshCodeViews(); } void CutterCore::enableBreakpoint(RVA addr) { - cmdRaw("dbe " + RzAddressString(addr)); + CORE_LOCK(); + rz_bp_enable(core->dbg->bp, addr, true, 1); emit breakpointsChanged(addr); } void CutterCore::disableBreakpoint(RVA addr) { - cmdRaw("dbd " + RzAddressString(addr)); + CORE_LOCK(); + rz_bp_enable(core->dbg->bp, addr, false, 1); emit breakpointsChanged(addr); } @@ -2631,37 +2706,53 @@ CutterJson CutterCore::getBacktrace() return cmdj("dbtj"); } -QList CutterCore::getAllProcesses() +QList CutterCore::getProcessThreads(int pid = -1) { + CORE_LOCK(); + RzList *list = rz_debug_pids(core->dbg, pid != -1 ? pid : core->dbg->pid); + RzListIter *iter; + RzDebugPid *p; QList ret; - for (CutterJson procObject : cmdj("dplj")) { + CutterRzListForeach (list, iter, RzDebugPid, p) { ProcessDescription proc; - proc.pid = procObject[RJsonKey::pid].toSt64(); - proc.uid = procObject[RJsonKey::uid].toSt64(); - proc.status = procObject[RJsonKey::status].toString(); - proc.path = procObject[RJsonKey::path].toString(); + proc.current = core->dbg->pid == p->pid; + proc.ppid = p->ppid; + proc.pid = p->pid; + proc.uid = p->uid; + proc.status = static_cast(p->status); + proc.path = p->path; ret << proc; } - + rz_list_free(list); return ret; } +QList CutterCore::getAllProcesses() +{ + return getProcessThreads(0); +} + QList CutterCore::getMemoryMap() { + CORE_LOCK(); + RzList *list0 = rz_debug_map_list(core->dbg, false); + RzList *list1 = rz_debug_map_list(core->dbg, true); + rz_list_join(list0, list1); QList ret; - - for (CutterJson memMapObject : cmdj("dmj")) { + RzListIter *it; + RzDebugMap *map; + CutterRzListForeach (list0, it, RzDebugMap, map) { MemoryMapDescription memMap; - memMap.name = memMapObject[RJsonKey::name].toString(); - memMap.fileName = memMapObject[RJsonKey::file].toString(); - memMap.addrStart = memMapObject[RJsonKey::addr].toRVA(); - memMap.addrEnd = memMapObject[RJsonKey::addr_end].toRVA(); - memMap.type = memMapObject[RJsonKey::type].toString(); - memMap.permission = memMapObject[RJsonKey::perm].toString(); + memMap.name = map->name; + memMap.fileName = map->file; + memMap.addrStart = map->addr; + memMap.addrEnd = map->addr_end; + memMap.type = map->user ? "u" : "s"; + memMap.permission = rz_str_rwx_i(map->perm); ret << memMap; } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 249da7ce..4013f39e 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -24,6 +24,7 @@ class CutterCore; class Decompiler; class RizinTask; class RizinCmdTask; +class RizinFunctionTask; class RizinTaskDialog; #include "common/BasicBlockHighlighter.h" @@ -99,12 +100,19 @@ 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) + bool asyncCmd(const char *str, QSharedPointer &task); + bool asyncCmd(const QString &str, QSharedPointer &task) { return asyncCmd(str.toUtf8().constData(), task); } + /** + * @brief send a task to Rizin + * @param fcn the task you want to execute + * @return execute successful? + */ + bool asyncTask(std::function fcn, QSharedPointer &task); + /** * @brief Execute a Rizin command \a cmd. By nature, the API * is executing raw commands, and thus ignores multiple commands and overcome command @@ -148,6 +156,15 @@ public: seekSilent(oldOffset); } + void *returnAtSeek(std::function fn, RVA address) + { + RVA oldOffset = getOffset(); + seekSilent(address); + void *ret = fn(); + seekSilent(oldOffset); + return ret; + } + CutterJson cmdj(const char *str); CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } CutterJson cmdjAt(const char *str, RVA address); @@ -175,8 +192,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) + bool asyncCmdEsil(const char *command, QSharedPointer &task); + bool asyncCmdEsil(const QString &command, QSharedPointer &task) { return asyncCmdEsil(command.toUtf8().constData(), task); } @@ -431,15 +448,9 @@ public: /** * @brief Get a list of a given process's threads * @param pid The pid of the process, -1 for the currently debugged process - * @return JSON object result of dptj + * @return List of ProcessDescription */ - CutterJson getProcessThreads(int pid); - /** - * @brief Get a list of a given process's child processes - * @param pid The pid of the process, -1 for the currently debugged process - * @return JSON object result of dptj - */ - CutterJson getChildProcesses(int pid); + QList getProcessThreads(int pid); CutterJson getBacktrace(); /** * @brief Get a list of heap chunks @@ -493,7 +504,7 @@ public: void continueBackDebug(); void continueUntilCall(); void continueUntilSyscall(); - void continueUntilDebug(QString offset); + void continueUntilDebug(ut64 offset); void stepDebug(); void stepOverDebug(); void stepOutDebug(); @@ -814,7 +825,7 @@ private: bool iocache = false; BasicInstructionHighlighter biHighlighter; - QSharedPointer debugTask; + QSharedPointer debugTask; RizinTaskDialog *debugTaskDialog; QVector getCutterRCFilePaths() const; diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index e28894ee..a56f7186 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -339,9 +339,11 @@ struct BreakpointDescription struct ProcessDescription { + bool current; int pid; int uid; - QString status; + int ppid; + RzDebugPidState status; QString path; }; diff --git a/src/dialogs/EditVariablesDialog.cpp b/src/dialogs/EditVariablesDialog.cpp index 6954814a..1f2139ef 100644 --- a/src/dialogs/EditVariablesDialog.cpp +++ b/src/dialogs/EditVariablesDialog.cpp @@ -14,7 +14,8 @@ EditVariablesDialog::EditVariablesDialog(RVA offset, QString initialVar, QWidget connect(ui->dropdownLocalVars, &QComboBox::currentIndexChanged, this, &EditVariablesDialog::updateFields); - QString fcnName = Core()->cmdRawAt("afn.", offset).trimmed(); + RzAnalysisFunction *f = rz_analysis_get_function_at(Core()->core()->analysis, offset); + QString fcnName = f->name; functionAddress = offset; setWindowTitle(tr("Edit Variables in Function: %1").arg(fcnName)); diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index d36cf0b7..7113ec68 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -519,7 +519,7 @@ void DecompilerContextMenu::actionAdvancedBreakpointTriggered() void DecompilerContextMenu::actionContinueUntilTriggered() { - Core()->continueUntilDebug(RzAddressString(offset)); + Core()->continueUntilDebug(offset); } void DecompilerContextMenu::actionSetPCTriggered() diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 15e23f8c..f39bbd79 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -777,7 +777,7 @@ void DisassemblyContextMenu::on_actionAdvancedBreakpoint_triggered() void DisassemblyContextMenu::on_actionContinueUntil_triggered() { - Core()->continueUntilDebug(RzAddressString(offset)); + Core()->continueUntilDebug(offset); } void DisassemblyContextMenu::on_actionSetPC_triggered() diff --git a/src/widgets/DebugActions.cpp b/src/widgets/DebugActions.cpp index 3ed1b877..68d0362c 100644 --- a/src/widgets/DebugActions.cpp +++ b/src/widgets/DebugActions.cpp @@ -281,7 +281,7 @@ void DebugActions::continueUntilMain() return; } } - Core()->continueUntilDebug(QString::number(main_flag->offset)); + Core()->continueUntilDebug(main_flag->offset); } void DebugActions::attachRemoteDebugger() diff --git a/src/widgets/ProcessesWidget.cpp b/src/widgets/ProcessesWidget.cpp index b8e12435..2a9477f8 100644 --- a/src/widgets/ProcessesWidget.cpp +++ b/src/widgets/ProcessesWidget.cpp @@ -84,9 +84,9 @@ void ProcessesWidget::updateContents() } } -QString ProcessesWidget::translateStatus(QString status) +QString ProcessesWidget::translateStatus(const char status) { - switch (status.toStdString().c_str()[0]) { + switch (status) { case RZ_DBG_PROC_STOP: return "Stopped"; case RZ_DBG_PROC_RUN: @@ -109,12 +109,12 @@ void ProcessesWidget::setProcessesGrid() int i = 0; QFont font; - for (CutterJson processesItem : Core()->getChildProcesses(DEBUGGED_PID)) { - st64 pid = processesItem["pid"].toSt64(); - st64 uid = processesItem["uid"].toSt64(); - QString status = translateStatus(processesItem["status"].toString()); - QString path = processesItem["path"].toString(); - bool current = processesItem["current"].toBool(); + for (const auto &processesItem : Core()->getProcessThreads(DEBUGGED_PID)) { + st64 pid = processesItem.pid; + st64 uid = processesItem.uid; + QString status = translateStatus(processesItem.status); + QString path = processesItem.path; + bool current = processesItem.current; // Use bold font to highlight active thread font.setBold(current); @@ -143,7 +143,6 @@ void ProcessesWidget::setProcessesGrid() modelFilter->setSourceModel(modelProcesses); ui->viewProcesses->resizeColumnsToContents(); - ; } void ProcessesWidget::fontsUpdatedSlot() @@ -157,24 +156,23 @@ void ProcessesWidget::onActivated(const QModelIndex &index) return; int pid = modelFilter->data(index.sibling(index.row(), 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 (CutterJson value : Core()->getChildProcesses(DEBUGGED_PID)) { - QString status = value["status"].toString(); - if (pid == value["pid"].toSt64()) { - if (QString(QChar(RZ_DBG_PROC_ZOMBIE)) == status - || QString(QChar(RZ_DBG_PROC_DEAD)) == status) { - QMessageBox msgBox; + for (const auto &value : Core()->getAllProcesses()) { + if (pid == value.pid) { + QMessageBox msgBox; + switch (value.status) { + case RZ_DBG_PROC_ZOMBIE: + case RZ_DBG_PROC_DEAD: msgBox.setText(tr("Unable to switch to the requested process.")); msgBox.exec(); - } else { + break; + default: Core()->setCurrentDebugProcess(pid); + break; } - break; } } - updateContents(); } diff --git a/src/widgets/ProcessesWidget.h b/src/widgets/ProcessesWidget.h index 80e89007..fcc9db80 100644 --- a/src/widgets/ProcessesWidget.h +++ b/src/widgets/ProcessesWidget.h @@ -41,7 +41,7 @@ private slots: void onActivated(const QModelIndex &index); private: - QString translateStatus(QString status); + QString translateStatus(const char status); std::unique_ptr ui; QStandardItemModel *modelProcesses; ProcessesFilterModel *modelFilter; diff --git a/src/widgets/ThreadsWidget.cpp b/src/widgets/ThreadsWidget.cpp index 6cdde089..d9149108 100644 --- a/src/widgets/ThreadsWidget.cpp +++ b/src/widgets/ThreadsWidget.cpp @@ -82,9 +82,9 @@ void ThreadsWidget::updateContents() } } -QString ThreadsWidget::translateStatus(QString status) +QString ThreadsWidget::translateStatus(const char status) { - switch (status.toStdString().c_str()[0]) { + switch (status) { case RZ_DBG_PROC_STOP: return "Stopped"; case RZ_DBG_PROC_RUN: @@ -107,11 +107,11 @@ void ThreadsWidget::setThreadsGrid() int i = 0; QFont font; - for (CutterJson threadsItem : Core()->getProcessThreads(DEBUGGED_PID)) { - st64 pid = threadsItem["pid"].toSt64(); - QString status = translateStatus(threadsItem["status"].toString()); - QString path = threadsItem["path"].toString(); - bool current = threadsItem["current"].toBool(); + for (const auto &threadsItem : Core()->getProcessThreads(DEBUGGED_PID)) { + st64 pid = threadsItem.pid; + QString status = translateStatus(threadsItem.status); + QString path = threadsItem.path; + bool current = threadsItem.current; // Use bold font to highlight active thread font.setBold(current); QStandardItem *rowPid = new QStandardItem(QString::number(pid)); @@ -150,8 +150,8 @@ void ThreadsWidget::onActivated(const QModelIndex &index) // 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. - for (CutterJson value : Core()->getProcessThreads(DEBUGGED_PID)) { - if (tid == value["pid"].toSt64()) { + for (const auto &value : Core()->getProcessThreads(DEBUGGED_PID)) { + if (tid == value.pid) { Core()->setCurrentDebugThread(tid); break; } diff --git a/src/widgets/ThreadsWidget.h b/src/widgets/ThreadsWidget.h index 8d9c6a0e..259c919d 100644 --- a/src/widgets/ThreadsWidget.h +++ b/src/widgets/ThreadsWidget.h @@ -41,7 +41,7 @@ private slots: void onActivated(const QModelIndex &index); private: - QString translateStatus(QString status); + QString translateStatus(const char status); std::unique_ptr ui; QStandardItemModel *modelThreads; ThreadsFilterModel *modelFilter; From 12721aaa9ef1fd3d58023e4344fc659bfeafc955 Mon Sep 17 00:00:00 2001 From: tcoyvwac <53616399+tcoyvwac@users.noreply.github.com> Date: Sat, 2 Apr 2022 20:29:50 +0200 Subject: [PATCH 38/94] widgets: redundant return-break (#2922) Removed consecutive return-break statements. --- src/widgets/GraphView.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/widgets/GraphView.cpp b/src/widgets/GraphView.cpp index 1cd9b497..95b81348 100644 --- a/src/widgets/GraphView.cpp +++ b/src/widgets/GraphView.cpp @@ -664,13 +664,11 @@ void GraphView::mousePressEvent(QMouseEvent *event) showBlock(blocks[edge.target]); // TODO: Callback to child return; - break; } if (checkPointClicked(end, pos.x(), pos.y(), true)) { showBlock(block); // TODO: Callback to child return; - break; } } } From 5440a0ef5083ee3c29489a904027c307f12c8269 Mon Sep 17 00:00:00 2001 From: Islam Bassuni Date: Sun, 3 Apr 2022 16:50:14 +0200 Subject: [PATCH 39/94] Added report issue button in "About" window (#2908) --- src/dialogs/AboutDialog.cpp | 6 + src/dialogs/AboutDialog.h | 1 + src/dialogs/AboutDialog.ui | 256 +++++++++++++++++++++--------------- 3 files changed, 159 insertions(+), 104 deletions(-) diff --git a/src/dialogs/AboutDialog.cpp b/src/dialogs/AboutDialog.cpp index d332cb29..d60a5566 100644 --- a/src/dialogs/AboutDialog.cpp +++ b/src/dialogs/AboutDialog.cpp @@ -5,6 +5,8 @@ #include "ui_AboutDialog.h" #include "RizinPluginsDialog.h" #include "common/Configuration.h" +#include "common/BugReporting.h" + #include #include @@ -85,6 +87,10 @@ void AboutDialog::on_showPluginsButton_clicked() RizinPluginsDialog dialog(this); dialog.exec(); } +void AboutDialog::on_Issue_clicked() +{ + openIssue(); +} void AboutDialog::on_checkForUpdatesButton_clicked() { diff --git a/src/dialogs/AboutDialog.h b/src/dialogs/AboutDialog.h index 2d3ae342..c21baea5 100644 --- a/src/dialogs/AboutDialog.h +++ b/src/dialogs/AboutDialog.h @@ -21,6 +21,7 @@ private slots: void on_buttonBox_rejected(); void on_showVersionButton_clicked(); void on_showPluginsButton_clicked(); + void on_Issue_clicked(); /** * @fn AboutDialog::on_checkForUpdatesButton_clicked() diff --git a/src/dialogs/AboutDialog.ui b/src/dialogs/AboutDialog.ui index e6023527..13742312 100644 --- a/src/dialogs/AboutDialog.ui +++ b/src/dialogs/AboutDialog.ui @@ -6,8 +6,8 @@ 0 0 - 570 - 393 + 935 + 554 @@ -15,6 +15,121 @@ + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + QDialogButtonBox::Close + + + + + + + 5 + + + 15 + + + + + + 0 + 0 + + + + Check for updates on start + + + + + + + + 0 + 0 + + + + Check for updates + + + + + + + + 0 + 0 + + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">Cutter is a free and open-source reverse engineering platform powered by Rizin</span></p><p align="center"><span style=" font-size:11pt;">Read more on </span><a href="https://cutter.re"><span style=" text-decoration: underline; color:#2980b9;">cutter.re</span></a></p></body></html> + + + + + + + <html><head/><body><p><span style=" font-size:28pt; font-weight:600;">Cutter</span></p></body></html> + + + + + + + + 0 + 0 + + + + Report an issue + + + + + + + + 0 + 0 + + + + Show Rizin plugin information + + + + + + + + 0 + 0 + + + + Show version information + + + + + + @@ -42,111 +157,40 @@ - - - - QDialogButtonBox::Close + + + + true + + + + 0 + 0 + + + + + 96 + 96 + + + + + 96 + 96 + + + + Qt::NoFocus + + + Qt::DefaultContextMenu + + + 0 - - - - 5 - - - 15 - - - - - - 0 - 0 - - - - Check for updates on start - - - - - - - - 0 - 0 - - - - Check for updates - - - - - - - - 0 - 0 - - - - Show version information - - - - - - - - 0 - 0 - - - - Show Rizin plugin information - - - - - - - - 0 - 0 - - - - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">Cutter is a free and open-source reverse engineering platform powered by Rizin</span></p><p align="center"><span style=" font-size:11pt;">Read more on </span><a href="https://cutter.re"><span style=" text-decoration: underline; color:#2980b9;">cutter.re</span></a></p></body></html> - - - - - - - <html><head/><body><p><span style=" font-size:28pt; font-weight:600;">Cutter</span></p></body></html> - - - - - - - - 96 - 96 - - - - - 96 - 96 - - - - - - @@ -159,4 +203,8 @@ + + signal1() + on_reportIssueButton_clicked() + From cbda0ad27e9738d7ab4fb801730937070e54aa90 Mon Sep 17 00:00:00 2001 From: rgnter <32541639+rgnter@users.noreply.github.com> Date: Sun, 3 Apr 2022 20:28:45 +0200 Subject: [PATCH 40/94] Fixed a segfault during debugging with gdbserver (#2830) Fixes issue #2829 --- src/widgets/DebugActions.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/widgets/DebugActions.cpp b/src/widgets/DebugActions.cpp index 68d0362c..8745cb86 100644 --- a/src/widgets/DebugActions.cpp +++ b/src/widgets/DebugActions.cpp @@ -297,6 +297,10 @@ void DebugActions::attachRemoteDebugger() void DebugActions::onAttachedRemoteDebugger(bool successfully) { + // TODO(#2829): Investigate why this is happening + if (remoteDialog == nullptr) + return; + if (!successfully) { QMessageBox msgBox; msgBox.setText(tr("Error connecting.")); From a48399f73b7ad932af88d63fb9956da8d1c6bcb7 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Tue, 5 Apr 2022 11:35:45 +0200 Subject: [PATCH 41/94] Adds support for RZ_SIGDB path and fixes sorting on some columns (#2923) --- src/core/Cutter.cpp | 35 +++++++++++++++++++++++++---------- src/widgets/FlirtWidget.cpp | 4 ++-- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 4721ab4f..b11c5ebf 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3054,19 +3054,10 @@ QList CutterCore::getAllHeaders() return ret; } -QList CutterCore::getSignaturesDB() +static void sigdb_insert_element_into_qlist(RzList *list, QList &sigdb) { - CORE_LOCK(); - QList sigdb; - const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path"); - if (RZ_STR_ISEMPTY(sigdb_path)) { - return sigdb; - } - - RzList *list = rz_sign_sigdb_load_database(sigdb_path, true); void *ptr = NULL; RzListIter *iter = NULL; - rz_list_foreach(list, iter, ptr) { RzSigDBEntry *sig = static_cast(ptr); @@ -3081,6 +3072,30 @@ QList CutterCore::getSignaturesDB() flirt.arch_bits = QString::number(sig->arch_bits); sigdb << flirt; } + rz_list_free(list); +} + +QList CutterCore::getSignaturesDB() +{ + CORE_LOCK(); + QList sigdb; + RzList *list = nullptr; + + char *system_sigdb = rz_path_system(RZ_SIGDB); + if (RZ_STR_ISNOTEMPTY(system_sigdb) && rz_file_is_directory(system_sigdb)) { + list = rz_sign_sigdb_load_database(system_sigdb, true); + sigdb_insert_element_into_qlist(list, sigdb); + } + free(system_sigdb); + + const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path"); + if (RZ_STR_ISEMPTY(sigdb_path)) { + return sigdb; + } + + list = rz_sign_sigdb_load_database(sigdb_path, true); + sigdb_insert_element_into_qlist(list, sigdb); + return sigdb; } diff --git a/src/widgets/FlirtWidget.cpp b/src/widgets/FlirtWidget.cpp index 61d43d87..874a63e3 100644 --- a/src/widgets/FlirtWidget.cpp +++ b/src/widgets/FlirtWidget.cpp @@ -107,9 +107,9 @@ bool FlirtProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right case FlirtModel::ArchNameColumn: return leftEntry.arch_name < rightEntry.arch_name; case FlirtModel::ArchBitsColumn: - return leftEntry.arch_bits < rightEntry.arch_bits; + return leftEntry.arch_bits.toULongLong() < rightEntry.arch_bits.toULongLong(); case FlirtModel::NumModulesColumn: - return leftEntry.n_modules < rightEntry.n_modules; + return leftEntry.n_modules.toULongLong() < rightEntry.n_modules.toULongLong(); case FlirtModel::NameColumn: return leftEntry.base_name < rightEntry.base_name; case FlirtModel::DetailsColumn: From 7d42a5c7e662f8f13854bf7604f3fb5c2c7b0325 Mon Sep 17 00:00:00 2001 From: billow Date: Sun, 10 Apr 2022 11:43:42 +0800 Subject: [PATCH 42/94] Convert from Rizin commands to the API for `w` (#2926) --- src/common/IOModesController.cpp | 2 +- src/core/Cutter.cpp | 13 +++++++++++-- src/core/Cutter.h | 4 ++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/common/IOModesController.cpp b/src/common/IOModesController.cpp index 88378c10..26f0801f 100644 --- a/src/common/IOModesController.cpp +++ b/src/common/IOModesController.cpp @@ -100,7 +100,7 @@ bool IOModesController::askCommitUnsavedChanges() if (ret == QMessageBox::Save) { Core()->commitWriteCache(); } else if (ret == QMessageBox::Discard) { - Core()->cmdRaw("wcr"); + Core()->resetWriteCache(); emit Core()->refreshCodeViews(); } else if (ret == QMessageBox::Cancel) { return false; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index b11c5ebf..bd801a0e 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -4126,18 +4126,27 @@ bool CutterCore::isIOCacheEnabled() const void CutterCore::commitWriteCache() { + CORE_LOCK(); // Temporarily disable cache mode TempConfig tempConfig; tempConfig.set("io.cache", false); if (!isWriteModeEnabled()) { cmdRaw("oo+"); - cmdRaw("wci"); + rz_io_cache_commit(core->io, 0, UT64_MAX); + rz_core_block_read(core); cmdRaw("oo"); } else { - cmdRaw("wci"); + rz_io_cache_commit(core->io, 0, UT64_MAX); + rz_core_block_read(core); } } +void CutterCore::resetWriteCache() +{ + CORE_LOCK(); + rz_io_cache_reset(core->io, core->io->cached); +} + // Enable or disable write-mode. Avoid unecessary changes if not need. void CutterCore::setWriteMode(bool enabled) { diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 4013f39e..f36796a4 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -721,6 +721,10 @@ public: * @brief Commit write cache to the file on disk. */ void commitWriteCache(); + /** + * @brief Reset write cache. + */ + void resetWriteCache(); /** * @brief Enable or disable Write mode. When the file is opened in write mode, any changes to it From 6fca09d313c2ebf13d158b9b7f95c4e74020f10b Mon Sep 17 00:00:00 2001 From: Islam Bassuni Date: Wed, 13 Apr 2022 06:50:57 +0200 Subject: [PATCH 43/94] Created adding comments option inside Hexdump. (#2927) --- src/widgets/HexWidget.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/widgets/HexWidget.h | 5 +++++ 2 files changed, 43 insertions(+) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 39d9d2e2..b02a0e12 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -2,6 +2,7 @@ #include "Cutter.h" #include "Configuration.h" #include "dialogs/WriteCommandsDialogs.h" +#include "dialogs/CommentsDialog.h" #include #include @@ -120,6 +121,19 @@ HexWidget::HexWidget(QWidget *parent) connect(actionCopyAddress, &QAction::triggered, this, &HexWidget::copyAddress); addAction(actionCopyAddress); + // Add comment option + actionComment = new QAction(tr("Add Comment"), this); + actionComment->setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut); + actionComment->setShortcut(Qt::Key_Semicolon); + connect(actionComment, &QAction::triggered, this, &HexWidget::on_actionAddComment_triggered); + addAction(actionComment); + + // delete comment option + actionDeleteComment = new QAction(tr("Delete Comment"), this); + actionDeleteComment->setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut); + connect(actionDeleteComment, &QAction::triggered, this, &HexWidget::on_actionDeleteComment_triggered); + addAction(actionDeleteComment); + actionSelectRange = new QAction(tr("Select range"), this); connect(actionSelectRange, &QAction::triggered, this, [this]() { rangeDialog.open(cursor.address); }); @@ -620,6 +634,16 @@ void HexWidget::contextMenuEvent(QContextMenuEvent *event) actionCopyAddress->setDisabled(disable); }; + QString comment = Core()->getCommentAt(cursor.address); + + if (comment.isNull() || comment.isEmpty()) { + actionDeleteComment->setVisible(false); + actionComment->setText(tr("Add Comment")); + } else { + actionDeleteComment->setVisible(true); + actionComment->setText(tr("Edit Comment")); + } + QMenu *menu = new QMenu(); QMenu *sizeMenu = menu->addMenu(tr("Item size:")); sizeMenu->addActions(actionsItemSize); @@ -689,6 +713,20 @@ void HexWidget::copyAddress() clipboard->setText(RzAddressString(addr)); } +//slot for add comment action +void HexWidget::on_actionAddComment_triggered() +{ + uint64_t addr = cursor.address; + CommentsDialog::addOrEditComment(addr, this); +} + +//slot for deleting comment action +void HexWidget::on_actionDeleteComment_triggered() +{ + uint64_t addr = cursor.address; + Core()->delComment(addr); +} + void HexWidget::onRangeDialogAccepted() { if (rangeDialog.empty()) { diff --git a/src/widgets/HexWidget.h b/src/widgets/HexWidget.h index 5a6a15f0..b46f0574 100644 --- a/src/widgets/HexWidget.h +++ b/src/widgets/HexWidget.h @@ -311,6 +311,8 @@ private slots: void copy(); void copyAddress(); void onRangeDialogAccepted(); + void on_actionAddComment_triggered(); + void on_actionDeleteComment_triggered(); // Write command slots void w_writeString(); @@ -475,6 +477,9 @@ private: QAction *actionHexPairs; QAction *actionCopy; QAction *actionCopyAddress; + QAction *actionComment; + QAction *actionDeleteComment; + QAction *actionSetFlag; QAction *actionSelectRange; QList actionsWriteString; QList actionsWriteOther; From 34b1f01a8681a6f65ec2f548bd1fb844a6627c0b Mon Sep 17 00:00:00 2001 From: staz <74452129+alyanser@users.noreply.github.com> Date: Sat, 7 May 2022 16:59:46 +0500 Subject: [PATCH 44/94] Fixed an invalid index check (#2937) --- src/widgets/GlibcHeapWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/GlibcHeapWidget.cpp b/src/widgets/GlibcHeapWidget.cpp index 47278fa6..a06f6a77 100644 --- a/src/widgets/GlibcHeapWidget.cpp +++ b/src/widgets/GlibcHeapWidget.cpp @@ -71,7 +71,7 @@ void GlibcHeapWidget::updateArenas() } // check if arenas reduced or invalid index and restore the previously selected arena - if (arenaSelectorView->count() < currentIndex || currentIndex == -1) { + if (arenaSelectorView->count() <= currentIndex || currentIndex == -1) { currentIndex = 0; } arenaSelectorView->setCurrentIndex(currentIndex); From e022e444743ad7a26baa5c0e2257dc632f562f48 Mon Sep 17 00:00:00 2001 From: Jakob Zielinski <60484807+jsz6389@users.noreply.github.com> Date: Sat, 7 May 2022 08:01:10 -0400 Subject: [PATCH 45/94] Search button disabled and button text changed while search is occurring (#2928) --- src/widgets/SearchWidget.cpp | 17 +++++++++++++++++ src/widgets/SearchWidget.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/src/widgets/SearchWidget.cpp b/src/widgets/SearchWidget.cpp index ae3c419b..fc5e5d43 100644 --- a/src/widgets/SearchWidget.cpp +++ b/src/widgets/SearchWidget.cpp @@ -195,14 +195,18 @@ SearchWidget::SearchWidget(MainWindow *main) : CutterDockWidget(main), ui(new Ui QShortcut *enter_press = new QShortcut(QKeySequence(Qt::Key_Return), this); connect(enter_press, &QShortcut::activated, this, [this]() { + disableSearch(); refreshSearch(); checkSearchResultEmpty(); + enableSearch(); }); enter_press->setContext(Qt::WidgetWithChildrenShortcut); connect(ui->searchButton, &QAbstractButton::clicked, this, [this]() { + disableSearch(); refreshSearch(); checkSearchResultEmpty(); + enableSearch(); }); connect(ui->searchspaceCombo, @@ -310,3 +314,16 @@ void SearchWidget::updatePlaceholderText(int index) ui->filterLineEdit->setPlaceholderText("jmp rax"); } } + +void SearchWidget::disableSearch() +{ + ui->searchButton->setEnabled(false); + ui->searchButton->setText("Searching..."); + qApp->processEvents(); +} + +void SearchWidget::enableSearch() +{ + ui->searchButton->setEnabled(true); + ui->searchButton->setText("Search"); +} diff --git a/src/widgets/SearchWidget.h b/src/widgets/SearchWidget.h index 8da8b25b..08a9fc14 100644 --- a/src/widgets/SearchWidget.h +++ b/src/widgets/SearchWidget.h @@ -77,6 +77,8 @@ private: void refreshSearch(); void checkSearchResultEmpty(); + void enableSearch(); + void disableSearch(); void setScrollMode(); void updatePlaceholderText(int index); }; From 6345604172fc49dedbf48cd029a7e74aba634141 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sun, 8 May 2022 14:17:52 +0200 Subject: [PATCH 46/94] Replace afcf with C api. (#2940) --- src/core/Cutter.cpp | 11 ++++++++++- src/widgets/GraphWidget.cpp | 8 +++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index bd801a0e..8759c04c 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1266,7 +1266,16 @@ RzAnalysisFunction *CutterCore::functionIn(ut64 addr) RzAnalysisFunction *CutterCore::functionAt(ut64 addr) { CORE_LOCK(); - return rz_analysis_get_function_at(core->analysis, addr); + RzAnalysisFunction *fcn = rz_analysis_get_function_at(core->analysis, addr); + if (fcn) { + return fcn; + } + RzList *list = rz_analysis_get_functions_in(core->analysis, addr); + if (rz_list_length(list) == 1) { + fcn = static_cast(rz_list_first(list)); + } + rz_list_free(list); + return fcn; } /** diff --git a/src/widgets/GraphWidget.cpp b/src/widgets/GraphWidget.cpp index 046babe0..f4b2b43e 100644 --- a/src/widgets/GraphWidget.cpp +++ b/src/widgets/GraphWidget.cpp @@ -84,11 +84,13 @@ QString GraphWidget::getWidgetType() void GraphWidget::prepareHeader() { - QString afcf = Core()->cmdRawAt("afcf", seekable->getOffset()).trimmed(); - if (afcf.isEmpty()) { + RzAnalysisFunction *f = Core()->functionAt(seekable->getOffset()); + char *str = f ? rz_analysis_function_get_signature(f) : nullptr; + if (!str) { header->hide(); return; } header->show(); - header->setText(afcf); + header->setText(str); + free(str); } From 493ff68365e08a1f2490d22ec5d34e0607fcd72f Mon Sep 17 00:00:00 2001 From: Paul I Date: Thu, 12 May 2022 17:55:55 +0300 Subject: [PATCH 47/94] Revert changes in functionAt (#2941) --- src/core/Cutter.cpp | 11 +---------- src/widgets/GraphWidget.cpp | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 8759c04c..bd801a0e 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1266,16 +1266,7 @@ RzAnalysisFunction *CutterCore::functionIn(ut64 addr) RzAnalysisFunction *CutterCore::functionAt(ut64 addr) { CORE_LOCK(); - RzAnalysisFunction *fcn = rz_analysis_get_function_at(core->analysis, addr); - if (fcn) { - return fcn; - } - RzList *list = rz_analysis_get_functions_in(core->analysis, addr); - if (rz_list_length(list) == 1) { - fcn = static_cast(rz_list_first(list)); - } - rz_list_free(list); - return fcn; + return rz_analysis_get_function_at(core->analysis, addr); } /** diff --git a/src/widgets/GraphWidget.cpp b/src/widgets/GraphWidget.cpp index f4b2b43e..beec0644 100644 --- a/src/widgets/GraphWidget.cpp +++ b/src/widgets/GraphWidget.cpp @@ -84,7 +84,7 @@ QString GraphWidget::getWidgetType() void GraphWidget::prepareHeader() { - RzAnalysisFunction *f = Core()->functionAt(seekable->getOffset()); + RzAnalysisFunction *f = Core()->functionIn(seekable->getOffset()); char *str = f ? rz_analysis_function_get_signature(f) : nullptr; if (!str) { header->hide(); From 6e07f4d97ac4b3a27d47d3557d790754467a997d Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 14 May 2022 17:03:59 +0800 Subject: [PATCH 48/94] convert to api for `aoj` --- src/core/Cutter.cpp | 38 +++++++++++++++++++++++++--- src/menus/DisassemblyContextMenu.cpp | 34 +++++++++++++++++-------- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index bd801a0e..bcb9b728 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -746,12 +746,32 @@ void CutterCore::delFlag(const QString &name) QString CutterCore::getInstructionBytes(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::bytes].toString(); + auto ret = (char *)Core()->returnAtSeek( + [&]() { + CORE_LOCK(); + RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); + auto *ab = static_cast(rz_pvector_head(vec)); + char *str = strdup(ab->bytes); + rz_pvector_free(vec); + return str; + }, + addr); + return fromOwnedCharPtr(ret); } QString CutterCore::getInstructionOpcode(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::opcode].toString(); + auto ret = (char *)Core()->returnAtSeek( + [&]() { + CORE_LOCK(); + RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); + auto *ab = static_cast(rz_pvector_head(vec)); + char *str = strdup(ab->opcode); + rz_pvector_free(vec); + return str; + }, + addr); + return fromOwnedCharPtr(ret); } void CutterCore::editInstruction(RVA addr, const QString &inst) @@ -1358,7 +1378,19 @@ CutterJson CutterCore::getRegistersInfo() RVA CutterCore::getOffsetJump(RVA addr) { - return cmdj("aoj @" + QString::number(addr)).first().toRVA(); + auto rva = (RVA *)Core()->returnAtSeek( + [&]() { + CORE_LOCK(); + RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); + auto *ab = static_cast(rz_pvector_head(vec)); + RVA *rva = new RVA(ab->op->jump); + rz_pvector_free(vec); + return rva; + }, + addr); + RVA ret = *rva; + delete rva; + return ret; } QList CutterCore::getDecompilers() diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index f39bbd79..2f6c6d66 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -482,8 +482,15 @@ void DisassemblyContextMenu::setupRenaming() void DisassemblyContextMenu::aboutToShowSlot() { // check if set immediate base menu makes sense - CutterJson instObject = Core()->cmdj("aoj @ " + QString::number(offset)).first(); - bool immBase = instObject["val"].valid() || instObject["ptr"].valid(); + RzPVector *vec = (RzPVector *)Core()->returnAtSeek( + [&]() { + RzCoreLocked core(Core()); + return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); + }, + offset); + auto *ab = static_cast(rz_pvector_head(vec)); + + bool immBase = ab && ab->op && (ab->op->val || ab->op->ptr); setBaseMenu->menuAction()->setVisible(immBase); setBitsMenu->menuAction()->setVisible(true); @@ -491,17 +498,24 @@ void DisassemblyContextMenu::aboutToShowSlot() QString memBaseReg; // Base register st64 memDisp = 0; // Displacement - // Loop through both the operands of the instruction - for (const CutterJson operand : instObject["opex"]["operands"]) { - if (operand["type"].toString() == "mem" && !operand["base"].toString().contains("bp") - && operand["disp"].toSt64() > 0) { + if (ab && ab->op) { + const char *opexstr = RZ_STRBUF_SAFEGET(&ab->op->opex); + CutterJson operands = Core()->parseJson(strdup(opexstr), nullptr); - // The current operand is the one which has an immediate displacement - memBaseReg = operand["base"].toString(); - memDisp = operand["disp"].toSt64(); - break; + // Loop through both the operands of the instruction + for (const CutterJson operand : operands) { + if (operand["type"].toString() == "mem" && !operand["base"].toString().contains("bp") + && operand["disp"].toSt64() > 0) { + + // The current operand is the one which has an immediate displacement + memBaseReg = operand["base"].toString(); + memDisp = operand["disp"].toSt64(); + break; + } } } + rz_pvector_free(vec); + if (memBaseReg.isEmpty()) { // hide structure offset menu structureOffsetMenu->menuAction()->setVisible(false); From fb82370dfc7dd8b3a4423546afd2f0613d53b93d Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 14 May 2022 17:08:52 +0800 Subject: [PATCH 49/94] convert to api for `aht` --- src/core/Cutter.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index bcb9b728..ee9fbf9d 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -951,7 +951,12 @@ void CutterCore::applyStructureOffset(const QString &structureOffset, RVA offset offset = getOffset(); } - this->cmdRawAt("aht " + structureOffset, offset); + applyAtSeek( + [&]() { + CORE_LOCK(); + rz_core_analysis_hint_set_offset(core, structureOffset.toUtf8().constData()); + }, + offset); emit instructionChanged(offset); } From df8c2749a66adfa9210ba9854072a58eb5113a76 Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 14 May 2022 19:13:45 +0800 Subject: [PATCH 50/94] convert to api for `dr` --- src/core/Cutter.cpp | 92 ++++++++++++++++-------------- src/core/Cutter.h | 4 +- src/widgets/RegisterRefsWidget.cpp | 2 +- src/widgets/StackWidget.cpp | 4 +- 4 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index ee9fbf9d..44a79343 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -127,6 +127,11 @@ static QString fromOwnedCharPtr(char *str) return result; } +static bool reg_sync(RzCore *core, RzRegisterType type, bool write) +{ + return rz_debug_reg_sync(core->dbg, type, write); +} + RzCoreLocked::RzCoreLocked(CutterCore *core) : core(core) { core->coreMutex.lock(); @@ -1376,11 +1381,6 @@ void CutterCore::createFunctionAt(RVA addr, QString name) emit functionsChanged(); } -CutterJson CutterCore::getRegistersInfo() -{ - return cmdj("aeafj"); -} - RVA CutterCore::getOffsetJump(RVA addr) { auto rva = (RVA *)Core()->returnAtSeek( @@ -1448,20 +1448,20 @@ static inline const QString appendVar(QString &dst, const QString val, const QSt return val; } -RefDescription CutterCore::formatRefDesc(const AddrRefs &refItem) +RefDescription CutterCore::formatRefDesc(const QSharedPointer &refItem) { RefDescription desc; - if (refItem.addr == RVA_INVALID) { + if (refItem->addr == RVA_INVALID) { return desc; } - QString str = refItem.string; + QString str = refItem->string; if (!str.isEmpty()) { desc.ref = str; desc.refColor = ConfigColor("comment"); } else { - QSharedPointer cursor(&refItem); + QSharedPointer cursor(refItem); QString type, string; while (true) { desc.ref += " ->"; @@ -1508,15 +1508,21 @@ QList CutterCore::getRegisterRefs(int depth) return ret; } - CutterJson registers = cmdj("drj"); - for (CutterJson value : registers) { + CORE_LOCK(); + RzList *ritems = rz_core_reg_filter_items_sync(core, core->dbg->reg, reg_sync, nullptr); + if (!ritems) { + return ret; + } + RzListIter *it; + RzRegItem *ri; + CutterRzListForeach (ritems, it, RzRegItem, ri) { RegisterRef reg; - reg.value = value.toUt64(); + reg.value = rz_reg_get_value(core->dbg->reg, ri); reg.ref = getAddrRefs(reg.value, depth); - reg.name = value.key(); + reg.name = ri->name; ret.append(reg); } - + rz_list_free(ritems); return ret; } @@ -1528,9 +1534,8 @@ QList CutterCore::getStack(int size, int depth) } CORE_LOCK(); - bool ret; - RVA addr = cmdRaw("dr SP").toULongLong(&ret, 16); - if (!ret) { + RVA addr = rz_debug_reg_get(core->dbg, "SP"); + if (addr == RVA_INVALID) { return stack; } @@ -1793,11 +1798,6 @@ bool CutterCore::writeHeapChunk(RzHeapChunkSimple *chunk_simple) return rz_heap_write_chunk(core, chunk_simple); } -CutterJson CutterCore::getRegisterValues() -{ - return cmdj("drj"); -} - QList CutterCore::getVariables(RVA at) { QList ret; @@ -1837,42 +1837,52 @@ QList CutterCore::getVariables(RVA at) QVector CutterCore::getRegisterRefValues() { - CutterJson registerRefArray = cmdj("drrj"); QVector result; - - for (CutterJson regRefObject : registerRefArray) { + CORE_LOCK(); + RzList *ritems = rz_core_reg_filter_items_sync(core, core->dbg->reg, reg_sync, nullptr); + if (!ritems) { + return result; + } + RzListIter *it; + RzRegItem *ri; + CutterRzListForeach (ritems, it, RzRegItem, ri) { RegisterRefValueDescription desc; - desc.name = regRefObject[RJsonKey::reg].toString(); - desc.value = regRefObject[RJsonKey::value].toString(); - desc.ref = regRefObject[RJsonKey::ref].toString(); - + desc.name = ri->name; + ut64 value = rz_reg_get_value(core->dbg->reg, ri); + desc.value = QString::number(value); + desc.ref = rz_core_analysis_hasrefs(core, value, true); result.push_back(desc); } + rz_list_free(ritems); return result; } QString CutterCore::getRegisterName(QString registerRole) { - return cmdRaw("drn " + registerRole).trimmed(); + if (!currentlyDebugging) { + return ""; + } + CORE_LOCK(); + return rz_reg_get_name_by_type(core->dbg->reg, registerRole.toUtf8().constData()); } RVA CutterCore::getProgramCounterValue() { - bool ok; if (currentlyDebugging) { - // Use cmd because cmdRaw would not work with inner command backticked - // TODO: Risky command due to changes in API, search for something safer - RVA addr = cmd("dr `drn PC`").toULongLong(&ok, 16); - if (ok) { - return addr; - } + CORE_LOCK(); + return rz_debug_reg_get(core->dbg, "PC"); } return RVA_INVALID; } void CutterCore::setRegister(QString regName, QString regValue) { - cmdRaw(QString("dr %1=%2").arg(regName).arg(regValue)); + if (!currentlyDebugging) { + return; + } + CORE_LOCK(); + ut64 val = rz_num_math(core->num, regValue.toUtf8().constData()); + rz_core_reg_assign_sync(core, core->dbg->reg, reg_sync, regName.toUtf8().constData(), val); emit registersChanged(); emit refreshCodeViews(); } @@ -1940,7 +1950,7 @@ void CutterCore::startDebug() if (!asyncTask( [](RzCore *core) { rz_core_file_reopen_debug(core, ""); - return (void *)NULL; + return (void *)nullptr; }, debugTask)) { return; @@ -1949,9 +1959,7 @@ void CutterCore::startDebug() emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); emit registersChanged(); diff --git a/src/core/Cutter.h b/src/core/Cutter.h index f36796a4..bc76233a 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -417,8 +417,6 @@ public: bool sdbSet(QString path, QString key, QString val); /* Debug */ - CutterJson getRegistersInfo(); - CutterJson getRegisterValues(); QString getRegisterName(QString registerRole); RVA getProgramCounterValue(); void setRegister(QString regName, QString regValue); @@ -444,7 +442,7 @@ public: * @brief return a RefDescription with a formatted ref string and configured colors * @param ref the "ref" JSON node from getAddrRefs */ - RefDescription formatRefDesc(const AddrRefs &ref); + RefDescription formatRefDesc(const QSharedPointer &ref); /** * @brief Get a list of a given process's threads * @param pid The pid of the process, -1 for the currently debugged process diff --git a/src/widgets/RegisterRefsWidget.cpp b/src/widgets/RegisterRefsWidget.cpp index d0cfb4dd..c35e2936 100644 --- a/src/widgets/RegisterRefsWidget.cpp +++ b/src/widgets/RegisterRefsWidget.cpp @@ -190,7 +190,7 @@ void RegisterRefsWidget::refreshRegisterRef() desc.value = RzAddressString(reg.value); desc.reg = reg.name; - desc.refDesc = Core()->formatRefDesc(reg.ref); + desc.refDesc = Core()->formatRefDesc(QSharedPointer::create(reg.ref)); registerRefs.push_back(desc); } diff --git a/src/widgets/StackWidget.cpp b/src/widgets/StackWidget.cpp index d673f8b1..71b66fe4 100644 --- a/src/widgets/StackWidget.cpp +++ b/src/widgets/StackWidget.cpp @@ -154,7 +154,9 @@ void StackModel::reload() item.offset = stackItem.addr; item.value = RzAddressString(stackItem.value); - item.refDesc = Core()->formatRefDesc(*stackItem.ref); + if (!stackItem.ref.isNull()) { + item.refDesc = Core()->formatRefDesc(stackItem.ref); + } values.push_back(item); } From cf30b400f39a0caf03457c1b911db9b0d84ed576 Mon Sep 17 00:00:00 2001 From: billow Date: Sun, 22 May 2022 16:51:54 +0800 Subject: [PATCH 51/94] Convert Rizin commands to the API calls --- src/common/ColorThemeWorker.cpp | 82 +++-------- src/common/ColorThemeWorker.h | 9 +- src/common/Configuration.cpp | 8 +- src/common/SettingsUpgrade.cpp | 25 ++-- src/core/Cutter.cpp | 134 ++++++++++++------ src/core/Cutter.h | 6 +- .../preferences/ColorThemeEditDialog.cpp | 4 +- src/widgets/BacktraceWidget.cpp | 34 +++-- src/widgets/ColorThemeListView.cpp | 36 ++--- src/widgets/ColorThemeListView.h | 2 +- 10 files changed, 158 insertions(+), 182 deletions(-) diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index aabc0c1f..c4abfd5c 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -37,9 +37,7 @@ ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) QDir().mkpath(customRzThemesLocationPath); } - QDir currDir { - QStringLiteral("%1%2%3").arg(rz_path_prefix(nullptr)).arg(RZ_SYS_DIR).arg(RZ_THEMES) - }; + QDir currDir { QStringLiteral("%1%2%3").arg(rz_path_prefix(nullptr), RZ_SYS_DIR, RZ_THEMES) }; if (currDir.exists()) { standardRzThemesLocationPath = currDir.absolutePath(); } else { @@ -78,27 +76,15 @@ QString ColorThemeWorker::copy(const QString &srcThemeName, const QString ©T return save(getTheme(srcThemeName), copyThemeName); } -QString ColorThemeWorker::save(const QJsonDocument &theme, const QString &themeName) const +QString ColorThemeWorker::save(const Theme &theme, const QString &themeName) const { QFile fOut(QDir(customRzThemesLocationPath).filePath(themeName)); if (!fOut.open(QFile::WriteOnly | QFile::Truncate)) { return tr("The file %1 cannot be opened.").arg(QFileInfo(fOut).filePath()); } - QJsonObject obj = theme.object(); - for (auto it = obj.constBegin(); it != obj.constEnd(); it++) { - - QJsonArray arr = it.value().toArray(); - QColor color; - if (arr.isEmpty()) { - color = it.value().toVariant().value(); - } else if (arr.size() == 4) { - color = QColor(arr[0].toInt(), arr[1].toInt(), arr[2].toInt(), arr[3].toInt()); - } else if (arr.size() == 3) { - color = QColor(arr[0].toInt(), arr[1].toInt(), arr[2].toInt()); - } else { - continue; - } + for (auto it = theme.constBegin(); it != theme.constEnd(); it++) { + const QColor &color = it.value(); if (cutterSpecificOptions.contains(it.key())) { fOut.write(QString("#~%1 rgb:%2\n") .arg(it.key(), color.name(QColor::HexArgb).remove('#')) @@ -125,37 +111,18 @@ bool ColorThemeWorker::isThemeExist(const QString &name) const return themes.contains(name); } -QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const +ColorThemeWorker::Theme ColorThemeWorker::getTheme(const QString &themeName) const { - int r, g, b, a; - CutterJson rzTheme; - QVariantMap theme; + Theme theme; QString curr = Config()->getColorTheme(); if (themeName != curr) { RzCoreLocked core(Core()); rz_core_theme_load(core, themeName.toUtf8().constData()); - rzTheme = Core()->cmdj("ecj"); + theme = Core()->getTheme(); rz_core_theme_load(core, curr.toUtf8().constData()); } else { - rzTheme = Core()->cmdj("ecj"); - } - - for (CutterJson value : rzTheme) { - QJsonArray arr; - int count = 0; - for (CutterJson element : value) { - arr.append(element.toSt64()); - count++; - if (count >= 3) { - break; - } - } - while (count < 3) { - arr.append(0); - } - arr.append(255); - theme[value.key()] = arr; + theme = Core()->getTheme(); } ColorFlags colorFlags = ColorFlags::DarkFlag; @@ -164,14 +131,13 @@ QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const } for (auto &it : cutterSpecificOptions) { - Configuration::cutterOptionColors[it][colorFlags].getRgb(&r, &g, &b, &a); - theme.insert(it, QJsonArray { r, g, b, a }); + theme.insert(it, QColor(Configuration::cutterOptionColors[it][colorFlags])); } if (isCustomTheme(themeName)) { QFile src(QDir(customRzThemesLocationPath).filePath(themeName)); if (!src.open(QFile::ReadOnly)) { - return QJsonDocument(); + return {}; } QStringList sl; for (auto &line : QString(src.readAll()).split('\n', CUTTER_QT_SKIP_EMPTY_PARTS)) { @@ -181,8 +147,7 @@ QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const if (sl.size() != 3 || sl[0][0] == '#') { continue; } - QColor(sl[2]).getRgb(&r, &g, &b, &a); - theme.insert(sl[1], QJsonArray({ r, g, b, a })); + theme.insert(sl[1], QColor(sl[2])); } } @@ -190,21 +155,7 @@ QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const theme.remove(key); } - // manualy converting instead of using QJsonObject::fromVariantMap because - // Qt < 5.6 QJsonValue.fromVariant doesn't expect QVariant to already contain - // QJson values like QJsonArray. - // https://github.com/qt/qtbase/commit/26237f0a2d8db80024b601f676bbce54d483e672 - QJsonObject obj; - for (auto it = theme.begin(); it != theme.end(); it++) { - auto &value = it.value(); - if (value.canConvert()) { - obj[it.key()] = it.value().value(); - } else { - obj[it.key()] = QJsonValue::fromVariant(value); - } - } - - return QJsonDocument(obj); + return theme; } QString ColorThemeWorker::deleteTheme(const QString &themeName) const @@ -291,11 +242,10 @@ bool ColorThemeWorker::isFileTheme(const QString &filePath, bool *ok) const const QString colors = "black|red|white|green|magenta|yellow|cyan|blue|gray|none"; QString options = - (Core()->cmdj("ecj").keys() << cutterSpecificOptions).join('|').replace(".", "\\."); + (Core()->getThemeKeys() << cutterSpecificOptions).join('|').replace(".", "\\."); - QString pattern = QString("((ec\\s+(%1)\\s+(((rgb:|#)[0-9a-fA-F]{3,8})|(%2))))\\s*") - .arg(options) - .arg(colors); + QString pattern = + QString("((ec\\s+(%1)\\s+(((rgb:|#)[0-9a-fA-F]{3,8})|(%2))))\\s*").arg(options, colors); // The below construct mimics the behaviour of QRegexP::exactMatch(), which was here before QRegularExpression regexp("\\A(?:" + pattern + ")\\z"); @@ -326,7 +276,7 @@ QStringList ColorThemeWorker::customThemes() const const QStringList &ColorThemeWorker::getRizinSpecificOptions() { if (rizinSpecificOptions.isEmpty()) { - rizinSpecificOptions = Core()->cmdj("ecj").keys(); + rizinSpecificOptions << Core()->getThemeKeys(); } return rizinSpecificOptions; } diff --git a/src/common/ColorThemeWorker.h b/src/common/ColorThemeWorker.h index 3d67826f..3942a428 100644 --- a/src/common/ColorThemeWorker.h +++ b/src/common/ColorThemeWorker.h @@ -18,6 +18,8 @@ class ColorThemeWorker : public QObject { Q_OBJECT public: + typedef QHash Theme; + /** * @brief cutterSpecificOptions is list of all available Cutter-only color options. */ @@ -54,7 +56,7 @@ public: * Name of theme to save. * @return "" on success or error message. */ - QString save(const QJsonDocument &theme, const QString &themeName) const; + QString save(const Theme &theme, const QString &themeName) const; /** * @brief Returns whether or not @a themeName theme is custom (created by user or imported) or @@ -71,12 +73,11 @@ public: bool isThemeExist(const QString &name) const; /** - * @brief Returns theme as Json where key is option name and value is array of 3 Ints (Red, - * Green, Blue). + * @brief Returns theme as QHash where key is option name and value is QColor. * @param themeName * Theme to get. */ - QJsonDocument getTheme(const QString &themeName) const; + Theme getTheme(const QString &themeName) const; /** * @brief Deletes theme named @a themeName. diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 0a73eb34..5239ad6b 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -534,13 +534,9 @@ void Configuration::setColorTheme(const QString &theme) s.setValue("theme", theme); } - QJsonObject colorTheme = ThemeWorker().getTheme(theme).object(); + ColorThemeWorker::Theme colorTheme = ThemeWorker().getTheme(theme); for (auto it = colorTheme.constBegin(); it != colorTheme.constEnd(); it++) { - QJsonArray rgb = it.value().toArray(); - if (rgb.size() != 4) { - continue; - } - setColor(it.key(), QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt(), rgb[3].toInt())); + setColor(it.key(), it.value()); } emit colorsUpdated(); diff --git a/src/common/SettingsUpgrade.cpp b/src/common/SettingsUpgrade.cpp index 4ef57e59..a03a818a 100644 --- a/src/common/SettingsUpgrade.cpp +++ b/src/common/SettingsUpgrade.cpp @@ -181,26 +181,21 @@ void Cutter::initializeSettings() static void removeObsoleteOptionsFromCustomThemes() { - const QStringList options = Core()->cmdj("ecj").keys() - << ColorThemeWorker::cutterSpecificOptions; - RzList *themes_list = rz_core_theme_list(Core()->core()); - RzListIter *th_iter; - const char *th; - CutterRzListForeach (themes_list, th_iter, const char, th) { - auto theme = QString(th).trimmed(); - if (!ThemeWorker().isCustomTheme(theme)) { + const QStringList options = Core()->getThemeKeys() << ColorThemeWorker::cutterSpecificOptions; + QStringList themes = Core()->getColorThemes(); + for (const auto &themeName : themes) { + if (!ThemeWorker().isCustomTheme(themeName)) { continue; } - QJsonObject updatedTheme; - auto sch = ThemeWorker().getTheme(theme).object(); - for (const auto &key : sch.keys()) { - if (options.contains(key)) { - updatedTheme.insert(key, sch[key]); + ColorThemeWorker::Theme sch = ThemeWorker().getTheme(themeName); + ColorThemeWorker::Theme updatedTheme; + for (auto it = sch.constBegin(); it != sch.constEnd(); ++it) { + if (options.contains(it.key())) { + updatedTheme.insert(it.key(), it.value()); } } - ThemeWorker().save(QJsonDocument(updatedTheme), theme); + ThemeWorker().save(updatedTheme, themeName); } - rz_list_free(themes_list); } void Cutter::migrateThemes() diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 44a79343..3858b88b 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2157,26 +2157,9 @@ void CutterCore::stopDebug() if (currentlyEmulating) { cmdEsil("aeim-; aei-; wcr; .ar-; aets-"); currentlyEmulating = false; - } else if (currentlyAttachedToPID != -1) { - // Use cmd because cmdRaw would not work with command concatenation - cmd(QString("dp- %1; o %2; .ar-") - .arg(QString::number(currentlyAttachedToPID), currentlyOpenFile)); - currentlyAttachedToPID = -1; } else { - QString ptraceFiles = ""; - // close ptrace file descriptors left open - RzCoreLocked core(Core()); - RzList *descs = rz_id_storage_list(core->io->files); - RzListIter *it; - RzIODesc *desc; - CutterRzListForeach (descs, it, RzIODesc, desc) { - QString URI = QString(desc->uri); - if (URI.contains("ptrace")) { - ptraceFiles += "o-" + QString::number(desc->fd) + ";"; - } - } - // Use cmd because cmdRaw would not work with command concatenation - cmd("doc" + ptraceFiles); + rz_core_debug_process_close(core()); + currentlyAttachedToPID = -1; } syncAndSeekProgramCounter(); @@ -2331,7 +2314,16 @@ void CutterCore::continueUntilSyscall() return; } } else { - if (!asyncCmd("dcs", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_cons_break_push(reinterpret_cast(rz_debug_stop), core->dbg); + rz_reg_arena_swap(core->dbg->reg, true); + rz_debug_continue_syscalls(core->dbg, NULL, 0); + rz_cons_break_pop(); + rz_core_dbg_follow_seek_register(core); + return nullptr; + }, + debugTask)) { return; } } @@ -2390,7 +2382,15 @@ void CutterCore::stepOverDebug() return; } } else { - if (!asyncCmd("dso", debugTask)) { + bool ret; + asyncTask( + [&](RzCore *core) { + ret = rz_core_debug_step_over(core, 1); + rz_core_dbg_follow_seek_register(core); + return nullptr; + }, + debugTask); + if (!ret) { return; } } @@ -2413,7 +2413,15 @@ void CutterCore::stepOutDebug() } emit debugTaskStateChanged(); - if (!asyncCmd("dsf", debugTask)) { + bool ret; + asyncTask( + [&](RzCore *core) { + ret = rz_core_debug_step_until_frame(core); + rz_core_dbg_follow_seek_register(core); + return nullptr; + }, + debugTask); + if (!ret) { return; } @@ -2438,7 +2446,15 @@ void CutterCore::stepBackDebug() return; } } else { - if (!asyncCmd("dsb", debugTask)) { + bool ret; + asyncTask( + [&](RzCore *core) { + ret = rz_core_debug_step_back(core, 1); + rz_core_dbg_follow_seek_register(core); + return nullptr; + }, + debugTask); + if (!ret) { return; } } @@ -2457,11 +2473,11 @@ void CutterCore::stepBackDebug() QStringList CutterCore::getDebugPlugins() { QStringList plugins; - - for (CutterJson pluginObject : cmdj("dLj")) { - QString plugin = pluginObject[RJsonKey::name].toString(); - - plugins << plugin; + RzListIter *iter; + RzDebugPlugin *plugin; + CORE_LOCK(); + CutterRzListForeach (core->dbg->plugins, iter, RzDebugPlugin, plugin) { + plugins << plugin->name; } return plugins; } @@ -2661,11 +2677,9 @@ void CutterCore::disableBreakpoint(RVA addr) void CutterCore::setBreakpointTrace(int index, bool enabled) { - if (enabled) { - cmdRaw(QString("dbite %1").arg(index)); - } else { - cmdRaw(QString("dbitd %1").arg(index)); - } + CORE_LOCK(); + RzBreakpointItem *bpi = rz_bp_get_index(core->dbg->bp, index); + bpi->trace = enabled; } static BreakpointDescription breakpointDescriptionFromRizin(int index, rz_bp_item_t *bpi) @@ -2746,11 +2760,6 @@ bool CutterCore::isBreakpoint(const QList &breakpoints, RVA addr) return breakpoints.contains(addr); } -CutterJson CutterCore::getBacktrace() -{ - return cmdj("dbtj"); -} - QList CutterCore::getProcessThreads(int pid = -1) { CORE_LOCK(); @@ -4120,15 +4129,56 @@ QString CutterCore::getVersionInformation() return versionInfo; } -QList CutterCore::getColorThemes() +QStringList CutterCore::getColorThemes() { - QList r; - for (CutterJson s : cmdj("ecoj")) { - r << s.toString(); + QStringList r; + CORE_LOCK(); + RzList *themes_list = rz_core_theme_list(core); + RzListIter *it; + const char *th; + CutterRzListForeach (themes_list, it, const char, th) { + r << fromOwnedCharPtr(rz_str_trim_dup(th)); } + rz_list_free(themes_list); return r; } +QHash CutterCore::getTheme() +{ + QHash theme; + for (int i = 0;; ++i) { + const char *k = rz_cons_pal_get_name(i); + if (!k) { + break; + } + RzColor color = rz_cons_pal_get_i(i); + theme.insert(k, QColor(color.r, color.g, color.b)); + } + return theme; +} + +QStringList CutterCore::getThemeKeys() +{ + QStringList stringList; + for (int i = 0;; ++i) { + const char *k = rz_cons_pal_get_name(i); + if (!k) { + break; + } + stringList << k; + } + return stringList; +} + +bool CutterCore::setColor(const QString &key, const QString &color) +{ + if (!rz_cons_pal_set(key.toUtf8().constData(), color.toUtf8().constData())) { + return false; + } + rz_cons_pal_update_event(); + return true; +} + QString CutterCore::ansiEscapeToHtml(const QString &text) { int len; diff --git a/src/core/Cutter.h b/src/core/Cutter.h index bc76233a..66b7b0f3 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -393,7 +393,10 @@ public: QString getConfig(const char *k); QString getConfig(const QString &k) { return getConfig(k.toUtf8().constData()); } QString getConfigDescription(const char *k); - QList getColorThemes(); + QStringList getColorThemes(); + QHash getTheme(); + QStringList getThemeKeys(); + bool setColor(const QString &key, const QString &color); /* Assembly\Hexdump related methods */ QByteArray assemble(const QString &code); @@ -449,7 +452,6 @@ public: * @return List of ProcessDescription */ QList getProcessThreads(int pid); - CutterJson getBacktrace(); /** * @brief Get a list of heap chunks * Uses RZ_API rz_heap_chunks_list to get vector of chunks diff --git a/src/dialogs/preferences/ColorThemeEditDialog.cpp b/src/dialogs/preferences/ColorThemeEditDialog.cpp index 93838698..bc0dff62 100644 --- a/src/dialogs/preferences/ColorThemeEditDialog.cpp +++ b/src/dialogs/preferences/ColorThemeEditDialog.cpp @@ -72,7 +72,7 @@ ColorThemeEditDialog::~ColorThemeEditDialog() void ColorThemeEditDialog::accept() { colorTheme = Config()->getColorTheme(); - QJsonDocument sch = ui->colorThemeListView->colorSettingsModel()->getTheme(); + ColorThemeWorker::Theme sch = ui->colorThemeListView->colorSettingsModel()->getTheme(); if (ThemeWorker().isCustomTheme(colorTheme)) { QString err = ThemeWorker().save(sch, colorTheme); if (!err.isEmpty()) { @@ -133,7 +133,7 @@ void ColorThemeEditDialog::colorOptionChanged(const QColor &newColor) Config()->setColor(currOption.optionName, currOption.color); if (!ColorThemeWorker::cutterSpecificOptions.contains(currOption.optionName)) { - Core()->cmdRaw(QString("ec %1 %2").arg(currOption.optionName).arg(currOption.color.name())); + Core()->setColor(currOption.optionName, currOption.color.name()); } previewDisasmWidget->colorsUpdatedSlot(); } diff --git a/src/widgets/BacktraceWidget.cpp b/src/widgets/BacktraceWidget.cpp index 433a1b1e..d4413c39 100644 --- a/src/widgets/BacktraceWidget.cpp +++ b/src/widgets/BacktraceWidget.cpp @@ -44,27 +44,25 @@ void BacktraceWidget::updateContents() void BacktraceWidget::setBacktraceGrid() { + RzList *list = rz_core_debug_backtraces(Core()->core()); int i = 0; - for (CutterJson backtraceItem : Core()->getBacktrace()) { - QString progCounter = RzAddressString(backtraceItem["pc"].toRVA()); - QString stackPointer = RzAddressString(backtraceItem["sp"].toRVA()); - st64 frameSize = backtraceItem["frame_size"].toSt64(); - QString funcName = backtraceItem["fname"].toString(); - QString desc = backtraceItem["desc"].toString(); + RzListIter *iter; + RzBacktrace *bt; + CutterRzListForeach (list, iter, RzBacktrace, bt) { + QString funcName = bt->fcn ? bt->fcn->name : ""; + QString pc = RzAddressString(bt->frame ? bt->frame->addr : 0); + QString sp = RzAddressString(bt->frame ? bt->frame->sp : 0); + QString frameSize = QString::number(bt->frame ? bt->frame->size : 0); + QString desc = bt->desc; - QStandardItem *rowPC = new QStandardItem(progCounter); - QStandardItem *rowSP = new QStandardItem(stackPointer); - QStandardItem *rowFrameSize = new QStandardItem(QString::number(frameSize)); - QStandardItem *rowFuncName = new QStandardItem(funcName); - QStandardItem *rowDesc = new QStandardItem(desc); - - modelBacktrace->setItem(i, 0, rowFuncName); - modelBacktrace->setItem(i, 1, rowSP); - modelBacktrace->setItem(i, 2, rowPC); - modelBacktrace->setItem(i, 3, rowDesc); - modelBacktrace->setItem(i, 4, rowFrameSize); - i++; + modelBacktrace->setItem(i, 0, new QStandardItem(funcName)); + modelBacktrace->setItem(i, 1, new QStandardItem(sp)); + modelBacktrace->setItem(i, 2, new QStandardItem(pc)); + modelBacktrace->setItem(i, 3, new QStandardItem(desc)); + modelBacktrace->setItem(i, 4, new QStandardItem(frameSize)); + ++i; } + rz_list_free(list); // Remove irrelevant old rows if (modelBacktrace->rowCount() > i) { diff --git a/src/widgets/ColorThemeListView.cpp b/src/widgets/ColorThemeListView.cpp index a5c93354..7d534f57 100644 --- a/src/widgets/ColorThemeListView.cpp +++ b/src/widgets/ColorThemeListView.cpp @@ -220,13 +220,7 @@ ColorThemeListView::ColorThemeListView(QWidget *parent) : QListView(parent) setItemDelegate(new ColorOptionDelegate(this)); setResizeMode(ResizeMode::Adjust); - QJsonArray rgb = - colorSettingsModel()->getTheme().object().find("gui.background").value().toArray(); - if (rgb.size() == 3) { - backgroundColor = QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt()); - } else { - backgroundColor = palette().base().color(); - } + backgroundColor = colorSettingsModel()->getTheme().find("gui.background").value(); connect(&blinkTimer, &QTimer::timeout, this, &ColorThemeListView::blinkTimeout); @@ -241,7 +235,7 @@ void ColorThemeListView::currentChanged(const QModelIndex ¤t, const QModel ColorOption prev = previous.data(Qt::UserRole).value(); Config()->setColor(prev.optionName, prev.color); if (ThemeWorker().getRizinSpecificOptions().contains(prev.optionName)) { - Core()->cmdRaw(QString("ec %1 %2").arg(prev.optionName).arg(prev.color.name())); + Core()->setColor(prev.optionName, prev.color.name()); } QListView::currentChanged(current, previous); @@ -267,9 +261,7 @@ void ColorThemeListView::mouseReleaseEvent(QMouseEvent *e) .contains(e->pos())) { ColorOption co = currentIndex().data(Qt::UserRole).value(); co.changed = false; - QJsonArray rgb = - ThemeWorker().getTheme(Config()->getColorTheme()).object()[co.optionName].toArray(); - co.color = QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt()); + co.color = ThemeWorker().getTheme(Config()->getColorTheme())[co.optionName]; model()->setData(currentIndex(), QVariant::fromValue(co)); QCursor c; c.setShape(Qt::CursorShape::ArrowCursor); @@ -307,7 +299,7 @@ void ColorThemeListView::blinkTimeout() auto updateColor = [](const QString &name, const QColor &color) { Config()->setColor(name, color); if (ThemeWorker().getRizinSpecificOptions().contains(name)) { - Core()->cmdRaw(QString("ec %1 %2").arg(name).arg(color.name())); + Core()->setColor(name, color.name()); } }; @@ -374,16 +366,10 @@ void ColorSettingsModel::updateTheme() { beginResetModel(); theme.clear(); - QJsonObject obj = ThemeWorker().getTheme(Config()->getColorTheme()).object(); + ColorThemeWorker::Theme obj = ThemeWorker().getTheme(Config()->getColorTheme()); for (auto it = obj.constBegin(); it != obj.constEnd(); it++) { - QJsonArray rgb = it.value().toArray(); - if (rgb.size() != 4) { - continue; - } - theme.push_back({ it.key(), - QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt(), rgb[3].toInt()), - false }); + theme.push_back({ it.key(), it.value(), false }); } std::sort(theme.begin(), theme.end(), [](const ColorOption &f, const ColorOption &s) { @@ -395,15 +381,13 @@ void ColorSettingsModel::updateTheme() endResetModel(); } -QJsonDocument ColorSettingsModel::getTheme() const +ColorThemeWorker::Theme ColorSettingsModel::getTheme() const { - QJsonObject obj; - int r, g, b, a; + ColorThemeWorker::Theme th; for (auto &it : theme) { - it.color.getRgb(&r, &g, &b, &a); - obj.insert(it.optionName, QJsonArray({ r, g, b, a })); + th.insert(it.optionName, it.color); } - return QJsonDocument(obj); + return th; } const QMap optionInfoMap__ = { diff --git a/src/widgets/ColorThemeListView.h b/src/widgets/ColorThemeListView.h index 8525312d..f992f2f7 100644 --- a/src/widgets/ColorThemeListView.h +++ b/src/widgets/ColorThemeListView.h @@ -73,7 +73,7 @@ public: void updateTheme(); - QJsonDocument getTheme() const; + QHash getTheme() const; private: QList theme; From ebe4ca507217733a83079517d8f6d4742be7cc9e Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Tue, 24 May 2022 20:47:59 +0200 Subject: [PATCH 52/94] Fix the lib name on windows (#2950) --- cmake/BundledRizin.cmake | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 4dcf4301..83e4c128 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -46,6 +46,10 @@ else() link_directories("${RIZIN_INSTALL_DIR}/lib") endif() +# TODO: This version number should be fetched automatically +# instead of being hardcoded. +set (Rizin_VERSION 0.4) + 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 @@ -62,11 +66,11 @@ target_include_directories(Rizin INTERFACE install(TARGETS Rizin EXPORT CutterTargets) if (WIN32) - foreach(_lib ${RZ_LIBS} ${RZ_EXTRA_LIBS}) - install(FILES "${RIZIN_INSTALL_DIR}/${RZ_INSTALL_BINPATH}/${_lib}.dll" DESTINATION "${CMAKE_INSTALL_BINDIR}") + foreach(_lib ${RZ_LIBS} ${RZ_EXTRA_LIBS}) + install(FILES "${RIZIN_INSTALL_DIR}/${_lib}-${Rizin_VERSION}.dll" DESTINATION "${CMAKE_INSTALL_BINDIR}") endforeach() foreach(_exe ${RZ_BIN}) - install(FILES "${RIZIN_INSTALL_DIR}/${RZ_INSTALL_BINPATH}/${_exe}.exe" DESTINATION "${CMAKE_INSTALL_BINDIR}") + install(FILES "${RIZIN_INSTALL_DIR}/${_exe}.exe" DESTINATION "${CMAKE_INSTALL_BINDIR}") endforeach() install(DIRECTORY "${RIZIN_INSTALL_DIR}/share" DESTINATION ".") install(DIRECTORY "${RIZIN_INSTALL_DIR}/include" DESTINATION "." From b3e74b2dad3d892f19aee49605c494c2c1499a31 Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 28 May 2022 16:09:00 +0800 Subject: [PATCH 53/94] Convert Rizin commands to the API calls (#2948) Including wx wr wd ws ww wz ahi ahb aec aecu aecc aecs aes aesb aets+ aets- afc afcl omfg+w oo+ oo p8 aei aeim aeip aecb aeso dbs avj --- src/core/Cutter.cpp | 194 ++++++++++++++++++--------- src/dialogs/WriteCommandsDialogs.cpp | 10 +- src/menus/DisassemblyContextMenu.cpp | 24 +++- src/widgets/HexWidget.cpp | 156 ++++++++++++--------- 4 files changed, 246 insertions(+), 138 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 3858b88b..40cd43ff 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -656,7 +656,10 @@ bool CutterCore::loadFile(QString path, ut64 baddr, ut64 mapaddr, int perms, int } if (perms & RZ_PERM_W) { - rz_core_cmd0(core, "omfg+w"); + RzPVector *maps = rz_io_maps(core->io); + for (auto map : CutterPVector(maps)) { + map->perm |= RZ_PERM_W; + } } fflush(stdout); @@ -802,7 +805,8 @@ void CutterCore::jmpReverse(RVA addr) void CutterCore::editBytes(RVA addr, const QString &bytes) { - cmdRawAt(QString("wx %1").arg(bytes), addr); + CORE_LOCK(); + rz_core_write_hexpair(core, addr, bytes.toUtf8().constData()); emit instructionChanged(addr); } @@ -935,8 +939,9 @@ void CutterCore::setImmediateBase(const QString &rzBaseName, RVA offset) if (offset == RVA_INVALID) { offset = getOffset(); } - - this->cmdRawAt(QString("ahi %1").arg(rzBaseName), offset); + CORE_LOCK(); + int base = (int)rz_num_base_of_string(core->num, rzBaseName.toUtf8().constData()); + rz_analysis_hint_set_immbase(core->analysis, offset, base); emit instructionChanged(offset); } @@ -946,7 +951,8 @@ void CutterCore::setCurrentBits(int bits, RVA offset) offset = getOffset(); } - this->cmdRawAt(QString("ahb %1").arg(bits), offset); + CORE_LOCK(); + rz_analysis_hint_set_bits(core->analysis, offset, bits); emit instructionChanged(offset); } @@ -1950,7 +1956,7 @@ void CutterCore::startDebug() if (!asyncTask( [](RzCore *core) { rz_core_file_reopen_debug(core, ""); - return (void *)nullptr; + return nullptr; }, debugTask)) { return; @@ -1991,14 +1997,19 @@ void CutterCore::startEmulation() } // clear registers, init esil state, stack, progcounter at current seek - asyncCmd("aei; aeim; aeip", debugTask); + asyncTask( + [&](RzCore *core) { + rz_core_analysis_esil_reinit(core); + rz_core_analysis_esil_init_mem(core, NULL, UT64_MAX, UT32_MAX); + rz_core_analysis_esil_init_regs(core); + return nullptr; + }, + debugTask); emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); if (!currentlyDebugging || !currentlyEmulating) { @@ -2105,9 +2116,7 @@ void CutterCore::attachDebug(int pid) emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this, pid]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); syncAndSeekProgramCounter(); @@ -2184,14 +2193,20 @@ void CutterCore::continueDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aec", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_esil_step(core, UT64_MAX, "0", NULL, false); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [](RzCore *core) { rz_debug_continue(core->dbg); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2216,14 +2231,20 @@ void CutterCore::continueBackDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aecb", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_esil_continue_back(core); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [](RzCore *core) { rz_debug_continue_back(core->dbg); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2248,14 +2269,20 @@ void CutterCore::continueUntilDebug(ut64 offset) } if (currentlyEmulating) { - if (!asyncCmdEsil("aecu " + QString::number(offset), debugTask)) { + if (!asyncTask( + [=](RzCore *core) { + rz_core_esil_step(core, offset, NULL, NULL, false); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [=](RzCore *core) { rz_core_debug_continue_until(core, offset, offset); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2278,14 +2305,19 @@ void CutterCore::continueUntilCall() } if (currentlyEmulating) { - if (!asyncCmdEsil("aecc", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_analysis_continue_until_call(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [](RzCore *core) { rz_core_debug_step_one(core, 0); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2310,7 +2342,12 @@ void CutterCore::continueUntilSyscall() } if (currentlyEmulating) { - if (!asyncCmdEsil("aecs", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_analysis_continue_until_syscall(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2346,14 +2383,20 @@ void CutterCore::stepDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aes", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_esil_step(core, UT64_MAX, NULL, NULL, false); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [](RzCore *core) { rz_core_debug_step_one(core, 1); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2378,7 +2421,12 @@ void CutterCore::stepOverDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aeso", debugTask)) { + if (!asyncTask( + [&](RzCore *core) { + rz_core_analysis_esil_step_over(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2442,7 +2490,13 @@ void CutterCore::stepBackDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aesb", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_esil_step_back(core); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2499,7 +2553,12 @@ void CutterCore::startTraceSession() } if (currentlyEmulating) { - if (!asyncCmdEsil("aets+", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_analysis_esil_trace_start(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2507,7 +2566,7 @@ void CutterCore::startTraceSession() [](RzCore *core) { core->dbg->session = rz_debug_session_new(); rz_debug_add_checkpoint(core->dbg); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2516,9 +2575,7 @@ void CutterCore::startTraceSession() emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); currentlyTracing = true; @@ -2541,7 +2598,12 @@ void CutterCore::stopTraceSession() } if (currentlyEmulating) { - if (!asyncCmdEsil("aets-", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_analysis_esil_trace_stop(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2549,7 +2611,7 @@ void CutterCore::stopTraceSession() [](RzCore *core) { rz_debug_session_free(core->dbg->session); core->dbg->session = NULL; - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2558,9 +2620,7 @@ void CutterCore::stopTraceSession() emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); currentlyTracing = false; @@ -2578,7 +2638,8 @@ void CutterCore::stopTraceSession() void CutterCore::toggleBreakpoint(RVA addr) { - cmdRaw(QString("dbs %1").arg(addr)); + CORE_LOCK(); + rz_core_debug_breakpoint_toggle(core, addr); emit breakpointsChanged(addr); } @@ -3649,25 +3710,29 @@ QList CutterCore::getAllResources() QList CutterCore::getAllVTables() { CORE_LOCK(); - QList vtables; - - for (CutterJson vTableObject : cmdj("avj")) { - VTableDescription res; - - res.addr = vTableObject[RJsonKey::offset].toRVA(); - - for (CutterJson methodObject : vTableObject[RJsonKey::methods]) { - BinClassMethodDescription method; - - method.addr = methodObject[RJsonKey::offset].toRVA(); - method.name = methodObject[RJsonKey::name].toString(); - - res.methods << method; + QList vtableDescs; + RVTableContext context; + rz_analysis_vtable_begin(core->analysis, &context); + RzList *vtables = rz_analysis_vtable_search(&context); + RzListIter *iter; + RVTableInfo *table; + RVTableMethodInfo *method; + CutterRzListForeach (vtables, iter, RVTableInfo, table) { + VTableDescription tableDesc; + tableDesc.addr = table->saddr; + CutterRzVectorForeach(&table->methods, method, RVTableMethodInfo) + { + BinClassMethodDescription methodDesc; + RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, method->addr, 0); + const char *fname = fcn ? fcn->name : nullptr; + methodDesc.addr = method->addr; + methodDesc.name = fname ? fname : "No Name found"; + tableDesc.methods << methodDesc; } - - vtables << res; + vtableDescs << tableDesc; } - return vtables; + rz_list_free(vtables); + return vtableDescs; } QList CutterCore::getAllTypes() @@ -4226,10 +4291,10 @@ void CutterCore::commitWriteCache() TempConfig tempConfig; tempConfig.set("io.cache", false); if (!isWriteModeEnabled()) { - cmdRaw("oo+"); + rz_core_io_file_reopen(core, core->io->desc->fd, RZ_PERM_RW); rz_io_cache_commit(core->io, 0, UT64_MAX); rz_core_block_read(core); - cmdRaw("oo"); + rz_core_io_file_open(core, core->io->desc->fd); } else { rz_io_cache_commit(core->io, 0, UT64_MAX); rz_core_block_read(core); @@ -4252,17 +4317,22 @@ void CutterCore::setWriteMode(bool enabled) return; } + CORE_LOCK(); // Change from read-only to write-mode - if (enabled && !writeModeState) { - cmdRaw("oo+"); - // Change from write-mode to read-only + if (enabled) { + if (!writeModeState) { + rz_core_io_file_reopen(core, core->io->desc->fd, RZ_PERM_RW); + } } else { - cmdRaw("oo"); + // Change from write-mode to read-only + rz_core_io_file_open(core, core->io->desc->fd); } // Disable cache mode because we specifically set write or // read-only modes. - setIOCache(false); - writeModeChanged(enabled); + if (this->iocache) { + setIOCache(false); + } + emit writeModeChanged(enabled); emit ioModeChanged(); } diff --git a/src/dialogs/WriteCommandsDialogs.cpp b/src/dialogs/WriteCommandsDialogs.cpp index 5826a9ae..9cd509a3 100644 --- a/src/dialogs/WriteCommandsDialogs.cpp +++ b/src/dialogs/WriteCommandsDialogs.cpp @@ -77,14 +77,12 @@ size_t DuplicateFromOffsetDialog::getNBytes() const void DuplicateFromOffsetDialog::refresh() { - RVA offestFrom = getOffset(); - QSignalBlocker sb(Core()); + RzCoreLocked core(Core()); + auto buf = Core()->ioRead(getOffset(), (int)getNBytes()); // Add space every two characters for word wrap in hex sequence QRegularExpression re { "(.{2})" }; - QString bytes = Core()->cmdRawAt(QString("p8 %1").arg(QString::number(getNBytes())), offestFrom) - .replace(re, "\\1 "); - - ui->bytesLabel->setText(bytes.trimmed()); + auto bytes = QString(buf).replace(re, "\\1 ").trimmed(); + ui->bytesLabel->setText(bytes); } diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 2f6c6d66..a60e2196 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -1014,8 +1014,18 @@ void DisassemblyContextMenu::on_actionEditFunction_triggered() dialog.setStackSizeText(QString::number(fcn->stack)); - QStringList callConList = Core()->cmdRaw("afcl").split("\n"); - callConList.removeLast(); + QStringList callConList; + RzList *list = rz_analysis_calling_conventions(core->analysis); + if (!list) { + return; + } + RzListIter *iter; + const char *cc; + CutterRzListForeach (list, iter, const char, cc) { + callConList << cc; + } + rz_list_free(list); + dialog.setCallConList(callConList); dialog.setCallConSelected(fcn->cc); @@ -1026,7 +1036,15 @@ void DisassemblyContextMenu::on_actionEditFunction_triggered() fcn->addr = Core()->math(new_start_addr); QString new_stack_size = dialog.getStackSizeText(); fcn->stack = int(Core()->math(new_stack_size)); - Core()->cmdRaw("afc " + dialog.getCallConSelected()); + + const char *ccSelected = dialog.getCallConSelected().toUtf8().constData(); + if (RZ_STR_ISEMPTY(ccSelected)) { + return; + } + if (rz_analysis_cc_exist(core->analysis, ccSelected)) { + fcn->cc = rz_str_constpool_get(&core->analysis->constpool, ccSelected); + } + emit Core()->functionsChanged(); } } diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index b02a0e12..76cc586a 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -131,7 +131,8 @@ HexWidget::HexWidget(QWidget *parent) // delete comment option actionDeleteComment = new QAction(tr("Delete Comment"), this); actionDeleteComment->setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut); - connect(actionDeleteComment, &QAction::triggered, this, &HexWidget::on_actionDeleteComment_triggered); + connect(actionDeleteComment, &QAction::triggered, this, + &HexWidget::on_actionDeleteComment_triggered); addAction(actionDeleteComment); actionSelectRange = new QAction(tr("Select range"), this); @@ -713,14 +714,14 @@ void HexWidget::copyAddress() clipboard->setText(RzAddressString(addr)); } -//slot for add comment action +// slot for add comment action void HexWidget::on_actionAddComment_triggered() { uint64_t addr = cursor.address; CommentsDialog::addOrEditComment(addr, this); } -//slot for deleting comment action +// slot for deleting comment action void HexWidget::on_actionDeleteComment_triggered() { uint64_t addr = cursor.address; @@ -742,14 +743,16 @@ void HexWidget::w_writeString() return; } bool ok = false; - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QString str = d.getText(this, tr("Write string"), tr("String:"), QLineEdit::Normal, "", &ok); - if (ok && !str.isEmpty()) { + QString str = QInputDialog::getText(this, tr("Write string"), tr("String:"), QLineEdit::Normal, + "", &ok); + if (!ok || str.isEmpty()) { + return; + } + { RzCoreLocked core(Core()); rz_core_write_string_at(core, getLocationAddress(), str.toUtf8().constData()); - refresh(); } + refresh(); } void HexWidget::w_increaseDecrease() @@ -767,8 +770,10 @@ void HexWidget::w_increaseDecrease() if (d.getMode() == IncrementDecrementDialog::Decrease) { value *= -1; } - RzCoreLocked core(Core()); - rz_core_write_value_inc_at(core, getLocationAddress(), value, sz); + { + RzCoreLocked core(Core()); + rz_core_write_value_inc_at(core, getLocationAddress(), value, sz); + } refresh(); } @@ -784,10 +789,8 @@ void HexWidget::w_writeBytes() size = static_cast(selection.size()); } - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QByteArray bytes = d.getText(this, tr("Write hex bytes"), tr("Hex byte string:"), - QLineEdit::Normal, "", &ok) + QByteArray bytes = QInputDialog::getText(this, tr("Write hex bytes"), tr("Hex byte string:"), + QLineEdit::Normal, "", &ok) .toUtf8(); const int offset = bytes.startsWith("\\x") ? 2 : 0; const int incr = offset + 2; @@ -795,16 +798,18 @@ void HexWidget::w_writeBytes() if (!ok || !bytes_size) { return; } - uint8_t *buf = (uint8_t *)malloc(static_cast(bytes_size)); - if (!buf) { - return; + { + auto *buf = (uint8_t *)malloc(static_cast(bytes_size)); + if (!buf) { + return; + } + for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { + buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); + } + RzCoreLocked core(Core()); + rz_core_write_at(core, getLocationAddress(), buf, bytes_size); + free(buf); } - for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { - buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); - } - RzCoreLocked core(Core()); - rz_core_write_at(core, getLocationAddress(), buf, bytes_size); - free(buf); refresh(); } @@ -813,24 +818,25 @@ void HexWidget::w_writeZeros() if (!ioModesController.prepareForWriting()) { return; } - bool ok = false; - QInputDialog d; int size = 1; if (!selection.isEmpty() && selection.size() <= INT_MAX) { size = static_cast(selection.size()); } - int len = - d.getInt(this, tr("Write zeros"), tr("Number of zeros:"), size, 1, 0x7FFFFFFF, 1, &ok); - if (ok) { + bool ok = false; + int len = QInputDialog::getInt(this, tr("Write zeros"), tr("Number of zeros:"), size, 1, + 0x7FFFFFFF, 1, &ok); + if (!ok) { + return; + } + { RzCoreLocked core(Core()); - uint8_t *buf = (uint8_t *)calloc(len, sizeof(uint8_t)); + auto *buf = (uint8_t *)calloc(len, sizeof(uint8_t)); rz_core_write_at(core, getLocationAddress(), buf, len); free(buf); - - refresh(); } + refresh(); } void HexWidget::w_write64() @@ -855,11 +861,13 @@ void HexWidget::w_write64() return; } - RzCoreLocked core(Core()); - if (d.getMode() == Base64EnDecodedWriteDialog::Encode) { - rz_core_write_base64_at(core, getLocationAddress(), str.toHex().constData()); - } else { - rz_core_write_base64d_at(core, getLocationAddress(), str.constData()); + { + RzCoreLocked core(Core()); + if (d.getMode() == Base64EnDecodedWriteDialog::Encode) { + rz_core_write_base64_at(core, getLocationAddress(), str.toHex().constData()); + } else { + rz_core_write_base64d_at(core, getLocationAddress(), str.constData()); + } } refresh(); } @@ -869,19 +877,24 @@ void HexWidget::w_writeRandom() if (!ioModesController.prepareForWriting()) { return; } - bool ok = false; - QInputDialog d; int size = 1; if (!selection.isEmpty() && selection.size() <= INT_MAX) { size = static_cast(selection.size()); } - QString nbytes = QString::number(d.getInt(this, tr("Write random"), tr("Number of bytes:"), - size, 1, 0x7FFFFFFF, 1, &ok)); - if (ok && !nbytes.isEmpty()) { - Core()->cmdRawAt(QString("wr %1").arg(nbytes), getLocationAddress()); - refresh(); + + bool ok = false; + int nbytes = QInputDialog::getInt(this, tr("Write random"), tr("Number of bytes:"), size, 1, + 0x7FFFFFFF, 1, &ok); + if (!ok) { + return; } + + { + RzCoreLocked core(Core()); + rz_core_write_random_at(core, getLocationAddress(), nbytes); + } + refresh(); } void HexWidget::w_duplFromOffset() @@ -894,9 +907,12 @@ void HexWidget::w_duplFromOffset() if (ret == QDialog::Rejected) { return; } - RVA copyFrom = d.getOffset(); - QString nBytes = QString::number(d.getNBytes()); - Core()->cmdRawAt(QString("wd %1 %2").arg(copyFrom).arg(nBytes), getLocationAddress()); + RVA src = d.getOffset(); + int len = (int)d.getNBytes(); + { + RzCoreLocked core(Core()); + rz_core_write_duplicate_at(core, getLocationAddress(), src, len); + } refresh(); } @@ -906,14 +922,16 @@ void HexWidget::w_writePascalString() return; } bool ok = false; - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QString str = - d.getText(this, tr("Write Pascal string"), tr("String:"), QLineEdit::Normal, "", &ok); - if (ok && !str.isEmpty()) { - Core()->cmdRawAt(QString("ws %1").arg(str), getLocationAddress()); - refresh(); + QString str = QInputDialog::getText(this, tr("Write Pascal string"), tr("String:"), + QLineEdit::Normal, "", &ok); + if (!ok || str.isEmpty()) { + return; } + { + RzCoreLocked core(Core()); + rz_core_write_length_string_at(core, getLocationAddress(), str.toUtf8().constData()); + } + refresh(); } void HexWidget::w_writeWideString() @@ -922,14 +940,16 @@ void HexWidget::w_writeWideString() return; } bool ok = false; - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QString str = - d.getText(this, tr("Write wide string"), tr("String:"), QLineEdit::Normal, "", &ok); - if (ok && !str.isEmpty()) { - Core()->cmdRawAt(QString("ww %1").arg(str), getLocationAddress()); - refresh(); + QString str = QInputDialog::getText(this, tr("Write wide string"), tr("String:"), + QLineEdit::Normal, "", &ok); + if (!ok || str.isEmpty()) { + return; } + { + RzCoreLocked core(Core()); + rz_core_write_string_wide_at(core, getLocationAddress(), str.toUtf8().constData()); + } + refresh(); } void HexWidget::w_writeCString() @@ -938,14 +958,16 @@ void HexWidget::w_writeCString() return; } bool ok = false; - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QString str = d.getText(this, tr("Write zero-terminated string"), tr("String:"), - QLineEdit::Normal, "", &ok); - if (ok && !str.isEmpty()) { - Core()->cmdRawAt(QString("wz %1").arg(str), getLocationAddress()); - refresh(); + QString str = QInputDialog::getText(this, tr("Write zero-terminated string"), tr("String:"), + QLineEdit::Normal, "", &ok); + if (!ok || str.isEmpty()) { + return; } + { + RzCoreLocked core(Core()); + rz_core_write_string_zero_at(core, getLocationAddress(), str.toUtf8().constData()); + } + refresh(); } void HexWidget::updateItemLength() From 82f14b56675f02d655977ae56ab8d161d3e20de8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 30 May 2022 13:01:55 +0200 Subject: [PATCH 54/94] Refactor VisualNavbar to use API instead of p-j (#2953) With the updated rizin, this also fixes any error prints saying "Cannot alloc for this range" and json errors when no valid range is available. --- src/core/Cutter.cpp | 54 ---------------------------- src/core/Cutter.h | 1 - src/widgets/VisualNavbar.cpp | 69 ++++++++++++++++++++++++++---------- src/widgets/VisualNavbar.h | 6 +++- 4 files changed, 56 insertions(+), 74 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 40cd43ff..ee27caaa 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3857,60 +3857,6 @@ QList CutterCore::getAllSearch(QString searchFor, QString spa return searchRef; } -BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount) -{ - BlockStatistics blockStats; - if (blocksCount == 0) { - blockStats.from = blockStats.to = blockStats.blocksize = 0; - return blockStats; - } - - CutterJson statsObj; - - // User TempConfig here to set the search boundaries to all sections. This makes sure - // that the Visual Navbar will show all the relevant addresses. - { - TempConfig tempConfig; - tempConfig.set("search.in", "bin.sections"); - statsObj = cmdj("p-j " + QString::number(blocksCount)); - } - - blockStats.from = statsObj[RJsonKey::from].toRVA(); - blockStats.to = statsObj[RJsonKey::to].toRVA(); - blockStats.blocksize = statsObj[RJsonKey::blocksize].toRVA(); - - for (CutterJson blockObj : statsObj[RJsonKey::blocks]) { - BlockDescription block; - - block.addr = blockObj[RJsonKey::offset].toRVA(); - block.size = blockObj[RJsonKey::size].toRVA(); - block.flags = blockObj[RJsonKey::flags].toSt64(); - block.functions = blockObj[RJsonKey::functions].toSt64(); - block.inFunctions = blockObj[RJsonKey::in_functions].toSt64(); - block.comments = blockObj[RJsonKey::comments].toSt64(); - block.symbols = blockObj[RJsonKey::symbols].toSt64(); - block.strings = blockObj[RJsonKey::strings].toSt64(); - - block.rwx = 0; - QString rwxStr = blockObj[RJsonKey::rwx].toString(); - if (rwxStr.length() == 3) { - if (rwxStr[0] == 'r') { - block.rwx |= (1 << 0); - } - if (rwxStr[1] == 'w') { - block.rwx |= (1 << 1); - } - if (rwxStr[2] == 'x') { - block.rwx |= (1 << 2); - } - } - - blockStats.blocks << block; - } - - return blockStats; -} - QList CutterCore::getXRefsForVariable(QString variableName, bool findWrites, RVA offset) { diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 66b7b0f3..09a5d767 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -658,7 +658,6 @@ public: QList getMemoryMap(); QList getAllSearch(QString searchFor, QString space, QString in); - BlockStatistics getBlockStatistics(unsigned int blocksCount); QList getBreakpoints(); QList getAllProcesses(); /** diff --git a/src/widgets/VisualNavbar.cpp b/src/widgets/VisualNavbar.cpp index 3ff9f2ac..733430ca 100644 --- a/src/widgets/VisualNavbar.cpp +++ b/src/widgets/VisualNavbar.cpp @@ -21,7 +21,8 @@ VisualNavbar::VisualNavbar(MainWindow *main, QWidget *parent) graphicsView(new QGraphicsView), seekGraphicsItem(nullptr), PCGraphicsItem(nullptr), - main(main) + main(main), + stats(nullptr, rz_core_analysis_stats_free) { Q_UNUSED(parent); @@ -114,7 +115,34 @@ void VisualNavbar::fetchAndPaintData() void VisualNavbar::fetchStats() { - stats = Core()->getBlockStatistics(statsWidth); + static const ut64 blocksCount = 2048; + + RzCoreLocked core(Core()); + stats.reset(nullptr); + RzList *list = rz_core_get_boundaries_prot(core, -1, NULL, "search"); + if (!list) { + return; + } + RzListIter *iter; + RzIOMap *map; + ut64 from = UT64_MAX; + ut64 to = 0; + CutterRzListForeach (list, iter, RzIOMap, map) { + ut64 f = rz_itv_begin(map->itv); + ut64 t = rz_itv_end(map->itv); + if (f < from) { + from = f; + } + if (t > to) { + to = t; + } + } + rz_list_free(list); + to--; // rz_core_analysis_get_stats takes inclusive ranges + if (to < from) { + return; + } + stats.reset(rz_core_analysis_get_stats(core, from, to, RZ_MAX(1, (to + 1 - from) / blocksCount))); } enum class DataType : int { Empty, Code, String, Symbol, Count }; @@ -127,17 +155,18 @@ void VisualNavbar::updateGraphicsScene() PCGraphicsItem = nullptr; graphicsScene->setBackgroundBrush(QBrush(Config()->getColor("gui.navbar.empty"))); - if (stats.to <= stats.from) { + if (!stats) { return; } int w = graphicsView->width(); int h = graphicsView->height(); - RVA totalSize = stats.to - stats.from; - RVA beginAddr = stats.from; + RVA totalSize = stats->to - stats->from + 1; + RVA beginAddr = stats->from; - double widthPerByte = (double)w / (double)totalSize; + double widthPerByte = (double)w + / (double)(totalSize ? totalSize : pow(2.0, 64.0)); // account for overflow on 2^64 auto xFromAddr = [widthPerByte, beginAddr](RVA addr) -> double { return (addr - beginAddr) * widthPerByte; }; @@ -153,24 +182,28 @@ void VisualNavbar::updateGraphicsScene() DataType lastDataType = DataType::Empty; QGraphicsRectItem *dataItem = nullptr; QRectF dataItemRect(0.0, 0.0, 0.0, h); - for (const BlockDescription &block : stats.blocks) { + for (size_t i = 0; i < rz_vector_len(&stats->blocks); i++) { + RzCoreAnalysisStatsItem *block = + reinterpret_cast(rz_vector_index_ptr(&stats->blocks, i)); + ut64 from = rz_core_analysis_stats_get_block_from(stats.get(), i); + ut64 to = rz_core_analysis_stats_get_block_to(stats.get(), i) + 1; // Keep track of where which memory segment is mapped so we are able to convert from // address to X coordinate and vice versa. XToAddress x2a; - x2a.x_start = xFromAddr(block.addr); - x2a.x_end = xFromAddr(block.addr + block.size); - x2a.address_from = block.addr; - x2a.address_to = block.addr + block.size; + x2a.x_start = xFromAddr(from); + x2a.x_end = xFromAddr(to); + x2a.address_from = from; + x2a.address_to = to; xToAddress.append(x2a); DataType dataType; - if (block.functions > 0) { + if (block->functions) { dataType = DataType::Code; - } else if (block.strings > 0) { + } else if (block->strings) { dataType = DataType::String; - } else if (block.symbols > 0) { + } else if (block->symbols) { dataType = DataType::Symbol; - } else if (block.inFunctions > 0) { + } else if (block->in_functions) { dataType = DataType::Code; } else { lastDataType = DataType::Empty; @@ -178,7 +211,7 @@ void VisualNavbar::updateGraphicsScene() } if (dataType == lastDataType) { - double r = xFromAddr(block.addr + block.size); + double r = xFromAddr(to); if (r > dataItemRect.right()) { dataItemRect.setRight(r); dataItem->setRect(dataItemRect); @@ -187,8 +220,8 @@ void VisualNavbar::updateGraphicsScene() continue; } - dataItemRect.setX(xFromAddr(block.addr)); - dataItemRect.setRight(xFromAddr(block.addr + block.size)); + dataItemRect.setX(xFromAddr(from)); + dataItemRect.setRight(xFromAddr(to)); dataItem = new QGraphicsRectItem(); dataItem->setPen(Qt::NoPen); diff --git a/src/widgets/VisualNavbar.h b/src/widgets/VisualNavbar.h index b11eb170..848f7b18 100644 --- a/src/widgets/VisualNavbar.h +++ b/src/widgets/VisualNavbar.h @@ -6,6 +6,10 @@ #include "core/Cutter.h" +#include + +#include + class MainWindow; class QGraphicsView; @@ -43,7 +47,7 @@ private: QGraphicsRectItem *PCGraphicsItem; MainWindow *main; - BlockStatistics stats; + std::unique_ptr stats; unsigned int statsWidth = 0; unsigned int previousWidth = 0; From 575952d22e79ae79c3b2e7ddd99207b2f74ecc81 Mon Sep 17 00:00:00 2001 From: bartoszek Date: Mon, 30 May 2022 13:04:34 +0200 Subject: [PATCH 55/94] Add missing Rizin headers in python bindings (#2943) --- src/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4fb5d4d4..47357c69 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -503,6 +503,10 @@ if(CUTTER_ENABLE_PYTHON) target_link_libraries(Cutter PRIVATE Shiboken2::libshiboken PySide2::pyside2) get_target_property(RAW_BINDINGS_INCLUDE_DIRS Cutter INCLUDE_DIRECTORIES) + if(NOT CUTTER_USE_BUNDLED_RIZIN) + get_target_property(RAW_RIZIN_INCLUDE_DIRS ${RIZIN_TARGET} INTERFACE_INCLUDE_DIRECTORIES) + list(APPEND RAW_BINDINGS_INCLUDE_DIRS "${RAW_RIZIN_INCLUDE_DIRS}") + endif() set(BINDINGS_INCLUDE_DIRS "") foreach(_dir ${RAW_BINDINGS_INCLUDE_DIRS}) string(REGEX REPLACE "\\$" "\\1" _dir ${_dir}) From 832dae38b493b699ff3984ea005e9e0a59394000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 30 May 2022 18:13:55 +0200 Subject: [PATCH 56/94] Fix EditVariablesDialog parenting (#2954) This fixes the dialog being placed weirdly when using the 'Y' shortcut because it was parented to the DisassemblyContextMenu, which itself might not be shown at all. --- src/menus/DisassemblyContextMenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index a60e2196..c0791493 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -875,7 +875,7 @@ void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered() return; } - EditVariablesDialog dialog(fcn->addr, curHighlightedWord, this); + EditVariablesDialog dialog(fcn->addr, curHighlightedWord, this->mainWindow); if (dialog.empty()) { // don't show the dialog if there are no variables return; } From 49cf6555a89c34e0cdf331a0e56e779c24f02468 Mon Sep 17 00:00:00 2001 From: Islam Bassuni Date: Mon, 30 May 2022 19:34:17 +0200 Subject: [PATCH 57/94] Partially refactor Dashboard to API (#2930) Also fixes missing NX and PIC bits in Dashboard. --- src/widgets/Dashboard.cpp | 88 +++++++++++++++++++++------------------ src/widgets/Dashboard.h | 3 +- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index c0d0cf87..9b26927f 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -36,23 +36,8 @@ void Dashboard::updateContents() CutterJson item = docu["core"]; CutterJson item2 = docu["bin"]; - setPlainText(this->ui->fileEdit, item["file"].toString()); - setPlainText(this->ui->formatEdit, item["format"].toString()); setPlainText(this->ui->modeEdit, item["mode"].toString()); - setPlainText(this->ui->typeEdit, item["type"].toString()); - setPlainText(this->ui->sizeEdit, qhelpers::formatBytecount(item["size"].toUt64())); - setPlainText(this->ui->fdEdit, QString::number(item["fd"].toUt64())); - - setPlainText(this->ui->archEdit, item2["arch"].toString()); - setPlainText(this->ui->langEdit, item2["lang"].toString().toUpper()); - setPlainText(this->ui->classEdit, item2["class"].toString()); - setPlainText(this->ui->machineEdit, item2["machine"].toString()); - setPlainText(this->ui->osEdit, item2["os"].toString()); - setPlainText(this->ui->subsysEdit, item2["subsys"].toString()); - setPlainText(this->ui->endianEdit, item2["endian"].toString()); setPlainText(this->ui->compilationDateEdit, item2["compiled"].toString()); - setPlainText(this->ui->compilerEdit, item2["compiler"].toString()); - setPlainText(this->ui->bitsEdit, QString::number(item2["bits"].toUt64())); if (!item2["relro"].toString().isEmpty()) { QString relro = item2["relro"].toString().section(QLatin1Char(' '), 0, 0); @@ -62,21 +47,37 @@ void Dashboard::updateContents() setPlainText(this->ui->relroEdit, "N/A"); } - setPlainText(this->ui->baddrEdit, RzAddressString(item2["baddr"].toRVA())); - - // set booleans - setBool(this->ui->vaEdit, item2, "va"); - setBool(this->ui->canaryEdit, item2, "canary"); - setBool(this->ui->cryptoEdit, item2, "crypto"); - setBool(this->ui->nxEdit, item2, "nx"); - setBool(this->ui->picEdit, item2, "pic"); - setBool(this->ui->staticEdit, item2, "static"); - setBool(this->ui->strippedEdit, item2, "stripped"); - setBool(this->ui->relocsEdit, item2, "relocs"); - // Add file hashes, analysis info and libraries RzCoreLocked core(Core()); RzBinFile *bf = rz_bin_cur(core->bin); + RzBinInfo *binInfo = rz_bin_get_info(core->bin); + + setPlainText(ui->fileEdit, binInfo ? binInfo->file : ""); + setPlainText(ui->formatEdit, binInfo ? binInfo->rclass : ""); + setPlainText(ui->typeEdit, binInfo ? binInfo->type : ""); + setPlainText(ui->archEdit, binInfo ? binInfo->arch : ""); + setPlainText(ui->langEdit, binInfo ? binInfo->lang : ""); + setPlainText(ui->classEdit, binInfo ? binInfo->bclass : ""); + setPlainText(ui->machineEdit, binInfo ? binInfo->machine : ""); + setPlainText(ui->osEdit, binInfo ? binInfo->os : ""); + setPlainText(ui->subsysEdit, binInfo ? binInfo->subsystem : ""); + setPlainText(ui->compilerEdit, binInfo ? binInfo->compiler : ""); + setPlainText(ui->bitsEdit, binInfo ? QString::number(binInfo->bits) : ""); + setPlainText(ui->baddrEdit, binInfo ? RzAddressString(rz_bin_file_get_baddr(bf)) : ""); + setPlainText(ui->sizeEdit, binInfo ? qhelpers::formatBytecount(bf->size) : ""); + setPlainText(ui->fdEdit, binInfo ? QString::number(bf->fd) : ""); + + // Setting the value of "Endianness" + const char *endian = binInfo ? (binInfo->big_endian ? "BE" : "LE") : ""; + setPlainText(this->ui->endianEdit, endian); + + // Setting boolean values + setRzBinInfo(binInfo); + + // Setting the value of "static" + int static_value = rz_bin_is_static(core->bin); + setPlainText(ui->staticEdit, tr(setBoolText(static_value))); + RzList *hashes = rz_bin_file_compute_hashes(core->bin, bf, UT64_MAX); // Delete hashesWidget if it isn't null to avoid duplicate components @@ -222,19 +223,26 @@ void Dashboard::setPlainText(QLineEdit *textBox, const QString &text) } /** - * @brief Set the text of a QLineEdit as True, False or N/A if it does not exist - * @param textBox - * @param isTrue + * @brief Setting boolean values of binary information in dashboard + * @param RzBinInfo */ -void Dashboard::setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key) +void Dashboard::setRzBinInfo(RzBinInfo *binInfo) { - if (jsonObject[key].valid()) { - if (jsonObject[key].toBool()) { - setPlainText(textBox, tr("True")); - } else { - setPlainText(textBox, tr("False")); - } - } else { - setPlainText(textBox, tr("N/A")); - } + setPlainText(ui->vaEdit, binInfo ? setBoolText(binInfo->has_va) : ""); + setPlainText(ui->canaryEdit, binInfo ? setBoolText(binInfo->has_canary) : ""); + setPlainText(ui->cryptoEdit, binInfo ? setBoolText(binInfo->has_crypto) : ""); + setPlainText(ui->nxEdit, binInfo ? setBoolText(binInfo->has_nx) : ""); + setPlainText(ui->picEdit, binInfo ? setBoolText(binInfo->has_pi) : ""); + setPlainText(ui->strippedEdit, + binInfo ? setBoolText(RZ_BIN_DBG_STRIPPED & binInfo->dbg_info) : ""); + setPlainText(ui->relocsEdit, binInfo ? setBoolText(RZ_BIN_DBG_RELOCS & binInfo->dbg_info) : ""); +} + +/** + * @brief Set the text of a QLineEdit as True, False + * @param boolean value + */ +const char *Dashboard::setBoolText(bool value) +{ + return value ? "True" : "False"; } diff --git a/src/widgets/Dashboard.h b/src/widgets/Dashboard.h index 61a2c677..a7ee5c15 100644 --- a/src/widgets/Dashboard.h +++ b/src/widgets/Dashboard.h @@ -33,7 +33,8 @@ private slots: private: std::unique_ptr ui; void setPlainText(QLineEdit *textBox, const QString &text); - void setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key); + void setRzBinInfo(RzBinInfo *binInfo); + const char *setBoolText(bool value); QWidget *hashesWidget = nullptr; }; From 712709200aa9e11ac09e7d83a82e3a1ee0d1598f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 30 May 2022 19:34:33 +0200 Subject: [PATCH 58/94] Fix null deref in strings loading without any file (#2955) --- src/core/Cutter.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index ee27caaa..0f31eddd 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -542,10 +542,7 @@ CutterJson CutterCore::cmdjTask(const QString &str) RizinCmdTask task(str); task.startTask(); task.joinTask(); - const char *res = task.getResultRaw(); - char *copy = static_cast(rz_mem_alloc(strlen(res) + 1)); - strcpy(copy, res); - return parseJson(copy, str); + return task.getResultJson(); } CutterJson CutterCore::parseJson(char *res, const char *cmd) From 266db132aa35992a7595cc5c46852ea8db4c0bec Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Mon, 6 Jun 2022 11:27:13 +0200 Subject: [PATCH 59/94] Download and install sigdb option (#2949) * Download and install sigdb option and disable swift demangler when libswift is installed * Remove dir.prefix and use rz_core_analysis_sigdb_list for sigdb * Use a different color for flirts * Updated to rizin dev * Use rz_path_set_prefix to set the prefix path on OSX bundle --- .github/workflows/ccpp.yml | 3 ++ CMakeLists.txt | 4 ++ cmake/BundledRizin.cmake | 8 ++++ dist/CMakeLists.txt | 8 +--- src/CutterApplication.cpp | 4 +- src/common/ColorThemeWorker.cpp | 4 +- src/common/Configuration.cpp | 2 + src/core/Cutter.cpp | 73 ++++++++------------------------- src/widgets/FunctionsWidget.cpp | 2 + 9 files changed, 44 insertions(+), 64 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 64a3f7f6..a1aec8cb 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -120,6 +120,7 @@ jobs: -DCUTTER_USE_BUNDLED_RIZIN=ON \ -DCUTTER_APPIMAGE_BUILD=ON \ -DCUTTER_ENABLE_PACKAGING=ON \ + -DCUTTER_ENABLE_SIGDB=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ @@ -185,6 +186,7 @@ jobs: -DCUTTER_ENABLE_CRASH_REPORTS=ON \ -DCUTTER_USE_BUNDLED_RIZIN=ON \ -DCUTTER_ENABLE_PACKAGING=ON \ + -DCUTTER_ENABLE_SIGDB=ON \ -DCUTTER_PACKAGE_DEPENDENCIES=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ @@ -225,6 +227,7 @@ jobs: -DCUTTER_ENABLE_PYTHON=ON ^ -DCUTTER_ENABLE_PYTHON_BINDINGS=ON ^ -DCUTTER_ENABLE_PACKAGING=ON ^ + -DCUTTER_ENABLE_SIGDB=ON ^ -DCUTTER_PACKAGE_DEPENDENCIES=ON ^ -DCUTTER_PACKAGE_RZ_GHIDRA=ON ^ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON ^ diff --git a/CMakeLists.txt b/CMakeLists.txt index 991368ec..9498c796 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ set(SHIBOKEN_EXTRA_OPTIONS "" CACHE STRING "Extra options for shiboken generator set(CUTTER_EXTRA_PLUGIN_DIRS "" CACHE STRING "List of addition plugin locations") option(CUTTER_ENABLE_DEPENDENCY_DOWNLOADS "Enable downloading of dependencies. Setting to OFF doesn't affect any downloads done by rizin build." OFF) option(CUTTER_ENABLE_PACKAGING "Enable building platform-specific packages for distributing" OFF) +option(CUTTER_ENABLE_SIGDB "Downloads and installs sigdb (only available when CUTTER_USE_BUNDLED_RIZIN=ON)." OFF) option(CUTTER_PACKAGE_DEPENDENCIES "During install step include the third party dependencies." OFF) option(CUTTER_PACKAGE_RZ_GHIDRA "Compile and install rz-ghidra during install step." OFF) option(CUTTER_PACKAGE_RZ_LIBSWIFT, "Compile and install rz-libswift demangler during the install step." OFF) @@ -123,6 +124,9 @@ message(STATUS "") message(STATUS "Building Cutter version ${CUTTER_VERSION_FULL}") message(STATUS "Options:") message(STATUS "- Bundled rizin: ${CUTTER_USE_BUNDLED_RIZIN}") +if(CUTTER_USE_BUNDLED_RIZIN) + message(STATUS "- Bundled sigdb: ${CUTTER_ENABLE_SIGDB}") +endif() message(STATUS "- Python: ${CUTTER_ENABLE_PYTHON}") message(STATUS "- Python Bindings: ${CUTTER_ENABLE_PYTHON_BINDINGS}") message(STATUS "- Crash Handling: ${CUTTER_ENABLE_CRASH_REPORTS}") diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 83e4c128..7955c279 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -18,6 +18,14 @@ if (CUTTER_ENABLE_PACKAGING) list(APPEND MESON_OPTIONS "-Dportable=true") endif() +if (CUTTER_ENABLE_SIGDB) + list(APPEND MESON_OPTIONS "-Dinstall_sigdb=true") +endif() + +if (CUTTER_PACKAGE_RZ_LIBSWIFT AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + list(APPEND MESON_OPTIONS "-Duse_swift_demangler=false") +endif() + find_program(MESON meson) if(NOT MESON) message(FATAL_ERROR "Failed to find meson, which is required to build bundled rizin") diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index 6ce64463..fa4b80e5 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -92,7 +92,7 @@ if(APPLE) get_filename_component(QT_PREFIX "${MACDEPLOYQT_PATH}/../.." ABSOLUTE) list(APPEND RZ_GHIDRA_PREFIX_PATH "${QT_PREFIX}") - set(RIZIN_INSTALL_PLUGDIR "share/rizin/plugins") # escaped backslash on purpose, should be evaluated later + set(RIZIN_INSTALL_PLUGDIR "lib/rizin/plugins") # escaped backslash on purpose, should be evaluated later if (CUTTER_PACKAGE_JSDEC AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) install(CODE " @@ -139,11 +139,7 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) INSTALL_COMMAND "" ) endif() - if (WIN32) - set (GHIDRA_OPTIONS " - \"-DRIZIN_INSTALL_PLUGDIR=\${CMAKE_INSTALL_PREFIX}/${RIZIN_INSTALL_PLUGDIR}\" - -DCUTTER_INSTALL_PLUGDIR=plugins/native") - elseif (APPLE) + if (WIN32 OR APPLE) set (GHIDRA_OPTIONS " \"-DRIZIN_INSTALL_PLUGDIR=\${CMAKE_INSTALL_PREFIX}/${RIZIN_INSTALL_PLUGDIR}\" -DCUTTER_INSTALL_PLUGDIR=plugins/native") diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index 2dccd156..bfd7679a 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -177,11 +177,11 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc { auto rzprefix = QDir(QCoreApplication::applicationDirPath()); // Contents/MacOS rzprefix.cdUp(); // Contents - rzprefix.cd("Resources"); // Contents/Resources/rz + rzprefix.cd("Resources"); // Contents/Resources/ auto sleighHome = rzprefix; sleighHome.cd( - "share/rizin/plugins/rz_ghidra_sleigh"); // Contents/Resources/rz/share/rizin/plugins/rz_ghidra_sleigh + "lib/rizin/plugins/rz_ghidra_sleigh"); // Contents/Resources/lib/rizin/plugins/rz_ghidra_sleigh Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath()); } #endif diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index c4abfd5c..a9e592ba 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -37,7 +37,8 @@ ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) QDir().mkpath(customRzThemesLocationPath); } - QDir currDir { QStringLiteral("%1%2%3").arg(rz_path_prefix(nullptr), RZ_SYS_DIR, RZ_THEMES) }; + char *theme_dir = rz_path_prefix(RZ_THEMES); + QDir currDir { theme_dir }; if (currDir.exists()) { standardRzThemesLocationPath = currDir.absolutePath(); } else { @@ -46,6 +47,7 @@ ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) "Most likely, Rizin is not properly installed.") .arg(currDir.path())); } + free(theme_dir); } QColor ColorThemeWorker::mergeColors(const QColor &upper, const QColor &lower) const diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 5239ad6b..25d5907a 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -46,6 +46,8 @@ const QHash> Configuration::cutterOptionColor { { DarkFlag, QColor(0x9b, 0x9b, 0x9b) }, { LightFlag, QColor(0x9b, 0x9b, 0x9b) } } }, { "gui.main", { { DarkFlag, QColor(0x21, 0xd8, 0x93) }, { LightFlag, QColor(0x00, 0x80, 0x00) } } }, + { "gui.flirt", + { { DarkFlag, QColor(0xd8, 0xbb, 0x21) }, { LightFlag, QColor(0xf1, 0xc4, 0x0f) } } }, { "gui.item_unsafe", { { DarkFlag, QColor(0xff, 0x81, 0x7b) }, { LightFlag, QColor(0xff, 0x81, 0x7b) } } }, { "gui.navbar.seek", diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 0f31eddd..161916cd 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -188,11 +188,13 @@ CutterCore *CutterCore::instance() void CutterCore::initialize(bool loadPlugins) { - auto prefix = QDir(QCoreApplication::applicationDirPath()); - -#if defined(CUTTER_ENABLE_PACKAGING) && defined(Q_OS_WIN) - auto prefixBytes = prefix.absolutePath().toUtf8(); - rz_path_prefix(prefixBytes.constData()); +#if defined(MACOS_RZ_BUNDLED) + auto app_path = QDir(QCoreApplication::applicationDirPath()); + app_path.cdUp(); + app_path.cd("Resources"); + qInfo() << "Setting Rizin prefix =" << app_path.absolutePath() + << " for macOS Application Bundle."; + rz_path_set_prefix(app_path.absolutePath().toUtf8().constData()); #endif rz_cons_new(); // initialize console @@ -203,34 +205,11 @@ void CutterCore::initialize(bool loadPlugins) rz_event_hook(core_->analysis->ev, RZ_EVENT_ALL, cutterREventCallback, this); -#if defined(APPIMAGE) || defined(MACOS_RZ_BUNDLED) -# ifdef APPIMAGE - // Executable is in appdir/bin - prefix.cdUp(); - qInfo() << "Setting Rizin prefix =" << prefix.absolutePath() << " for AppImage."; -# else // MACOS_RZ_BUNDLED - // Executable is in Contents/MacOS, prefix is Contents/Resources/rz - prefix.cdUp(); - prefix.cd("Resources"); - qInfo() << "Setting Rizin prefix =" << prefix.absolutePath() - << " for macOS Application Bundle."; - setConfig("dir.prefix", prefix.absolutePath()); -# endif - - auto pluginsDir = prefix; - if (pluginsDir.cd("share/rizin/plugins")) { - qInfo() << "Setting Rizin plugins dir =" << pluginsDir.absolutePath(); - setConfig("dir.plugins", pluginsDir.absolutePath()); - } else { - qInfo() << "Rizin plugins dir under" << pluginsDir.absolutePath() << "does not exist!"; - } -#endif - - if (!loadPlugins) { - setConfig("cfg.plugins", 0); - } - if (getConfigi("cfg.plugins")) { + if (loadPlugins) { + setConfig("cfg.plugins", true); rz_core_loadlibs(this->core_, RZ_CORE_LOADLIBS_ALL); + } else { + setConfig("cfg.plugins", false); } // IMPLICIT rz_bin_iobind (core_->bin, core_->io); @@ -3166,10 +3145,16 @@ QList CutterCore::getAllHeaders() return ret; } -static void sigdb_insert_element_into_qlist(RzList *list, QList &sigdb) +QList CutterCore::getSignaturesDB() { + CORE_LOCK(); + void *ptr = NULL; RzListIter *iter = NULL; + QList sigdb; + + RzList *list = rz_core_analysis_sigdb_list(core, true); + rz_list_foreach(list, iter, ptr) { RzSigDBEntry *sig = static_cast(ptr); @@ -3185,28 +3170,6 @@ static void sigdb_insert_element_into_qlist(RzList *list, QList CutterCore::getSignaturesDB() -{ - CORE_LOCK(); - QList sigdb; - RzList *list = nullptr; - - char *system_sigdb = rz_path_system(RZ_SIGDB); - if (RZ_STR_ISNOTEMPTY(system_sigdb) && rz_file_is_directory(system_sigdb)) { - list = rz_sign_sigdb_load_database(system_sigdb, true); - sigdb_insert_element_into_qlist(list, sigdb); - } - free(system_sigdb); - - const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path"); - if (RZ_STR_ISEMPTY(sigdb_path)) { - return sigdb; - } - - list = rz_sign_sigdb_load_database(sigdb_path, true); - sigdb_insert_element_into_qlist(list, sigdb); return sigdb; } diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index ab92ecd9..6324467b 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -274,6 +274,8 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const return QVariant(ConfigColor("gui.imports")); } else if (functionIsMain(function.offset)) { return QVariant(ConfigColor("gui.main")); + } else if (function.name.startsWith("flirt.")) { + return QVariant(ConfigColor("gui.flirt")); } return QVariant(this->property("color")); From 544b904c2c3474571e112599e56fc2a377fee112 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 8 Jun 2022 01:18:43 +0200 Subject: [PATCH 60/94] Yara plugin + fix linuxdeployqt plugins (#2924) --- .github/workflows/ccpp.yml | 9 +++-- CMakeLists.txt | 9 +++++ dist/CMakeLists.txt | 64 +++++++++++++++++++++++++++------- dist/MacOSSetupBundle.cmake.in | 3 ++ dist/bundle_rz_libswift.ps1 | 2 +- dist/bundle_rz_libyara.ps1 | 26 ++++++++++++++ scripts/rz-libyara.sh | 25 +++++++++++++ src/CutterApplication.cpp | 7 +--- src/plugins/PluginManager.cpp | 2 ++ 9 files changed, 122 insertions(+), 25 deletions(-) create mode 100644 dist/bundle_rz_libyara.ps1 create mode 100755 scripts/rz-libyara.sh diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index a1aec8cb..a1c8e0c5 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -124,6 +124,7 @@ jobs: -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ + -DCUTTER_PACKAGE_RZ_LIBYARA=ON \ -DCMAKE_INSTALL_PREFIX=appdir/usr \ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ .. @@ -142,20 +143,16 @@ jobs: ninja install "../scripts/appimage_embed_python.sh" appdir APP_PREFIX=`pwd`/appdir/usr - # export LD_LIBRARY_PATH=${APP_PREFIX}/lib:$Shiboken2_ROOT/lib + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$APP_PREFIX/lib/rizin/plugins" export PATH=$PATH:${APP_PREFIX}/bin - "../scripts/jsdec.sh" --prefix=`pwd`/appdir/usr wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" chmod a+x linuxdeployqt*.AppImage rm -fv "../cutter-deps/qt/plugins/imageformats/libqjp2.so" - # ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -executable=./appdir/usr/bin/python3 -bundle-non-qt-libs -no-strip -exclude-libs=libnss3.so,libnssutil3.so,libqjp2.so -ignore-glob=usr/lib/python3.9/**/* -verbose=2 - # exclude librzghidra cutter plugin because cutter and rz plugin is loaded manuallly as they are plugins linuxdeployqt doesn't know this ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop \ -executable=./appdir/usr/bin/python3 \ -appimage \ -no-strip -exclude-libs=libnss3.so,libnssutil3.so,libqjp2.so \ -ignore-glob=usr/lib/python3.9/**/* \ - -ignore-glob=usr/share/rizin/cutter/plugins/native/librz_ghidra_cutter.so \ -verbose=2 find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq export APPIMAGE_FILE="Cutter-${PACKAGE_ID}-x64.Linux.AppImage" @@ -192,6 +189,7 @@ jobs: -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ -DCUTTER_PACKAGE_JSDEC=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ + -DCUTTER_PACKAGE_RZ_LIBYARA=ON \ -DCPACK_PACKAGE_FILE_NAME="$PACKAGE_NAME" \ -DCMAKE_FRAMEWORK_PATH="$BREAKPAD_FRAMEWORK_DIR" \ -DCPACK_BUNDLE_APPLE_CERT_APP="-" \ @@ -231,6 +229,7 @@ jobs: -DCUTTER_PACKAGE_DEPENDENCIES=ON ^ -DCUTTER_PACKAGE_RZ_GHIDRA=ON ^ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON ^ + -DCUTTER_PACKAGE_RZ_LIBYARA=ON ^ -DCUTTER_PACKAGE_JSDEC=ON ^ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON ^ -DCUTTER_ENABLE_CRASH_REPORTS=ON ^ diff --git a/CMakeLists.txt b/CMakeLists.txt index 9498c796..034478ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ option(CUTTER_ENABLE_SIGDB "Downloads and installs sigdb (only available when CU option(CUTTER_PACKAGE_DEPENDENCIES "During install step include the third party dependencies." OFF) option(CUTTER_PACKAGE_RZ_GHIDRA "Compile and install rz-ghidra during install step." OFF) option(CUTTER_PACKAGE_RZ_LIBSWIFT, "Compile and install rz-libswift demangler during the install step." OFF) +option(CUTTER_PACKAGE_RZ_LIBYARA, "Compile and install rz-libyara during the install step." OFF) option(CUTTER_PACKAGE_JSDEC "Compile and install jsdec during install step." OFF) OPTION(CUTTER_QT6 "Use QT6" OFF) @@ -132,6 +133,14 @@ message(STATUS "- Python Bindings: ${CUTTER_ENABLE_PYTHON_BINDINGS}") message(STATUS "- Crash Handling: ${CUTTER_ENABLE_CRASH_REPORTS}") message(STATUS "- KSyntaxHighlighting: ${KSYNTAXHIGHLIGHTING_STATUS}") message(STATUS "- Graphviz: ${CUTTER_ENABLE_GRAPHVIZ}") +message(STATUS "- Downloads dependencies: ${CUTTER_ENABLE_DEPENDENCY_DOWNLOADS}") +message(STATUS "- Enable Packaging: ${CUTTER_ENABLE_PACKAGING}") +message(STATUS "- Package Dependencies: ${CUTTER_PACKAGE_DEPENDENCIES}") +message(STATUS "- Package RzGhidra: ${CUTTER_PACKAGE_RZ_GHIDRA}") +message(STATUS "- Package RzLibSwift: ${CUTTER_PACKAGE_RZ_LIBSWIFT}") +message(STATUS "- Package RzLibYara: ${CUTTER_PACKAGE_RZ_LIBYARA}") +message(STATUS "- Package JSDec: ${CUTTER_PACKAGE_JSDEC}") +message(STATUS "- QT6: ${CUTTER_QT6}") message(STATUS "") add_subdirectory(src) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index fa4b80e5..ee962d2e 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -28,7 +28,7 @@ if(WIN32) WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to package jsdec\") + message(FATAL_ERROR \"Failed to package jsdec (returned \${SCRIPT_RESULT})\") endif() ") endif() @@ -40,7 +40,22 @@ if(WIN32) WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to package rz-libswift\") + message(FATAL_ERROR \"Failed to package rz-libswift (returned \${SCRIPT_RESULT})\") + endif() + ") + endif() + if (CUTTER_PACKAGE_RZ_LIBYARA AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + 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_rz_libyara.ps1\" + \"\${CMAKE_INSTALL_PREFIX}\" + \"-DCUTTER_INSTALL_PLUGDIR=plugins/native\" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz_libyara (returned \${SCRIPT_RESULT})\") endif() ") endif() @@ -93,29 +108,52 @@ if(APPLE) get_filename_component(QT_PREFIX "${MACDEPLOYQT_PATH}/../.." ABSOLUTE) list(APPEND RZ_GHIDRA_PREFIX_PATH "${QT_PREFIX}") set(RIZIN_INSTALL_PLUGDIR "lib/rizin/plugins") # escaped backslash on purpose, should be evaluated later +endif() - if (CUTTER_PACKAGE_JSDEC AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) +################################################ +# macOS + Linux +################################################ + +if(CUTTER_ENABLE_DEPENDENCY_DOWNLOADS AND (NOT WIN32)) + if (CUTTER_PACKAGE_JSDEC) install(CODE " - execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/jsdec.sh\" --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} + execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/jsdec.sh\" + --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to package jsdec\") + message(FATAL_ERROR \"Failed to package jsdec (returned \${SCRIPT_RESULT})\") endif() ") endif() - - if (CUTTER_PACKAGE_RZ_LIBSWIFT AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + if (CUTTER_PACKAGE_RZ_LIBSWIFT) install(CODE " - execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-libswift.sh\" --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} + execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-libswift.sh\" + --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to package rz-libswift\") + message(FATAL_ERROR \"Failed to package rz-libswift (returned \${SCRIPT_RESULT})\") + endif() + ") + endif() + if (CUTTER_PACKAGE_RZ_LIBYARA) + if(APPLE) + set (YARA_PLUGIN_OPTIONS "-DCUTTER_INSTALL_PLUGDIR=plugins/native") + else() + set (YARA_PLUGIN_OPTIONS "") + endif() + install(CODE " + execute_process(COMMAND + \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-libyara.sh\" + \"\${CMAKE_INSTALL_PREFIX}\" \"${YARA_PLUGIN_OPTIONS}\" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz-libyara (returned \${SCRIPT_RESULT})\") endif() ") endif() - endif() ################################################ @@ -144,7 +182,7 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) \"-DRIZIN_INSTALL_PLUGDIR=\${CMAKE_INSTALL_PREFIX}/${RIZIN_INSTALL_PLUGDIR}\" -DCUTTER_INSTALL_PLUGDIR=plugins/native") else() - set (GHIDRA_OPTIONS "") + set (GHIDRA_OPTIONS "-DCUTTER_INSTALL_PLUGDIR=\${CMAKE_INSTALL_PREFIX}/share/rizin/cutter/plugins/native") endif() install(CODE " execute_process( @@ -161,14 +199,14 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) -G Ninja ) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to configure rz-ghidra\") + message(FATAL_ERROR \"Failed to configure rz-ghidra (returned \${SCRIPT_RESULT})\") endif() execute_process(WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/rz-ghidra-prefix/src/rz-ghidra-build RESULT_VARIABLE SCRIPT_RESULT COMMAND \${CMAKE_COMMAND} --build . --target install ) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to install rz-ghidra plugin\") + message(FATAL_ERROR \"Failed to install rz-ghidra plugin (returned \${SCRIPT_RESULT})\") endif() ") endif() diff --git a/dist/MacOSSetupBundle.cmake.in b/dist/MacOSSetupBundle.cmake.in index 88bd6fd8..ff8bdb35 100644 --- a/dist/MacOSSetupBundle.cmake.in +++ b/dist/MacOSSetupBundle.cmake.in @@ -60,6 +60,9 @@ run_or_die(COMMAND install_name_tool run_or_die(COMMAND install_name_tool -add_rpath "@executable_path/../Resources/lib" "${EXECUTABLE_DIR}/cutter") +run_or_die(COMMAND install_name_tool + -add_rpath "@executable_path/../Resources/lib/rizin/plugins" + "${EXECUTABLE_DIR}/cutter") set(MACDEPLOYQT_COMMAND "${MACDEPLOYQT_PATH}" "${BUNDLE_PATH}" "-verbose=2" "-libpath=${CMAKE_INSTALL_PREFIX}/lib") message("Running macdeployqt \"${MACDEPLOYQT_COMMAND}\"") diff --git a/dist/bundle_rz_libswift.ps1 b/dist/bundle_rz_libswift.ps1 index 12928c93..9fec607c 100644 --- a/dist/bundle_rz_libswift.ps1 +++ b/dist/bundle_rz_libswift.ps1 @@ -13,4 +13,4 @@ if(![System.IO.File]::Exists($pathdll)) { ls "$dist/lib/plugins/" throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) } -Remove-Item -Recurse -Force $dist/lib/plugins/libswift.lib +Remove-Item -Recurse -Force $dist/lib/plugins/swift.lib diff --git a/dist/bundle_rz_libyara.ps1 b/dist/bundle_rz_libyara.ps1 new file mode 100644 index 00000000..c3309b94 --- /dev/null +++ b/dist/bundle_rz_libyara.ps1 @@ -0,0 +1,26 @@ +$dist = $args[0] +$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 -C rz_libyara submodule init + git -C rz_libyara submodule update +} +cd rz_libyara +& meson.exe --buildtype=release --prefix=$dist build +ninja -C build install +$pathdll = "$dist/lib/plugins/rz_yara.dll" +if(![System.IO.File]::Exists($pathdll)) { + type build/meson-logs/meson-log.txt + ls "$dist/lib/plugins/" + throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) +} +Remove-Item -Recurse -Force $dist/lib/plugins/rz_yara.lib + +cd cutter-plugin +mkdir build +cd build +cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DRIZIN_INSTALL_PLUGDIR="../build" -DCMAKE_INSTALL_PREFIX="$dist" $cmake_opts .. +ninja +ninja install diff --git a/scripts/rz-libyara.sh b/scripts/rz-libyara.sh new file mode 100755 index 00000000..f316f2c5 --- /dev/null +++ b/scripts/rz-libyara.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -e + +SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") +INSTALL_PREFIX="$1" +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 -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" build +ninja -C build install + +cd cutter-plugin +mkdir build && cd build +cmake -G Ninja -DRIZIN_INSTALL_PLUGDIR="../build" -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" $EXTRA_CMAKE_OPTS .. +ninja +ninja install diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index bfd7679a..9d4d4dff 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -163,13 +163,8 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc appdir.cdUp(); // appdir auto sleighHome = appdir; - sleighHome.cd( - "share/rizin/plugins/rz_ghidra_sleigh"); // appdir/share/rizin/plugins/rz_ghidra_sleigh + sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh/"); // appdir/lib/rizin/plugins/rz_ghidra_sleigh/ Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath()); - - auto jsdecHome = appdir; - jsdecHome.cd("share/rizin/plugins/jsdec"); // appdir/share/rizin/plugins/jsdec - qputenv("JSDEC_HOME", jsdecHome.absolutePath().toLocal8Bit()); } #endif diff --git a/src/plugins/PluginManager.cpp b/src/plugins/PluginManager.cpp index 28cffb44..ac9c6104 100644 --- a/src/plugins/PluginManager.cpp +++ b/src/plugins/PluginManager.cpp @@ -65,6 +65,7 @@ void PluginManager::loadPluginsFromDir(const QDir &pluginsDir, bool writable) nativePluginsDir.mkdir("native"); } if (nativePluginsDir.cd("native")) { + qInfo() << "Native plugins are loaded from" << nativePluginsDir.absolutePath(); loadNativePlugins(nativePluginsDir); } @@ -74,6 +75,7 @@ void PluginManager::loadPluginsFromDir(const QDir &pluginsDir, bool writable) pythonPluginsDir.mkdir("python"); } if (pythonPluginsDir.cd("python")) { + qInfo() << "Python plugins are loaded from" << pythonPluginsDir.absolutePath(); loadPythonPlugins(pythonPluginsDir.absolutePath()); } #endif From 5fd55df710c80e0754c6a7f172488f1fcf7dd154 Mon Sep 17 00:00:00 2001 From: billow Date: Wed, 8 Jun 2022 08:02:26 +0800 Subject: [PATCH 61/94] Convert Rizin command calls to te Rizin APIs (#2960) * Convert `iCj` call to the API * Convert `icj` call to the API * Convert `iij` call to the API * Convert `iej` call to the API * Convert `CClj` call to the API * Convert `iEj` call to the API * Convert 'ihj' call to the API * Convert 'iSSj' call to the API --- src/core/Cutter.cpp | 275 +++++++++++++++++++++++++------------- src/core/Cutter.h | 2 +- src/widgets/Dashboard.cpp | 4 +- 3 files changed, 188 insertions(+), 93 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 161916cd..80e41699 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1415,9 +1415,19 @@ CutterJson CutterCore::getFileVersionInfo() return cmdj("iVj"); } -CutterJson CutterCore::getSignatureInfo() +QString CutterCore::getSignatureInfo() { - return cmdj("iCj"); + CORE_LOCK(); + RzBinFile *cur = rz_bin_cur(core->bin); + RzBinPlugin *plg = rz_bin_file_cur_plugin(cur); + if (!plg || !plg->signature) { + return {}; + } + char *signature = plg->signature(cur, true); + if (!signature) { + return {}; + } + return fromOwnedCharPtr(signature); } // Utility function to check if a telescoped item exists and add it with prefixes to the desc @@ -3049,25 +3059,64 @@ QList CutterCore::getAllFunctions() return funcList; } +static inline uint64_t rva(RzBinObject *o, uint64_t paddr, uint64_t vaddr, int va) +{ + return va ? rz_bin_object_get_vaddr(o, paddr, vaddr) : paddr; +} + QList CutterCore::getAllImports() { CORE_LOCK(); - QList ret; - - for (CutterJson importObject : cmdj("iij")) { - ImportDescription import; - - import.plt = importObject[RJsonKey::plt].toRVA(); - import.ordinal = importObject[RJsonKey::ordinal].toSt64(); - import.bind = importObject[RJsonKey::bind].toString(); - import.type = importObject[RJsonKey::type].toString(); - import.libname = importObject[RJsonKey::libname].toString(); - import.name = importObject[RJsonKey::name].toString(); - - ret << import; + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; + } + const RzList *imports = rz_bin_object_get_imports(bf->o); + if (!imports) { + return {}; } - return ret; + QList qList; + RzBinImport *import; + RzListIter *iter; + bool va = core->io->va || core->bin->is_debugger; + int bin_demangle = getConfigi("bin.demangle"); + int keep_lib = getConfigi("bin.demangle.libs"); + CutterRzListForeach (imports, iter, RzBinImport, import) { + if (RZ_STR_ISEMPTY(import->name)) { + continue; + } + + ImportDescription importDescription; + + RzBinSymbol *sym = rz_bin_object_get_symbol_of_import(bf->o, import); + ut64 addr = sym ? rva(bf->o, sym->paddr, sym->vaddr, va) : UT64_MAX; + QString name { import->name }; + if (RZ_STR_ISNOTEMPTY(import->classname)) { + name = QString("%1.%2").arg(import->classname, import->name); + } + if (bin_demangle) { + char *dname = rz_bin_demangle(bf, NULL, name.toUtf8().constData(), + importDescription.plt, keep_lib); + if (dname) { + name = fromOwnedCharPtr(dname); + } + } + if (core->bin->prefix) { + name = QString("%1.%2").arg(core->bin->prefix, name); + } + + importDescription.ordinal = (int)import->ordinal; + importDescription.bind = import->bind; + importDescription.type = import->type; + importDescription.libname = import->libname; + importDescription.name = name; + importDescription.plt = addr; + + qList << importDescription; + } + + return qList; } QList CutterCore::getAllExports() @@ -3129,16 +3178,24 @@ QList CutterCore::getAllSymbols() QList CutterCore::getAllHeaders() { CORE_LOCK(); + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; + } + const RzList *fields = rz_bin_object_get_fields(bf->o); + if (!fields) { + return {}; + } + RzListIter *iter; + RzBinField *field; QList ret; - for (CutterJson headerObject : cmdj("ihj")) { + CutterRzListForeach (fields, iter, RzBinField, field) { HeaderDescription header; - - header.vaddr = headerObject[RJsonKey::vaddr].toRVA(); - header.paddr = headerObject[RJsonKey::paddr].toRVA(); - header.value = headerObject[RJsonKey::comment].toString(); - header.name = headerObject[RJsonKey::name].toString(); - + header.vaddr = field->vaddr; + header.paddr = field->paddr; + header.value = RZ_STR_ISEMPTY(field->comment) ? "" : field->comment; + header.name = field->name; ret << header; } @@ -3177,20 +3234,31 @@ QList CutterCore::getSignaturesDB() QList CutterCore::getAllComments(const QString &filterType) { CORE_LOCK(); - QList ret; - - for (CutterJson commentObject : cmdj("CClj")) { - QString type = commentObject[RJsonKey::type].toString(); - if (type != filterType) + QList qList; + RzIntervalTreeIter it; + void *pVoid; + RzAnalysisMetaItem *item; + RzSpace *spaces = rz_spaces_current(&core->analysis->meta_spaces); + rz_interval_tree_foreach(&core->analysis->meta, it, pVoid) + { + item = reinterpret_cast(pVoid); + if (item->type != RZ_META_TYPE_COMMENT) { continue; + } + if (spaces && spaces != item->space) { + continue; + } + if (filterType != rz_meta_type_to_string(item->type)) { + continue; + } + RzIntervalNode *node = rz_interval_tree_iter_get(&it); CommentDescription comment; - comment.offset = commentObject[RJsonKey::offset].toRVA(); - comment.name = commentObject[RJsonKey::name].toString(); - - ret << comment; + comment.offset = node->start; + comment.name = fromOwnedCharPtr(rz_str_escape(item->str)); + qList << comment; } - return ret; + return qList; } QList CutterCore::getAllRelocs() @@ -3354,82 +3422,109 @@ QStringList CutterCore::getSectionList() return ret; } +static inline QString perms_str(int perms) +{ + return QString((perms & RZ_PERM_SHAR) ? 's' : '-') + rz_str_rwx_i(perms); +} + QList CutterCore::getAllSegments() { CORE_LOCK(); - QList ret; - - for (CutterJson segmentObject : cmdj("iSSj")) { - QString name = segmentObject[RJsonKey::name].toString(); - if (name.isEmpty()) - continue; - - SegmentDescription segment; - segment.name = name; - segment.vaddr = segmentObject[RJsonKey::vaddr].toRVA(); - segment.paddr = segmentObject[RJsonKey::paddr].toRVA(); - segment.size = segmentObject[RJsonKey::size].toRVA(); - segment.vsize = segmentObject[RJsonKey::vsize].toRVA(); - segment.perm = segmentObject[RJsonKey::perm].toString(); - - ret << segment; + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; } + RzList *segments = rz_bin_object_get_segments(bf->o); + if (!segments) { + return {}; + } + + RzBinSection *segment; + RzListIter *iter; + QList ret; + CutterRzListForeach (segments, iter, RzBinSection, segment) { + SegmentDescription segDesc; + segDesc.name = segment->name; + segDesc.vaddr = segment->vaddr; + segDesc.paddr = segment->paddr; + segDesc.size = segment->size; + segDesc.vsize = segment->vsize; + segDesc.perm = perms_str(segment->perm); + } + rz_list_free(segments); + return ret; } QList CutterCore::getAllEntrypoint() { CORE_LOCK(); - QList ret; + RzBinFile *bf = rz_bin_cur(core->bin); + bool va = core->io->va || core->bin->is_debugger; + ut64 baddr = rz_bin_get_baddr(core->bin); + ut64 laddr = rz_bin_get_laddr(core->bin); - for (CutterJson entrypointObject : cmdj("iej")) { - EntrypointDescription entrypoint; + QList qList; + const RzList *entries = rz_bin_object_get_entries(bf->o); + RzListIter *iter; + RzBinAddr *entry; + CutterRzListForeach (entries, iter, RzBinAddr, entry) { + if (entry->type != RZ_BIN_ENTRY_TYPE_PROGRAM) { + continue; + } + const char *type = rz_bin_entry_type_string(entry->type); - entrypoint.vaddr = entrypointObject[RJsonKey::vaddr].toRVA(); - entrypoint.paddr = entrypointObject[RJsonKey::paddr].toRVA(); - entrypoint.baddr = entrypointObject[RJsonKey::baddr].toRVA(); - entrypoint.laddr = entrypointObject[RJsonKey::laddr].toRVA(); - entrypoint.haddr = entrypointObject[RJsonKey::haddr].toRVA(); - entrypoint.type = entrypointObject[RJsonKey::type].toString(); - - ret << entrypoint; + EntrypointDescription entrypointDescription; + entrypointDescription.vaddr = rva(bf->o, entry->paddr, entry->vaddr, va); + entrypointDescription.paddr = entry->paddr; + entrypointDescription.baddr = baddr; + entrypointDescription.laddr = laddr; + entrypointDescription.haddr = entry->hpaddr ? entry->hpaddr : UT64_MAX; + entrypointDescription.type = type ? type : "unknown"; + qList << entrypointDescription; } - return ret; + + return qList; } QList CutterCore::getAllClassesFromBin() { CORE_LOCK(); - QList ret; - - for (CutterJson classObject : cmdj("icj")) { - BinClassDescription cls; - - cls.name = classObject[RJsonKey::classname].toString(); - cls.addr = classObject[RJsonKey::addr].toRVA(); - cls.index = classObject[RJsonKey::index].toUt64(); - - for (CutterJson methObject : classObject[RJsonKey::methods]) { - BinClassMethodDescription meth; - - meth.name = methObject[RJsonKey::name].toString(); - meth.addr = methObject[RJsonKey::addr].toRVA(); - - cls.methods << meth; - } - - for (CutterJson fieldObject : classObject[RJsonKey::fields]) { - BinClassFieldDescription field; - - field.name = fieldObject[RJsonKey::name].toString(); - field.addr = fieldObject[RJsonKey::addr].toRVA(); - - cls.fields << field; - } - - ret << cls; + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; } - return ret; + + const RzList *cs = rz_bin_object_get_classes(bf->o); + if (!cs) { + return {}; + } + + QList qList; + RzListIter *iter, *iter2, *iter3; + RzBinClass *c; + RzBinSymbol *sym; + RzBinField *f; + CutterRzListForeach (cs, iter, RzBinClass, c) { + BinClassDescription classDescription; + classDescription.name = c->name; + classDescription.addr = c->addr; + classDescription.index = c->index; + CutterRzListForeach (c->methods, iter2, RzBinSymbol, sym) { + BinClassMethodDescription methodDescription; + methodDescription.name = sym->name; + methodDescription.addr = sym->vaddr; + classDescription.methods << methodDescription; + } + CutterRzListForeach (c->fields, iter3, RzBinField, f) { + BinClassFieldDescription fieldDescription; + fieldDescription.name = f->name; + fieldDescription.addr = f->vaddr; + classDescription.fields << fieldDescription; + } + qList << classDescription; + } + return qList; } QList CutterCore::getAllClassesFromFlags() diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 09a5d767..45cde76d 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -568,7 +568,7 @@ public: RVA getOffsetJump(RVA addr); CutterJson getFileInfo(); - CutterJson getSignatureInfo(); + QString getSignatureInfo(); CutterJson getFileVersionInfo(); void setGraphEmpty(bool empty); bool isGraphEmpty(); diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 9b26927f..0d491009 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -153,7 +153,7 @@ void Dashboard::updateContents() ui->verticalLayout_2->addSpacerItem(spacer); // Check if signature info and version info available - if (!Core()->getSignatureInfo().size()) { + if (Core()->getSignatureInfo().isEmpty()) { ui->certificateButton->setEnabled(false); } if (!Core()->getFileVersionInfo().size()) { @@ -171,7 +171,7 @@ void Dashboard::on_certificateButton_clicked() viewDialog = new QDialog(this); view = new CutterTreeView(viewDialog); model = new JsonModel(); - qstrCertificates = Core()->getSignatureInfo().toJson(); + qstrCertificates = Core()->getSignatureInfo(); } if (!viewDialog->isVisible()) { std::string strCertificates = qstrCertificates.toUtf8().constData(); From 05b771b8bbfbf321d61a50744e6ac92aaffd94b2 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 8 Jun 2022 18:34:03 +0200 Subject: [PATCH 62/94] Bump version to 2.1.0 from stable (#2962) --- .appveyor.yml | 2 +- CMakeLists.txt | 4 ++-- docs/source/conf.py | 4 ++-- rizin | 2 +- src/re.rizin.cutter.appdata.xml | 1 + 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4f0866ae..84a3b615 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.0.5-git-{build}' +version: '2.1.0-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 034478ca..9b9a9828 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,8 +36,8 @@ if(NOT CUTTER_ENABLE_PYTHON) endif() set(CUTTER_VERSION_MAJOR 2) -set(CUTTER_VERSION_MINOR 0) -set(CUTTER_VERSION_PATCH 5) +set(CUTTER_VERSION_MINOR 1) +set(CUTTER_VERSION_PATCH 0) set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index ba34c0fb..b2677d68 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.0' +version = '2.1' # The full version, including a2lpha/beta/rc tags -release = '2.0.5' +release = '2.1.0' # -- General configuration --------------------------------------------------- diff --git a/rizin b/rizin index 2373c538..6498ee67 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 2373c53880e017be86afed5454bca5b5017b920e +Subproject commit 6498ee6760d37f6abb11784aa550aecd2e03100b diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index a622e5cd..c28c481c 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,7 @@ xarkes + From d2e2bcd6b6bd938ff85aca45a7de4b111d31a144 Mon Sep 17 00:00:00 2001 From: billow Date: Fri, 10 Jun 2022 19:05:25 +0800 Subject: [PATCH 63/94] Convert more commands to rizin APIs (#2964) `fdj?`, `iRj`, `om.`, `psx`, `p8`, `fj` --- src/core/Cutter.cpp | 115 +++++++++++++++++---------------- src/core/Cutter.h | 4 +- src/widgets/CommentsWidget.cpp | 6 +- src/widgets/HexWidget.cpp | 14 ++-- 4 files changed, 68 insertions(+), 71 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 80e41699..59306d39 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -845,15 +845,19 @@ void CutterCore::removeString(RVA addr) QString CutterCore::getString(RVA addr) { CORE_LOCK(); - char *s = (char *)returnAtSeek( - [&]() { - RzStrStringifyOpt opt = { 0 }; - opt.buffer = core->block; - opt.length = core->blocksize; - opt.encoding = rz_str_guess_encoding_from_buffer(core->block, core->blocksize); - return rz_str_stringify_raw_buffer(&opt, NULL); - }, - addr); + return getString(addr, core->blocksize, + rz_str_guess_encoding_from_buffer(core->block, core->blocksize)); +} + +QString CutterCore::getString(RVA addr, uint64_t len, RzStrEnc encoding, bool escape_nl) +{ + CORE_LOCK(); + RzStrStringifyOpt opt = {}; + opt.buffer = core->block; + opt.length = len; + opt.encoding = encoding; + opt.escape_nl = escape_nl; + char *s = (char *)returnAtSeek([&]() { return rz_str_stringify_raw_buffer(&opt, NULL); }, addr); return fromOwnedCharPtr(s); } @@ -1023,9 +1027,7 @@ void CutterCore::updateSeek() RVA CutterCore::prevOpAddr(RVA startAddr, int count) { CORE_LOCK(); - bool ok; - RVA offset = cmdRawAt(QString("/O %1").arg(count), startAddr).toULongLong(&ok, 16); - return ok ? offset : startAddr - count; + return rz_core_prevop_addr_force(core, startAddr, count); } RVA CutterCore::nextOpAddr(RVA startAddr, int count) @@ -1322,17 +1324,14 @@ RVA CutterCore::getLastFunctionInstruction(RVA addr) return lastBB ? rz_analysis_block_get_op_addr(lastBB, lastBB->ninstr - 1) : RVA_INVALID; } -QString CutterCore::cmdFunctionAt(QString addr) +QString CutterCore::flagAt(RVA addr) { - QString ret; - // Use cmd because cmdRaw would not work with grep - ret = cmd(QString("fd @ %1~[0]").arg(addr)); - return ret.trimmed(); -} - -QString CutterCore::cmdFunctionAt(RVA addr) -{ - return cmdFunctionAt(QString::number(addr)); + CORE_LOCK(); + RzFlagItem *f = rz_flag_get_at(core->flags, addr, true); + if (!f) { + return {}; + } + return core->flags->realnames && f->realname ? f->realname : f->name; } void CutterCore::cmdEsil(const char *command) @@ -2035,7 +2034,7 @@ void CutterCore::attachRemote(const QString &uri) [&](RzCore *core) { setConfig("cfg.debug", true); rz_core_file_reopen_remote_debug(core, uri.toStdString().c_str(), 0); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2043,9 +2042,7 @@ void CutterCore::attachRemote(const QString &uri) emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this, uri]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); // Check if we actually connected bool connected = false; @@ -3536,10 +3533,8 @@ QList CutterCore::getAllClassesFromFlags() QList ret; QMap classesCache; - for (const CutterJson flagObject : cmdj("fj@F:classes")) { - QString flagName = flagObject[RJsonKey::name].toString(); - - QRegularExpressionMatch match = classFlagRegExp.match(flagName); + for (const auto &item : getAllFlags("classes")) { + QRegularExpressionMatch match = classFlagRegExp.match(item.name); if (match.hasMatch()) { QString className = match.captured(1); BinClassDescription *desc = nullptr; @@ -3553,12 +3548,12 @@ QList CutterCore::getAllClassesFromFlags() desc = it.value(); } desc->name = match.captured(1); - desc->addr = flagObject[RJsonKey::offset].toRVA(); + desc->addr = item.offset; desc->index = RVA_INVALID; continue; } - match = methodFlagRegExp.match(flagName); + match = methodFlagRegExp.match(item.name); if (match.hasMatch()) { QString className = match.captured(1); BinClassDescription *classDesc = nullptr; @@ -3578,7 +3573,7 @@ QList CutterCore::getAllClassesFromFlags() BinClassMethodDescription meth; meth.name = match.captured(2); - meth.addr = flagObject[RJsonKey::offset].toRVA(); + meth.addr = item.offset; classDesc->methods << meth; continue; } @@ -3745,21 +3740,27 @@ void CutterCore::renameAnalysisMethod(const QString &className, const QString &o QList CutterCore::getAllResources() { CORE_LOCK(); - QList resources; - - for (CutterJson resourceObject : cmdj("iRj")) { - ResourcesDescription res; - - res.name = resourceObject[RJsonKey::name].toString(); - res.vaddr = resourceObject[RJsonKey::vaddr].toRVA(); - res.index = resourceObject[RJsonKey::index].toUt64(); - res.type = resourceObject[RJsonKey::type].toString(); - res.size = resourceObject[RJsonKey::size].toUt64(); - res.lang = resourceObject[RJsonKey::lang].toString(); - - resources << res; + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; } - return resources; + const RzList *resources = rz_bin_object_get_resources(bf->o); + QList resourcesDescriptions; + + RzBinResource *r; + RzListIter *it; + CutterRzListForeach (resources, it, RzBinResource, r) { + ResourcesDescription description; + description.name = r->name; + description.vaddr = r->vaddr; + description.index = r->index; + description.type = r->type; + description.size = r->size; + description.lang = r->language; + resourcesDescriptions << description; + } + + return resourcesDescriptions; } QList CutterCore::getAllVTables() @@ -3867,8 +3868,8 @@ QString CutterCore::getTypeAsC(QString name) bool CutterCore::isAddressMapped(RVA addr) { - // If value returned by "om. @ addr" is empty means that address is not mapped - return !Core()->cmdRawAt(QString("om."), addr).isEmpty(); + CORE_LOCK(); + return rz_io_map_get(core->io, addr); } QList CutterCore::getAllSearch(QString searchFor, QString space, QString in) @@ -3966,7 +3967,7 @@ QList CutterCore::getXRefs(RVA addr, bool to, bool whole_functi } xd.from_str = RzAddressString(xd.from); - xd.to_str = Core()->cmdRaw(QString("fd %1").arg(xd.to)).trimmed(); + xd.to_str = Core()->flagAt(xd.to); xrefList << xd; } @@ -3997,13 +3998,15 @@ QString CutterCore::listFlagsAsStringAt(RVA addr) QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut) { - auto r = cmdj(QString("fdj @ ") + QString::number(offset)); - QString name = r["name"].toString(); - if (flagOffsetOut) { - auto offsetValue = r["offset"]; - *flagOffsetOut = offsetValue.valid() ? offsetValue.toRVA() : offset; + CORE_LOCK(); + auto r = rz_flag_get_at(core->flags, offset, true); + if (!r) { + return {}; } - return name; + if (flagOffsetOut) { + *flagOffsetOut = r->offset; + } + return r->name; } void CutterCore::handleREvent(int type, void *data) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 45cde76d..607fb7b2 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -237,8 +237,7 @@ public: RVA getFunctionStart(RVA addr); RVA getFunctionEnd(RVA addr); RVA getLastFunctionInstruction(RVA addr); - QString cmdFunctionAt(QString addr); - QString cmdFunctionAt(RVA addr); + QString flagAt(RVA addr); void createFunctionAt(RVA addr); void createFunctionAt(RVA addr, QString name); QStringList getDisassemblyPreview(RVA address, int num_of_lines); @@ -297,6 +296,7 @@ public: * @return string at requested address */ QString getString(RVA addr); + QString getString(RVA addr, uint64_t len, RzStrEnc encoding, bool escape_nl = false); void setToData(RVA addr, int size, int repeat = 1); int sizeofDataMeta(RVA addr); diff --git a/src/widgets/CommentsWidget.cpp b/src/widgets/CommentsWidget.cpp index ddb4bbb9..cf7bea12 100644 --- a/src/widgets/CommentsWidget.cpp +++ b/src/widgets/CommentsWidget.cpp @@ -128,7 +128,7 @@ QVariant CommentsModel::data(const QModelIndex &index, int role) const case CommentsModel::OffsetColumn: return RzAddressString(comment.offset); case CommentsModel::FunctionColumn: - return Core()->cmdFunctionAt(comment.offset); + return Core()->flagAt(comment.offset); case CommentsModel::CommentColumn: return comment.name; default: @@ -220,8 +220,8 @@ bool CommentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri case CommentsModel::OffsetColumn: return leftComment.offset < rightComment.offset; case CommentsModel::FunctionColumn: - return Core()->cmdFunctionAt(leftComment.offset) - < Core()->cmdFunctionAt(rightComment.offset); + return Core()->flagAt(leftComment.offset) + < Core()->flagAt(rightComment.offset); case CommentsModel::CommentColumn: return leftComment.name < rightComment.name; default: diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 76cc586a..39f63186 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -692,16 +692,10 @@ void HexWidget::copy() if (selection.isEmpty() || selection.size() > MAX_COPY_SIZE) return; - QClipboard *clipboard = QApplication::clipboard(); - if (cursorOnAscii) { - clipboard->setText( - Core()->cmdRawAt(QString("psx %1").arg(selection.size()), selection.start()) - .trimmed()); - } else { - clipboard->setText(Core()->cmdRawAt(QString("p8 %1").arg(selection.size()), - selection.start()) - .trimmed()); // TODO: copy in the format shown - } + auto x = cursorOnAscii + ? Core()->getString(selection.start(), selection.size(), RZ_STRING_ENC_8BIT, true) + : Core()->ioRead(selection.start(), (int)selection.size()).toHex(); + QApplication::clipboard()->setText(x); } void HexWidget::copyAddress() From a7d3eaffb036cea681156ed7ebd4b5ca189beb97 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Fri, 24 Jun 2022 18:24:43 +0200 Subject: [PATCH 64/94] `wcr` command does not exist anymore, use API (#2979) --- src/core/Cutter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 59306d39..8db7aa1b 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2147,7 +2147,9 @@ void CutterCore::stopDebug() emit debugTaskStateChanged(); if (currentlyEmulating) { - cmdEsil("aeim-; aei-; wcr; .ar-; aets-"); + cmdEsil("aeim-; aei-"); + resetWriteCache(); + cmdEsil(".ar-; aets-"); currentlyEmulating = false; } else { rz_core_debug_process_close(core()); From f20b59d8acc4134caf163d1ce6b5cea00d2dc5f6 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Sat, 25 Jun 2022 03:15:13 +0200 Subject: [PATCH 65/94] Use API instead of `ar-` and `aets-` commands (#2980) --- src/core/Cutter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 8db7aa1b..bd7b8377 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2146,13 +2146,15 @@ void CutterCore::stopDebug() currentlyRemoteDebugging = false; emit debugTaskStateChanged(); + CORE_LOCK(); if (currentlyEmulating) { cmdEsil("aeim-; aei-"); resetWriteCache(); - cmdEsil(".ar-; aets-"); + rz_core_debug_clear_register_flags(core); + rz_core_analysis_esil_trace_stop(core); currentlyEmulating = false; } else { - rz_core_debug_process_close(core()); + rz_core_debug_process_close(core); currentlyAttachedToPID = -1; } From ed47645405522a24adb1f58cdf916ba24be0cf6b Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sat, 25 Jun 2022 09:19:44 +0800 Subject: [PATCH 66/94] Update Rizin to the latest stable --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 6498ee67..7158b619 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 6498ee6760d37f6abb11784aa550aecd2e03100b +Subproject commit 7158b6192549322e51779ca74c9ec96b977124ec From c60a8ee134ade6aa6b837650e4b92c3b796853b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 25 Jun 2022 13:28:40 +0200 Subject: [PATCH 67/94] Use rz-ghidra v0.4.0 --- dist/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index ee962d2e..5e1c18a7 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -168,9 +168,9 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) # installed Cutter. ExternalProject_Add(rz-ghidra GIT_REPOSITORY https://github.com/rizinorg/rz-ghidra - #GIT_TAG v0.3.0 + GIT_TAG v0.4.0 #GIT_TAG c7a50a2e7c0a95cd52b167c9ee0fa1805223f08e - GIT_TAG dev + #GIT_TAG dev #GIT_SHALLOW ON # disable this line when using commit hash CONFIGURE_COMMAND "" BUILD_COMMAND "" From 70bd668af1a58cd425979a26f3a9e070de4eab7d Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sat, 25 Jun 2022 15:03:45 +0200 Subject: [PATCH 68/94] Add back jsdec which was wrongly removed. (#2983) --- .github/workflows/ccpp.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index a1c8e0c5..4adc9fd1 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -123,6 +123,7 @@ jobs: -DCUTTER_ENABLE_SIGDB=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ + -DCUTTER_PACKAGE_JSDEC=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ -DCUTTER_PACKAGE_RZ_LIBYARA=ON \ -DCMAKE_INSTALL_PREFIX=appdir/usr \ From 7eb4311c2be2c0e5e6bcd098abf06beda2e96519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 25 Jun 2022 15:20:50 +0200 Subject: [PATCH 69/94] Extend blocksize to work around pdJ printing to few lines (#2984) --- src/core/Cutter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index abb86e4b..76397be8 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -219,6 +219,11 @@ void CutterCore::initialize(bool loadPlugins) // Otherwise Rizin may ask the user for input and Cutter would freeze setConfig("scr.interactive", false); + // Temporary workaround for https://github.com/rizinorg/rizin/issues/2741 + // Otherwise sometimes disassembly is truncated. + // The blocksize here is a rather arbitrary value larger than the default 0x100. + rz_core_block_size(core, 0x400); + // Initialize graph node highlighter bbHighlighter = new BasicBlockHighlighter(); From bd49557cabfd74d301a925c5ba156379ccb31dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 10 Sep 2022 17:40:02 +0200 Subject: [PATCH 70/94] Update rizin to stable v0.4.1 --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 7158b619..9023f8b9 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 7158b6192549322e51779ca74c9ec96b977124ec +Subproject commit 9023f8b997db210cef3b9a25cf1748fbc94942ed From 2529196df07a1b726ca017698317f9a0629079bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 2 Jul 2022 14:23:13 +0200 Subject: [PATCH 71/94] Remove direct download from update check (#2989) Hardcoded prediction of filenames for future releases is too prone to break, which is what happened with v2.1.0. So better to provide the link to the release page only. --- src/common/UpdateWorker.cpp | 124 ++---------------------------------- src/common/UpdateWorker.h | 64 ++----------------- 2 files changed, 9 insertions(+), 179 deletions(-) diff --git a/src/common/UpdateWorker.cpp b/src/common/UpdateWorker.cpp index 1514bc38..065e19c2 100644 --- a/src/common/UpdateWorker.cpp +++ b/src/common/UpdateWorker.cpp @@ -52,29 +52,6 @@ void UpdateWorker::checkCurrentVersion(time_t timeoutMs) pending = true; } -void UpdateWorker::download(QString filename, QString version) -{ - downloadFile.setFileName(filename); - downloadFile.open(QIODevice::WriteOnly); - - QNetworkRequest request; -# if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) && QT_VERSION < QT_VERSION_CHECK(5, 9, 0) - request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); -# elif QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) - request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, - QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); -# endif - QUrl url(QString("https://github.com/rizinorg/cutter/releases/" - "download/v%1/%2") - .arg(version) - .arg(getRepositoryFileName())); - request.setUrl(url); - - downloadReply = nm.get(request); - connect(downloadReply, &QNetworkReply::downloadProgress, this, &UpdateWorker::process); - connect(downloadReply, &QNetworkReply::finished, this, &UpdateWorker::serveDownloadFinish); -} - void UpdateWorker::showUpdateDialog(bool showDontCheckForUpdatesButton) { QMessageBox mb; @@ -82,69 +59,23 @@ void UpdateWorker::showUpdateDialog(bool showDontCheckForUpdatesButton) mb.setText(tr("There is an update available for Cutter.
") + "" + tr("Current version:") + " " CUTTER_VERSION_FULL "
" + "" + tr("Latest version:") + " " + latestVersion.toString() + "

" - + tr("For update, please check the link:
") + + tr("To update, please check the link:
") + QString("" "https://github.com/rizinorg/cutter/releases/tag/v%1
") - .arg(latestVersion.toString()) - + tr("or click \"Download\" to download latest version of Cutter.")); + .arg(latestVersion.toString())); if (showDontCheckForUpdatesButton) { - mb.setStandardButtons(QMessageBox::Save | QMessageBox::Reset | QMessageBox::Ok); - mb.button(QMessageBox::Reset)->setText(tr("Don't check for updates")); + mb.setStandardButtons(QMessageBox::Reset | QMessageBox::Ok); + mb.button(QMessageBox::Reset)->setText(tr("Don't check for updates automatically")); } else { - mb.setStandardButtons(QMessageBox::Save | QMessageBox::Ok); + mb.setStandardButtons(QMessageBox::Ok); } - mb.button(QMessageBox::Save)->setText(tr("Download")); mb.setDefaultButton(QMessageBox::Ok); int ret = mb.exec(); if (ret == QMessageBox::Reset) { Config()->setAutoUpdateEnabled(false); - } else if (ret == QMessageBox::Save) { - QString fullFileName = QFileDialog::getSaveFileName( - nullptr, tr("Choose directory for downloading"), - QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() - + getRepositoryFileName(), - QString("%1 (*.%1)").arg(getRepositeryExt())); - if (!fullFileName.isEmpty()) { - QProgressDialog progressDial(tr("Downloading update..."), tr("Cancel"), 0, 100); - connect(this, &UpdateWorker::downloadProcess, &progressDial, - [&progressDial](size_t curr, size_t total) { - progressDial.setValue(100.0f * curr / total); - }); - connect(&progressDial, &QProgressDialog::canceled, this, &UpdateWorker::abortDownload); - connect(this, &UpdateWorker::downloadFinished, &progressDial, &QProgressDialog::cancel); - connect(this, &UpdateWorker::downloadFinished, this, [](QString filePath) { - QMessageBox info(QMessageBox::Information, tr("Download finished!"), - tr("Latest version of Cutter was succesfully downloaded!"), - QMessageBox::Yes | QMessageBox::Open | QMessageBox::Ok, nullptr); - info.button(QMessageBox::Open)->setText(tr("Open file")); - info.button(QMessageBox::Yes)->setText(tr("Open download folder")); - int r = info.exec(); - if (r == QMessageBox::Open) { - QDesktopServices::openUrl(filePath); - } else if (r == QMessageBox::Yes) { - auto path = filePath.split('/'); - path.removeLast(); - QDesktopServices::openUrl(path.join('/')); - } - }); - download(fullFileName, latestVersion.toString()); - // Calling show() before exec() is only way make dialog non-modal - // it seems weird, but it works - progressDial.show(); - progressDial.exec(); - } } } -void UpdateWorker::abortDownload() -{ - disconnect(downloadReply, &QNetworkReply::finished, this, &UpdateWorker::serveDownloadFinish); - disconnect(downloadReply, &QNetworkReply::downloadProgress, this, &UpdateWorker::process); - downloadReply->close(); - downloadReply->deleteLater(); - downloadFile.remove(); -} - void UpdateWorker::serveVersionCheckReply() { pending = false; @@ -168,51 +99,6 @@ void UpdateWorker::serveVersionCheckReply() emit checkComplete(versionReply, errStr); } -void UpdateWorker::serveDownloadFinish() -{ - downloadReply->close(); - downloadReply->deleteLater(); - if (downloadReply->error()) { - emit downloadError(downloadReply->errorString()); - } else { - emit downloadFinished(downloadFile.fileName()); - } -} - -void UpdateWorker::process(size_t bytesReceived, size_t bytesTotal) -{ - downloadFile.write(downloadReply->readAll()); - emit downloadProcess(bytesReceived, bytesTotal); -} - -QString UpdateWorker::getRepositeryExt() const -{ -# ifdef Q_OS_LINUX - return "AppImage"; -# elif defined(Q_OS_WIN64) || defined(Q_OS_WIN32) - return "zip"; -# elif defined(Q_OS_MACOS) - return "dmg"; -# endif -} - -QString UpdateWorker::getRepositoryFileName() const -{ - QString downloadFileName; -# ifdef Q_OS_LINUX - downloadFileName = "Cutter-v%1-x%2.Linux.AppImage"; -# elif defined(Q_OS_WIN64) || defined(Q_OS_WIN32) - downloadFileName = "Cutter-v%1-x%2.Windows.zip"; -# elif defined(Q_OS_MACOS) - downloadFileName = "Cutter-v%1-x%2.macOS.dmg"; -# endif - downloadFileName = - downloadFileName.arg(latestVersion.toString()) - .arg(QSysInfo::buildAbi().split('-').at(2).contains("64") ? "64" : "32"); - - return downloadFileName; -} - QVersionNumber UpdateWorker::currentVersionNumber() { return QVersionNumber(CUTTER_VERSION_MAJOR, CUTTER_VERSION_MINOR, CUTTER_VERSION_PATCH); diff --git a/src/common/UpdateWorker.h b/src/common/UpdateWorker.h index 61b8d038..46854f87 100644 --- a/src/common/UpdateWorker.h +++ b/src/common/UpdateWorker.h @@ -23,8 +23,7 @@ class QNetworkReply; /** * @class UpdateWorker - * @brief The UpdateWorker class is a class providing API to check for current Cutter version - * and download specific version of one. + * @brief The UpdateWorker class is a class providing API to check for current Cutter version. */ class UpdateWorker : public QObject @@ -47,23 +46,12 @@ public: void checkCurrentVersion(time_t timeoutMs); - /** - * @fn void UpdateWorker::download(QDir downloadPath, QString version) - * - * @brief Downloads provided @a version of Cutter into @a downloadDir. - * - * @sa downloadProcess(size_t bytesReceived, size_t bytesTotal) - */ - void download(QString filename, QString version); - /** * @fn void UpdateWorker::showUpdateDialog() * - * Shows dialog that allows user to either download latest version of Cutter from website - * or download it by clicking on a button. This dialog also has "Don't check for updates" - * button which disables on-start update checks if @a showDontCheckForUpdatesButton is true. - * - * @sa downloadProcess(size_t bytesReceived, size_t bytesTotal) + * Shows dialog that allows user to download latest version of Cutter from website. + * This dialog also has "Don't check for updates" button which disables on-start update + * checks if @a showDontCheckForUpdatesButton is true. */ void showUpdateDialog(bool showDontCheckForUpdatesButton); @@ -73,18 +61,6 @@ public: */ static QVersionNumber currentVersionNumber(); -public slots: - /** - * @fn void UpdateWorker::abortDownload() - * - * @brief Stops current process of downloading. - * - * @note UpdateWorker::downloadFinished(QString filename) is not send after this function. - * - * @sa download(QDir downloadDir, QString version) - */ - void abortDownload(); - signals: /** * @fn UpdateWorker::checkComplete(const QString& verson, const QString& errorMsg) @@ -95,46 +71,14 @@ signals: */ void checkComplete(const QVersionNumber &currVerson, const QString &errorMsg); - /** - * @fn UpdateWorker::downloadProcess(size_t bytesReceived, size_t bytesTotal) - * - * The signal is emitted each time when some amount of bytes was downloaded. - * May be used as indicator of download progress. - */ - void downloadProcess(size_t bytesReceived, size_t bytesTotal); - - /** - * @fn UpdateWorker::downloadFinished(QString filename) - * - * @brief The signal is emitted as soon as downloading completes. - */ - void downloadFinished(QString filename); - - /** - * @fn UpdateWorker::downloadError(QString errorStr) - * - * @brief The signal is emitted when error occures during download. - */ - void downloadError(QString errorStr); - private slots: void serveVersionCheckReply(); - void serveDownloadFinish(); - - void process(size_t bytesReceived, size_t bytesTotal); - -private: - QString getRepositeryExt() const; - QString getRepositoryFileName() const; - private: QNetworkAccessManager nm; QVersionNumber latestVersion; QTimer t; bool pending; - QFile downloadFile; - QNetworkReply *downloadReply; QNetworkReply *checkReply; }; From a6dca2956dcb63c22a62acaadbde2fd5140c16d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 4 Jul 2022 13:01:38 +0200 Subject: [PATCH 72/94] Update cutter-deps to v15 with macOS/arm64 included (#2990) --- scripts/fetch_deps.sh | 59 ++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/scripts/fetch_deps.sh b/scripts/fetch_deps.sh index 4079c6aa..fedace6d 100755 --- a/scripts/fetch_deps.sh +++ b/scripts/fetch_deps.sh @@ -1,54 +1,55 @@ #!/bin/bash +set -e + cd $(dirname "${BASH_SOURCE[0]}")/.. mkdir -p cutter-deps && cd cutter-deps -LINUX_FILE="cutter-deps-linux.tar.gz" -LINUX_MD5=eb2710548d951823e6b5340c33c8fc99 -LINUX_URL=https://github.com/rizinorg/cutter-deps/releases/download/v14/cutter-deps-linux.tar.gz +DEPS_FILE_linux_x86_64=cutter-deps-linux-x86_64.tar.gz +DEPS_SHA256_linux_x86_64=0721c85548bbcf31f6911cdb2227e5efb4a20c34262672d4cd2193db166b2f8c -MACOS_FILE="cutter-deps-macos.tar.gz" -MACOS_MD5=f921c007430eec38b06acef8cc0fe42a -MACOS_URL=https://github.com/rizinorg/cutter-deps/releases/download/v14/cutter-deps-macos.tar.gz +DEPS_FILE_macos_x86_64=cutter-deps-macos-x86_64.tar.gz +DEPS_SHA256_macos_x86_64=0a23fdec3012a8af76675d6f3ff39cf9df9b08c13d1156fb7ffcc0e495c9407f -WIN_FILE="cutter-deps-win.tar.gz" -WIN_MD5=09aa544e62cdd786df3598f1ff340f9e -WIN_URL=https://github.com/rizinorg/cutter-deps/releases/download/v14/cutter-deps-win.tar.gz +DEPS_FILE_macos_arm64=cutter-deps-macos-arm64.tar.gz +DEPS_SHA256_macos_arm64=f9b9a5569bd23c9b5e45836b82aba7576a5c53df4871380a55c370b9d7f88615 +DEPS_FILE_win_x86_64=cutter-deps-win-x86_64.tar.gz +DEPS_SHA256_win_x86_64=9ab4e89732a3df0859a26fd5de6d9f3cb80106cbe2539340af831ed298625076 + +DEPS_BASE_URL=https://github.com/rizinorg/cutter-deps/releases/download/v15 + +ARCH=x86_64 if [ "$OS" == "Windows_NT" ]; then - FILE="${WIN_FILE}" - MD5="${WIN_MD5}" - URL="${WIN_URL}" + PLATFORM=win else UNAME_S="$(uname -s)" if [ "$UNAME_S" == "Linux" ]; then - FILE="${LINUX_FILE}" - MD5="${LINUX_MD5}" - URL="${LINUX_URL}" + PLATFORM=linux elif [ "$UNAME_S" == "Darwin" ]; then - FILE="${MACOS_FILE}" - MD5="${MACOS_MD5}" - URL="${MACOS_URL}" + PLATFORM=macos + ARCH=$(uname -m) else echo "Unsupported Platform: uname -s => $UNAME_S, \$OS => $OS" exit 1 fi fi -curl -L "$URL" -o "$FILE" || exit 1 +DEPS_FILE=DEPS_FILE_${PLATFORM}_${ARCH} +DEPS_FILE=${!DEPS_FILE} +DEPS_SHA256=DEPS_SHA256_${PLATFORM}_${ARCH} +DEPS_SHA256=${!DEPS_SHA256} +DEPS_URL=${DEPS_BASE_URL}/${DEPS_FILE} -if [ "$UNAME_S" == "Darwin" ]; then - if [ "$(md5 -r "$FILE")" != "$MD5 $FILE" ]; then \ - echo "MD5 mismatch for file $FILE"; \ - exit 1; \ - else \ - echo "$FILE OK"; \ - fi -else - echo "$MD5 $FILE" | md5sum -c - || exit 1 +SHA256SUM=sha256sum +if ! command -v ${SHA256SUM} &> /dev/null; then + SHA256SUM="shasum -a 256" fi -tar -xf "$FILE" || exit 1 +curl -L "$DEPS_URL" -o "$DEPS_FILE" || exit 1 +echo "$DEPS_SHA256 $DEPS_FILE" | ${SHA256SUM} -c - || exit 1 + +tar -xf "$DEPS_FILE" || exit 1 if [ -f relocate.sh ]; then ./relocate.sh || exit 1 From ba4f8a3024127cf59ebe78f88430b17a4d2acbf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Tue, 5 Jul 2022 14:06:06 +0200 Subject: [PATCH 73/94] Add Woodpecker macOS/arm64 CI (#2992) Package names have also been updated to the scheme used since v2.1.0, to better represent different architectures. --- .github/workflows/ccpp.yml | 6 ++--- .woodpecker/macos-arm64.yml | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 .woodpecker/macos-arm64.yml diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 4adc9fd1..4680f131 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -156,7 +156,7 @@ jobs: -ignore-glob=usr/lib/python3.9/**/* \ -verbose=2 find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq - export APPIMAGE_FILE="Cutter-${PACKAGE_ID}-x64.Linux.AppImage" + export APPIMAGE_FILE="Cutter-${PACKAGE_ID}-Linux-x86_64.AppImage" mv Cutter-*-x86_64.AppImage "$APPIMAGE_FILE" echo PACKAGE_NAME=$APPIMAGE_FILE >> $GITHUB_ENV echo UPLOAD_ASSET_TYPE=application/x-executable >> $GITHUB_ENV @@ -173,7 +173,7 @@ jobs: source scripts/prepare_breakpad_macos.sh mkdir build cd build - PACKAGE_NAME=Cutter-${PACKAGE_ID}-x64.macOS + PACKAGE_NAME=Cutter-${PACKAGE_ID}-macOS-x86_64 cmake \ -DCMAKE_BUILD_TYPE=Release \ -DPYTHON_LIBRARY="$CUTTER_DEPS_PYTHON_PREFIX/lib/libpython3.9.dylib" \ @@ -219,7 +219,7 @@ jobs: cd mkdir build cd build - set PACKAGE_NAME=cutter-%PACKAGE_ID%-x64.Windows + set PACKAGE_NAME=Cutter-%PACKAGE_ID%-Windows-x86_64 cmake ^ -DCMAKE_BUILD_TYPE=Release ^ -DCUTTER_USE_BUNDLED_RIZIN=ON ^ diff --git a/.woodpecker/macos-arm64.yml b/.woodpecker/macos-arm64.yml new file mode 100644 index 00000000..96ce1457 --- /dev/null +++ b/.woodpecker/macos-arm64.yml @@ -0,0 +1,49 @@ +platform: darwin/arm64 + +pipeline: + fetch-deps: + image: /bin/bash + commands: + - scripts/fetch_deps.sh + build: + image: /bin/bash + commands: + - set -e + - export PACKAGE_ID=${CI_COMMIT_TAG=git-`date "+%Y-%m-%d"`-${CI_COMMIT_SHA}} + - export PACKAGE_NAME=Cutter-$${PACKAGE_ID}-macOS-arm64 + - source cutter-deps/env.sh + - source scripts/prepare_breakpad_macos.sh + - cmake -Bbuild -GNinja + -DCMAKE_BUILD_TYPE=Release + -DPYTHON_LIBRARY="$$CUTTER_DEPS_PYTHON_PREFIX/lib/libpython3.9.dylib" + -DPYTHON_INCLUDE_DIR="$$CUTTER_DEPS_PYTHON_PREFIX/include/python3.9" + -DPYTHON_EXECUTABLE="$$CUTTER_DEPS_PYTHON_PREFIX/bin/python3" + -DCUTTER_ENABLE_PYTHON=ON + -DCUTTER_ENABLE_PYTHON_BINDINGS=ON + -DCUTTER_ENABLE_CRASH_REPORTS=ON + -DCUTTER_USE_BUNDLED_RIZIN=ON + -DCUTTER_ENABLE_PACKAGING=ON + -DCUTTER_ENABLE_SIGDB=ON + -DCUTTER_PACKAGE_DEPENDENCIES=ON + -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON + -DCUTTER_PACKAGE_RZ_GHIDRA=ON + -DCUTTER_PACKAGE_JSDEC=ON + -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON + -DCUTTER_PACKAGE_RZ_LIBYARA=ON + -DCPACK_PACKAGE_FILE_NAME="$$PACKAGE_NAME" + -DCMAKE_FRAMEWORK_PATH="$$BREAKPAD_FRAMEWORK_DIR" + -DCPACK_BUNDLE_APPLE_CERT_APP="-" + - ninja -C build + package: + image: /bin/bash + commands: + - source cutter-deps/env.sh + - ninja -C build package + deploy: + when: + event: tag + tag: v* + image: /bin/bash + commands: + - gh release upload "${CI_COMMIT_TAG}" build/Cutter-*.dmg + secrets: [ github_token ] From 39dc10a43093f650736ce5f35b7cb936b73fe9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 9 Jul 2022 12:48:48 +0200 Subject: [PATCH 74/94] Construct and destruct CutterCore singleton locally (Fix #2704) (#2994) Using Q_GLOBAL_STATIC meant that the CutterCore was destructed late as part of a binary destructor. It would then free the RzCore, calling for example the fini callbacks of all plugins. However global destructors in shared library plugins may have already been run at this point, leading to for example rz-ghidra's decompiler_mutex being used after destruction. Instead of the Q_GLOBAL_STATIC-managed global object, we are now handling the lifetime of the CutterCore ourselves and only injecting its instance to be accessed globally. This can also be a first step towards making the core instance completely local. --- src/CutterApplication.h | 1 + src/core/Cutter.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/CutterApplication.h b/src/CutterApplication.h index f8dc01e3..cd27a26a 100644 --- a/src/CutterApplication.h +++ b/src/CutterApplication.h @@ -50,6 +50,7 @@ private: private: bool m_FileAlreadyDropped; + CutterCore core; MainWindow *mainWindow; CutterCommandLineOptions clOptions; }; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 76397be8..490e363b 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -24,7 +24,7 @@ #include #include -Q_GLOBAL_STATIC(CutterCore, uniqueInstance) +static CutterCore *uniqueInstance; #define RZ_JSON_KEY(name) static const QString name = QStringLiteral(#name) @@ -182,6 +182,10 @@ CutterCore::CutterCore(QObject *parent) coreMutex(QMutex::Recursive) #endif { + if (uniqueInstance) { + throw std::logic_error("Only one instance of CutterCore must exist"); + } + uniqueInstance = this; } CutterCore *CutterCore::instance() @@ -238,6 +242,8 @@ CutterCore::~CutterCore() rz_core_task_sync_end(&core_->tasks); rz_core_free(this->core_); rz_cons_free(); + assert(uniqueInstance == this); + uniqueInstance = nullptr; } RzCoreLocked CutterCore::core() From 181506cb1fa6ccac38a13f041e5722a7e5d75a8a Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Sat, 6 Aug 2022 21:50:41 +0200 Subject: [PATCH 75/94] Mention OBS install mode for Linux (#3006) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4962b466..5642875b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Cutter is a free and open-source reverse engineering platform powered by [rizin] Cutter release binaries for all major platforms (Linux, macOS, Windows) can be downloaded from [GitHub Releases](https://github.com/rizinorg/cutter/releases). -- **Linux**: Download the `.AppImage` file. Then make it executable and run as below or use [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher). +- **Linux**: If your distribution provides it, check for `cutter` package in your package manager (or `cutter-re`). If not available there, we have setup repositories in [OBS](https://openbuildservice.org/) for some common distributions. Look at [https://software.opensuse.org/package/cutter-re](https://software.opensuse.org/download/package?package=cutter-re&project=home%3ARizinOrg) and follow the instructions there. Otherwise download the `.AppImage` file from our release, make it executable and run as below or use [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher). `chmod +x Cutter*.AppImage; ./Cutter*.AppImage` - **macOS**: Download the `.dmg` file or use [Homebrew Cask](https://github.com/Homebrew/homebrew-cask): From fd42ddb0bbb67c138877160ea2f11f175bb79a45 Mon Sep 17 00:00:00 2001 From: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> Date: Wed, 10 Aug 2022 09:05:01 -0400 Subject: [PATCH 76/94] Update GraphGridLayout documentation (#3000) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Updated GraphGridLayout documentation * Don't use potentially misleading name "segment tree" . Not exactly segment tree (although sometimes called that), and for the purpose of high level understanding how graph layout works doesn't matter what it is. Any data structure which provides required queries could be used. Co-authored-by: Kārlis Seņko --- src/widgets/GraphGridLayout.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/widgets/GraphGridLayout.cpp b/src/widgets/GraphGridLayout.cpp index 0f636e2f..cf100e24 100644 --- a/src/widgets/GraphGridLayout.cpp +++ b/src/widgets/GraphGridLayout.cpp @@ -103,14 +103,24 @@ Edge routing can be split into: main column selection, rough routing, segment of Transition from source to target row is done using single vertical segment. This is called main column. +A sweep line is used for computing main columns: 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 +if it is not blocked. If both the source and target columns are blocked, nearest unblocked column +is chosen. An empty column can always be found, in the worst case there are empty columns at the +sides of drawing. If two columns are equally close, the tie is broken based on whether the edge is a +true or false branch. In case of upward edges it is allowed to choose a column on the outside which +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. 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. - short vertical segment from node to horizontal line - move to empty column -- vertical segment between starting row and end row, an empty column can always be found, in the -worst case there are empty columns at the sides of drawing +- vertical segment between starting row and end row - horizontal segment to target node column - short vertical segment connecting to target node @@ -118,9 +128,6 @@ There are 3 special cases: - source and target nodes are in the same column with no nodes between - single vertical segment - column bellow stating node is empty - segments 1-3 are merged - column above target node is empty - segments 3-5 are merged -Vertical segment intersection with nodes is prevented using a 2d array marking which vertical -segments are blocked and naively iterating through all rows between start and end at the desired -column. After rough routing segment offsets are calculated relative to their corresponding edge column. This ensures that two segments don't overlap. Segment offsets within each column are assigned greedily From 77b93fbab051c826f23f99eaba0d9b1f7c36ad6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C4=81rlis=20Se=C5=86ko?= Date: Wed, 10 Aug 2022 14:01:44 +0300 Subject: [PATCH 77/94] Don't leak memory in bb highlighter. --- src/common/BasicBlockHighlighter.cpp | 21 ++++++--------------- src/common/BasicBlockHighlighter.h | 17 +++++++---------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/common/BasicBlockHighlighter.cpp b/src/common/BasicBlockHighlighter.cpp index f81b336b..d8270d44 100644 --- a/src/common/BasicBlockHighlighter.cpp +++ b/src/common/BasicBlockHighlighter.cpp @@ -2,21 +2,14 @@ BasicBlockHighlighter::BasicBlockHighlighter() {} -BasicBlockHighlighter::~BasicBlockHighlighter() -{ - for (BasicBlockIt itr = bbMap.begin(); itr != bbMap.end(); ++itr) { - delete itr->second; - } -} - /** * @brief Highlight the basic block at address */ void BasicBlockHighlighter::highlight(RVA address, const QColor &color) { - BasicBlock *block = new BasicBlock; - block->address = address; - block->color = color; + BasicBlock block; + block.address = address; + block.color = color; bbMap[address] = block; } @@ -33,13 +26,11 @@ void BasicBlockHighlighter::clear(RVA address) * * If there is nothing to highlight at specified address, returns nullptr */ -BasicBlock *BasicBlockHighlighter::getBasicBlock(RVA address) +BasicBlockHighlighter::BasicBlock *BasicBlockHighlighter::getBasicBlock(RVA address) { - BasicBlockIt it; - - it = bbMap.find(address); + auto it = bbMap.find(address); if (it != bbMap.end()) { - return it->second; + return &it->second; } return nullptr; diff --git a/src/common/BasicBlockHighlighter.h b/src/common/BasicBlockHighlighter.h index fc84b32a..2e0825e3 100644 --- a/src/common/BasicBlockHighlighter.h +++ b/src/common/BasicBlockHighlighter.h @@ -6,26 +6,23 @@ class BasicBlockHighlighter; #include "Cutter.h" #include -struct BasicBlock -{ - RVA address; - QColor color; -}; - -typedef std::map::iterator BasicBlockIt; - class BasicBlockHighlighter { public: + struct BasicBlock + { + RVA address; + QColor color; + }; + BasicBlockHighlighter(); - ~BasicBlockHighlighter(); void highlight(RVA address, const QColor &color); void clear(RVA address); BasicBlock *getBasicBlock(RVA address); private: - std::map bbMap; + std::map bbMap; }; #endif // BASICBLOCKHIGHLIGHTER_H From be565f3a8853e7df14558019dd3a0fdb86251084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C4=81rlis=20Se=C5=86ko?= Date: Thu, 11 Aug 2022 10:19:18 +0300 Subject: [PATCH 78/94] Do not check "Built from source" in bug report template by default. --- src/common/BugReporting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/BugReporting.cpp b/src/common/BugReporting.cpp index 7d5ec919..1f1ca3ea 100644 --- a/src/common/BugReporting.cpp +++ b/src/common/BugReporting.cpp @@ -31,7 +31,7 @@ void openIssue() url = "https://github.com/rizinorg/cutter/issues/new?&body=**Environment information**\n* " "Operating System: " + osInfo + "\n* Cutter version: " + CUTTER_VERSION_FULL + "\n* Obtained from:\n" - + " - [x] Built from source\n - [ ] Downloaded release from Cutter website or GitHub " + + " - [ ] Built from source\n - [ ] Downloaded release from Cutter website or GitHub " "\n" " - [ ] Distribution repository\n* File format: " + format + "\n * Arch: " + arch + "\n * Type: " + type From dd4af7e8a054e5ebdbbff14c980946119ad55d6e Mon Sep 17 00:00:00 2001 From: Edd Barrett Date: Thu, 18 Aug 2022 15:18:40 +0000 Subject: [PATCH 79/94] Fix build on 32-bit systems. (#3032) --- src/widgets/GraphGridLayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/GraphGridLayout.cpp b/src/widgets/GraphGridLayout.cpp index cf100e24..0cf7840d 100644 --- a/src/widgets/GraphGridLayout.cpp +++ b/src/widgets/GraphGridLayout.cpp @@ -554,7 +554,7 @@ void GraphGridLayout::calculateEdgeMainColumn(GraphGridLayout::LayoutState &stat struct Event { - size_t blockId; + ut64 blockId; size_t edgeId; int row; enum Type { Edge = 0, Block = 1 } type; From 2475ffe1a11383058172199d54473ff4a615e1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 24 Aug 2022 15:51:00 +0200 Subject: [PATCH 80/94] Generate and deploy source tarball (Fix #2878) (#3036) This builds a real tarball, as opposed to the flawed GitHub-generated one, and also includes the following changes: Individual builds now have dedicated names like "linux-x86_64". The structure in the yml is now very similar to how it is in rizin. Since that means builds are renamed, the filename has also been changed from the meaningless "ccpp.yml" to "ci.yml", as that would have happened sooner or later anyway and now will not produce additional intermediate rename states. The workflow name inside that file is now also just "CI" since adding "Cutter" there is redundant. --- .github/workflows/{ccpp.yml => ci.yml} | 56 +++++++++++++++++++++----- scripts/tarball.sh | 32 +++++++++++++++ 2 files changed, 77 insertions(+), 11 deletions(-) rename .github/workflows/{ccpp.yml => ci.yml} (85%) create mode 100755 scripts/tarball.sh diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ci.yml similarity index 85% rename from .github/workflows/ccpp.yml rename to .github/workflows/ci.yml index 4680f131..d56b8546 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Cutter CI +name: CI on: push: @@ -16,25 +16,48 @@ on: jobs: build: + name: ${{ matrix.name }} runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, ubuntu-18.04, macos-latest, windows-2019] - python-version: [3.7.x] - system-deps: [false] - cc-override: [default] - cxx-override: [default] + name: [ + linux-x86_64, + linux-x86_64-system-deps, + macos-x86_64, + windows-x86_64, + tarball + ] include: - - os: windows-2019 + - name: windows-x86_64 + os: windows-2019 package: true - - os: ubuntu-18.04 # ensure that Cutter can be built at least in basic config on Ubuntu 18.04 using sytem libraries + system-deps: false + python-version: 3.7.x + - name: linux-x86_64-system-deps # ensure that Cutter can be built at least in basic config on Ubuntu 18.04 using sytem libraries + os: ubuntu-18.04 python-version: 3.6.x system-deps: true cc-override: '/usr/bin/gcc-7' cxx-override: '/usr/bin/g++-7' - - os: ubuntu-18.04 # release package build + - name: linux-x86_64 + os: ubuntu-18.04 + python-version: 3.7.x system-deps: false package: true + cc-override: default + cxx-override: default + - name: macos-x86_64 + os: macos-latest + python-version: 3.7.x + system-deps: false + package: true + cc-override: default + cxx-override: default + - name: tarball + python-version: 3.7.x + os: ubuntu-20.04 + system-deps: false + tarball: true # Prevent one job from pausing the rest fail-fast: false steps: @@ -159,6 +182,7 @@ jobs: export APPIMAGE_FILE="Cutter-${PACKAGE_ID}-Linux-x86_64.AppImage" mv Cutter-*-x86_64.AppImage "$APPIMAGE_FILE" echo PACKAGE_NAME=$APPIMAGE_FILE >> $GITHUB_ENV + echo PACKAGE_PATH=build/$APPIMAGE_FILE >> $GITHUB_ENV echo UPLOAD_ASSET_TYPE=application/x-executable >> $GITHUB_ENV fi - name: cmake macos @@ -199,6 +223,7 @@ jobs: make package export CUTTER_VERSION=$(python3 ../scripts/get_version.py) echo PACKAGE_NAME=${PACKAGE_NAME}.dmg >> $GITHUB_ENV + echo PACKAGE_PATH=build/${PACKAGE_NAME}.dmg >> $GITHUB_ENV echo UPLOAD_ASSET_TYPE=application/x-apple-diskimage >> $GITHUB_ENV - name: windows dependencies if: contains(matrix.os, 'windows') @@ -241,12 +266,21 @@ jobs: cmake --build . --config Release cmake --build . --config Release --target package echo PACKAGE_NAME=%PACKAGE_NAME%.zip >> %GITHUB_ENV% + echo PACKAGE_PATH=build/%PACKAGE_NAME%.zip >> %GITHUB_ENV% echo UPLOAD_ASSET_TYPE=application/zip >> %GITHUB_ENV% + - name: Create tarball + if: matrix.tarball + shell: bash + run: | + scripts/tarball.sh "Cutter-${PACKAGE_ID}" + echo PACKAGE_NAME=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV + echo PACKAGE_PATH=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV + echo UPLOAD_ASSET_TYPE=application/gzip >> $GITHUB_ENV - uses: actions/upload-artifact@v2 if: env.PACKAGE_NAME != null with: name: ${{ env.PACKAGE_NAME }} - path: build/${{ env.PACKAGE_NAME }} + path: ${{ env.PACKAGE_PATH }} - name: Get release if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') id: get_release @@ -260,6 +294,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url }} - asset_path: build/${{ env.PACKAGE_NAME }} + asset_path: ${{ env.PACKAGE_PATH }} asset_name: ${{ env.PACKAGE_NAME }} asset_content_type: ${{ env.UPLOAD_ASSET_TYPE }} diff --git a/scripts/tarball.sh b/scripts/tarball.sh new file mode 100755 index 00000000..3876b449 --- /dev/null +++ b/scripts/tarball.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +NAME=${1:-Cutter} + +set -xe +cd $(dirname "${BASH_SOURCE[0]}")/.. + +shopt -s extglob +shopt -s dotglob +mkdir "${NAME}" +cp -r !(${NAME}) "${NAME}" + +pushd "${NAME}" +git clean -dxff . +git submodule update --init --recursive + +pushd rizin +git clean -dxff . +# Possible option: pre-download all subproject, however this makes the tarball huge. +# As opposed to meson dist used for rizin tarballs, this will not just download the ones +# used in a default build, but all of them, including multiple capstone variants. +# meson subprojects download +popd + +pushd src/translations +git clean -dxff . +popd + +find . -name ".git*" | xargs rm -rfv +popd + +tar -czvf "${NAME}-src.tar.gz" "${NAME}" From 8e232bed9107f54b1dea48d50898d88c2a308525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sun, 11 Sep 2022 10:25:39 +0200 Subject: [PATCH 81/94] Bump version to 2.1.2 --- .appveyor.yml | 2 +- CMakeLists.txt | 2 +- docs/source/conf.py | 2 +- src/re.rizin.cutter.appdata.xml | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 84a3b615..dc3f82d3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.1.0-git-{build}' +version: '2.1.2-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b9a9828..e7f950f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ endif() set(CUTTER_VERSION_MAJOR 2) set(CUTTER_VERSION_MINOR 1) -set(CUTTER_VERSION_PATCH 0) +set(CUTTER_VERSION_PATCH 2) set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index b2677d68..640b7f9b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ author = 'The Cutter Developers' # The short X.Y version version = '2.1' # The full version, including a2lpha/beta/rc tags -release = '2.1.0' +release = '2.1.2' # -- General configuration --------------------------------------------------- diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index c28c481c..e8e0de5e 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,8 @@ xarkes + + From bc979211fef1d840222503ff90f426ce5f4f785a Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 22 Feb 2023 07:51:09 +0800 Subject: [PATCH 82/94] Use rz-ghidra v0.5.0 --- dist/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index 956fbd18..70fd8e3a 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -164,9 +164,9 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) # installed Cutter. ExternalProject_Add(rz-ghidra GIT_REPOSITORY https://github.com/rizinorg/rz-ghidra - #GIT_TAG v0.3.0 + GIT_TAG v0.5.0 #GIT_TAG c7a50a2e7c0a95cd52b167c9ee0fa1805223f08e - GIT_TAG dev + #GIT_TAG dev #GIT_SHALLOW ON # disable this line when using commit hash CONFIGURE_COMMAND "" BUILD_COMMAND "" From ef0d69b53ac7daba8e2d762e6bdf2a1e7107335e Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 22 Feb 2023 00:00:00 +0800 Subject: [PATCH 83/94] Bump version to v2.2.0 --- .appveyor.yml | 2 +- CMakeLists.txt | 4 ++-- docs/source/conf.py | 4 ++-- src/re.rizin.cutter.appdata.xml | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 375d116e..ef25be60 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.1.2-git-{build}' +version: '2.2.0-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index aeb35127..8645b267 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,8 @@ if(NOT CUTTER_ENABLE_PYTHON) endif() set(CUTTER_VERSION_MAJOR 2) -set(CUTTER_VERSION_MINOR 1) -set(CUTTER_VERSION_PATCH 2) +set(CUTTER_VERSION_MINOR 2) +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 640b7f9b..34af39b1 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.1' +version = '2.2' # The full version, including a2lpha/beta/rc tags -release = '2.1.2' +release = '2.2.0' # -- General configuration --------------------------------------------------- diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index e8e0de5e..9ef364ba 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,7 @@ xarkes + From c0f260ca6913f3928259309766692e50131f7270 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 22 Feb 2023 23:09:24 +0800 Subject: [PATCH 84/94] Fix attaching debugger (#3139) * Fix attaching debugger * Fix deadlock on attach Co-authored-by: wargio --- src/core/Cutter.cpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index dad33c8e..7a18898c 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2075,16 +2075,23 @@ void CutterCore::attachDebug(int pid) offsetPriorDebugging = getOffset(); } - CORE_LOCK(); - setConfig("cfg.debug", true); - auto uri = rz_str_newf("dbg://%d", pid); - if (currentlyOpenFile.isEmpty()) { - rz_core_file_open_load(core, uri, 0, RZ_PERM_R, false); - } else { - rz_core_file_reopen_remote_debug(core, uri, 0); + if (!asyncTask( + [&](RzCore *core) { + // cannot use setConfig because core is + // already locked, which causes a deadlock + rz_config_set_b(core->config, "cfg.debug", true); + auto uri = rz_str_newf("dbg://%d", pid); + if (currentlyOpenFile.isEmpty()) { + rz_core_file_open_load(core, uri, 0, RZ_PERM_R, false); + } else { + rz_core_file_reopen_remote_debug(core, uri, 0); + } + free(uri); + return nullptr; + }, + debugTask)) { + return; } - free(uri); - emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this, pid]() { @@ -2144,7 +2151,10 @@ void CutterCore::stopDebug() rz_core_analysis_esil_trace_stop(core); currentlyEmulating = false; } else { - rz_core_debug_process_close(core); + // ensure we have opened a file. + if (core->io->desc) { + rz_core_debug_process_close(core); + } currentlyAttachedToPID = -1; } @@ -4579,4 +4589,4 @@ void CutterCore::writeGraphvizGraphToFile(QString path, QString format, RzCoreGr qWarning() << "Cannot get graph at " << RzAddressString(address); } } -} \ No newline at end of file +} From 937c01a8067b42964ad4d8c59fdeb5e5eba349a6 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 4 May 2023 16:49:03 +0800 Subject: [PATCH 85/94] Update Rizin to 0.5.2 --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 12898a36..e2646b53 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 12898a365e70c22892d78abdd2627e7269533c5f +Subproject commit e2646b53b0f1aba8202f98b22d345ae73ad0e35f From 4f0d8f7e2be676e5281927a3f544406f87498a46 Mon Sep 17 00:00:00 2001 From: xarkes Date: Thu, 4 May 2023 06:13:57 +0200 Subject: [PATCH 86/94] Update MapFileDialog.cpp (#3165) --- src/dialogs/MapFileDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dialogs/MapFileDialog.cpp b/src/dialogs/MapFileDialog.cpp index dfcd2647..24cbbf7a 100644 --- a/src/dialogs/MapFileDialog.cpp +++ b/src/dialogs/MapFileDialog.cpp @@ -33,7 +33,7 @@ void MapFileDialog::on_buttonBox_accepted() } if (!Core()->mapFile(filePath, mapAddress)) { - QMessageBox::critical(this, tr("Map new file file"), tr("Failed to map a new file")); + QMessageBox::critical(this, tr("Map new file"), tr("Failed to map a new file")); return; } close(); From 546999978e3cfd3f85e816033dee437d50ac50c1 Mon Sep 17 00:00:00 2001 From: xarkes Date: Thu, 4 May 2023 06:14:13 +0200 Subject: [PATCH 87/94] Update IOModesController.cpp (#3166) --- src/common/IOModesController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/IOModesController.cpp b/src/common/IOModesController.cpp index 26f0801f..a3ba1edc 100644 --- a/src/common/IOModesController.cpp +++ b/src/common/IOModesController.cpp @@ -91,7 +91,7 @@ bool IOModesController::askCommitUnsavedChanges() // Check if there are uncommitted changes if (!allChangesComitted()) { QMessageBox::StandardButton ret = QMessageBox::question( - NULL, QObject::tr("Uncomitted changes"), + NULL, QObject::tr("Uncommitted changes"), QObject::tr("It seems that you have changes or patches that are not committed to " "the file.\n" "Do you want to commit them now?"), From b6e17783440fdc417a195e6cce68806e61c8af9c Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 4 May 2023 16:51:34 +0800 Subject: [PATCH 88/94] Update Japanese, Spanish, Ukranian translations (#3167) --- src/translations | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations b/src/translations index 41c0c778..433de885 160000 --- a/src/translations +++ b/src/translations @@ -1 +1 @@ -Subproject commit 41c0c778b942577749ea2fed117e48a2cf3892df +Subproject commit 433de8859d1b1853b52e2e82cf75786d09943efb From 4191a009651311cd6efaa70e0f4b7c48c30a2a1e Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Thu, 11 May 2023 13:44:33 +0800 Subject: [PATCH 89/94] Fix 'Rizin Graph' widget (#3179) --- src/widgets/RizinGraphWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/RizinGraphWidget.cpp b/src/widgets/RizinGraphWidget.cpp index 346cf012..b228e4a4 100644 --- a/src/widgets/RizinGraphWidget.cpp +++ b/src/widgets/RizinGraphWidget.cpp @@ -96,7 +96,7 @@ void GenericRizinGraphView::loadCurrentGraph() return; } - CutterJson functionsDoc = Core()->cmdj(QString("%1j").arg(graphCommand)); + CutterJson functionsDoc = Core()->cmdj(QString("%1 json").arg(graphCommand)); auto nodes = functionsDoc["nodes"]; for (CutterJson block : nodes) { From a96206e7ab480db685e0be35eb8261194c787e6f Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Fri, 12 May 2023 14:48:27 +0800 Subject: [PATCH 90/94] Update Hindi, French, Russian translations (#3182) --- src/translations | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations b/src/translations index 433de885..e8fc5ca1 160000 --- a/src/translations +++ b/src/translations @@ -1 +1 @@ -Subproject commit 433de8859d1b1853b52e2e82cf75786d09943efb +Subproject commit e8fc5ca1acd70fd82a2ac9ac02b0261e57703250 From 9cbacff32994bc9dc0ad37267313ce5048400f77 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sat, 13 May 2023 10:22:05 +0800 Subject: [PATCH 91/94] Fix broken English in UI (#3184) --- src/common/Configuration.cpp | 4 ++-- src/common/DisassemblyPreview.cpp | 7 ------- src/dialogs/InitialOptionsDialog.ui | 2 +- src/dialogs/NewFileDialog.cpp | 2 +- src/dialogs/preferences/AsmOptionsWidget.ui | 4 ++-- src/menus/DisassemblyContextMenu.cpp | 2 +- src/widgets/ColorThemeListView.cpp | 3 +-- src/widgets/HexWidget.cpp | 4 ++-- 8 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 7fc76715..12af053f 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -143,8 +143,8 @@ Configuration::Configuration() : QObject(), nativePalette(qApp->palette()) mPtr = this; if (!s.isWritable()) { QMessageBox::critical( - nullptr, tr("Critical!"), - tr("!!! Settings are not writable! Make sure you have a write access to \"%1\"") + nullptr, tr("Critical Error!"), + tr("Settings are not writable! Make sure you have a write access to \"%1\".") .arg(s.fileName())); } #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING diff --git a/src/common/DisassemblyPreview.cpp b/src/common/DisassemblyPreview.cpp index e80e6eaa..4861c769 100644 --- a/src/common/DisassemblyPreview.cpp +++ b/src/common/DisassemblyPreview.cpp @@ -44,13 +44,6 @@ bool DisassemblyPreview::showDisasPreview(QWidget *parent, const QPoint &pointOf } RVA offsetTo = refs.at(0).to; // This is the offset we want to preview - - if (Q_UNLIKELY(offsetFrom != refs.at(0).from)) { - qWarning() << QObject::tr("offsetFrom (%1) differs from refs.at(0).from (%(2))") - .arg(offsetFrom) - .arg(refs.at(0).from); - } - /* * Only if the offset we point *to* is different from the one the cursor is currently * on *and* the former is a valid offset, we are allowed to get a preview of offsetTo diff --git a/src/dialogs/InitialOptionsDialog.ui b/src/dialogs/InitialOptionsDialog.ui index e3db9f83..38316893 100644 --- a/src/dialogs/InitialOptionsDialog.ui +++ b/src/dialogs/InitialOptionsDialog.ui @@ -323,7 +323,7 @@ - Auto Exp + Experimental Qt::AlignCenter diff --git a/src/dialogs/NewFileDialog.cpp b/src/dialogs/NewFileDialog.cpp index cde5fc85..58d0d391 100644 --- a/src/dialogs/NewFileDialog.cpp +++ b/src/dialogs/NewFileDialog.cpp @@ -287,7 +287,7 @@ void NewFileDialog::fillIOPluginsList() { ui->ioPlugin->clear(); ui->ioPlugin->addItem("file://"); - ui->ioPlugin->setItemData(0, tr("Open a file with no extra treatment."), Qt::ToolTipRole); + ui->ioPlugin->setItemData(0, tr("Open a file without additional options/settings."), Qt::ToolTipRole); int index = 1; QList ioPlugins = Core()->getRIOPluginDescriptions(); diff --git a/src/dialogs/preferences/AsmOptionsWidget.ui b/src/dialogs/preferences/AsmOptionsWidget.ui index e96421a4..f3f14952 100644 --- a/src/dialogs/preferences/AsmOptionsWidget.ui +++ b/src/dialogs/preferences/AsmOptionsWidget.ui @@ -142,7 +142,7 @@ - Tabs before assembly (asm.tabs.off): + The number of tabulate spaces after the offset (asm.tabs.off): Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse @@ -479,7 +479,7 @@ - Substitute variables (asm.sub.var) + Substitute variables in disassembly (asm.sub.var) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index ab54328d..c3ce0b6c 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -163,7 +163,7 @@ DisassemblyContextMenu::~DisassemblyContextMenu() {} void DisassemblyContextMenu::addSetBaseMenu() { - setBaseMenu = addMenu(tr("Set Immediate Base to...")); + setBaseMenu = addMenu(tr("Set base of immediate value to..")); initAction(&actionSetBaseBinary, tr("Binary")); setBaseMenu->addAction(&actionSetBaseBinary); diff --git a/src/widgets/ColorThemeListView.cpp b/src/widgets/ColorThemeListView.cpp index 4f56ba17..84df6d67 100644 --- a/src/widgets/ColorThemeListView.cpp +++ b/src/widgets/ColorThemeListView.cpp @@ -400,8 +400,7 @@ const QMap optionInfoMap__ = { { "fname", { QObject::tr("Color of names of functions"), QObject::tr("Function name") } }, { "floc", { QObject::tr("Color of function location"), QObject::tr("Function location") } }, { "fline", - { QObject::tr( - "Color of ascii line in left side that shows what opcodes are belong to function"), + { QObject::tr("Color of the line which shows which opcodes belongs to a function"), QObject::tr("Function line") } }, { "flag", { QObject::tr("Color of flags (similar to bookmarks for offset)"), QObject::tr("Flag") } }, diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index d933b944..c9d09a71 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -160,7 +160,7 @@ HexWidget::HexWidget(QWidget *parent) connect(actionWriteCString, &QAction::triggered, this, &HexWidget::w_writeCString); actionsWriteString.append(actionWriteCString); - QAction *actionWrite64 = new QAction(tr("Write De\\Encoded Base64 string"), this); + QAction *actionWrite64 = new QAction(tr("Write a decoded or encoded Base64 string"), this); connect(actionWrite64, &QAction::triggered, this, &HexWidget::w_write64); actionsWriteString.append(actionWrite64); @@ -1407,7 +1407,7 @@ void HexWidget::w_writeRandom() } bool ok = false; - int nbytes = QInputDialog::getInt(this, tr("Write random"), tr("Number of bytes:"), size, 1, + int nbytes = QInputDialog::getInt(this, tr("Write random bytes"), tr("Number of bytes:"), size, 1, 0x7FFFFFFF, 1, &ok); if (!ok) { return; From e523ac836543bede2126ad198ecf6f0b973c5e5d Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Sun, 14 May 2023 06:59:13 +0200 Subject: [PATCH 92/94] Get rid of stale jump arrows in disassembly widget. (#3175) This commit clears arrows from edited instructions, in order to avoid stale arrows to remain drawn. closes #3114 --- src/widgets/DisassemblyWidget.cpp | 17 ++++++++++++++++- src/widgets/DisassemblyWidget.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 4c18b57f..d892ffd1 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -132,7 +132,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main) connect(Core(), &CutterCore::functionRenamed, this, [this]() { refreshDisasm(); }); connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshDisasm())); connect(Core(), SIGNAL(asmOptionsChanged()), this, SLOT(refreshDisasm())); - connect(Core(), &CutterCore::instructionChanged, this, &DisassemblyWidget::refreshIfInRange); + connect(Core(), &CutterCore::instructionChanged, this, &DisassemblyWidget::instructionChanged); connect(Core(), &CutterCore::breakpointsChanged, this, &DisassemblyWidget::refreshIfInRange); connect(Core(), SIGNAL(refreshCodeViews()), this, SLOT(refreshDisasm())); @@ -226,6 +226,12 @@ void DisassemblyWidget::refreshIfInRange(RVA offset) } } +void DisassemblyWidget::instructionChanged(RVA offset) +{ + leftPanel->clearArrowFrom(offset); + refreshDisasm(); +} + void DisassemblyWidget::refreshDisasm(RVA offset) { if (!disasmRefresh->attemptRefresh(offset == RVA_INVALID ? nullptr : new RVA(offset))) { @@ -988,3 +994,12 @@ void DisassemblyLeftPanel::paintEvent(QPaintEvent *event) lastBeginOffset = lines.first().offset; } + +void DisassemblyLeftPanel::clearArrowFrom(RVA offset) +{ + auto it = std::find_if(arrows.begin(), arrows.end(), + [&](const Arrow &it) { return it.jmpFromOffset() == offset; }); + if (it != arrows.end()) { + arrows.erase(it); + } +} diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 1ab16216..ce3e8a62 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -53,6 +53,7 @@ public slots: protected slots: void on_seekChanged(RVA offset); void refreshIfInRange(RVA offset); + void instructionChanged(RVA offset); void refreshDisasm(RVA offset = RVA_INVALID); bool updateMaxLines(); @@ -153,6 +154,7 @@ public: DisassemblyLeftPanel(DisassemblyWidget *disas); void paintEvent(QPaintEvent *event) override; void wheelEvent(QWheelEvent *event) override; + void clearArrowFrom(RVA offset); private: DisassemblyWidget *disas; From dd216beb9c98c8cbe22237cfbdc0ccc9f4488c55 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 15 May 2023 20:37:45 +0800 Subject: [PATCH 93/94] Use Ubuntu 18.04 docker image (#3180) Co-authored-by: wargio --- .github/workflows/ci.yml | 263 ++++++++++++++++++++++++++++++--------- src/CMakeLists.txt | 2 +- 2 files changed, 202 insertions(+), 63 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 757189d2..1938f3d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,100 +14,164 @@ on: - dev - stable +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - build: + build-linux: name: ${{ matrix.name }} - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest + container: + image: ${{ matrix.image }} + options: --privileged strategy: matrix: name: [ linux-x86_64, linux-x86_64-system-deps, linux-x86_64-qt6-system-deps, - macos-x86_64, - windows-x86_64, tarball ] include: - - name: windows-x86_64 - os: windows-2019 - package: true - system-deps: false - python-version: 3.7.x - name: linux-x86_64-system-deps # ensure that Cutter can be built at least in basic config on Ubuntu 18.04 using sytem libraries - os: ubuntu-18.04 + image: ubuntu:18.04 python-version: 3.6.x system-deps: true + package: false + tarball: false cc-override: '/usr/bin/gcc-7' cxx-override: '/usr/bin/g++-7' - name: linux-x86_64-qt6-system-deps # ensure that Cutter can be built at least in basic config on Ubuntu 22.04 using sytem libraries - os: ubuntu-22.04 + image: ubuntu:22.04 python-version: 3.10.x system-deps: true + package: false + tarball: false cc-override: '/usr/bin/gcc-12' cxx-override: '/usr/bin/g++-12' - name: linux-x86_64 - os: ubuntu-18.04 - python-version: 3.7.x - system-deps: false - package: true - cc-override: default - cxx-override: default - - name: macos-x86_64 - os: macos-latest - python-version: 3.7.x + image: ubuntu:18.04 + python-version: 3.6.x system-deps: false package: true + tarball: false cc-override: default cxx-override: default - name: tarball - python-version: 3.7.x - os: ubuntu-20.04 + python-version: 3.6.x + image: ubuntu:20.04 system-deps: false + package: false tarball: true # Prevent one job from pausing the rest fail-fast: false steps: + - name: set timezone + run: | + # Fix timezone on ubuntu to prevent user input request during the apt-get phase. + export TZ=UTC + ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + + - name: install latest git and cmake + shell: bash + run: | + set -e + apt-get -y update + echo "Using image: ${{ matrix.image }}" + + export GIT_VERSION="git-2.36.1" + export CMAKE_VERSION="3.25.3" + + apt-get -y install wget libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev build-essential + + wget "https://www.kernel.org/pub/software/scm/git/$GIT_VERSION.tar.gz" + tar -zxf "$GIT_VERSION.tar.gz" + + # build. + make -C "$GIT_VERSION" prefix=/usr install -j > "$GIT_VERSION/build.log" + + # ensure git is installed. + git version + + wget "https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-x86_64.sh" + bash ./cmake-$CMAKE_VERSION-linux-x86_64.sh --skip-license --prefix=/usr + + # ensure cmake is installed. + cmake --version + + # cleanup dev environment. + rm -rf "$GIT_VERSION.tar.gz" "$GIT_VERSION" cmake-$CMAKE_VERSION-linux-x86_64.sh + unset CMAKE_VERSION + unset GIT_VERSION + - uses: actions/checkout@v3 with: submodules: recursive persist-credentials: false - - name: apt dependencies - if: contains(matrix.os, 'ubuntu') + + - name: apt cutter dependencies + shell: bash run: | - sudo apt-get update - sudo apt-get install libgraphviz-dev mesa-common-dev libxkbcommon-x11-dev ninja-build - if [[ "${{ matrix.os }}" = "ubuntu-18.04" || "${{ matrix.os }}" = "ubuntu-20.04" ]] - then + # install needed packages + apt-get -y install libgraphviz-dev \ + mesa-common-dev \ + libxkbcommon-x11-dev \ + ninja-build \ + python3-pip \ + curl \ + libpcre2-dev \ + libfuse2 \ + pkg-config + + if [ "${{ matrix.image }}" = "ubuntu:18.04" ]; then # install additional packages needed for appimage - sudo apt-get install libxcb1-dev libxkbcommon-dev libxcb-*-dev libegl1 libclang-8-dev llvm-8 + apt-get -y install gcc-7 \ + libglu1-mesa-dev \ + freeglut3-dev \ + mesa-common-dev + fi - if [[ "${{ matrix.os }}" = "ubuntu-18.04" && "${{ matrix.system-deps }}" = "true" ]] - then - sudo apt-get install qt5-default libqt5svg5-dev qttools5-dev qttools5-dev-tools + if [ "${{ matrix.image }}" = "ubuntu:18.04" ] || [ "${{ matrix.image }}" = "ubuntu:20.04" ]; then + # install additional packages needed for appimage + apt-get -y install libxcb1-dev \ + libxkbcommon-dev \ + libxcb-*-dev \ + libegl1 \ + libclang-8-dev \ + llvm-8 + ln -s /usr/bin/llvm-config-8 /usr/bin/llvm-config fi - if [[ "${{ matrix.os }}" = "ubuntu-22.04" ]] - then - sudo apt-get install libclang-12-dev llvm-12 qt6-base-dev qt6-tools-dev \ - qt6-tools-dev-tools libqt6svg6-dev libqt6core5compat6-dev libqt6svgwidgets6 qt6-l10n-tools + if [ "${{ matrix.image }}" = "ubuntu:18.04" ] && [ "${{ matrix.system-deps }}" = "true" ]; then + apt-get -y install qt5-default \ + libqt5svg5-dev \ + qttools5-dev \ + qttools5-dev-tools + fi + if [ "${{ matrix.image }}" = "ubuntu:22.04" ]; then + apt-get -y install libclang-12-dev \ + llvm-12 \ + qt6-base-dev \ + qt6-tools-dev \ + qt6-tools-dev-tools \ + libqt6svg6-dev \ + libqt6core5compat6-dev \ + libqt6svgwidgets6 \ + qt6-l10n-tools \ + gcc-12 \ + g++-12 fi - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: homebrew dependencies - if: contains(matrix.os, 'macos') - run: | - cd scripts - rm /usr/local/bin/2to3* # symlink to some kind of existing python2.7 installation conflicts with brew python3 which gets installed as indirect dependency - brew bundle - name: py dependencies run: | - python3 -m pip install -U pip==21.3.1 - pip install meson==0.61.5 # https://github.com/rizinorg/cutter/runs/7170222817?check_suite_focus=true + # https://github.com/rizinorg/cutter/runs/7170222817?check_suite_focus=true + python3 -m pip install meson==0.61.5 - name: Prepare package id shell: bash run: | - if [[ "${{ startsWith(github.event.ref, 'refs/tags')}}" = "true" ]] + if [ "${{ startsWith(github.event.ref, 'refs/tags')}}" = "true" ] then PACKAGE_ID="${{ github.event.ref }}" else @@ -116,17 +180,17 @@ jobs: PACKAGE_ID=${PACKAGE_ID##refs/tags/} echo PACKAGE_ID=$PACKAGE_ID >> $GITHUB_ENV - name: cmake ubuntu - if: contains(matrix.os, 'ubuntu') + shell: bash run: | - if [[ "${{ matrix.system-deps }}" = "false" ]] + if [ "${{ matrix.system-deps }}" = "false" ] then scripts/fetch_deps.sh - source cutter-deps/env.sh + . cutter-deps/env.sh export PKG_CONFIG_PATH="$CUTTER_DEPS_PYTHON_PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}" export LD_LIBRARY_PATH="`llvm-config --libdir`:$LD_LIBRARY_PATH" fi - set -euo pipefail #TODO: move to top once cutter-deps doesn't fail - if [[ "${{ matrix.cc-override }}" != "default" ]] + set -e #TODO: move to top once cutter-deps doesn't fail + if [ "${{ matrix.cc-override }}" != "default" ] then export CC="${{matrix.cc-override}}" export CXX="${{matrix.cxx-override}}" @@ -134,8 +198,7 @@ jobs: mkdir build cd build - cmake --version - if [[ "${{ matrix.system-deps }}" = "false" ]] + if [ "${{ matrix.system-deps }}" = "false" ] then cmake \ -G Ninja \ @@ -149,6 +212,7 @@ jobs: -DCUTTER_USE_BUNDLED_RIZIN=ON \ -DCUTTER_APPIMAGE_BUILD=ON \ -DCUTTER_ENABLE_PACKAGING=ON \ + -DCUTTER_ENABLE_KSYNTAXHIGHLIGHTING=OFF \ -DCUTTER_ENABLE_SIGDB=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ @@ -158,7 +222,7 @@ jobs: -DCMAKE_INSTALL_PREFIX=appdir/usr \ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ .. - elif [[ "${{ matrix.os }}" = "ubuntu-22.04" ]] + elif [ "${{ matrix.image }}" = "ubuntu:22.04" ] then cmake \ -G Ninja \ @@ -174,7 +238,7 @@ jobs: .. fi ninja - if [[ "${{ matrix.package || false }}" = "true" ]] + if [ "${{ matrix.package }}" = "true" ] then export CUTTER_VERSION=$(python ../scripts/get_version.py) export VERSION=$CUTTER_VERSION @@ -199,6 +263,89 @@ jobs: echo PACKAGE_PATH=build/$APPIMAGE_FILE >> $GITHUB_ENV echo UPLOAD_ASSET_TYPE=application/x-executable >> $GITHUB_ENV fi + - name: Create tarball + if: matrix.tarball + shell: bash + run: | + scripts/tarball.sh "Cutter-${PACKAGE_ID}" + echo PACKAGE_NAME=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV + echo PACKAGE_PATH=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV + echo UPLOAD_ASSET_TYPE=application/gzip >> $GITHUB_ENV + - uses: actions/upload-artifact@v3 + if: env.PACKAGE_NAME != null + with: + name: ${{ env.PACKAGE_NAME }} + path: ${{ env.PACKAGE_PATH }} + - name: Get release + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') + id: get_release + uses: rizinorg/gha-get-release@c8074dd5d13ddd0a194d8c9205a1466973c7dc0d + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload release assets + if: steps.get_release.outputs.upload_url != null && env.PACKAGE_NAME != null + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.get_release.outputs.upload_url }} + asset_path: ${{ env.PACKAGE_PATH }} + asset_name: ${{ env.PACKAGE_NAME }} + asset_content_type: ${{ env.UPLOAD_ASSET_TYPE }} + + build: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + name: [ + macos-x86_64, + windows-x86_64, + ] + include: + - name: windows-x86_64 + os: windows-2019 + package: true + system-deps: false + python-version: 3.7.x + - name: macos-x86_64 + os: macos-latest + python-version: 3.7.x + system-deps: false + package: true + cc-override: default + cxx-override: default + # Prevent one job from pausing the rest + fail-fast: false + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + persist-credentials: false + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: homebrew dependencies + if: contains(matrix.os, 'macos') + run: | + cd scripts + rm /usr/local/bin/2to3* # symlink to some kind of existing python2.7 installation conflicts with brew python3 which gets installed as indirect dependency + brew bundle + - name: py dependencies + run: | + python3 -m pip install -U pip==21.3.1 + pip install meson==0.61.5 # https://github.com/rizinorg/cutter/runs/7170222817?check_suite_focus=true + - name: Prepare package id + shell: bash + run: | + if [[ "${{ startsWith(github.event.ref, 'refs/tags')}}" = "true" ]] + then + PACKAGE_ID="${{ github.event.ref }}" + else + PACKAGE_ID="git-`date "+%Y-%m-%d"`-${{ format('{0}', github.sha) }}" + fi + PACKAGE_ID=${PACKAGE_ID##refs/tags/} + echo PACKAGE_ID=$PACKAGE_ID >> $GITHUB_ENV - name: cmake macos shell: bash if: contains(matrix.os, 'macos') @@ -277,14 +424,6 @@ jobs: echo PACKAGE_NAME=%PACKAGE_NAME%.zip >> %GITHUB_ENV% echo PACKAGE_PATH=build/%PACKAGE_NAME%.zip >> %GITHUB_ENV% echo UPLOAD_ASSET_TYPE=application/zip >> %GITHUB_ENV% - - name: Create tarball - if: matrix.tarball - shell: bash - run: | - scripts/tarball.sh "Cutter-${PACKAGE_ID}" - echo PACKAGE_NAME=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV - echo PACKAGE_PATH=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV - echo UPLOAD_ASSET_TYPE=application/gzip >> $GITHUB_ENV - uses: actions/upload-artifact@v3 if: env.PACKAGE_NAME != null with: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f340ee6e..f8fa5fd3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -518,7 +518,7 @@ if(CUTTER_ENABLE_PYTHON) endif() configure_file("${BINDINGS_SRC_DIR}/bindings.txt.in" "${BINDINGS_BUILD_DIR}/bindings.txt") - add_compile_definitions(WIN32_LEAN_AND_MEAN) + add_definitions(-DWIN32_LEAN_AND_MEAN) endif() endif() From f4be9a8266ce290bc73fd4ba114ec08606c0450c Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 15 May 2023 20:42:27 +0800 Subject: [PATCH 94/94] Bump version to v2.2.1 --- .appveyor.yml | 2 +- CMakeLists.txt | 2 +- docs/source/conf.py | 2 +- src/re.rizin.cutter.appdata.xml | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index ef25be60..3c24dc0a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.2.0-git-{build}' +version: '2.2.1-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 8645b267..578bd5ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ endif() set(CUTTER_VERSION_MAJOR 2) set(CUTTER_VERSION_MINOR 2) -set(CUTTER_VERSION_PATCH 0) +set(CUTTER_VERSION_PATCH 1) 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..beee1b0d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ author = 'The Cutter Developers' # The short X.Y version version = '2.2' # The full version, including a2lpha/beta/rc tags -release = '2.2.0' +release = '2.2.1' # -- General configuration --------------------------------------------------- diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index 9ef364ba..1e1d9e3e 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,7 @@ xarkes +