mirror of
https://github.com/rizinorg/cutter.git
synced 2024-12-19 03:16:10 +00:00
Merge 'dev' branch into stable
This commit is contained in:
commit
48b35953bb
@ -1,4 +1,4 @@
|
||||
version: '2.2.1-git-{build}'
|
||||
version: '2.2.0-git-{build}'
|
||||
image: 'Visual Studio 2017'
|
||||
clone_depth: 1
|
||||
|
||||
|
3
.github/workflows/ci.yml
vendored
3
.github/workflows/ci.yml
vendored
@ -219,6 +219,7 @@ jobs:
|
||||
-DCUTTER_PACKAGE_JSDEC=ON \
|
||||
-DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \
|
||||
-DCUTTER_PACKAGE_RZ_LIBYARA=ON \
|
||||
-DCUTTER_PACKAGE_RZ_SILHOUETTE=ON \
|
||||
-DCMAKE_INSTALL_PREFIX=appdir/usr \
|
||||
-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \
|
||||
..
|
||||
@ -374,6 +375,7 @@ jobs:
|
||||
-DCUTTER_PACKAGE_JSDEC=ON \
|
||||
-DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \
|
||||
-DCUTTER_PACKAGE_RZ_LIBYARA=ON \
|
||||
-DCUTTER_PACKAGE_RZ_SILHOUETTE=ON \
|
||||
-DCPACK_PACKAGE_FILE_NAME="$PACKAGE_NAME" \
|
||||
-DCPACK_BUNDLE_APPLE_CERT_APP="-" \
|
||||
.. && \
|
||||
@ -413,6 +415,7 @@ jobs:
|
||||
-DCUTTER_PACKAGE_RZ_GHIDRA=ON ^
|
||||
-DCUTTER_PACKAGE_RZ_LIBSWIFT=ON ^
|
||||
-DCUTTER_PACKAGE_RZ_LIBYARA=ON ^
|
||||
-DCUTTER_PACKAGE_RZ_SILHOUETTE=ON ^
|
||||
-DCUTTER_PACKAGE_JSDEC=ON ^
|
||||
-DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON ^
|
||||
-DCMAKE_PREFIX_PATH="%CUTTER_DEPS%\pyside" ^
|
||||
|
23
.github/workflows/linter.yml
vendored
23
.github/workflows/linter.yml
vendored
@ -26,27 +26,34 @@ jobs:
|
||||
- '**.c'
|
||||
- '**.h'
|
||||
- '.github/workflows/linter.yml'
|
||||
- 'scripts/clang-format.py'
|
||||
- '_clang-format'
|
||||
|
||||
clang-format:
|
||||
needs: changes
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
if: ${{ needs.changes.outputs.clang-format == 'true' }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install wget
|
||||
run: sudo apt --assume-yes install wget
|
||||
- name: Install wget, software-properties-common, lsb-release (dependencies of LLVM install script)
|
||||
run: sudo apt --assume-yes install wget software-properties-common lsb-release
|
||||
|
||||
- name: Install automatic llvm (stable branch)
|
||||
run: sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
|
||||
- name: Uninstall old conflicting packages
|
||||
run: sudo apt purge --assume-yes --auto-remove llvm python3-lldb-14 llvm-14
|
||||
|
||||
- name: Install clang-format-11
|
||||
run: sudo apt --assume-yes install clang-format-11
|
||||
- name: Install automatic LLVM 16
|
||||
run: wget https://apt.llvm.org/llvm.sh -O /tmp/llvm-install.sh; chmod +x /tmp/llvm-install.sh; sudo /tmp/llvm-install.sh 16
|
||||
|
||||
- name: Install clang-format-16
|
||||
run: sudo apt --assume-yes install clang-format-16
|
||||
|
||||
- name: Install gitpython
|
||||
run: sudo pip install gitpython
|
||||
|
||||
- name: Run clang-format
|
||||
run: |
|
||||
find ./src -regex '.*\.\(cpp\|h\|c\)' -exec clang-format -style=file --dry-run --Werror {} \;
|
||||
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-16 160
|
||||
clang-format --version
|
||||
python scripts/clang-format.py --check --verbose
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -94,3 +94,7 @@ docs/source/_build
|
||||
# Local gdb files
|
||||
.gdb_history
|
||||
.gdbinit
|
||||
|
||||
# Kdevelop
|
||||
.kdev/
|
||||
*.kdev4
|
||||
|
@ -28,6 +28,7 @@ pipeline:
|
||||
-DCUTTER_PACKAGE_JSDEC=ON
|
||||
-DCUTTER_PACKAGE_RZ_LIBSWIFT=ON
|
||||
-DCUTTER_PACKAGE_RZ_LIBYARA=ON
|
||||
-DCUTTER_PACKAGE_RZ_SILHOUETTE=ON
|
||||
-DCPACK_PACKAGE_FILE_NAME="$$PACKAGE_NAME"
|
||||
-DCPACK_BUNDLE_APPLE_CERT_APP="-"
|
||||
- ninja -C build
|
||||
|
@ -14,7 +14,7 @@ option(CUTTER_USE_BUNDLED_RIZIN "Use rizin from ./rizin submodule instead of sea
|
||||
option(CUTTER_USE_ADDITIONAL_RIZIN_PATHS "Search rizin in additional paths which are not part of default system library paths.\
|
||||
Disable this option if you are linking against rizin pacakged as proper system library or in a custom path and additional are paths causing problems." ON)
|
||||
option(CUTTER_ENABLE_PYTHON "Enable Python integration. Requires Python >= ${CUTTER_PYTHON_MIN}." OFF)
|
||||
option(CUTTER_ENABLE_PYTHON_BINDINGS "Enable generating Python bindings with Shiboken2. Unused if CUTTER_ENABLE_PYTHON=OFF." OFF)
|
||||
option(CUTTER_ENABLE_PYTHON_BINDINGS "Enable generating Python bindings with Shiboken. Unused if CUTTER_ENABLE_PYTHON=OFF." OFF)
|
||||
option(CUTTER_APPIMAGE_BUILD "Enable Appimage specific changes. Doesn't cause building of Appimage itself." OFF)
|
||||
tri_option(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING "Use KSyntaxHighlighting" AUTO)
|
||||
tri_option(CUTTER_ENABLE_GRAPHVIZ "Enable use of graphviz for graph layout" AUTO)
|
||||
@ -27,6 +27,7 @@ option(CUTTER_PACKAGE_DEPENDENCIES "During install step include the third party
|
||||
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_RZ_SILHOUETTE "Compile and install rz-silhouette during the install step." OFF)
|
||||
option(CUTTER_PACKAGE_JSDEC "Compile and install jsdec during install step." OFF)
|
||||
OPTION(CUTTER_QT6 "Use QT6" OFF)
|
||||
|
||||
@ -36,7 +37,7 @@ endif()
|
||||
|
||||
set(CUTTER_VERSION_MAJOR 2)
|
||||
set(CUTTER_VERSION_MINOR 2)
|
||||
set(CUTTER_VERSION_PATCH 1)
|
||||
set(CUTTER_VERSION_PATCH 0)
|
||||
|
||||
set(CUTTER_VERSION "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}")
|
||||
|
||||
@ -99,6 +100,24 @@ if(CUTTER_ENABLE_PYTHON)
|
||||
add_definitions(-DCUTTER_ENABLE_PYTHON)
|
||||
|
||||
if(CUTTER_ENABLE_PYTHON_BINDINGS)
|
||||
if (CUTTER_QT6)
|
||||
# 6.12.3 => 6.12
|
||||
if("${Qt6_VERSION}" MATCHES "^([0-9]+\\.[0-9]+)\\.[0-9]+")
|
||||
set(Shiboken6_VERSION_REQUIRED "${CMAKE_MATCH_1}")
|
||||
else()
|
||||
message(FATAL_ERROR "Failed to recognize Qt version")
|
||||
endif()
|
||||
find_package(Shiboken6 "${Shiboken6_VERSION_REQUIRED}" REQUIRED)
|
||||
find_package(Shiboken6Tools "${Shiboken6_VERSION_REQUIRED}" REQUIRED)
|
||||
find_package(PySide6 "${Shiboken6_VERSION_REQUIRED}" REQUIRED)
|
||||
get_target_property(LIBSHIBOKEN_INCLUDE_DIRS Shiboken6::libshiboken INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_target_property(PYSIDE_INCLUDE_DIRS PySide6::pyside6 INTERFACE_INCLUDE_DIRECTORIES)
|
||||
# Check the presence of "pysidecleanup.h"
|
||||
include(CheckIncludeFileCXX)
|
||||
set(CMAKE_REQUIRED_INCLUDES "${PYSIDE_INCLUDE_DIRS};${LIBSHIBOKEN_INCLUDE_DIRS}")
|
||||
CHECK_INCLUDE_FILE_CXX("pysidecleanup.h" HAVE_PYSIDECLEANUP)
|
||||
add_compile_definitions("HAVE_PYSIDECLEANUP=${HAVE_PYSIDECLEANUP}")
|
||||
else()
|
||||
# 5.12.3 => 5.12
|
||||
if("${Qt5_VERSION}" MATCHES "^([0-9]+\\.[0-9]+)\\.[0-9]+")
|
||||
set(Shiboken2_VERSION_REQUIRED "${CMAKE_MATCH_1}")
|
||||
@ -107,19 +126,21 @@ if(CUTTER_ENABLE_PYTHON)
|
||||
endif()
|
||||
find_package(Shiboken2 "${Shiboken2_VERSION_REQUIRED}" REQUIRED)
|
||||
find_package(PySide2 "${Shiboken2_VERSION_REQUIRED}" REQUIRED)
|
||||
get_target_property(PYSIDE_INCLUDE_DIRS PySide2::pyside2 INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif()
|
||||
|
||||
get_target_property(PYSIDE_INCLUDE_DIR PySide2::pyside2 INTERFACE_INCLUDE_DIRECTORIES)
|
||||
list(GET PYSIDE_INCLUDE_DIR 0 PYSIDE_INCLUDE_DIR)
|
||||
include_directories(${PYSIDE_INCLUDE_DIR}
|
||||
${PYSIDE_INCLUDE_DIR}/QtCore
|
||||
${PYSIDE_INCLUDE_DIR}/QtGui
|
||||
${PYSIDE_INCLUDE_DIR}/QtWidgets)
|
||||
foreach(_dir IN LISTS PYSIDE_INCLUDE_DIRS)
|
||||
include_directories(${_dir}
|
||||
${_dir}/QtCore
|
||||
${_dir}/QtGui
|
||||
${_dir}/QtWidgets)
|
||||
endforeach()
|
||||
|
||||
add_definitions(-DCUTTER_ENABLE_PYTHON_BINDINGS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING)
|
||||
if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING AND (NOT CUTTER_QT6))
|
||||
if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING STREQUAL AUTO)
|
||||
find_package(KF5SyntaxHighlighting)
|
||||
if(KF5SyntaxHighlighting_FOUND)
|
||||
@ -132,6 +153,9 @@ if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING)
|
||||
set(KSYNTAXHIGHLIGHTING_STATUS ON)
|
||||
endif()
|
||||
else()
|
||||
if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING AND CUTTER_QT6)
|
||||
message(WARNING "KSyntaxHighlighting has been disabled because not supported in QT6")
|
||||
endif()
|
||||
set(KSYNTAXHIGHLIGHTING_STATUS OFF)
|
||||
endif()
|
||||
|
||||
@ -161,6 +185,7 @@ 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 RzSilhouette: ${CUTTER_PACKAGE_RZ_SILHOUETTE}")
|
||||
message(STATUS "- Package JSDec: ${CUTTER_PACKAGE_JSDEC}")
|
||||
message(STATUS "- QT6: ${CUTTER_QT6}")
|
||||
message(STATUS "")
|
||||
|
@ -57,7 +57,7 @@ endif()
|
||||
|
||||
# TODO: This version number should be fetched automatically
|
||||
# instead of being hardcoded.
|
||||
set (Rizin_VERSION 0.5)
|
||||
set (Rizin_VERSION 0.6)
|
||||
|
||||
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
|
||||
|
68
cmake/FindPySide6.cmake
Normal file
68
cmake/FindPySide6.cmake
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
set(_module PySide6)
|
||||
|
||||
find_package(${_module} ${${_module}_FIND_VERSION} CONFIG QUIET)
|
||||
set(_lib_target ${_module}::pyside6)
|
||||
|
||||
if(NOT ${_module}_FOUND)
|
||||
include(PythonInfo)
|
||||
find_python_site_packages(PYTHON_SITE_PACKAGES)
|
||||
get_python_extension_suffix(PYTHON_EXTENSION_SUFFIX)
|
||||
|
||||
find_library(PYSIDE_LIBRARY
|
||||
NAMES
|
||||
"pyside6${PYTHON_EXTENSION_SUFFIX}"
|
||||
"pyside6${PYTHON_EXTENSION_SUFFIX}.${${_module}_FIND_VERSION_MAJOR}.${${_module}_FIND_VERSION_MINOR}"
|
||||
PATH_SUFFIXES "${PYTHON_SITE_PACKAGES}/PySide6")
|
||||
|
||||
find_path(PYSIDE_INCLUDE_DIR
|
||||
pyside.h
|
||||
PATH_SUFFIXES "${PYTHON_SITE_PACKAGES}/PySide6/include")
|
||||
|
||||
find_path(PYSIDE_TYPESYSTEMS
|
||||
typesystem_core.xml
|
||||
PATH_SUFFIXES "${PYTHON_SITE_PACKAGES}/PySide6/typesystems")
|
||||
endif()
|
||||
|
||||
if(TARGET ${_lib_target})
|
||||
get_target_property(_is_imported ${_lib_target} IMPORTED)
|
||||
if(_is_imported)
|
||||
get_target_property(_imported_location ${_lib_target} IMPORTED_LOCATION)
|
||||
if(NOT _imported_location)
|
||||
message(STATUS "Target ${_lib_target} does not specify its IMPORTED_LOCATION! Trying to find it ourselves...")
|
||||
set(_find_args)
|
||||
if(${_module}_CONFIG)
|
||||
get_filename_component(_pyside6_lib_dir "${${_module}_CONFIG}/../../../" ABSOLUTE)
|
||||
set(_find_args PATHS "${_pyside6_lib_dir}")
|
||||
endif()
|
||||
find_library(PYSIDE_LIBRARY
|
||||
NAMES
|
||||
"pyside6${PYTHON_CONFIG_SUFFIX}"
|
||||
"pyside6${PYTHON_CONFIG_SUFFIX}.${${_module}_FIND_VERSION_MAJOR}.${${_module}_FIND_VERSION_MINOR}"
|
||||
${_find_args})
|
||||
if(NOT PYSIDE_LIBRARY)
|
||||
set(_message_type WARNING)
|
||||
if(${_module}_FIND_REQUIRED)
|
||||
set(_message_type FATAL_ERROR)
|
||||
endif()
|
||||
message(${_message_type} "Failed to manually find library for ${_module}")
|
||||
return()
|
||||
endif()
|
||||
message(STATUS "IMPORTED_LOCATION for ${_lib_target} found: ${PYSIDE_LIBRARY}")
|
||||
set_target_properties(${_lib_target} PROPERTIES IMPORTED_LOCATION "${PYSIDE_LIBRARY}")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(${_module}
|
||||
FOUND_VAR ${_module}_FOUND
|
||||
REQUIRED_VARS PYSIDE_LIBRARY PYSIDE_INCLUDE_DIR PYSIDE_TYPESYSTEMS
|
||||
VERSION_VAR ${_module}_VERSION)
|
||||
|
||||
add_library(${_module}::pyside6 INTERFACE IMPORTED)
|
||||
set_target_properties(${_module}::pyside6 PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${PYSIDE_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${PYSIDE_LIBRARY}")
|
||||
endif()
|
||||
|
||||
mark_as_advanced(PYSIDE_INCLUDE_DIR PYSIDE_LIBRARY PYSIDE_BINARY)
|
@ -14,6 +14,7 @@ set(TS_FILES
|
||||
translations/ro/cutter_ro.ts
|
||||
translations/ru/cutter_ru.ts
|
||||
translations/tr/cutter_tr.ts
|
||||
translations/uk/cutter_uk.ts
|
||||
translations/zh-CN/cutter_zh.ts
|
||||
)
|
||||
# translations/ko/cutter_ko.ts problems with fonts
|
||||
|
30
dist/CMakeLists.txt
vendored
30
dist/CMakeLists.txt
vendored
@ -7,7 +7,7 @@ unset(RZ_GHIDRA_PREFIX_PATH)
|
||||
|
||||
if(WIN32)
|
||||
set(CPACK_GENERATOR "ZIP")
|
||||
set(RIZIN_INSTALL_PLUGDIR "lib/plugins")
|
||||
set(RIZIN_INSTALL_PLUGDIR "lib/rizin/plugins")
|
||||
|
||||
if (CUTTER_PACKAGE_DEPENDENCIES)
|
||||
if (CUTTER_ENABLE_PYTHON)
|
||||
@ -59,6 +59,18 @@ if(WIN32)
|
||||
endif()
|
||||
")
|
||||
endif()
|
||||
if (CUTTER_PACKAGE_RZ_SILHOUETTE 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_silhouette.ps1\" \"\${CMAKE_INSTALL_PREFIX}\"
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
RESULT_VARIABLE SCRIPT_RESULT)
|
||||
if (SCRIPT_RESULT)
|
||||
message(FATAL_ERROR \"Failed to package rz-silhouette (returned \${SCRIPT_RESULT})\")
|
||||
endif()
|
||||
")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
################################################
|
||||
@ -150,6 +162,18 @@ if(CUTTER_ENABLE_DEPENDENCY_DOWNLOADS AND (NOT WIN32))
|
||||
endif()
|
||||
")
|
||||
endif()
|
||||
if (CUTTER_PACKAGE_RZ_SILHOUETTE)
|
||||
install(CODE "
|
||||
execute_process(COMMAND
|
||||
\"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-silhouette.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-silhouette (returned \${SCRIPT_RESULT})\")
|
||||
endif()
|
||||
")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
################################################
|
||||
@ -164,9 +188,9 @@ if(CUTTER_PACKAGE_RZ_GHIDRA)
|
||||
# installed Cutter.
|
||||
ExternalProject_Add(rz-ghidra
|
||||
GIT_REPOSITORY https://github.com/rizinorg/rz-ghidra
|
||||
GIT_TAG v0.5.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 ""
|
||||
|
7
dist/bundle_jsdec.ps1
vendored
7
dist/bundle_jsdec.ps1
vendored
@ -5,12 +5,13 @@ if (-not (Test-Path -Path 'jsdec' -PathType Container)) {
|
||||
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=".." --prefix=$dist 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"
|
||||
$pathdll = "$dist\lib\rizin\plugins\core_pdd.dll"
|
||||
if(![System.IO.File]::Exists($pathdll)) {
|
||||
type build\meson-logs\meson-log.txt
|
||||
ls "$dist\lib\rizin\plugins\"
|
||||
throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll))
|
||||
}
|
||||
Remove-Item -Recurse -Force $dist\lib\plugins\core_pdd.lib
|
||||
Remove-Item -Recurse -Force "$dist\lib\rizin\plugins\core_pdd.lib"
|
||||
|
6
dist/bundle_rz_libswift.ps1
vendored
6
dist/bundle_rz_libswift.ps1
vendored
@ -7,10 +7,10 @@ if (-not (Test-Path -Path 'libswift' -PathType Container)) {
|
||||
cd libswift
|
||||
& meson.exe --buildtype=release --prefix=$dist build
|
||||
ninja -C build install
|
||||
$pathdll = "$dist/lib/plugins/swift.dll"
|
||||
$pathdll = "$dist\lib\rizin\plugins\swift.dll"
|
||||
if(![System.IO.File]::Exists($pathdll)) {
|
||||
type build/meson-logs/meson-log.txt
|
||||
ls "$dist/lib/plugins/"
|
||||
ls "$dist\lib\rizin\plugins\"
|
||||
throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll))
|
||||
}
|
||||
Remove-Item -Recurse -Force $dist/lib/plugins/swift.lib
|
||||
Remove-Item -Recurse -Force "$dist\lib\rizin\plugins\swift.lib"
|
||||
|
8
dist/bundle_rz_libyara.ps1
vendored
8
dist/bundle_rz_libyara.ps1
vendored
@ -8,15 +8,15 @@ if (-not (Test-Path -Path 'rz_libyara' -PathType Container)) {
|
||||
git -C rz_libyara submodule update
|
||||
}
|
||||
cd rz_libyara
|
||||
& meson.exe --buildtype=release --prefix=$dist build
|
||||
& meson.exe --buildtype=release --prefix=$dist -Duse_sys_yara=disabled -Denable_openssl=false build
|
||||
ninja -C build install
|
||||
$pathdll = "$dist/lib/plugins/rz_yara.dll"
|
||||
$pathdll = "$dist\lib\rizin\plugins\rz_yara.dll"
|
||||
if(![System.IO.File]::Exists($pathdll)) {
|
||||
type build/meson-logs/meson-log.txt
|
||||
ls "$dist/lib/plugins/"
|
||||
ls "$dist\lib\rizin\plugins\"
|
||||
throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll))
|
||||
}
|
||||
Remove-Item -Recurse -Force $dist/lib/plugins/rz_yara.lib
|
||||
Remove-Item -Recurse -Force "$dist\lib\rizin\plugins\rz_yara.lib"
|
||||
|
||||
cd cutter-plugin
|
||||
mkdir build
|
||||
|
17
dist/bundle_rz_silhouette.ps1
vendored
Normal file
17
dist/bundle_rz_silhouette.ps1
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
$dist = $args[0]
|
||||
$cmake_opts = $args[1]
|
||||
$python = Split-Path((Get-Command python.exe).Path)
|
||||
|
||||
if (-not (Test-Path -Path 'rz-silhouette' -PathType Container)) {
|
||||
git clone https://github.com/rizinorg/rz-silhouette.git --depth 1 rz-silhouette
|
||||
}
|
||||
cd rz-silhouette
|
||||
& meson.exe --buildtype=release --prefix=$dist build
|
||||
ninja -C build install
|
||||
$pathdll = "$dist\lib\rizin\plugins\rz_silhouette.dll"
|
||||
if(![System.IO.File]::Exists($pathdll)) {
|
||||
type build/meson-logs/meson-log.txt
|
||||
ls "$dist\lib\rizin\plugins\"
|
||||
throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll))
|
||||
}
|
||||
Remove-Item -Recurse -Force "$dist\lib\rizin\plugins\rz_silhouette.lib"
|
@ -247,7 +247,7 @@ Note that there are some major building options available:
|
||||
|
||||
* ``CUTTER_USE_BUNDLED_RIZIN`` automatically compile Rizin from submodule (Enabled by default).
|
||||
* ``CUTTER_ENABLE_PYTHON`` compile with Python support.
|
||||
* ``CUTTER_ENABLE_PYTHON_BINDINGS`` automatically generate Python Bindings with Shiboken2, required for Python plugins!
|
||||
* ``CUTTER_ENABLE_PYTHON_BINDINGS`` automatically generate Python Bindings with Shiboken, required for Python plugins!
|
||||
* ``CUTTER_ENABLE_KSYNTAXHIGHLIGHTING`` use KSyntaxHighlighting for code highlighting.
|
||||
* ``CUTTER_ENABLE_GRAPHVIZ`` enable Graphviz for graph layouts.
|
||||
* ``CUTTER_EXTRA_PLUGIN_DIRS`` List of addition plugin locations. Useful when preparing package for Linux distros that have strict package layout rules.
|
||||
|
@ -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.1'
|
||||
release = '2.2.0'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
@ -40,21 +40,45 @@ Options
|
||||
**2**
|
||||
aaaa (experimental)
|
||||
|
||||
.. option:: -a, --arch <arch>
|
||||
|
||||
Sets a specific architecture name.
|
||||
|
||||
.. option:: -b, --bits <bits>
|
||||
|
||||
Sets a specific architecture bits.
|
||||
|
||||
.. option:: -c, --cpu <cpu>
|
||||
|
||||
Sets a specific CPU.
|
||||
|
||||
.. option:: -o, --os <os>
|
||||
|
||||
Sets a specific operating system.
|
||||
|
||||
.. option:: -e, --endian <big|little>
|
||||
|
||||
Sets the endianness (big or little).
|
||||
|
||||
.. option:: -F, --format <name>
|
||||
|
||||
Force using a specific file format (bin plugin)
|
||||
Force using a specific file format (bin plugin).
|
||||
|
||||
.. option:: -B, --base <base address>
|
||||
|
||||
Load binary at a specific base address
|
||||
Load binary at a specific base address.
|
||||
|
||||
.. option:: -m, --map <map address>
|
||||
|
||||
Map the binary at a specific address.
|
||||
|
||||
.. option:: -i <file>
|
||||
|
||||
Run script file
|
||||
Run script file.
|
||||
|
||||
.. option:: -p, --project <file>
|
||||
|
||||
Load project file
|
||||
Load project file.
|
||||
|
||||
.. option:: -w, --writemode
|
||||
|
||||
@ -62,9 +86,13 @@ Options
|
||||
When used together with -A/--analysis <level>, it will open a file directly
|
||||
in write mode without any further dialog or confirmation.
|
||||
|
||||
.. option:: -P, --phymode
|
||||
|
||||
Disables virtual addressing.
|
||||
|
||||
.. option:: --pythonhome <PYTHONHOME>
|
||||
|
||||
PYTHONHOME to use for the embedded python interpreter
|
||||
PYTHONHOME to use for the embedded python interpreter.
|
||||
|
||||
.. option:: --no-output-redirect
|
||||
|
||||
|
2
rizin
2
rizin
@ -1 +1 @@
|
||||
Subproject commit e2646b53b0f1aba8202f98b22d345ae73ad0e35f
|
||||
Subproject commit 48b088056236254356fdde46f28d1cbe8bc28316
|
123
scripts/clang-format.py
Executable file
123
scripts/clang-format.py
Executable file
@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2021 Anton Kochkov <anton.kochkov@gmail.com>
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import itertools
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from git import Repo
|
||||
|
||||
dirlist = [
|
||||
"src",
|
||||
]
|
||||
|
||||
skiplist = [
|
||||
"translations",
|
||||
]
|
||||
|
||||
patterns = ["*.cpp", "*.h", "*.hpp"]
|
||||
|
||||
|
||||
def should_scan(filename):
|
||||
return any(directory in filename for directory in dirlist) and any(
|
||||
pattern[1:] in filename for pattern in patterns
|
||||
)
|
||||
|
||||
|
||||
def skip(filename):
|
||||
return any(skipfile in filename for skipfile in skiplist)
|
||||
|
||||
|
||||
def get_matching_files():
|
||||
for directory, pattern in itertools.product(dirlist, patterns):
|
||||
for filename in glob.iglob(directory + "/**/" + pattern, recursive=True):
|
||||
if not skip(filename):
|
||||
yield filename
|
||||
|
||||
|
||||
def get_edited_files(args):
|
||||
repo = Repo()
|
||||
|
||||
for diff in repo.index.diff(args.diff):
|
||||
filename = diff.a_path
|
||||
if should_scan(filename) and not skip(filename):
|
||||
yield filename
|
||||
|
||||
|
||||
def build_command(clangformat, check, filenames, verbose):
|
||||
cmd = [clangformat, "--style=file"]
|
||||
if verbose:
|
||||
cmd += ["--verbose"]
|
||||
if check:
|
||||
cmd += ["--Werror", "--dry-run"]
|
||||
else:
|
||||
cmd += ["-i"]
|
||||
return cmd + filenames
|
||||
|
||||
|
||||
def format_files(args, files):
|
||||
if len(files) == 0:
|
||||
print("No C files to format.")
|
||||
sys.exit(0)
|
||||
cmd = build_command(args.clang_format, args.check, files, args.verbose)
|
||||
r = subprocess.run(cmd, check=False)
|
||||
sys.exit(r.returncode)
|
||||
|
||||
|
||||
def get_file(args):
|
||||
filename = args.file
|
||||
if should_scan(filename) and not skip(filename):
|
||||
return [filename]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def get_files(args):
|
||||
if args.diff:
|
||||
return get_edited_files(args)
|
||||
|
||||
if args.file:
|
||||
return get_file(args)
|
||||
|
||||
return get_matching_files()
|
||||
|
||||
|
||||
def process(args):
|
||||
files = get_files(args)
|
||||
format_files(args, list(files))
|
||||
|
||||
|
||||
def parse():
|
||||
parser = argparse.ArgumentParser(description="Clang format the rizin project")
|
||||
|
||||
parser.add_argument(
|
||||
"-C", "--clang-format", default="clang-format", help="path of clang-format"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c", "--check", action="store_true", help="enable the check mode"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", "--verbose", action="store_true", help="use verbose output"
|
||||
)
|
||||
parser.add_argument("-f", "--file", help="formats (or checks) only the given file")
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--diff",
|
||||
type=str,
|
||||
default=None,
|
||||
help="format all modified file related to branch",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main():
|
||||
args = parse()
|
||||
process(args)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -15,7 +15,7 @@ fi
|
||||
|
||||
cd rz_libyara
|
||||
|
||||
meson --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" --prefix="$INSTALL_PREFIX" build
|
||||
meson --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" --prefix="$INSTALL_PREFIX" -Duse_sys_yara=disabled build
|
||||
ninja -C build install
|
||||
|
||||
cd cutter-plugin
|
||||
|
17
scripts/rz-silhouette.sh
Executable file
17
scripts/rz-silhouette.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
|
||||
INSTALL_PREFIX="$1"
|
||||
EXTRA_CMAKE_OPTS="$2"
|
||||
|
||||
cd "$SCRIPTPATH/.."
|
||||
|
||||
if [[ ! -d rz-silhouette ]]; then
|
||||
git clone https://github.com/rizinorg/rz-silhouette.git --depth 1 rz-silhouette
|
||||
fi
|
||||
|
||||
cd rz-silhouette
|
||||
|
||||
meson --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" --prefix="$INSTALL_PREFIX" build
|
||||
ninja -C build install
|
@ -6,6 +6,7 @@ set(SOURCES
|
||||
core/Cutter.cpp
|
||||
core/CutterJson.cpp
|
||||
core/RizinCpp.cpp
|
||||
core/Basefind.cpp
|
||||
dialogs/EditStringDialog.cpp
|
||||
dialogs/WriteCommandsDialogs.cpp
|
||||
widgets/DisassemblerGraphView.cpp
|
||||
@ -17,6 +18,7 @@ set(SOURCES
|
||||
dialogs/CommentsDialog.cpp
|
||||
dialogs/EditInstructionDialog.cpp
|
||||
dialogs/FlagDialog.cpp
|
||||
dialogs/GlobalVariableDialog.cpp
|
||||
dialogs/RemoteDebugDialog.cpp
|
||||
dialogs/NativeDebugDialog.cpp
|
||||
dialogs/XrefsDialog.cpp
|
||||
@ -35,6 +37,7 @@ set(SOURCES
|
||||
widgets/ExportsWidget.cpp
|
||||
widgets/FlagsWidget.cpp
|
||||
widgets/FunctionsWidget.cpp
|
||||
widgets/GlobalsWidget.cpp
|
||||
widgets/ImportsWidget.cpp
|
||||
widgets/Omnibar.cpp
|
||||
widgets/RelocsWidget.cpp
|
||||
@ -149,6 +152,9 @@ set(SOURCES
|
||||
dialogs/GlibcHeapBinsDialog.cpp
|
||||
widgets/HeapBinsGraphView.cpp
|
||||
dialogs/ArenaInfoDialog.cpp
|
||||
tools/basefind/BaseFindDialog.cpp
|
||||
tools/basefind/BaseFindSearchDialog.cpp
|
||||
tools/basefind/BaseFindResultsDialog.cpp
|
||||
)
|
||||
set(HEADER_FILES
|
||||
core/Cutter.h
|
||||
@ -156,6 +162,7 @@ set(HEADER_FILES
|
||||
core/CutterDescriptions.h
|
||||
core/CutterJson.h
|
||||
core/RizinCpp.h
|
||||
core/Basefind.h
|
||||
dialogs/EditStringDialog.h
|
||||
dialogs/WriteCommandsDialogs.h
|
||||
widgets/DisassemblerGraphView.h
|
||||
@ -167,6 +174,7 @@ set(HEADER_FILES
|
||||
dialogs/CommentsDialog.h
|
||||
dialogs/EditInstructionDialog.h
|
||||
dialogs/FlagDialog.h
|
||||
dialogs/GlobalVariableDialog.h
|
||||
dialogs/RemoteDebugDialog.h
|
||||
dialogs/NativeDebugDialog.h
|
||||
dialogs/XrefsDialog.h
|
||||
@ -308,6 +316,9 @@ set(HEADER_FILES
|
||||
dialogs/GlibcHeapBinsDialog.h
|
||||
widgets/HeapBinsGraphView.h
|
||||
dialogs/ArenaInfoDialog.h
|
||||
tools/basefind/BaseFindDialog.h
|
||||
tools/basefind/BaseFindSearchDialog.h
|
||||
tools/basefind/BaseFindResultsDialog.h
|
||||
)
|
||||
set(UI_FILES
|
||||
dialogs/AboutDialog.ui
|
||||
@ -319,6 +330,7 @@ set(UI_FILES
|
||||
dialogs/CommentsDialog.ui
|
||||
dialogs/EditInstructionDialog.ui
|
||||
dialogs/FlagDialog.ui
|
||||
dialogs/GlobalVariableDialog.ui
|
||||
dialogs/RemoteDebugDialog.ui
|
||||
dialogs/NativeDebugDialog.ui
|
||||
dialogs/XrefsDialog.ui
|
||||
@ -330,6 +342,7 @@ set(UI_FILES
|
||||
widgets/Dashboard.ui
|
||||
widgets/EntrypointWidget.ui
|
||||
widgets/FlagsWidget.ui
|
||||
widgets/GlobalsWidget.ui
|
||||
widgets/StringsWidget.ui
|
||||
widgets/HexdumpWidget.ui
|
||||
dialogs/preferences/PreferencesDialog.ui
|
||||
@ -338,7 +351,6 @@ set(UI_FILES
|
||||
dialogs/preferences/InitializationFileEditor.ui
|
||||
widgets/QuickFilterView.ui
|
||||
widgets/DecompilerWidget.ui
|
||||
widgets/ClassesWidget.ui
|
||||
widgets/VTablesWidget.ui
|
||||
widgets/TypesWidget.ui
|
||||
widgets/SearchWidget.ui
|
||||
@ -378,6 +390,9 @@ set(UI_FILES
|
||||
widgets/GlibcHeapWidget.ui
|
||||
dialogs/GlibcHeapBinsDialog.ui
|
||||
dialogs/ArenaInfoDialog.ui
|
||||
tools/basefind/BaseFindDialog.ui
|
||||
tools/basefind/BaseFindSearchDialog.ui
|
||||
tools/basefind/BaseFindResultsDialog.ui
|
||||
)
|
||||
set(QRC_FILES
|
||||
resources.qrc
|
||||
@ -387,16 +402,26 @@ set(QRC_FILES
|
||||
themes/lightstyle/light.qrc
|
||||
)
|
||||
|
||||
set(CUTTER_INCLUDE_DIRECTORIES core widgets common plugins menus .)
|
||||
|
||||
if (CUTTER_ENABLE_PYTHON)
|
||||
list(APPEND SOURCES common/QtResImporter.cpp common/PythonManager.cpp common/PythonAPI.cpp)
|
||||
list(APPEND HEADER_FILES common/QtResImporter.h common/PythonManager.h common/PythonAPI.h)
|
||||
endif()
|
||||
|
||||
if(CUTTER_ENABLE_PYTHON_BINDINGS)
|
||||
if (CUTTER_QT6)
|
||||
set(PYSIDE_NAME PySide6)
|
||||
set(SHIBOKEN_COMMAND Shiboken6::shiboken6)
|
||||
else()
|
||||
set(PYSIDE_NAME PySide2)
|
||||
set(SHIBOKEN_COMMAND Shiboken2::shiboken2)
|
||||
endif()
|
||||
|
||||
set(BINDINGS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bindings")
|
||||
set(BINDINGS_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/bindings")
|
||||
|
||||
configure_file("${BINDINGS_SRC_DIR}/bindings.xml" "${BINDINGS_BUILD_DIR}/bindings.xml" COPYONLY) # trigger reconfigure if file changes
|
||||
configure_file("${BINDINGS_SRC_DIR}/bindings.xml.in" "${BINDINGS_BUILD_DIR}/bindings.xml")
|
||||
|
||||
execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${BINDINGS_SRC_DIR}/src_list.py" cmake "${BINDINGS_BUILD_DIR}" OUTPUT_VARIABLE BINDINGS_SOURCE)
|
||||
|
||||
@ -404,14 +429,40 @@ if(CUTTER_ENABLE_PYTHON_BINDINGS)
|
||||
|
||||
include_directories("${BINDINGS_BUILD_DIR}/CutterBindings")
|
||||
|
||||
set(SHIBOKEN_INCLUDE_DIRS "")
|
||||
if(APPLE AND _qt6Core_install_prefix)
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS "${_qt6Core_install_prefix}/include")
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS "${_qt6Core_install_prefix}/include/QtCore")
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS "${_qt6Core_install_prefix}/include/QtGui")
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS "${_qt6Core_install_prefix}/include/QtWidgets")
|
||||
endif()
|
||||
|
||||
if (CUTTER_QT6)
|
||||
list(APPEND SHIBOKEN_INCLUDE_DIRS ${Qt6Core_INCLUDE_DIRS} ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Gui_INCLUDE_DIRS})
|
||||
else()
|
||||
list(APPEND SHIBOKEN_INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
foreach(_dir ${CUTTER_INCLUDE_DIRECTORIES})
|
||||
list(APPEND SHIBOKEN_INCLUDE_DIRS
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${_dir}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cutter/${_dir}>
|
||||
)
|
||||
endforeach()
|
||||
list(APPEND SHIBOKEN_INCLUDE_DIRS ${Rizin_INCLUDE_DIRS})
|
||||
if (NOT WIN32)
|
||||
string(REPLACE ";" ":" SHIBOKEN_INCLUDE_DIRS "${SHIBOKEN_INCLUDE_DIRS}")
|
||||
endif()
|
||||
|
||||
set(SHIBOKEN_OPTIONS)
|
||||
list(APPEND SHIBOKEN_OPTIONS --include-paths="${SHIBOKEN_INCLUDE_DIRS}")
|
||||
if (WIN32)
|
||||
list(APPEND SHIBOKEN_OPTIONS --avoid-protected-hack)
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${BINDINGS_SOURCE}
|
||||
COMMAND Shiboken2::shiboken2 --project-file="${BINDINGS_BUILD_DIR}/bindings.txt" ${SHIBOKEN_OPTIONS} ${SHIBOKEN_EXTRA_OPTIONS}
|
||||
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/bindings/bindings.xml" "${BINDINGS_BUILD_DIR}/bindings.txt"
|
||||
COMMAND "${SHIBOKEN_COMMAND}" --project-file="${BINDINGS_BUILD_DIR}/bindings.txt" ${SHIBOKEN_OPTIONS} ${SHIBOKEN_EXTRA_OPTIONS}
|
||||
DEPENDS "${BINDINGS_BUILD_DIR}/bindings.xml" "${BINDINGS_BUILD_DIR}/bindings.txt"
|
||||
IMPLICIT_DEPENDS CXX "${CMAKE_CURRENT_SOURCE_DIR}/bindings/bindings.h"
|
||||
COMMENT "Generating Python bindings with shiboken2")
|
||||
else()
|
||||
@ -453,7 +504,6 @@ target_compile_definitions(Cutter PRIVATE CUTTER_SOURCE_BUILD)
|
||||
# Set Cutter as the startup project in Visual Studio
|
||||
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Cutter)
|
||||
|
||||
set(CUTTER_INCLUDE_DIRECTORIES core widgets common plugins menus .)
|
||||
foreach(_dir ${CUTTER_INCLUDE_DIRECTORIES})
|
||||
target_include_directories(Cutter PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${_dir}>
|
||||
@ -488,7 +538,11 @@ if(CUTTER_ENABLE_PYTHON)
|
||||
endif()
|
||||
target_link_libraries(Cutter PRIVATE ${PYTHON_LIBRARIES})
|
||||
if(CUTTER_ENABLE_PYTHON_BINDINGS)
|
||||
if (CUTTER_QT6)
|
||||
target_link_libraries(Cutter PRIVATE Shiboken6::libshiboken PySide6::pyside6)
|
||||
else()
|
||||
target_link_libraries(Cutter PRIVATE Shiboken2::libshiboken PySide2::pyside2)
|
||||
endif()
|
||||
|
||||
get_target_property(RAW_BINDINGS_INCLUDE_DIRS Cutter INCLUDE_DIRECTORIES)
|
||||
if(NOT CUTTER_USE_BUNDLED_RIZIN)
|
||||
@ -510,7 +564,11 @@ if(CUTTER_ENABLE_PYTHON)
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS "${_qt5Core_install_prefix}/include/QtGui")
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS "${_qt5Core_install_prefix}/include/QtWidgets")
|
||||
endif()
|
||||
if (CUTTER_QT6)
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS ${Qt6Core_INCLUDE_DIRS} ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Gui_INCLUDE_DIRS})
|
||||
else()
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS})
|
||||
endif()
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS ${Rizin_INCLUDE_DIRS})
|
||||
list(APPEND BINDINGS_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
if (NOT WIN32)
|
||||
|
@ -33,9 +33,9 @@
|
||||
// has RZ_GITTAP defined and uses it in rz_core_version().
|
||||
// After that, RZ_GITTAP is not defined anymore and RZ_VERSION is used.
|
||||
#ifdef RZ_GITTAP
|
||||
#define CUTTER_COMPILE_TIME_RZ_VERSION "" RZ_GITTAP
|
||||
# define CUTTER_COMPILE_TIME_RZ_VERSION "" RZ_GITTAP
|
||||
#else
|
||||
#define CUTTER_COMPILE_TIME_RZ_VERSION "" RZ_VERSION
|
||||
# define CUTTER_COMPILE_TIME_RZ_VERSION "" RZ_VERSION
|
||||
#endif
|
||||
|
||||
CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc, argv)
|
||||
@ -162,7 +162,8 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
appdir.cdUp(); // appdir
|
||||
|
||||
auto sleighHome = appdir;
|
||||
sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh/"); // appdir/lib/rizin/plugins/rz_ghidra_sleigh/
|
||||
// appdir/lib/rizin/plugins/rz_ghidra_sleigh/
|
||||
sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh/");
|
||||
Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath());
|
||||
}
|
||||
#endif
|
||||
@ -174,8 +175,8 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
rzprefix.cd("Resources"); // Contents/Resources/
|
||||
|
||||
auto sleighHome = rzprefix;
|
||||
sleighHome.cd(
|
||||
"lib/rizin/plugins/rz_ghidra_sleigh"); // Contents/Resources/lib/rizin/plugins/rz_ghidra_sleigh
|
||||
// Contents/Resources/lib/rizin/plugins/rz_ghidra_sleigh
|
||||
sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh");
|
||||
Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath());
|
||||
}
|
||||
#endif
|
||||
@ -183,7 +184,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
||||
#if defined(Q_OS_WIN) && defined(CUTTER_ENABLE_PACKAGING)
|
||||
{
|
||||
auto sleighHome = QDir(QCoreApplication::applicationDirPath());
|
||||
sleighHome.cd("lib/plugins/rz_ghidra_sleigh");
|
||||
sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh");
|
||||
Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath());
|
||||
}
|
||||
#endif
|
||||
@ -295,6 +296,89 @@ bool CutterApplication::loadTranslations()
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList CutterApplication::getArgs() const
|
||||
{
|
||||
auto &options = clOptions.fileOpenOptions;
|
||||
|
||||
QStringList args;
|
||||
switch (clOptions.analysisLevel) {
|
||||
case AutomaticAnalysisLevel::None:
|
||||
args.push_back("-A");
|
||||
args.push_back("0");
|
||||
break;
|
||||
case AutomaticAnalysisLevel::AAA:
|
||||
args.push_back("-A");
|
||||
args.push_back("1");
|
||||
break;
|
||||
case AutomaticAnalysisLevel::AAAA:
|
||||
args.push_back("-A");
|
||||
args.push_back("2");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!options.useVA) {
|
||||
args.push_back("-P");
|
||||
}
|
||||
if (options.writeEnabled) {
|
||||
args.push_back("-w");
|
||||
}
|
||||
if (!options.script.isEmpty()) {
|
||||
args.push_back("-i");
|
||||
args.push_back(options.script);
|
||||
}
|
||||
if (!options.projectFile.isEmpty()) {
|
||||
args.push_back("-p");
|
||||
args.push_back(options.projectFile);
|
||||
}
|
||||
if (!options.arch.isEmpty()) {
|
||||
args.push_back("-a");
|
||||
args.push_back(options.arch);
|
||||
}
|
||||
if (options.bits > 0) {
|
||||
args.push_back("-b");
|
||||
args.push_back(QString::asprintf("%d", options.bits));
|
||||
}
|
||||
if (!options.cpu.isEmpty()) {
|
||||
args.push_back("-c");
|
||||
args.push_back(options.cpu);
|
||||
}
|
||||
if (!options.os.isEmpty()) {
|
||||
args.push_back("-o");
|
||||
args.push_back(options.os);
|
||||
}
|
||||
|
||||
switch (options.endian) {
|
||||
case InitialOptions::Endianness::Little:
|
||||
args.push_back("-e");
|
||||
args.push_back("little");
|
||||
break;
|
||||
case InitialOptions::Endianness::Big:
|
||||
args.push_back("-e");
|
||||
args.push_back("big");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!options.forceBinPlugin.isEmpty()) {
|
||||
args.push_back("-F");
|
||||
args.push_back(options.forceBinPlugin);
|
||||
}
|
||||
if (options.binLoadAddr != RVA_INVALID) {
|
||||
args.push_back("-B");
|
||||
args.push_back(RzAddressString(options.binLoadAddr));
|
||||
}
|
||||
if (options.mapAddr != RVA_INVALID) {
|
||||
args.push_back("-m");
|
||||
args.push_back(RzAddressString(options.mapAddr));
|
||||
}
|
||||
if (!options.filename.isEmpty()) {
|
||||
args.push_back(options.filename);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
bool CutterApplication::parseCommandLineOptions()
|
||||
{
|
||||
// Keep this function in sync with documentation
|
||||
@ -314,6 +398,27 @@ bool CutterApplication::parseCommandLineOptions()
|
||||
QObject::tr("level"));
|
||||
cmd_parser.addOption(analOption);
|
||||
|
||||
QCommandLineOption archOption({ "a", "arch" }, QObject::tr("Sets a specific architecture name"),
|
||||
QObject::tr("arch"));
|
||||
cmd_parser.addOption(archOption);
|
||||
|
||||
QCommandLineOption bitsOption({ "b", "bits" }, QObject::tr("Sets a specific architecture bits"),
|
||||
QObject::tr("bits"));
|
||||
cmd_parser.addOption(bitsOption);
|
||||
|
||||
QCommandLineOption cpuOption({ "c", "cpu" }, QObject::tr("Sets a specific CPU"),
|
||||
QObject::tr("cpu"));
|
||||
cmd_parser.addOption(cpuOption);
|
||||
|
||||
QCommandLineOption osOption({ "o", "os" }, QObject::tr("Sets a specific operating system"),
|
||||
QObject::tr("os"));
|
||||
cmd_parser.addOption(osOption);
|
||||
|
||||
QCommandLineOption endianOption({ "e", "endian" },
|
||||
QObject::tr("Sets the endianness (big or little)"),
|
||||
QObject::tr("big|little"));
|
||||
cmd_parser.addOption(endianOption);
|
||||
|
||||
QCommandLineOption formatOption({ "F", "format" },
|
||||
QObject::tr("Force using a specific file format (bin plugin)"),
|
||||
QObject::tr("name"));
|
||||
@ -324,6 +429,11 @@ bool CutterApplication::parseCommandLineOptions()
|
||||
QObject::tr("base address"));
|
||||
cmd_parser.addOption(baddrOption);
|
||||
|
||||
QCommandLineOption maddrOption({ "m", "map" },
|
||||
QObject::tr("Map the binary at a specific address"),
|
||||
QObject::tr("map address"));
|
||||
cmd_parser.addOption(maddrOption);
|
||||
|
||||
QCommandLineOption scriptOption("i", QObject::tr("Run script file"), QObject::tr("file"));
|
||||
cmd_parser.addOption(scriptOption);
|
||||
|
||||
@ -335,6 +445,10 @@ bool CutterApplication::parseCommandLineOptions()
|
||||
QObject::tr("Open file in write mode"));
|
||||
cmd_parser.addOption(writeModeOption);
|
||||
|
||||
QCommandLineOption phyModeOption({ "P", "phymode" },
|
||||
QObject::tr("Disables virtual addressing"));
|
||||
cmd_parser.addOption(phyModeOption);
|
||||
|
||||
QCommandLineOption pythonHomeOption(
|
||||
"pythonhome", QObject::tr("PYTHONHOME to use for embedded python interpreter"),
|
||||
"PYTHONHOME");
|
||||
@ -396,15 +510,21 @@ bool CutterApplication::parseCommandLineOptions()
|
||||
return false;
|
||||
}
|
||||
|
||||
InitialOptions options;
|
||||
if (!opts.args.isEmpty()) {
|
||||
opts.fileOpenOptions.filename = opts.args[0];
|
||||
opts.fileOpenOptions.forceBinPlugin = cmd_parser.value(formatOption);
|
||||
if (cmd_parser.isSet(baddrOption)) {
|
||||
bool ok;
|
||||
bool ok = false;
|
||||
RVA baddr = cmd_parser.value(baddrOption).toULongLong(&ok, 0);
|
||||
if (ok) {
|
||||
options.binLoadAddr = baddr;
|
||||
opts.fileOpenOptions.binLoadAddr = baddr;
|
||||
}
|
||||
}
|
||||
if (cmd_parser.isSet(maddrOption)) {
|
||||
bool ok = false;
|
||||
RVA maddr = cmd_parser.value(maddrOption).toULongLong(&ok, 0);
|
||||
if (ok) {
|
||||
opts.fileOpenOptions.mapAddr = maddr;
|
||||
}
|
||||
}
|
||||
switch (opts.analysisLevel) {
|
||||
@ -421,8 +541,36 @@ bool CutterApplication::parseCommandLineOptions()
|
||||
break;
|
||||
}
|
||||
opts.fileOpenOptions.script = cmd_parser.value(scriptOption);
|
||||
opts.fileOpenOptions.arch = cmd_parser.value(archOption);
|
||||
opts.fileOpenOptions.cpu = cmd_parser.value(cpuOption);
|
||||
opts.fileOpenOptions.os = cmd_parser.value(osOption);
|
||||
if (cmd_parser.isSet(bitsOption)) {
|
||||
bool ok = false;
|
||||
int bits = cmd_parser.value(bitsOption).toInt(&ok, 10);
|
||||
if (ok && bits > 0) {
|
||||
opts.fileOpenOptions.bits = bits;
|
||||
}
|
||||
}
|
||||
if (cmd_parser.isSet(endianOption)) {
|
||||
QString endian = cmd_parser.value(endianOption).toLower();
|
||||
opts.fileOpenOptions.endian = InitialOptions::Endianness::Auto;
|
||||
if (endian == "little") {
|
||||
opts.fileOpenOptions.endian = InitialOptions::Endianness::Little;
|
||||
} else if (endian == "big") {
|
||||
opts.fileOpenOptions.endian = InitialOptions::Endianness::Big;
|
||||
} else {
|
||||
fprintf(stderr, "%s\n",
|
||||
QObject::tr("Invalid Endianness. You can only set it to `big` or `little`.")
|
||||
.toLocal8Bit()
|
||||
.constData());
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
opts.fileOpenOptions.endian = InitialOptions::Endianness::Auto;
|
||||
}
|
||||
|
||||
opts.fileOpenOptions.writeEnabled = cmd_parser.isSet(writeModeOption);
|
||||
opts.fileOpenOptions.useVA = !cmd_parser.isSet(phyModeOption);
|
||||
}
|
||||
|
||||
opts.fileOpenOptions.projectFile = cmd_parser.value(projectOption);
|
||||
|
@ -33,6 +33,10 @@ public:
|
||||
|
||||
void launchNewInstance(const QStringList &args = {});
|
||||
|
||||
InitialOptions getInitialOptions() const { return clOptions.fileOpenOptions; }
|
||||
void setInitialOptions(const InitialOptions &options) { clOptions.fileOpenOptions = options; }
|
||||
QStringList getArgs() const;
|
||||
|
||||
protected:
|
||||
bool event(QEvent *e);
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
* @brief Attempt to connect to a parent console and configure outputs.
|
||||
*/
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
# include <windows.h>
|
||||
|
||||
static void connectToConsole()
|
||||
{
|
||||
@ -67,9 +67,9 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
QCoreApplication::setApplicationName("cutter");
|
||||
|
||||
// Importing settings after setting rename, needs separate handling in addition to regular version to version upgrade.
|
||||
if (Cutter::shouldOfferSettingImport())
|
||||
{
|
||||
// Importing settings after setting rename, needs separate handling in addition to regular
|
||||
// version to version upgrade.
|
||||
if (Cutter::shouldOfferSettingImport()) {
|
||||
Cutter::showSettingImportDialog(argc, argv);
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
generator-set = shiboken
|
||||
|
||||
header-file = ${BINDINGS_SRC_DIR}/bindings.h
|
||||
typesystem-file = ${BINDINGS_SRC_DIR}/bindings.xml
|
||||
typesystem-file = ${BINDINGS_BUILD_DIR}/bindings.xml
|
||||
|
||||
output-directory = ${BINDINGS_BUILD_DIR}
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
PyErr_Print();
|
||||
return QString();
|
||||
}
|
||||
PythonToCppFunc pythonToCpp = Shiboken::Conversions::isPythonToCppConvertible(SbkPySide2_QtCoreTypeConverters[SBK_QSTRING_IDX], pyResult);
|
||||
PythonToCppFunc pythonToCpp = Shiboken::Conversions::isPythonToCppConvertible(Sbk${PYSIDE_NAME}_QtCoreTypeConverters[SBK_QSTRING_IDX], pyResult);
|
||||
if (!pythonToCpp) {
|
||||
Shiboken::warning(PyExc_RuntimeWarning, 2, "Invalid return value for plugin metadata VAR_NAME, expected %s, got %s.", "QString", Py_TYPE(pyResult)->tp_name);
|
||||
return ::QString();
|
@ -9,7 +9,7 @@ script_path = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
def get_cpp_files_gen(args, include_package=True):
|
||||
ts_tree = et.parse(os.path.join(script_path, "bindings.xml"))
|
||||
ts_tree = et.parse(os.path.join(script_path, "bindings.xml.in"))
|
||||
ts_root = ts_tree.getroot()
|
||||
|
||||
package = ts_root.attrib["package"]
|
||||
|
@ -13,11 +13,17 @@ AddressableFilterProxyModel::AddressableFilterProxyModel(AddressableItemModelI *
|
||||
|
||||
RVA AddressableFilterProxyModel::address(const QModelIndex &index) const
|
||||
{
|
||||
if (!addressableSourceModel) {
|
||||
return RVA_INVALID;
|
||||
}
|
||||
return addressableSourceModel->address(this->mapToSource(index));
|
||||
}
|
||||
|
||||
QString AddressableFilterProxyModel::name(const QModelIndex &index) const
|
||||
{
|
||||
if (!addressableSourceModel) {
|
||||
return QString();
|
||||
}
|
||||
return addressableSourceModel->name(this->mapToSource(index));
|
||||
}
|
||||
|
||||
@ -28,6 +34,6 @@ void AddressableFilterProxyModel::setSourceModel(QAbstractItemModel *)
|
||||
|
||||
void AddressableFilterProxyModel::setSourceModel(AddressableItemModelI *sourceModel)
|
||||
{
|
||||
ParentClass::setSourceModel(sourceModel->asItemModel());
|
||||
ParentClass::setSourceModel(sourceModel ? sourceModel->asItemModel() : nullptr);
|
||||
addressableSourceModel = sourceModel;
|
||||
}
|
||||
|
@ -783,6 +783,16 @@ bool Configuration::getPreviewValue() const
|
||||
return s.value("asm.preview").toBool();
|
||||
}
|
||||
|
||||
void Configuration::setShowVarTooltips(bool enabled)
|
||||
{
|
||||
s.setValue("showVarTooltips", enabled);
|
||||
}
|
||||
|
||||
bool Configuration::getShowVarTooltips() const
|
||||
{
|
||||
return s.value("showVarTooltips").toBool();
|
||||
}
|
||||
|
||||
bool Configuration::getGraphBlockEntryOffset()
|
||||
{
|
||||
return s.value("graphBlockEntryOffset", true).value<bool>();
|
||||
|
@ -215,6 +215,12 @@ public:
|
||||
void setPreviewValue(bool checked);
|
||||
bool getPreviewValue() const;
|
||||
|
||||
/**
|
||||
* @brief Show tooltips for known values of registers, variables, and memory when debugging
|
||||
*/
|
||||
void setShowVarTooltips(bool enabled);
|
||||
bool getShowVarTooltips() const;
|
||||
|
||||
/**
|
||||
* @brief Recently opened binaries, as shown in NewFileDialog.
|
||||
*/
|
||||
|
@ -13,18 +13,18 @@ CutterSeekable::~CutterSeekable() {}
|
||||
void CutterSeekable::setSynchronization(bool sync)
|
||||
{
|
||||
synchronized = sync;
|
||||
onCoreSeekChanged(Core()->getOffset());
|
||||
onCoreSeekChanged(Core()->getOffset(), CutterCore::SeekHistoryType::New);
|
||||
emit syncChanged();
|
||||
}
|
||||
|
||||
void CutterSeekable::onCoreSeekChanged(RVA addr)
|
||||
void CutterSeekable::onCoreSeekChanged(RVA addr, CutterCore::SeekHistoryType type)
|
||||
{
|
||||
if (synchronized && widgetOffset != addr) {
|
||||
updateSeek(addr, true);
|
||||
updateSeek(addr, type, true);
|
||||
}
|
||||
}
|
||||
|
||||
void CutterSeekable::updateSeek(RVA addr, bool localOnly)
|
||||
void CutterSeekable::updateSeek(RVA addr, CutterCore::SeekHistoryType type, bool localOnly)
|
||||
{
|
||||
previousOffset = widgetOffset;
|
||||
widgetOffset = addr;
|
||||
@ -32,7 +32,7 @@ void CutterSeekable::updateSeek(RVA addr, bool localOnly)
|
||||
Core()->seek(addr);
|
||||
}
|
||||
|
||||
emit seekableSeekChanged(addr);
|
||||
emit seekableSeekChanged(addr, type);
|
||||
}
|
||||
|
||||
void CutterSeekable::seekPrev()
|
||||
@ -40,7 +40,7 @@ void CutterSeekable::seekPrev()
|
||||
if (synchronized) {
|
||||
Core()->seekPrev();
|
||||
} else {
|
||||
this->seek(previousOffset);
|
||||
this->seek(previousOffset, CutterCore::SeekHistoryType::Undo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,12 @@ public:
|
||||
* signal will be emitted.
|
||||
* In any case, CutterSeekable::seekableSeekChanged is emitted.
|
||||
* @param addr the location to seek at.
|
||||
* @param type the type of seek wrt history (Undo, Redo, or New)
|
||||
*/
|
||||
void seek(RVA addr) { updateSeek(addr, false); }
|
||||
void seek(RVA addr, CutterCore::SeekHistoryType type = CutterCore::SeekHistoryType::New)
|
||||
{
|
||||
updateSeek(addr, type, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief setSynchronization sets
|
||||
@ -67,7 +71,7 @@ private slots:
|
||||
/**
|
||||
* @brief onCoreSeekChanged
|
||||
*/
|
||||
void onCoreSeekChanged(RVA addr);
|
||||
void onCoreSeekChanged(RVA addr, CutterCore::SeekHistoryType type);
|
||||
|
||||
private:
|
||||
/**
|
||||
@ -91,9 +95,9 @@ private:
|
||||
* @brief internal method for changing the seek
|
||||
* @param localOnly whether the seek should be updated globally if synchronized
|
||||
*/
|
||||
void updateSeek(RVA addr, bool localOnly);
|
||||
void updateSeek(RVA addr, CutterCore::SeekHistoryType type, bool localOnly);
|
||||
|
||||
signals:
|
||||
void seekableSeekChanged(RVA addr);
|
||||
void seekableSeekChanged(RVA addr, CutterCore::SeekHistoryType type);
|
||||
void syncChanged();
|
||||
};
|
||||
|
@ -82,3 +82,75 @@ RVA DisassemblyPreview::readDisassemblyOffset(QTextCursor tc)
|
||||
|
||||
return userData->line.offset;
|
||||
}
|
||||
|
||||
typedef struct mmio_lookup_context
|
||||
{
|
||||
QString selected;
|
||||
RVA mmio_address;
|
||||
} mmio_lookup_context_t;
|
||||
|
||||
static bool lookup_mmio_addr_cb(void *user, const ut64 key, const void *value)
|
||||
{
|
||||
mmio_lookup_context_t *ctx = (mmio_lookup_context_t *)user;
|
||||
if (ctx->selected == (const char *)value) {
|
||||
ctx->mmio_address = key;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DisassemblyPreview::showDebugValueTooltip(QWidget *parent, const QPoint &pointOfEvent,
|
||||
const QString &selectedText, const RVA offset)
|
||||
{
|
||||
if (selectedText.isEmpty())
|
||||
return false;
|
||||
|
||||
if (selectedText.at(0).isLetter()) {
|
||||
{
|
||||
const auto registerRefs = Core()->getRegisterRefValues();
|
||||
for (auto ® : registerRefs) {
|
||||
if (reg.name == selectedText) {
|
||||
auto msg = QString("reg %1 = %2").arg(reg.name, reg.value);
|
||||
QToolTip::showText(pointOfEvent, msg, parent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (offset != RVA_INVALID) {
|
||||
auto vars = Core()->getVariables(offset);
|
||||
for (auto &var : vars) {
|
||||
if (var.name == selectedText) {
|
||||
auto msg = QString("var %1 = %2").arg(var.name, var.value);
|
||||
QToolTip::showText(pointOfEvent, msg, parent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Lookup MMIO address
|
||||
mmio_lookup_context_t ctx;
|
||||
ctx.selected = selectedText;
|
||||
ctx.mmio_address = RVA_INVALID;
|
||||
auto core = Core()->core();
|
||||
RzPlatformTarget *arch_target = core->analysis->arch_target;
|
||||
if (arch_target && arch_target->profile) {
|
||||
ht_up_foreach(arch_target->profile->registers_mmio, lookup_mmio_addr_cb, &ctx);
|
||||
}
|
||||
if (ctx.mmio_address != RVA_INVALID) {
|
||||
int len = 8; // TODO: Determine proper len of mmio address for the cpu
|
||||
if (char *r = rz_core_print_hexdump_or_hexdiff_str(core, RZ_OUTPUT_MODE_STANDARD,
|
||||
ctx.mmio_address, len, false)) {
|
||||
auto val = QString::fromUtf8(r).trimmed().split("\n").last();
|
||||
auto msg = QString("mmio %1 %2").arg(selectedText, val);
|
||||
free(r);
|
||||
QToolTip::showText(pointOfEvent, msg, parent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Else show preview for value?
|
||||
return false;
|
||||
}
|
||||
|
@ -41,5 +41,13 @@ bool showDisasPreview(QWidget *parent, const QPoint &pointOfEvent, const RVA off
|
||||
* @return The disassembly offset of the hovered asm text
|
||||
*/
|
||||
RVA readDisassemblyOffset(QTextCursor tc);
|
||||
|
||||
/**
|
||||
* @brief Show a QToolTip that shows the value of the highlighted register, variable, or memory
|
||||
* @return True if the tooltip is shown
|
||||
*/
|
||||
bool showDebugValueTooltip(QWidget *parent, const QPoint &pointOfEvent, const QString &selectedText,
|
||||
const RVA offset);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
@ -16,8 +16,8 @@ static qreal GetDevicePixelRatio(qreal devicePixelRatio)
|
||||
}
|
||||
|
||||
HighDpiPixmap::HighDpiPixmap(int width, int height, qreal devicePixelRatio)
|
||||
: QPixmap(int(width *GetDevicePixelRatio(devicePixelRatio)),
|
||||
int(height *GetDevicePixelRatio(devicePixelRatio)))
|
||||
: QPixmap(int(width * GetDevicePixelRatio(devicePixelRatio)),
|
||||
int(height * GetDevicePixelRatio(devicePixelRatio)))
|
||||
{
|
||||
setDevicePixelRatio(GetDevicePixelRatio(devicePixelRatio));
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ PyObject *api_refresh(PyObject *self, PyObject *args)
|
||||
Q_UNUSED(self);
|
||||
Q_UNUSED(args);
|
||||
Core()->triggerRefreshAll();
|
||||
return Py_None;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *api_message(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
@ -46,8 +46,7 @@ PyObject *api_message(PyObject *self, PyObject *args, PyObject *kwargs)
|
||||
return NULL;
|
||||
}
|
||||
Core()->message(QString(message), debug);
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyMethodDef CutterMethods[] = {
|
||||
|
@ -13,6 +13,10 @@
|
||||
#ifdef CUTTER_ENABLE_PYTHON_BINDINGS
|
||||
# include <shiboken.h>
|
||||
# include <pyside.h>
|
||||
# ifdef HAVE_PYSIDECLEANUP
|
||||
// This header is introduced in PySide 6
|
||||
# include <pysidecleanup.h>
|
||||
# endif
|
||||
# include <signalmanager.h>
|
||||
#endif
|
||||
|
||||
@ -72,7 +76,10 @@ void PythonManager::initialize()
|
||||
PyImport_AppendInittab("CutterBindings", &PyInit_CutterBindings);
|
||||
#endif
|
||||
Py_Initialize();
|
||||
// This function is deprecated does nothing starting from Python 3.9
|
||||
#if (PY_MAJOR_VERSION <= 3) && (PY_MICRO_VERSION < 9)
|
||||
PyEval_InitThreads();
|
||||
#endif
|
||||
pyThreadStateCounter = 1; // we have the thread now => 1
|
||||
|
||||
RegQtResImporter();
|
||||
@ -159,7 +166,7 @@ void PythonManager::addPythonPath(char *path)
|
||||
if (!append) {
|
||||
return;
|
||||
}
|
||||
PyEval_CallFunction(append, "(s)", path);
|
||||
PyObject_CallFunction(append, "(s)", path);
|
||||
|
||||
saveThread();
|
||||
}
|
||||
|
@ -7,7 +7,8 @@
|
||||
namespace Cutter {
|
||||
void initializeSettings();
|
||||
/**
|
||||
* @brief Check if Cutter should offer importing settings from version that can't be directly updated.
|
||||
* @brief Check if Cutter should offer importing settings from version that can't be directly
|
||||
* updated.
|
||||
* @return True if this is first time running Cutter and r2 based Cutter <= 1.12 settings exist.
|
||||
*/
|
||||
bool shouldOfferSettingImport();
|
||||
|
109
src/core/Basefind.cpp
Normal file
109
src/core/Basefind.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
#include "Basefind.h"
|
||||
|
||||
bool Basefind::threadCallback(const RzBaseFindThreadInfo *info, void *user)
|
||||
{
|
||||
auto th = reinterpret_cast<Basefind *>(user);
|
||||
return th->updateProgress(info);
|
||||
}
|
||||
|
||||
Basefind::Basefind(CutterCore *core)
|
||||
: core(core),
|
||||
scores(nullptr),
|
||||
continue_run(true)
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
,
|
||||
mutex(QMutex::Recursive)
|
||||
#endif
|
||||
{
|
||||
memset(&options, 0, sizeof(RzBaseFindOpt));
|
||||
}
|
||||
|
||||
Basefind::~Basefind()
|
||||
{
|
||||
cancel();
|
||||
wait();
|
||||
rz_list_free(scores);
|
||||
}
|
||||
|
||||
bool Basefind::setOptions(const RzBaseFindOpt *opts)
|
||||
{
|
||||
mutex.lock();
|
||||
options.max_threads = opts->max_threads;
|
||||
options.pointer_size = opts->pointer_size;
|
||||
options.start_address = opts->start_address;
|
||||
options.end_address = opts->end_address;
|
||||
options.alignment = opts->alignment;
|
||||
options.min_score = opts->min_score;
|
||||
options.min_string_len = opts->min_string_len;
|
||||
mutex.unlock();
|
||||
|
||||
if (options.start_address >= options.end_address) {
|
||||
qWarning() << tr("Start address is >= end address");
|
||||
return false;
|
||||
} else if (options.alignment < RZ_BASEFIND_BASE_ALIGNMENT) {
|
||||
qWarning() << tr("Alignment must be at least ")
|
||||
<< QString::asprintf("0x%x", RZ_BASEFIND_BASE_ALIGNMENT);
|
||||
return false;
|
||||
} else if (options.min_score < 1) {
|
||||
qWarning() << tr("Min score must be at least 1");
|
||||
return false;
|
||||
} else if (options.min_string_len < 1) {
|
||||
qWarning() << tr("Min string length must be at least 1");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Basefind::run()
|
||||
{
|
||||
qRegisterMetaType<BasefindCoreStatusDescription>();
|
||||
|
||||
mutex.lock();
|
||||
rz_list_free(scores);
|
||||
scores = nullptr;
|
||||
continue_run = true;
|
||||
mutex.unlock();
|
||||
|
||||
core->coreMutex.lock();
|
||||
options.callback = threadCallback;
|
||||
options.user = this;
|
||||
scores = rz_basefind(core->core_, &options);
|
||||
core->coreMutex.unlock();
|
||||
|
||||
emit complete();
|
||||
}
|
||||
|
||||
void Basefind::cancel()
|
||||
{
|
||||
mutex.lock();
|
||||
continue_run = false;
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
QList<BasefindResultDescription> Basefind::results()
|
||||
{
|
||||
QList<BasefindResultDescription> pairs;
|
||||
RzListIter *it;
|
||||
RzBaseFindScore *pair;
|
||||
CutterRzListForeach (scores, it, RzBaseFindScore, pair) {
|
||||
BasefindResultDescription desc;
|
||||
desc.candidate = pair->candidate;
|
||||
desc.score = pair->score;
|
||||
pairs.push_back(desc);
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
bool Basefind::updateProgress(const RzBaseFindThreadInfo *info)
|
||||
{
|
||||
mutex.lock();
|
||||
|
||||
BasefindCoreStatusDescription status;
|
||||
status.index = info->thread_idx;
|
||||
status.percentage = info->percentage;
|
||||
|
||||
emit progress(status);
|
||||
bool ret = continue_run;
|
||||
mutex.unlock();
|
||||
return ret;
|
||||
}
|
47
src/core/Basefind.h
Normal file
47
src/core/Basefind.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef CUTTER_BASEFIND_CORE_H
|
||||
#define CUTTER_BASEFIND_CORE_H
|
||||
|
||||
#include <QThread>
|
||||
#include <QMutex>
|
||||
|
||||
#include "Cutter.h"
|
||||
#include "CutterDescriptions.h"
|
||||
#include <rz_basefind.h>
|
||||
|
||||
class CutterCore;
|
||||
|
||||
class Basefind : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Basefind(CutterCore *core);
|
||||
virtual ~Basefind();
|
||||
|
||||
void run();
|
||||
bool setOptions(const RzBaseFindOpt *opts);
|
||||
QList<BasefindResultDescription> results();
|
||||
|
||||
public slots:
|
||||
void cancel();
|
||||
|
||||
signals:
|
||||
void progress(BasefindCoreStatusDescription status);
|
||||
void complete();
|
||||
|
||||
private:
|
||||
CutterCore *const core;
|
||||
RzList *scores;
|
||||
bool continue_run;
|
||||
RzBaseFindOpt options;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
QMutex mutex;
|
||||
#else
|
||||
QRecursiveMutex mutex;
|
||||
#endif
|
||||
|
||||
bool updateProgress(const RzBaseFindThreadInfo *info);
|
||||
static bool threadCallback(const RzBaseFindThreadInfo *info, void *user);
|
||||
};
|
||||
|
||||
#endif // CUTTER_BASEFIND_CORE_H
|
@ -271,7 +271,7 @@ void CutterCore::loadCutterRC()
|
||||
if (!cutterRCFileInfo.exists() || !cutterRCFileInfo.isFile()) {
|
||||
continue;
|
||||
}
|
||||
qInfo() << "Loading initialization file from " << cutterRCFilePath;
|
||||
qInfo() << tr("Loading initialization file from ") << cutterRCFilePath;
|
||||
rz_core_cmd_file(core, cutterRCFilePath.toUtf8().constData());
|
||||
}
|
||||
}
|
||||
@ -284,7 +284,7 @@ void CutterCore::loadDefaultCutterRC()
|
||||
if (!cutterRCFileInfo.exists() || !cutterRCFileInfo.isFile()) {
|
||||
return;
|
||||
}
|
||||
qInfo() << "Loading initialization file from " << cutterRCFilePath;
|
||||
qInfo() << tr("Loading initialization file from ") << cutterRCFilePath;
|
||||
rz_core_cmd_file(core, cutterRCFilePath.toUtf8().constData());
|
||||
}
|
||||
|
||||
@ -1002,19 +1002,19 @@ void CutterCore::seekPrev()
|
||||
{
|
||||
CORE_LOCK();
|
||||
rz_core_seek_undo(core);
|
||||
updateSeek();
|
||||
updateSeek(SeekHistoryType::Undo);
|
||||
}
|
||||
|
||||
void CutterCore::seekNext()
|
||||
{
|
||||
CORE_LOCK();
|
||||
rz_core_seek_redo(core);
|
||||
updateSeek();
|
||||
updateSeek(SeekHistoryType::Redo);
|
||||
}
|
||||
|
||||
void CutterCore::updateSeek()
|
||||
void CutterCore::updateSeek(SeekHistoryType type)
|
||||
{
|
||||
emit seekChanged(getOffset());
|
||||
emit seekChanged(getOffset(), type);
|
||||
}
|
||||
|
||||
RVA CutterCore::prevOpAddr(RVA startAddr, int count)
|
||||
@ -1804,11 +1804,43 @@ QList<VariableDescription> CutterCore::getVariables(RVA at)
|
||||
}
|
||||
desc.type = QString::fromUtf8(tn);
|
||||
rz_mem_free(tn);
|
||||
|
||||
if (char *v = rz_core_analysis_var_display(core, var, false)) {
|
||||
desc.value = QString::fromUtf8(v).trimmed();
|
||||
rz_mem_free(v);
|
||||
}
|
||||
|
||||
ret.push_back(desc);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QList<GlobalDescription> CutterCore::getAllGlobals()
|
||||
{
|
||||
CORE_LOCK();
|
||||
RzListIter *it;
|
||||
|
||||
QList<GlobalDescription> ret;
|
||||
|
||||
RzAnalysisVarGlobal *glob;
|
||||
if (core && core->analysis && core->analysis->typedb) {
|
||||
const RzList *globals = rz_analysis_var_global_get_all(core->analysis);
|
||||
CutterRzListForeach (globals, it, RzAnalysisVarGlobal, glob) {
|
||||
const char *gtype = rz_type_as_string(core->analysis->typedb, glob->type);
|
||||
if (!gtype) {
|
||||
continue;
|
||||
}
|
||||
GlobalDescription global;
|
||||
global.addr = glob->addr;
|
||||
global.name = QString(glob->name);
|
||||
global.type = QString(gtype);
|
||||
ret << global;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVector<RegisterRefValueDescription> CutterCore::getRegisterRefValues()
|
||||
{
|
||||
QVector<RegisterRefValueDescription> result;
|
||||
@ -3084,8 +3116,6 @@ QList<ImportDescription> CutterCore::getAllImports()
|
||||
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;
|
||||
@ -3099,13 +3129,6 @@ QList<ImportDescription> CutterCore::getAllImports()
|
||||
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);
|
||||
}
|
||||
@ -3135,8 +3158,8 @@ QList<ExportDescription> CutterCore::getAllExports()
|
||||
return {};
|
||||
}
|
||||
|
||||
QString lang = getConfigi("bin.demangle") ? getConfig("bin.lang") : "";
|
||||
bool va = core->io->va || core->bin->is_debugger;
|
||||
bool demangle = rz_config_get_b(core->config, "bin.demangle");
|
||||
|
||||
QList<ExportDescription> ret;
|
||||
for (const auto &symbol : CutterRzList<RzBinSymbol>(symbols)) {
|
||||
@ -3145,7 +3168,7 @@ QList<ExportDescription> CutterCore::getAllExports()
|
||||
}
|
||||
|
||||
RzBinSymNames sn = {};
|
||||
rz_core_sym_name_init(core, &sn, symbol, lang.isEmpty() ? NULL : lang.toUtf8().constData());
|
||||
rz_core_sym_name_init(&sn, symbol, demangle);
|
||||
|
||||
ExportDescription exportDescription;
|
||||
exportDescription.vaddr = rva(bf->o, symbol->paddr, symbol->vaddr, va);
|
||||
@ -3543,19 +3566,18 @@ QList<BinClassDescription> CutterCore::getAllClassesFromBin()
|
||||
RzListIter *iter, *iter2, *iter3;
|
||||
RzBinClass *c;
|
||||
RzBinSymbol *sym;
|
||||
RzBinField *f;
|
||||
RzBinClassField *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) {
|
||||
CutterRzListForeach (c->fields, iter3, RzBinClassField, f) {
|
||||
BinClassFieldDescription fieldDescription;
|
||||
fieldDescription.name = f->name;
|
||||
fieldDescription.addr = f->vaddr;
|
||||
@ -3591,7 +3613,6 @@ QList<BinClassDescription> CutterCore::getAllClassesFromFlags()
|
||||
}
|
||||
desc->name = match.captured(1);
|
||||
desc->addr = item.offset;
|
||||
desc->index = RVA_INVALID;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3605,7 +3626,6 @@ QList<BinClassDescription> CutterCore::getAllClassesFromFlags()
|
||||
BinClassDescription cls;
|
||||
cls.name = tr("Unknown (%1)").arg(className);
|
||||
cls.addr = RVA_INVALID;
|
||||
cls.index = 0;
|
||||
ret << cls;
|
||||
classDesc = &ret.last();
|
||||
classesCache[className] = classDesc;
|
||||
@ -4028,6 +4048,99 @@ QList<XrefDescription> CutterCore::getXRefs(RVA addr, bool to, bool whole_functi
|
||||
return xrefList;
|
||||
}
|
||||
|
||||
void CutterCore::addGlobalVariable(RVA offset, QString name, QString typ)
|
||||
{
|
||||
name = sanitizeStringForCommand(name);
|
||||
CORE_LOCK();
|
||||
char *errmsg = NULL;
|
||||
RzType *globType = rz_type_parse_string_single(core->analysis->typedb->parser,
|
||||
typ.toStdString().c_str(), &errmsg);
|
||||
if (errmsg) {
|
||||
qWarning() << tr("Error parsing type: \"%1\" message: ").arg(typ) << errmsg;
|
||||
free(errmsg);
|
||||
return;
|
||||
}
|
||||
if (!rz_analysis_var_global_create(core->analysis, name.toStdString().c_str(), globType,
|
||||
offset)) {
|
||||
qWarning() << tr("Error creating global variable: \"%1\"").arg(name);
|
||||
return;
|
||||
}
|
||||
|
||||
emit globalVarsChanged();
|
||||
}
|
||||
|
||||
void CutterCore::modifyGlobalVariable(RVA offset, QString name, QString typ)
|
||||
{
|
||||
name = sanitizeStringForCommand(name);
|
||||
CORE_LOCK();
|
||||
RzAnalysisVarGlobal *glob = rz_analysis_var_global_get_byaddr_at(core->analysis, offset);
|
||||
if (!glob) {
|
||||
return;
|
||||
}
|
||||
// Compare if the name is not the same - also rename it
|
||||
if (name.compare(glob->name)) {
|
||||
rz_analysis_var_global_rename(core->analysis, glob->name, name.toStdString().c_str());
|
||||
}
|
||||
char *errmsg = NULL;
|
||||
RzType *globType = rz_type_parse_string_single(core->analysis->typedb->parser,
|
||||
typ.toStdString().c_str(), &errmsg);
|
||||
if (errmsg) {
|
||||
qWarning() << tr("Error parsing type: \"%1\" message: ").arg(typ) << errmsg;
|
||||
free(errmsg);
|
||||
return;
|
||||
}
|
||||
rz_analysis_var_global_set_type(glob, globType);
|
||||
|
||||
emit globalVarsChanged();
|
||||
}
|
||||
|
||||
void CutterCore::delGlobalVariable(QString name)
|
||||
{
|
||||
name = sanitizeStringForCommand(name);
|
||||
CORE_LOCK();
|
||||
rz_analysis_var_global_delete_byname(core->analysis, name.toStdString().c_str());
|
||||
|
||||
emit globalVarsChanged();
|
||||
}
|
||||
|
||||
void CutterCore::delGlobalVariable(RVA offset)
|
||||
{
|
||||
CORE_LOCK();
|
||||
rz_analysis_var_global_delete_byaddr_at(core->analysis, offset);
|
||||
|
||||
emit globalVarsChanged();
|
||||
}
|
||||
|
||||
QString CutterCore::getGlobalVariableType(QString name)
|
||||
{
|
||||
name = sanitizeStringForCommand(name);
|
||||
CORE_LOCK();
|
||||
RzAnalysisVarGlobal *glob =
|
||||
rz_analysis_var_global_get_byname(core->analysis, name.toStdString().c_str());
|
||||
if (!glob) {
|
||||
return QString("");
|
||||
}
|
||||
const char *gtype = rz_type_as_string(core->analysis->typedb, glob->type);
|
||||
if (!gtype) {
|
||||
return QString("");
|
||||
}
|
||||
return QString(gtype);
|
||||
}
|
||||
|
||||
QString CutterCore::getGlobalVariableType(RVA offset)
|
||||
{
|
||||
CORE_LOCK();
|
||||
RzAnalysisVarGlobal *glob = rz_analysis_var_global_get_byaddr_at(core->analysis, offset);
|
||||
if (!glob) {
|
||||
return QString("");
|
||||
}
|
||||
const char *gtype = rz_type_as_string(core->analysis->typedb, glob->type);
|
||||
if (!gtype) {
|
||||
return QString("");
|
||||
}
|
||||
return QString(gtype);
|
||||
}
|
||||
|
||||
void CutterCore::addFlag(RVA offset, QString name, RVA size)
|
||||
{
|
||||
name = sanitizeStringForCommand(name);
|
||||
@ -4149,11 +4262,20 @@ QList<DisassemblyLine> CutterCore::disassembleLines(RVA offset, int lines)
|
||||
|
||||
QList<DisassemblyLine> r;
|
||||
for (const auto &t : CutterPVector<RzAnalysisDisasmText>(vec.get())) {
|
||||
QString text = t->text;
|
||||
QStringList tokens = text.split('\n');
|
||||
// text might contain multiple lines
|
||||
// so we split them and keep only one
|
||||
// arrow/jump to addr.
|
||||
for (const auto &tok : tokens) {
|
||||
DisassemblyLine line;
|
||||
line.offset = t->offset;
|
||||
line.text = ansiEscapeToHtml(t->text);
|
||||
line.text = ansiEscapeToHtml(tok);
|
||||
line.arrow = t->arrow;
|
||||
r << line;
|
||||
// only the first one.
|
||||
t->arrow = RVA_INVALID;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
@ -4533,9 +4655,9 @@ char *CutterCore::getTextualGraphAt(RzCoreGraphType type, RzCoreGraphFormat form
|
||||
RzGraph *graph = rz_core_graph(core, type, address);
|
||||
if (!graph) {
|
||||
if (address == RVA_INVALID) {
|
||||
qWarning() << "Cannot get global graph";
|
||||
qWarning() << tr("Cannot get global graph");
|
||||
} else {
|
||||
qWarning() << "Cannot get graph at " << RzAddressString(address);
|
||||
qWarning() << tr("Cannot get graph at ") << RzAddressString(address);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -4566,7 +4688,7 @@ char *CutterCore::getTextualGraphAt(RzCoreGraphType type, RzCoreGraphFormat form
|
||||
rz_graph_free(graph);
|
||||
|
||||
if (!string) {
|
||||
qWarning() << "Failed to generate graph";
|
||||
qWarning() << tr("Failed to generate graph");
|
||||
}
|
||||
|
||||
return string;
|
||||
@ -4584,9 +4706,15 @@ void CutterCore::writeGraphvizGraphToFile(QString path, QString format, RzCoreGr
|
||||
|
||||
if (!rz_core_graph_write(core, address, type, filepath)) {
|
||||
if (address == RVA_INVALID) {
|
||||
qWarning() << "Cannot get global graph";
|
||||
qWarning() << tr("Cannot get global graph");
|
||||
} else {
|
||||
qWarning() << "Cannot get graph at " << RzAddressString(address);
|
||||
qWarning() << tr("Cannot get graph at ") << RzAddressString(address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CutterCore::rebaseBin(RVA base_address)
|
||||
{
|
||||
CORE_LOCK();
|
||||
return rz_core_bin_rebase(core, base_address);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "core/CutterCommon.h"
|
||||
#include "core/CutterDescriptions.h"
|
||||
#include "core/CutterJson.h"
|
||||
#include "core/Basefind.h"
|
||||
#include "common/BasicInstructionHighlighter.h"
|
||||
|
||||
#include <QMap>
|
||||
@ -69,6 +70,7 @@ class CUTTER_EXPORT CutterCore : public QObject
|
||||
|
||||
friend class RzCoreLocked;
|
||||
friend class RizinTask;
|
||||
friend class Basefind;
|
||||
|
||||
public:
|
||||
explicit CutterCore(QObject *parent = nullptr);
|
||||
@ -172,6 +174,8 @@ public:
|
||||
return returner;
|
||||
}
|
||||
|
||||
enum class SeekHistoryType { New, Undo, Redo };
|
||||
|
||||
CutterJson cmdj(const char *str);
|
||||
CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); }
|
||||
QString cmdTask(const QString &str);
|
||||
@ -235,6 +239,14 @@ public:
|
||||
QString nearestFlag(RVA offset, RVA *flagOffsetOut);
|
||||
void triggerFlagsChanged();
|
||||
|
||||
/* Global Variables */
|
||||
void addGlobalVariable(RVA offset, QString name, QString typ);
|
||||
void delGlobalVariable(QString name);
|
||||
void delGlobalVariable(RVA offset);
|
||||
void modifyGlobalVariable(RVA offset, QString name, QString typ);
|
||||
QString getGlobalVariableType(QString name);
|
||||
QString getGlobalVariableType(RVA offset);
|
||||
|
||||
/* Edition functions */
|
||||
PRzAnalysisBytes getRzAnalysisBytesSingle(RVA addr);
|
||||
QString getInstructionBytes(RVA addr);
|
||||
@ -324,7 +336,7 @@ public:
|
||||
void seekSilent(QString thing) { seekSilent(math(thing)); }
|
||||
void seekPrev();
|
||||
void seekNext();
|
||||
void updateSeek();
|
||||
void updateSeek(SeekHistoryType type = SeekHistoryType::New);
|
||||
/**
|
||||
* @brief Raise a memory widget showing current offset, prefer last active
|
||||
* memory widget.
|
||||
@ -554,6 +566,8 @@ public:
|
||||
void setGraphEmpty(bool empty);
|
||||
bool isGraphEmpty();
|
||||
|
||||
bool rebaseBin(RVA base_address);
|
||||
|
||||
void getRegs();
|
||||
QList<QString> regs;
|
||||
void setSettings();
|
||||
@ -578,6 +592,7 @@ public:
|
||||
QList<ExportDescription> getAllExports();
|
||||
QList<SymbolDescription> getAllSymbols();
|
||||
QList<HeaderDescription> getAllHeaders();
|
||||
QList<GlobalDescription> getAllGlobals();
|
||||
QList<FlirtDescription> getSignaturesDB();
|
||||
QList<CommentDescription> getAllComments(const QString &filterType);
|
||||
QList<RelocDescription> getAllRelocs();
|
||||
@ -744,6 +759,7 @@ signals:
|
||||
|
||||
void functionRenamed(const RVA offset, const QString &new_name);
|
||||
void varsChanged();
|
||||
void globalVarsChanged();
|
||||
void functionsChanged();
|
||||
void flagsChanged();
|
||||
void commentsChanged(RVA addr);
|
||||
@ -794,8 +810,9 @@ signals:
|
||||
/**
|
||||
* @brief seekChanged is emitted each time Rizin's seek value is modified
|
||||
* @param offset
|
||||
* @param historyType
|
||||
*/
|
||||
void seekChanged(RVA offset);
|
||||
void seekChanged(RVA offset, SeekHistoryType type = SeekHistoryType::New);
|
||||
|
||||
void toggleDebugView();
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
# undef max
|
||||
#endif // Q_OS_WIN
|
||||
|
||||
|
||||
// Global information for Cutter
|
||||
#define APPNAME "Cutter"
|
||||
|
||||
|
@ -239,7 +239,6 @@ struct BinClassDescription
|
||||
QString name;
|
||||
RVA addr = RVA_INVALID;
|
||||
RVA vtableAddr = RVA_INVALID;
|
||||
ut64 index = 0;
|
||||
QList<BinClassBaseClassDescription> baseClasses;
|
||||
QList<BinClassMethodDescription> methods;
|
||||
QList<BinClassFieldDescription> fields;
|
||||
@ -358,6 +357,14 @@ struct VariableDescription
|
||||
RzAnalysisVarStorageType storageType;
|
||||
QString name;
|
||||
QString type;
|
||||
QString value;
|
||||
};
|
||||
|
||||
struct GlobalDescription
|
||||
{
|
||||
RVA addr;
|
||||
QString type;
|
||||
QString name;
|
||||
};
|
||||
|
||||
struct RegisterRefValueDescription
|
||||
@ -386,6 +393,18 @@ struct Arena
|
||||
ut64 max_system_mem;
|
||||
};
|
||||
|
||||
struct BasefindCoreStatusDescription
|
||||
{
|
||||
size_t index;
|
||||
ut32 percentage;
|
||||
};
|
||||
|
||||
struct BasefindResultDescription
|
||||
{
|
||||
RVA candidate;
|
||||
ut32 score;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(FunctionDescription)
|
||||
Q_DECLARE_METATYPE(ImportDescription)
|
||||
Q_DECLARE_METATYPE(ExportDescription)
|
||||
@ -395,6 +414,7 @@ Q_DECLARE_METATYPE(RelocDescription)
|
||||
Q_DECLARE_METATYPE(StringDescription)
|
||||
Q_DECLARE_METATYPE(FlagspaceDescription)
|
||||
Q_DECLARE_METATYPE(FlagDescription)
|
||||
Q_DECLARE_METATYPE(GlobalDescription)
|
||||
Q_DECLARE_METATYPE(XrefDescription)
|
||||
Q_DECLARE_METATYPE(EntrypointDescription)
|
||||
Q_DECLARE_METATYPE(RzBinPluginDescription)
|
||||
@ -424,5 +444,7 @@ Q_DECLARE_METATYPE(BreakpointDescription::PositionType)
|
||||
Q_DECLARE_METATYPE(ProcessDescription)
|
||||
Q_DECLARE_METATYPE(RefDescription)
|
||||
Q_DECLARE_METATYPE(VariableDescription)
|
||||
Q_DECLARE_METATYPE(BasefindCoreStatusDescription)
|
||||
Q_DECLARE_METATYPE(BasefindResultDescription)
|
||||
|
||||
#endif // DESCRIPTIONS_H
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "widgets/DisassemblerGraphView.h"
|
||||
#include "widgets/GraphView.h"
|
||||
#include "widgets/GraphWidget.h"
|
||||
#include "widgets/GlobalsWidget.h"
|
||||
#include "widgets/OverviewWidget.h"
|
||||
#include "widgets/OverviewView.h"
|
||||
#include "widgets/FunctionsWidget.h"
|
||||
@ -115,6 +116,9 @@
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
|
||||
// Tools
|
||||
#include "tools/basefind/BaseFindDialog.h"
|
||||
|
||||
#define PROJECT_FILE_FILTER tr("Rizin Project (*.rzdb)")
|
||||
|
||||
template<class T>
|
||||
@ -268,7 +272,7 @@ void MainWindow::initUI()
|
||||
readSettings();
|
||||
|
||||
// Display tooltip for the Analyze Program action
|
||||
ui->actionAnalyze->setToolTip("Analyze the program using Rizin's \"aaa\" command");
|
||||
ui->actionAnalyze->setToolTip(tr("Analyze the program using Rizin's \"aaa\" command"));
|
||||
ui->menuFile->setToolTipsVisible(true);
|
||||
}
|
||||
|
||||
@ -398,6 +402,7 @@ void MainWindow::initDocks()
|
||||
sectionsDock = new SectionsWidget(this),
|
||||
segmentsDock = new SegmentsWidget(this),
|
||||
symbolsDock = new SymbolsWidget(this),
|
||||
globalsDock = new GlobalsWidget(this),
|
||||
vTablesDock = new VTablesWidget(this),
|
||||
flirtDock = new FlirtWidget(this),
|
||||
rzGraphDock = new RizinGraphWidget(this),
|
||||
@ -902,6 +907,7 @@ void MainWindow::restoreDocks()
|
||||
tabifyDockWidget(dashboardDock, headersDock);
|
||||
tabifyDockWidget(dashboardDock, flirtDock);
|
||||
tabifyDockWidget(dashboardDock, symbolsDock);
|
||||
tabifyDockWidget(dashboardDock, globalsDock);
|
||||
tabifyDockWidget(dashboardDock, classesDock);
|
||||
tabifyDockWidget(dashboardDock, resourcesDock);
|
||||
tabifyDockWidget(dashboardDock, vTablesDock);
|
||||
@ -1637,6 +1643,12 @@ void MainWindow::on_actionTabs_triggered()
|
||||
setTabLocation();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionBaseFind_triggered()
|
||||
{
|
||||
auto dialog = new BaseFindDialog(this);
|
||||
dialog->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAbout_triggered()
|
||||
{
|
||||
AboutDialog *a = new AboutDialog(this);
|
||||
@ -1759,7 +1771,7 @@ void MainWindow::on_actionExport_as_code_triggered()
|
||||
|
||||
QFile file(dialog.selectedFiles()[0]);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
qWarning() << "Can't open file";
|
||||
qWarning() << tr("Can't open file");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1774,8 +1786,6 @@ void MainWindow::on_actionExport_as_code_triggered()
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
auto string = fromOwned(
|
||||
dialog.selectedNameFilter() != instructionsInComments
|
||||
? rz_lang_byte_array(buffer.data(), size, typMap[dialog.selectedNameFilter()])
|
||||
|
@ -26,6 +26,7 @@ class FunctionsWidget;
|
||||
class ImportsWidget;
|
||||
class ExportsWidget;
|
||||
class SymbolsWidget;
|
||||
class GlobalsWidget;
|
||||
class RelocsWidget;
|
||||
class CommentsWidget;
|
||||
class StringsWidget;
|
||||
@ -152,6 +153,7 @@ public slots:
|
||||
|
||||
void toggleOverview(bool visibility, GraphWidget *targetGraph);
|
||||
private slots:
|
||||
void on_actionBaseFind_triggered();
|
||||
void on_actionAbout_triggered();
|
||||
void on_actionIssue_triggered();
|
||||
void documentationClicked();
|
||||
@ -239,6 +241,7 @@ private:
|
||||
TypesWidget *typesDock = nullptr;
|
||||
SearchWidget *searchDock = nullptr;
|
||||
SymbolsWidget *symbolsDock = nullptr;
|
||||
GlobalsWidget *globalsDock = nullptr;
|
||||
RelocsWidget *relocsDock = nullptr;
|
||||
CommentsWidget *commentsDock = nullptr;
|
||||
StringsWidget *stringsDock = nullptr;
|
||||
|
@ -128,6 +128,12 @@
|
||||
<addaction name="actionSaveLayout"/>
|
||||
<addaction name="menuLayouts"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuTools">
|
||||
<property name="title">
|
||||
<string>Tools</string>
|
||||
</property>
|
||||
<addaction name="actionBaseFind"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
@ -184,6 +190,7 @@
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menuWindows"/>
|
||||
<addaction name="menuDebug"/>
|
||||
<addaction name="menuTools"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="mainToolBar">
|
||||
@ -233,6 +240,11 @@
|
||||
<string>Zen mode</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionBaseFind">
|
||||
<property name="text">
|
||||
<string>BaseFind</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout">
|
||||
<property name="text">
|
||||
<string>About</string>
|
||||
|
@ -1,2 +1 @@
|
||||
#include "RizinCpp.h"
|
||||
|
||||
|
@ -46,8 +46,7 @@ static inline auto fromOwned(RZ_OWN RzPVector *data)
|
||||
return { data, {} };
|
||||
}
|
||||
|
||||
static inline auto fromOwned(RZ_OWN RzList *data)
|
||||
-> UniquePtrCP<decltype(data), &rz_list_free>
|
||||
static inline auto fromOwned(RZ_OWN RzList *data) -> UniquePtrCP<decltype(data), &rz_list_free>
|
||||
{
|
||||
return { data, {} };
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "CommentsDialog.h"
|
||||
#include "ui_CommentsDialog.h"
|
||||
|
||||
#include <QErrorMessage>
|
||||
|
||||
#include "core/Cutter.h"
|
||||
|
||||
CommentsDialog::CommentsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::CommentsDialog)
|
||||
|
@ -74,7 +74,7 @@ private:
|
||||
QString fixedClass;
|
||||
|
||||
bool inputValid();
|
||||
static QString convertRealNameToName(const QString& realName);
|
||||
static QString convertRealNameToName(const QString &realName);
|
||||
};
|
||||
|
||||
#endif // EDITMETHODDIALOG_H
|
||||
|
@ -49,8 +49,7 @@ void GlibcHeapBinsDialog::setChainInfo(int index)
|
||||
RzHeapChunkListItem *item;
|
||||
RzList *chunks = binsModel->getChunks(index);
|
||||
QString chainInfo;
|
||||
CutterRzListForeach(chunks, iter, RzHeapChunkListItem, item)
|
||||
{
|
||||
CutterRzListForeach (chunks, iter, RzHeapChunkListItem, item) {
|
||||
chainInfo += " → " + RzAddressString(item->addr);
|
||||
}
|
||||
|
||||
|
71
src/dialogs/GlobalVariableDialog.cpp
Normal file
71
src/dialogs/GlobalVariableDialog.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "GlobalVariableDialog.h"
|
||||
#include "ui_GlobalVariableDialog.h"
|
||||
|
||||
#include <QIntValidator>
|
||||
#include "core/Cutter.h"
|
||||
|
||||
GlobalVariableDialog::GlobalVariableDialog(RVA offset, QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::GlobalVariableDialog),
|
||||
offset(offset),
|
||||
globalVariableName(""),
|
||||
globalVariableOffset(RVA_INVALID)
|
||||
{
|
||||
// Setup UI
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
RzAnalysisVarGlobal *globalVariable =
|
||||
rz_analysis_var_global_get_byaddr_at(Core()->core()->analysis, offset);
|
||||
if (globalVariable) {
|
||||
globalVariableName = QString(globalVariable->name);
|
||||
globalVariableOffset = globalVariable->addr;
|
||||
}
|
||||
|
||||
if (globalVariable) {
|
||||
ui->nameEdit->setText(globalVariable->name);
|
||||
QString globalVarType = Core()->getGlobalVariableType(globalVariable->name);
|
||||
ui->typeEdit->setText(globalVarType);
|
||||
ui->labelAction->setText(tr("Edit global variable at %1").arg(RzAddressString(offset)));
|
||||
} else {
|
||||
ui->labelAction->setText(tr("Add global variable at %1").arg(RzAddressString(offset)));
|
||||
}
|
||||
|
||||
// Connect slots
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
|
||||
&GlobalVariableDialog::buttonBoxAccepted);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this,
|
||||
&GlobalVariableDialog::buttonBoxRejected);
|
||||
}
|
||||
|
||||
GlobalVariableDialog::~GlobalVariableDialog() {}
|
||||
|
||||
void GlobalVariableDialog::buttonBoxAccepted()
|
||||
{
|
||||
QString name = ui->nameEdit->text();
|
||||
QString typ = ui->typeEdit->text();
|
||||
|
||||
if (name.isEmpty()) {
|
||||
if (globalVariableOffset != RVA_INVALID) {
|
||||
// Empty name and global variable exists -> delete the global variable
|
||||
Core()->delGlobalVariable(globalVariableOffset);
|
||||
} else {
|
||||
// GlobalVariable was not existing and we gave an empty name, do nothing
|
||||
}
|
||||
} else {
|
||||
if (globalVariableOffset != RVA_INVALID) {
|
||||
// Name provided and global variable exists -> rename the global variable
|
||||
Core()->modifyGlobalVariable(globalVariableOffset, name, typ);
|
||||
} else {
|
||||
// Name provided and global variable does not exist -> create the global variable
|
||||
Core()->addGlobalVariable(offset, name, typ);
|
||||
}
|
||||
}
|
||||
close();
|
||||
this->setResult(QDialog::Accepted);
|
||||
}
|
||||
|
||||
void GlobalVariableDialog::buttonBoxRejected()
|
||||
{
|
||||
close();
|
||||
this->setResult(QDialog::Rejected);
|
||||
}
|
32
src/dialogs/GlobalVariableDialog.h
Normal file
32
src/dialogs/GlobalVariableDialog.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef GLOBALVARIABLEDIALOG_H
|
||||
#define GLOBALVARIABLEDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <memory>
|
||||
#include "core/CutterCommon.h"
|
||||
|
||||
namespace Ui {
|
||||
class GlobalVariableDialog;
|
||||
}
|
||||
|
||||
class GlobalVariableDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GlobalVariableDialog(RVA offset, QWidget *parent = nullptr);
|
||||
~GlobalVariableDialog();
|
||||
|
||||
private slots:
|
||||
void buttonBoxAccepted();
|
||||
void buttonBoxRejected();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::GlobalVariableDialog> ui;
|
||||
RVA offset;
|
||||
QString globalVariableName;
|
||||
RVA globalVariableOffset;
|
||||
QString typ;
|
||||
};
|
||||
|
||||
#endif // GLOBALVARIABLEDIALOG_H
|
100
src/dialogs/GlobalVariableDialog.ui
Normal file
100
src/dialogs/GlobalVariableDialog.ui
Normal file
@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GlobalVariableDialog</class>
|
||||
<widget class="QDialog" name="GlobalVariableDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>452</width>
|
||||
<height>121</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Add Global Variable</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelAction">
|
||||
<property name="text">
|
||||
<string>Add global variable at</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="horizontalSpacing">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelName">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="nameEdit">
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="typeEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>int</string>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelType">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "core/Cutter.h"
|
||||
#include "common/AnalysisTask.h"
|
||||
#include "CutterApplication.h"
|
||||
|
||||
InitialOptionsDialog::InitialOptionsDialog(MainWindow *main)
|
||||
: QDialog(nullptr), // parent must not be main
|
||||
@ -179,9 +180,56 @@ void InitialOptionsDialog::loadOptions(const InitialOptions &options)
|
||||
ui->entry_loadOffset->setText(RzAddressString(options.binLoadAddr));
|
||||
}
|
||||
|
||||
if (options.mapAddr != RVA_INVALID) {
|
||||
ui->entry_mapOffset->setText(RzAddressString(options.mapAddr));
|
||||
}
|
||||
|
||||
ui->vaCheckBox->setChecked(options.useVA);
|
||||
ui->writeCheckBox->setChecked(options.writeEnabled);
|
||||
|
||||
// TODO: all other options should also be applied to the ui
|
||||
if (!options.arch.isNull() && !options.arch.isEmpty()) {
|
||||
ui->archComboBox->setCurrentText(options.arch);
|
||||
}
|
||||
|
||||
if (!options.cpu.isNull() && !options.cpu.isEmpty()) {
|
||||
ui->cpuComboBox->setCurrentText(options.cpu);
|
||||
}
|
||||
|
||||
if (options.bits > 0) {
|
||||
ui->bitsComboBox->setCurrentText(QString::asprintf("%d", options.bits));
|
||||
}
|
||||
|
||||
if (!options.os.isNull() && !options.os.isEmpty()) {
|
||||
ui->kernelComboBox->setCurrentText(options.os);
|
||||
}
|
||||
|
||||
if (!options.forceBinPlugin.isNull() && !options.forceBinPlugin.isEmpty()) {
|
||||
ui->formatComboBox->setCurrentText(options.forceBinPlugin);
|
||||
}
|
||||
|
||||
if (!options.loadBinInfo) {
|
||||
ui->binCheckBox->setChecked(false);
|
||||
}
|
||||
|
||||
ui->writeCheckBox->setChecked(options.writeEnabled);
|
||||
|
||||
switch (options.endian) {
|
||||
case InitialOptions::Endianness::Little:
|
||||
ui->endiannessComboBox->setCurrentIndex(1);
|
||||
break;
|
||||
case InitialOptions::Endianness::Big:
|
||||
ui->endiannessComboBox->setCurrentIndex(2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ui->demangleCheckBox->setChecked(options.demangle);
|
||||
|
||||
if (!options.pdbFile.isNull() && !options.pdbFile.isEmpty()) {
|
||||
ui->pdbCheckBox->setChecked(true);
|
||||
ui->pdbLineEdit->setText(options.pdbFile);
|
||||
}
|
||||
}
|
||||
|
||||
void InitialOptionsDialog::setTooltipWithConfigHelp(QWidget *w, const char *config)
|
||||
@ -246,7 +294,7 @@ QList<CommandDescription> InitialOptionsDialog::getSelectedAdvancedAnalCmds() co
|
||||
return advanced;
|
||||
}
|
||||
|
||||
void InitialOptionsDialog::setupAndStartAnalysis(/*int level, QList<QString> advanced*/)
|
||||
void InitialOptionsDialog::setupAndStartAnalysis()
|
||||
{
|
||||
InitialOptions options;
|
||||
|
||||
@ -322,6 +370,8 @@ void InitialOptionsDialog::setupAndStartAnalysis(/*int level, QList<QString> adv
|
||||
Core()->getAsyncTaskManager()->start(analysisTaskPtr);
|
||||
|
||||
done(0);
|
||||
|
||||
static_cast<CutterApplication *>(qApp)->setInitialOptions(options);
|
||||
}
|
||||
|
||||
void InitialOptionsDialog::on_okButton_clicked()
|
||||
|
@ -20,7 +20,7 @@ public:
|
||||
explicit InitialOptionsDialog(MainWindow *main);
|
||||
~InitialOptionsDialog();
|
||||
|
||||
void setupAndStartAnalysis(/*int level, QList<QString> advanced*/);
|
||||
void setupAndStartAnalysis();
|
||||
|
||||
private slots:
|
||||
void on_okButton_clicked();
|
||||
|
@ -287,7 +287,8 @@ void NewFileDialog::fillIOPluginsList()
|
||||
{
|
||||
ui->ioPlugin->clear();
|
||||
ui->ioPlugin->addItem("file://");
|
||||
ui->ioPlugin->setItemData(0, tr("Open a file without additional options/settings."), Qt::ToolTipRole);
|
||||
ui->ioPlugin->setItemData(0, tr("Open a file without additional options/settings."),
|
||||
Qt::ToolTipRole);
|
||||
|
||||
int index = 1;
|
||||
QList<RzIOPluginDescription> ioPlugins = Core()->getRIOPluginDescriptions();
|
||||
|
@ -70,8 +70,10 @@ void TypesInteractionDialog::done(int r)
|
||||
ui->plainTextEdit->toPlainText().toUtf8().constData());
|
||||
} else {
|
||||
char *error_msg = NULL;
|
||||
success = rz_type_parse_string_stateless(core->analysis->typedb->parser,
|
||||
ui->plainTextEdit->toPlainText().toUtf8().constData(), &error_msg) == 0;
|
||||
success = rz_type_parse_string_stateless(
|
||||
core->analysis->typedb->parser,
|
||||
ui->plainTextEdit->toPlainText().toUtf8().constData(), &error_msg)
|
||||
== 0;
|
||||
if (error_msg) {
|
||||
RZ_LOG_ERROR("%s\n", error_msg);
|
||||
rz_mem_free(error_msg);
|
||||
|
@ -65,6 +65,12 @@ AsmOptionsWidget::AsmOptionsWidget(PreferencesDialog *dialog)
|
||||
&AsmOptionsWidget::relOffCheckBoxToggled);
|
||||
connect(Core(), &CutterCore::asmOptionsChanged, this,
|
||||
&AsmOptionsWidget::updateAsmOptionsFromVars);
|
||||
|
||||
connect(ui->varTooltipsCheckBox, &QCheckBox::toggled, [this](bool checked) {
|
||||
Config()->setShowVarTooltips(checked);
|
||||
triggerAsmOptionsChanged();
|
||||
});
|
||||
|
||||
updateAsmOptionsFromVars();
|
||||
}
|
||||
|
||||
@ -138,6 +144,8 @@ void AsmOptionsWidget::updateAsmOptionsFromVars()
|
||||
ui->previewCheckBox->setChecked(Config()->getPreviewValue());
|
||||
ui->previewCheckBox->blockSignals(false);
|
||||
|
||||
qhelpers::setCheckedWithoutSignals(ui->varTooltipsCheckBox, Config()->getShowVarTooltips());
|
||||
|
||||
QList<ConfigCheckbox>::iterator confCheckbox;
|
||||
|
||||
// Set the value for each checkbox in "checkboxes" as it exists in the configuration
|
||||
|
@ -48,8 +48,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>582</width>
|
||||
<height>766</height>
|
||||
<width>686</width>
|
||||
<height>886</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
@ -65,51 +65,114 @@
|
||||
<string>Disassembly</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="12" column="2">
|
||||
<widget class="QSpinBox" name="nbytesSpinBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="2">
|
||||
<widget class="QSpinBox" name="asmTabsOffSpinBox">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="lbytesCheckBox">
|
||||
<item row="5" column="2">
|
||||
<widget class="QComboBox" name="caseComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Align bytes to the left (asm.lbytes)</string>
|
||||
<string>Lowercase</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Uppercase (asm.ucase)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Capitalize (asm.capitalize)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="previewCheckBox">
|
||||
<item row="17" column="1">
|
||||
<widget class="QLabel" name="asmTabsLabel">
|
||||
<property name="text">
|
||||
<string>Show preview when hovering:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="syntaxLabel">
|
||||
<property name="text">
|
||||
<string>Syntax (asm.syntax):</string>
|
||||
<string>Tabs in assembly (asm.tabs):</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
<widget class="QCheckBox" name="relOffFlagsCheckBox">
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="bytesCheckBox">
|
||||
<property name="text">
|
||||
<string>Flags (asm.reloff.flags)</string>
|
||||
<string>Display the bytes of each instruction (asm.bytes)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Show Disassembly as:</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QCheckBox" name="realnameCheckBox">
|
||||
<property name="text">
|
||||
<string>Display flags' real name (asm.flags.real)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="relOffsetLabel">
|
||||
<property name="text">
|
||||
<string>Show offsets relative to:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="relOffsetCheckBox">
|
||||
<property name="text">
|
||||
<string>Functions (asm.reloff)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="18" column="1">
|
||||
<widget class="QLabel" name="asmTabsOffLabel">
|
||||
<property name="text">
|
||||
<string>The number of tabulate spaces after the offset (asm.tabs.off):</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="19" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="indentCheckBox">
|
||||
<property name="text">
|
||||
<string>Indent disassembly based on reflines depth (asm.indent)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="offsetCheckBox">
|
||||
<property name="text">
|
||||
<string>Show offsets (asm.offset)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -132,23 +195,47 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QCheckBox" name="offsetCheckBox">
|
||||
<item row="14" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="bblineCheckBox">
|
||||
<property name="text">
|
||||
<string>Show offsets (asm.offset)</string>
|
||||
<string>Show empty line after every basic block (asm.bb.line)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<widget class="QLabel" name="asmTabsOffLabel">
|
||||
<item row="15" column="1">
|
||||
<widget class="QCheckBox" name="previewCheckBox">
|
||||
<property name="text">
|
||||
<string>The number of tabulate spaces after the offset (asm.tabs.off):</string>
|
||||
<string>Show preview when hovering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="syntaxLabel">
|
||||
<property name="text">
|
||||
<string>Syntax (asm.syntax):</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="21" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="bytespaceCheckBox">
|
||||
<property name="text">
|
||||
<string>Separate bytes with whitespace (asm.bytes.space)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="2">
|
||||
<widget class="QSpinBox" name="asmTabsOffSpinBox">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QLabel" name="nbytesLabel">
|
||||
<property name="enabled">
|
||||
@ -163,13 +250,13 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="20" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="bytespaceCheckBox">
|
||||
<widget class="QCheckBox" name="lbytesCheckBox">
|
||||
<property name="text">
|
||||
<string>Separate bytes with whitespace (asm.bytes.space)</string>
|
||||
<string>Align bytes to the left (asm.lbytes)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="2">
|
||||
<item row="17" column="2">
|
||||
<widget class="QSpinBox" name="asmTabsSpinBox">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
@ -179,107 +266,27 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="bytesCheckBox">
|
||||
<item row="8" column="2">
|
||||
<widget class="QCheckBox" name="relOffFlagsCheckBox">
|
||||
<property name="text">
|
||||
<string>Display the bytes of each instruction (asm.bytes)</string>
|
||||
<string>Flags (asm.reloff.flags)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QComboBox" name="caseComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Lowercase</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Uppercase (asm.ucase)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Capitalize (asm.capitalize)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="bblineCheckBox">
|
||||
<property name="text">
|
||||
<string>Show empty line after every basic block (asm.bb.line)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="relOffsetLabel">
|
||||
<property name="text">
|
||||
<string>Show offsets relative to:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="relOffsetCheckBox">
|
||||
<property name="text">
|
||||
<string>Functions (asm.reloff)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QComboBox" name="syntaxComboBox"/>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Show Disassembly as:</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
<item row="12" column="2">
|
||||
<widget class="QSpinBox" name="nbytesSpinBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<widget class="QLabel" name="asmTabsLabel">
|
||||
<widget class="QCheckBox" name="varTooltipsCheckBox">
|
||||
<property name="text">
|
||||
<string>Tabs in assembly (asm.tabs):</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="18" column="1" colspan="2">
|
||||
<widget class="QCheckBox" name="indentCheckBox">
|
||||
<property name="text">
|
||||
<string>Indent disassembly based on reflines depth (asm.indent)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QCheckBox" name="realnameCheckBox">
|
||||
<property name="text">
|
||||
<string>Display flags' real name (asm.flags.real)</string>
|
||||
<string>Show known variable values when hovering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -415,8 +422,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>454</width>
|
||||
<height>286</height>
|
||||
<width>518</width>
|
||||
<height>326</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
|
@ -112,7 +112,8 @@ void AddressableItemContextMenu::aboutToShowSlot()
|
||||
void AddressableItemContextMenu::setHasTarget(bool hasTarget)
|
||||
{
|
||||
this->hasTarget = hasTarget;
|
||||
for (const auto &action : this->actions()) {
|
||||
action->setEnabled(hasTarget);
|
||||
}
|
||||
actionShowInMenu->setEnabled(hasTarget);
|
||||
actionCopyAddress->setEnabled(hasTarget);
|
||||
actionShowXrefs->setEnabled(hasTarget);
|
||||
actionAddcomment->setEnabled(hasTarget);
|
||||
}
|
||||
|
@ -387,7 +387,7 @@ void DecompilerContextMenu::actionCopyReferenceAddressTriggered()
|
||||
|
||||
void DecompilerContextMenu::actionAddCommentTriggered()
|
||||
{
|
||||
CommentsDialog::addOrEditComment(this->firstOffsetInLine, this);
|
||||
CommentsDialog::addOrEditComment(this->firstOffsetInLine, parentForDialog());
|
||||
}
|
||||
|
||||
void DecompilerContextMenu::actionDeleteCommentTriggered()
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "dialogs/EditInstructionDialog.h"
|
||||
#include "dialogs/CommentsDialog.h"
|
||||
#include "dialogs/FlagDialog.h"
|
||||
#include "dialogs/GlobalVariableDialog.h"
|
||||
#include "dialogs/XrefsDialog.h"
|
||||
#include "dialogs/EditVariablesDialog.h"
|
||||
#include "dialogs/SetToDataDialog.h"
|
||||
@ -34,6 +35,7 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
|
||||
actionAnalyzeFunction(this),
|
||||
actionEditFunction(this),
|
||||
actionRename(this),
|
||||
actionGlobalVar(this),
|
||||
actionSetFunctionVarTypes(this),
|
||||
actionXRefs(this),
|
||||
actionXRefsForVariables(this),
|
||||
@ -83,10 +85,6 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
|
||||
getCommentSequence());
|
||||
addAction(&actionAddComment);
|
||||
|
||||
initAction(&actionRename, tr("Rename or add flag"), SLOT(on_actionRename_triggered()),
|
||||
getRenameSequence());
|
||||
addAction(&actionRename);
|
||||
|
||||
initAction(&actionSetFunctionVarTypes, tr("Re-type Local Variables"),
|
||||
SLOT(on_actionSetFunctionVarTypes_triggered()), getRetypeSequence());
|
||||
addAction(&actionSetFunctionVarTypes);
|
||||
@ -112,6 +110,8 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
|
||||
|
||||
addSeparator();
|
||||
|
||||
addAddAtMenu();
|
||||
|
||||
addSetBaseMenu();
|
||||
|
||||
addSetBitsMenu();
|
||||
@ -161,6 +161,24 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main
|
||||
|
||||
DisassemblyContextMenu::~DisassemblyContextMenu() {}
|
||||
|
||||
QWidget *DisassemblyContextMenu::parentForDialog()
|
||||
{
|
||||
return parentWidget();
|
||||
}
|
||||
|
||||
void DisassemblyContextMenu::addAddAtMenu()
|
||||
{
|
||||
setAsMenu = addMenu(tr("Add at..."));
|
||||
|
||||
initAction(&actionRename, tr("Rename or add flag"), SLOT(on_actionRename_triggered()),
|
||||
getRenameSequence());
|
||||
setAsMenu->addAction(&actionRename);
|
||||
|
||||
initAction(&actionGlobalVar, tr("Modify or add global variable"),
|
||||
SLOT(on_actionGlobalVar_triggered()), getGlobalVarSequence());
|
||||
setAsMenu->addAction(&actionGlobalVar);
|
||||
}
|
||||
|
||||
void DisassemblyContextMenu::addSetBaseMenu()
|
||||
{
|
||||
setBaseMenu = addMenu(tr("Set base of immediate value to.."));
|
||||
@ -314,8 +332,7 @@ void DisassemblyContextMenu::addDebugMenu()
|
||||
QVector<DisassemblyContextMenu::ThingUsedHere> DisassemblyContextMenu::getThingUsedHere(RVA offset)
|
||||
{
|
||||
RzCoreLocked core(Core());
|
||||
auto p = fromOwned(
|
||||
rz_core_analysis_name(core, offset), rz_core_analysis_name_free);
|
||||
auto p = fromOwned(rz_core_analysis_name(core, offset), rz_core_analysis_name_free);
|
||||
if (!p) {
|
||||
return {};
|
||||
}
|
||||
@ -475,7 +492,12 @@ void DisassemblyContextMenu::setupRenaming()
|
||||
|
||||
// Now, build the renaming menu and show it
|
||||
buildRenameMenu(tuh);
|
||||
|
||||
auto name = RzAddressString(tuh->offset);
|
||||
actionGlobalVar.setText(tr("Add or change global variable at %1 (used here)").arg(name));
|
||||
|
||||
actionRename.setVisible(true);
|
||||
actionGlobalVar.setVisible(true);
|
||||
}
|
||||
|
||||
void DisassemblyContextMenu::aboutToShowSlot()
|
||||
@ -651,6 +673,11 @@ QKeySequence DisassemblyContextMenu::getRenameSequence() const
|
||||
return { Qt::Key_N };
|
||||
}
|
||||
|
||||
QKeySequence DisassemblyContextMenu::getGlobalVarSequence() const
|
||||
{
|
||||
return { Qt::Key_G };
|
||||
}
|
||||
|
||||
QKeySequence DisassemblyContextMenu::getRetypeSequence() const
|
||||
{
|
||||
return { Qt::Key_Y };
|
||||
@ -691,7 +718,7 @@ void DisassemblyContextMenu::on_actionEditInstruction_triggered()
|
||||
if (!ioModesController.prepareForWriting()) {
|
||||
return;
|
||||
}
|
||||
EditInstructionDialog e(EDIT_TEXT, this);
|
||||
EditInstructionDialog e(EDIT_TEXT, parentForDialog());
|
||||
e.setWindowTitle(tr("Edit Instruction at %1").arg(RzAddressString(offset)));
|
||||
|
||||
QString oldInstructionOpcode = Core()->getInstructionOpcode(offset);
|
||||
@ -741,7 +768,7 @@ void DisassemblyContextMenu::on_actionEditBytes_triggered()
|
||||
if (!ioModesController.prepareForWriting()) {
|
||||
return;
|
||||
}
|
||||
EditInstructionDialog e(EDIT_BYTES, this);
|
||||
EditInstructionDialog e(EDIT_BYTES, parentForDialog());
|
||||
e.setWindowTitle(tr("Edit Bytes at %1").arg(RzAddressString(offset)));
|
||||
|
||||
QString oldBytes = Core()->getInstructionBytes(offset);
|
||||
@ -775,9 +802,9 @@ void DisassemblyContextMenu::on_actionAdvancedBreakpoint_triggered()
|
||||
{
|
||||
int index = Core()->breakpointIndexAt(offset);
|
||||
if (index >= 0) {
|
||||
BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(offset), this);
|
||||
BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(offset), parentForDialog());
|
||||
} else {
|
||||
BreakpointsDialog::createNewBreakpoint(offset, this);
|
||||
BreakpointsDialog::createNewBreakpoint(offset, parentForDialog());
|
||||
}
|
||||
}
|
||||
|
||||
@ -794,12 +821,11 @@ void DisassemblyContextMenu::on_actionSetPC_triggered()
|
||||
|
||||
void DisassemblyContextMenu::on_actionAddComment_triggered()
|
||||
{
|
||||
CommentsDialog::addOrEditComment(offset, this);
|
||||
CommentsDialog::addOrEditComment(offset, parentForDialog());
|
||||
}
|
||||
|
||||
void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered()
|
||||
{
|
||||
bool ok;
|
||||
RVA flagOffset;
|
||||
QString name = Core()->nearestFlag(offset, &flagOffset);
|
||||
if (name.isEmpty() || flagOffset != offset) {
|
||||
@ -812,12 +838,20 @@ void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered()
|
||||
}
|
||||
|
||||
// Create dialog
|
||||
QString functionName =
|
||||
QInputDialog::getText(this, tr("New function at %1").arg(RzAddressString(offset)),
|
||||
tr("Function name:"), QLineEdit::Normal, name, &ok);
|
||||
QInputDialog inputDialog(parentForDialog());
|
||||
inputDialog.resize(500, 100);
|
||||
inputDialog.setWindowTitle(tr("New function at %1").arg(RzAddressString(offset)));
|
||||
inputDialog.setLabelText(tr("Function name:"));
|
||||
inputDialog.setTextValue(name);
|
||||
inputDialog.setWindowFlags(Qt::Window | Qt::WindowMinimizeButtonHint);
|
||||
|
||||
// If user accepted
|
||||
if (ok && !functionName.isEmpty()) {
|
||||
if (inputDialog.exec() != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString functionName = inputDialog.textValue().trimmed();
|
||||
|
||||
if (!functionName.isEmpty()) {
|
||||
Core()->createFunctionAt(offset, functionName);
|
||||
}
|
||||
}
|
||||
@ -833,12 +867,12 @@ void DisassemblyContextMenu::on_actionRename_triggered()
|
||||
Core()->renameFunction(doRenameInfo.addr, newName);
|
||||
}
|
||||
} else if (doRenameAction == RENAME_FLAG || doRenameAction == RENAME_ADD_FLAG) {
|
||||
FlagDialog dialog(doRenameInfo.addr, this->mainWindow);
|
||||
FlagDialog dialog(doRenameInfo.addr, parentForDialog());
|
||||
ok = dialog.exec();
|
||||
} else if (doRenameAction == RENAME_LOCAL) {
|
||||
RzAnalysisFunction *fcn = Core()->functionIn(offset);
|
||||
if (fcn) {
|
||||
EditVariablesDialog dialog(fcn->addr, curHighlightedWord, this->mainWindow);
|
||||
EditVariablesDialog dialog(fcn->addr, curHighlightedWord, parentForDialog());
|
||||
if (!dialog.empty()) {
|
||||
// Don't show the dialog if there are no variables
|
||||
ok = dialog.exec();
|
||||
@ -857,6 +891,18 @@ void DisassemblyContextMenu::on_actionRename_triggered()
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyContextMenu::on_actionGlobalVar_triggered()
|
||||
{
|
||||
bool ok = false;
|
||||
GlobalVariableDialog dialog(doRenameInfo.addr, parentForDialog());
|
||||
ok = dialog.exec();
|
||||
|
||||
if (ok) {
|
||||
// Rebuild menu in case the user presses the rename shortcut directly before clicking
|
||||
setupRenaming();
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered()
|
||||
{
|
||||
RzAnalysisFunction *fcn = Core()->functionIn(offset);
|
||||
@ -867,7 +913,7 @@ void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered()
|
||||
return;
|
||||
}
|
||||
|
||||
EditVariablesDialog dialog(fcn->addr, curHighlightedWord, this->mainWindow);
|
||||
EditVariablesDialog dialog(fcn->addr, curHighlightedWord, parentForDialog());
|
||||
if (dialog.empty()) { // don't show the dialog if there are no variables
|
||||
return;
|
||||
}
|
||||
@ -892,7 +938,7 @@ void DisassemblyContextMenu::on_actionXRefsForVariables_triggered()
|
||||
|
||||
void DisassemblyContextMenu::on_actionDisplayOptions_triggered()
|
||||
{
|
||||
PreferencesDialog dialog(this->window());
|
||||
PreferencesDialog dialog(parentForDialog());
|
||||
dialog.showSection(PreferencesDialog::Section::Disassembly);
|
||||
dialog.exec();
|
||||
}
|
||||
@ -914,7 +960,7 @@ void DisassemblyContextMenu::on_actionSetAsStringRemove_triggered()
|
||||
|
||||
void DisassemblyContextMenu::on_actionSetAsStringAdvanced_triggered()
|
||||
{
|
||||
EditStringDialog dialog(parentWidget());
|
||||
EditStringDialog dialog(parentForDialog());
|
||||
const int predictedStrSize = Core()->getString(offset).size();
|
||||
dialog.setStringSizeValue(predictedStrSize);
|
||||
dialog.setStringStartAddress(offset);
|
||||
@ -964,7 +1010,7 @@ void DisassemblyContextMenu::on_actionSetToData_triggered()
|
||||
|
||||
void DisassemblyContextMenu::on_actionSetToDataEx_triggered()
|
||||
{
|
||||
SetToDataDialog dialog(offset, this->window());
|
||||
SetToDataDialog dialog(offset, parentForDialog());
|
||||
if (!dialog.exec()) {
|
||||
return;
|
||||
}
|
||||
@ -994,7 +1040,7 @@ void DisassemblyContextMenu::on_actionDeleteFunction_triggered()
|
||||
void DisassemblyContextMenu::on_actionEditFunction_triggered()
|
||||
{
|
||||
RzCore *core = Core()->core();
|
||||
EditFunctionDialog dialog(mainWindow);
|
||||
EditFunctionDialog dialog(parentForDialog());
|
||||
RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, offset, 0);
|
||||
|
||||
if (fcn) {
|
||||
|
@ -45,6 +45,7 @@ private slots:
|
||||
void on_actionAddComment_triggered();
|
||||
void on_actionAnalyzeFunction_triggered();
|
||||
void on_actionRename_triggered();
|
||||
void on_actionGlobalVar_triggered();
|
||||
void on_actionSetFunctionVarTypes_triggered();
|
||||
void on_actionXRefs_triggered();
|
||||
void on_actionXRefsForVariables_triggered();
|
||||
@ -78,6 +79,7 @@ private:
|
||||
QKeySequence getCopySequence() const;
|
||||
QKeySequence getCommentSequence() const;
|
||||
QKeySequence getCopyAddressSequence() const;
|
||||
QKeySequence getGlobalVarSequence() const;
|
||||
QKeySequence getSetToCodeSequence() const;
|
||||
QKeySequence getSetAsStringSequence() const;
|
||||
QKeySequence getSetAsStringAdvanced() const;
|
||||
@ -114,6 +116,7 @@ private:
|
||||
QAction actionAnalyzeFunction;
|
||||
QAction actionEditFunction;
|
||||
QAction actionRename;
|
||||
QAction actionGlobalVar;
|
||||
QAction actionSetFunctionVarTypes;
|
||||
QAction actionXRefs;
|
||||
QAction actionXRefsForVariables;
|
||||
@ -168,6 +171,11 @@ private:
|
||||
QMenu *pluginMenu = nullptr;
|
||||
QAction *pluginActionMenuAction = nullptr;
|
||||
|
||||
/**
|
||||
* \return widget that should be used as parent for presenting dialogs
|
||||
*/
|
||||
QWidget *parentForDialog();
|
||||
|
||||
// For creating anonymous entries (that are always visible)
|
||||
QAction *addAnonymousAction(QString name, const char *slot, QKeySequence shortcut);
|
||||
|
||||
@ -185,6 +193,7 @@ private:
|
||||
void addSetAsMenu();
|
||||
void addSetToDataMenu();
|
||||
void addEditMenu();
|
||||
void addAddAtMenu();
|
||||
void addBreakpointMenu();
|
||||
void addDebugMenu();
|
||||
|
||||
|
@ -25,7 +25,6 @@
|
||||
<update_contact>xarkes</update_contact>
|
||||
|
||||
<releases>
|
||||
<release version="2.2.1" date="2023-05-15" />
|
||||
<release version="2.2.0" date="2023-02-22" />
|
||||
<release version="2.1.2" date="2022-09-11" />
|
||||
<release version="2.1.1" date="2022-09-10" />
|
||||
|
97
src/tools/basefind/BaseFindDialog.cpp
Normal file
97
src/tools/basefind/BaseFindDialog.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include "BaseFindDialog.h"
|
||||
#include "ui_BaseFindDialog.h"
|
||||
|
||||
#include "BaseFindSearchDialog.h"
|
||||
|
||||
#include <core/Cutter.h>
|
||||
#include <rz_th.h>
|
||||
|
||||
BaseFindDialog::BaseFindDialog(QWidget *parent) : QDialog(parent), ui(new Ui::BaseFindDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
|
||||
// Fill in N-thread Combo
|
||||
size_t n_cores = rz_th_physical_core_number();
|
||||
ui->nCoresCombo->clear();
|
||||
for (size_t i = n_cores; i > 0; i--) {
|
||||
if (n_cores == i) {
|
||||
ui->nCoresCombo->addItem("All Cores");
|
||||
continue;
|
||||
}
|
||||
ui->nCoresCombo->addItem(QString::number(i));
|
||||
}
|
||||
|
||||
ui->startAddressEdit->setText(Core()->getConfig("basefind.search.start"));
|
||||
ui->endAddressEdit->setText(Core()->getConfig("basefind.search.end"));
|
||||
ui->alignmentEdit->setText(Core()->getConfig("basefind.alignment"));
|
||||
ui->minStrLenEdit->setValue(Core()->getConfigut64("basefind.min.string"));
|
||||
ui->minScoreEdit->setValue(Core()->getConfigut64("basefind.min.score"));
|
||||
|
||||
size_t selected_n_cores = Core()->getConfigut64("basefind.max.threads");
|
||||
if (selected_n_cores < n_cores && selected_n_cores > 0) {
|
||||
ui->nCoresCombo->setCurrentIndex(n_cores - selected_n_cores);
|
||||
}
|
||||
}
|
||||
|
||||
BaseFindDialog::~BaseFindDialog() {}
|
||||
|
||||
size_t BaseFindDialog::getNCores() const
|
||||
{
|
||||
size_t n_cores = rz_th_physical_core_number();
|
||||
return n_cores - ui->nCoresCombo->currentIndex();
|
||||
}
|
||||
|
||||
ut32 BaseFindDialog::getPointerSize() const
|
||||
{
|
||||
auto index = ui->pointerSizeCombo->currentIndex();
|
||||
QString value = ui->pointerSizeCombo->itemText(index);
|
||||
return value.toULong(nullptr, 0);
|
||||
}
|
||||
|
||||
RVA BaseFindDialog::getStartAddress() const
|
||||
{
|
||||
QString value = ui->startAddressEdit->text();
|
||||
return value.toULongLong(nullptr, 0);
|
||||
}
|
||||
|
||||
RVA BaseFindDialog::getEndAddress() const
|
||||
{
|
||||
QString value = ui->endAddressEdit->text();
|
||||
return value.toULongLong(nullptr, 0);
|
||||
}
|
||||
|
||||
RVA BaseFindDialog::getAlignment() const
|
||||
{
|
||||
QString value = ui->alignmentEdit->text();
|
||||
return value.toULongLong(nullptr, 0);
|
||||
}
|
||||
|
||||
ut32 BaseFindDialog::getMinStrLen() const
|
||||
{
|
||||
return ui->minStrLenEdit->value();
|
||||
}
|
||||
|
||||
ut32 BaseFindDialog::getMinScore() const
|
||||
{
|
||||
return ui->minScoreEdit->value();
|
||||
}
|
||||
|
||||
void BaseFindDialog::on_buttonBox_accepted()
|
||||
{
|
||||
RzBaseFindOpt options = {};
|
||||
options.max_threads = getNCores();
|
||||
options.pointer_size = getPointerSize();
|
||||
options.start_address = getStartAddress();
|
||||
options.end_address = getEndAddress();
|
||||
options.alignment = getAlignment();
|
||||
options.min_score = getMinScore();
|
||||
options.min_string_len = getMinStrLen();
|
||||
options.callback = nullptr;
|
||||
options.user = nullptr;
|
||||
|
||||
BaseFindSearchDialog *bfs = new BaseFindSearchDialog(parentWidget());
|
||||
bfs->show(&options);
|
||||
}
|
||||
|
||||
void BaseFindDialog::on_buttonBox_rejected() {}
|
38
src/tools/basefind/BaseFindDialog.h
Normal file
38
src/tools/basefind/BaseFindDialog.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef BASEFIND_DIALOG_H
|
||||
#define BASEFIND_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidgetItem>
|
||||
#include <memory>
|
||||
|
||||
#include <core/Cutter.h>
|
||||
|
||||
namespace Ui {
|
||||
class BaseFindDialog;
|
||||
}
|
||||
|
||||
class BaseFindDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BaseFindDialog(QWidget *parent = nullptr);
|
||||
~BaseFindDialog();
|
||||
|
||||
size_t getNCores() const;
|
||||
ut32 getPointerSize() const;
|
||||
RVA getStartAddress() const;
|
||||
RVA getEndAddress() const;
|
||||
RVA getAlignment() const;
|
||||
ut32 getMinStrLen() const;
|
||||
ut32 getMinScore() const;
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_accepted();
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::BaseFindDialog> ui;
|
||||
};
|
||||
|
||||
#endif // BASEFIND_DIALOG_H
|
246
src/tools/basefind/BaseFindDialog.ui
Normal file
246
src/tools/basefind/BaseFindDialog.ui
Normal file
@ -0,0 +1,246 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BaseFindDialog</class>
|
||||
<widget class="QDialog" name="BaseFindDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>373</width>
|
||||
<height>348</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">BaseFind</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="nCoresLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cores:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="nCoresCombo"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="pointerSizeLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pointer Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="pointerSizeCombo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>32</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>64</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="startAddressLabel">
|
||||
<property name="text">
|
||||
<string>Start Address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="startAddressEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>382</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="endAddressLabel">
|
||||
<property name="text">
|
||||
<string>End Address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="endAddressEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>382</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="alignmentLabel">
|
||||
<property name="text">
|
||||
<string>Alignment:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="alignmentEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>382</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="minStrLenLabel">
|
||||
<property name="text">
|
||||
<string>Min String Length:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="minStrLenEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>382</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="minScoreLabel">
|
||||
<property name="text">
|
||||
<string>Min Score:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="minScoreEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>382</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999999</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="actionRemoveItem">
|
||||
<property name="text">
|
||||
<string>Remove item</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRemoveAll">
|
||||
<property name="text">
|
||||
<string>Remove all</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Remove all</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>BaseFindDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>234</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>BaseFindDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>240</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
161
src/tools/basefind/BaseFindResultsDialog.cpp
Normal file
161
src/tools/basefind/BaseFindResultsDialog.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
#include "BaseFindResultsDialog.h"
|
||||
#include "ui_BaseFindResultsDialog.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <core/Cutter.h>
|
||||
#include <CutterApplication.h>
|
||||
|
||||
BaseFindResultsModel::BaseFindResultsModel(QList<BasefindResultDescription> *list, QObject *parent)
|
||||
: QAbstractListModel(parent), list(list)
|
||||
{
|
||||
}
|
||||
|
||||
int BaseFindResultsModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return list->count();
|
||||
}
|
||||
|
||||
int BaseFindResultsModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return BaseFindResultsModel::ColumnCount;
|
||||
}
|
||||
|
||||
QVariant BaseFindResultsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.row() >= list->count())
|
||||
return QVariant();
|
||||
|
||||
const BasefindResultDescription &entry = list->at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column()) {
|
||||
case ScoreColumn:
|
||||
return QString::asprintf("%u", entry.score);
|
||||
case CandidateColumn:
|
||||
return QString::asprintf("%#010llx", entry.candidate);
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
case Qt::ToolTipRole: {
|
||||
return QString::asprintf("%#010llx", entry.candidate);
|
||||
}
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant BaseFindResultsModel::headerData(int section, Qt::Orientation, int role) const
|
||||
{
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (section) {
|
||||
case ScoreColumn:
|
||||
return tr("Score");
|
||||
case CandidateColumn:
|
||||
return tr("Address");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
BaseFindResultsDialog::BaseFindResultsDialog(QList<BasefindResultDescription> results,
|
||||
QWidget *parent)
|
||||
: QDialog(parent), list(results), ui(new Ui::BaseFindResultsDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
|
||||
model = new BaseFindResultsModel(&list, this);
|
||||
ui->tableView->setModel(model);
|
||||
ui->tableView->sortByColumn(BaseFindResultsModel::ScoreColumn, Qt::AscendingOrder);
|
||||
ui->tableView->verticalHeader()->hide();
|
||||
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
blockMenu = new QMenu(this);
|
||||
actionCopyCandidate = new QAction(tr("Copy %1"), this);
|
||||
actionSetLoadAddr = new QAction(tr("Reopen Cutter with base address as %1"), this);
|
||||
actionSetMapAddr = new QAction(tr("Reopen Cutter with map address as %1"), this);
|
||||
|
||||
connect(ui->tableView, &QWidget::customContextMenuRequested, this,
|
||||
&BaseFindResultsDialog::showItemContextMenu);
|
||||
connect(actionCopyCandidate, &QAction::triggered, this,
|
||||
&BaseFindResultsDialog::onActionCopyLine);
|
||||
connect(actionSetLoadAddr, &QAction::triggered, this,
|
||||
&BaseFindResultsDialog::onActionSetLoadAddr);
|
||||
connect(actionSetMapAddr, &QAction::triggered, this,
|
||||
&BaseFindResultsDialog::onActionSetMapAddr);
|
||||
|
||||
blockMenu->addAction(actionSetLoadAddr);
|
||||
blockMenu->addAction(actionSetMapAddr);
|
||||
blockMenu->addAction(actionCopyCandidate);
|
||||
addActions(blockMenu->actions());
|
||||
}
|
||||
|
||||
void BaseFindResultsDialog::showItemContextMenu(const QPoint &pt)
|
||||
{
|
||||
auto index = ui->tableView->currentIndex();
|
||||
if (index.isValid()) {
|
||||
const BasefindResultDescription &entry = list.at(index.row());
|
||||
candidate = entry.candidate;
|
||||
auto addr = QString::asprintf("%#010llx", candidate);
|
||||
actionCopyCandidate->setText(tr("Copy %1").arg(addr));
|
||||
actionSetLoadAddr->setText(tr("Reopen Cutter with base address as %1").arg(addr));
|
||||
actionSetMapAddr->setText(tr("Reopen Cutter with map address as %1").arg(addr));
|
||||
blockMenu->exec(this->mapToGlobal(pt));
|
||||
}
|
||||
}
|
||||
|
||||
void BaseFindResultsDialog::onActionCopyLine()
|
||||
{
|
||||
auto clipboard = QApplication::clipboard();
|
||||
clipboard->setText(QString::asprintf("%#010llx", candidate));
|
||||
}
|
||||
|
||||
void BaseFindResultsDialog::onActionSetLoadAddr()
|
||||
{
|
||||
auto cutter = static_cast<CutterApplication *>(qApp);
|
||||
auto options = cutter->getInitialOptions();
|
||||
auto oldValue = options.binLoadAddr;
|
||||
|
||||
// override options to generate correct args
|
||||
options.binLoadAddr = candidate;
|
||||
cutter->setInitialOptions(options);
|
||||
auto args = cutter->getArgs();
|
||||
|
||||
// revert back options
|
||||
options.binLoadAddr = oldValue;
|
||||
cutter->setInitialOptions(options);
|
||||
|
||||
cutter->launchNewInstance(args);
|
||||
}
|
||||
|
||||
void BaseFindResultsDialog::onActionSetMapAddr()
|
||||
{
|
||||
auto cutter = static_cast<CutterApplication *>(qApp);
|
||||
auto options = cutter->getInitialOptions();
|
||||
auto oldValue = options.mapAddr;
|
||||
|
||||
// override options to generate correct args
|
||||
options.mapAddr = candidate;
|
||||
cutter->setInitialOptions(options);
|
||||
auto args = cutter->getArgs();
|
||||
|
||||
// revert back options
|
||||
options.mapAddr = oldValue;
|
||||
cutter->setInitialOptions(options);
|
||||
|
||||
cutter->launchNewInstance(args);
|
||||
}
|
||||
|
||||
BaseFindResultsDialog::~BaseFindResultsDialog() {}
|
||||
|
||||
void BaseFindResultsDialog::on_buttonBox_rejected() {}
|
68
src/tools/basefind/BaseFindResultsDialog.h
Normal file
68
src/tools/basefind/BaseFindResultsDialog.h
Normal file
@ -0,0 +1,68 @@
|
||||
#ifndef BASEFIND_RESULTS_DIALOG_H
|
||||
#define BASEFIND_RESULTS_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <memory>
|
||||
|
||||
#include <core/Cutter.h>
|
||||
|
||||
class BaseFindResultsDialog;
|
||||
|
||||
namespace Ui {
|
||||
class BaseFindResultsDialog;
|
||||
}
|
||||
|
||||
class BaseFindResultsModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend BaseFindResultsDialog;
|
||||
|
||||
public:
|
||||
enum Column { ScoreColumn = 0, CandidateColumn, ColumnCount };
|
||||
|
||||
BaseFindResultsModel(QList<BasefindResultDescription> *list, QObject *parent = nullptr);
|
||||
|
||||
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<BasefindResultDescription> *list;
|
||||
};
|
||||
|
||||
class BaseFindResultsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BaseFindResultsDialog(QList<BasefindResultDescription> results,
|
||||
QWidget *parent = nullptr);
|
||||
~BaseFindResultsDialog();
|
||||
|
||||
public slots:
|
||||
void showItemContextMenu(const QPoint &pt);
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
private:
|
||||
void onActionCopyLine();
|
||||
void onActionSetLoadAddr();
|
||||
void onActionSetMapAddr();
|
||||
|
||||
QList<BasefindResultDescription> list;
|
||||
std::unique_ptr<Ui::BaseFindResultsDialog> ui;
|
||||
BaseFindResultsModel *model;
|
||||
QMenu *blockMenu;
|
||||
QAction *actionCopyCandidate;
|
||||
QAction *actionSetLoadAddr;
|
||||
QAction *actionSetMapAddr;
|
||||
RVA candidate;
|
||||
};
|
||||
|
||||
#endif // BASEFIND_RESULTS_DIALOG_H
|
70
src/tools/basefind/BaseFindResultsDialog.ui
Normal file
70
src/tools/basefind/BaseFindResultsDialog.ui
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BaseFindResultsDialog</class>
|
||||
<widget class="QDialog" name="BaseFindResultsDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>582</width>
|
||||
<height>382</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">BaseFind Results</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="mainVerticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>BaseFindResultsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>240</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
66
src/tools/basefind/BaseFindSearchDialog.cpp
Normal file
66
src/tools/basefind/BaseFindSearchDialog.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include "BaseFindSearchDialog.h"
|
||||
#include "ui_BaseFindSearchDialog.h"
|
||||
|
||||
#include "BaseFindResultsDialog.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QFormLayout>
|
||||
|
||||
#include <core/Cutter.h>
|
||||
#include <rz_th.h>
|
||||
|
||||
BaseFindSearchDialog::BaseFindSearchDialog(QWidget *parent)
|
||||
: QDialog(parent), basefind(new Basefind(Core())), ui(new Ui::BaseFindSearchDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
}
|
||||
|
||||
BaseFindSearchDialog::~BaseFindSearchDialog() {}
|
||||
|
||||
void BaseFindSearchDialog::show(RzBaseFindOpt *opts)
|
||||
{
|
||||
size_t n_cores = rz_th_physical_core_number();
|
||||
if (opts->max_threads > n_cores || opts->max_threads < 1) {
|
||||
opts->max_threads = n_cores;
|
||||
}
|
||||
|
||||
QFormLayout *layout = new QFormLayout();
|
||||
ui->scrollAreaWidgetContents->setLayout(layout);
|
||||
for (ut32 i = 0; i < opts->max_threads; ++i) {
|
||||
QString label = QString::asprintf("Core %u", i);
|
||||
QProgressBar *pbar = new QProgressBar(nullptr);
|
||||
layout->addRow(label, pbar);
|
||||
pbar->setRange(0, 100);
|
||||
bars.push_back(pbar);
|
||||
}
|
||||
|
||||
if (!basefind->setOptions(opts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
connect(this, &BaseFindSearchDialog::cancelSearch, basefind.get(), &Basefind::cancel);
|
||||
connect(basefind.get(), &Basefind::progress, this, &BaseFindSearchDialog::onProgress);
|
||||
connect(basefind.get(), &Basefind::complete, this, &BaseFindSearchDialog::onCompletion);
|
||||
|
||||
basefind->start();
|
||||
this->QDialog::show();
|
||||
}
|
||||
|
||||
void BaseFindSearchDialog::onProgress(BasefindCoreStatusDescription status)
|
||||
{
|
||||
bars[status.index]->setValue(status.percentage);
|
||||
}
|
||||
|
||||
void BaseFindSearchDialog::onCompletion()
|
||||
{
|
||||
auto results = basefind->results();
|
||||
BaseFindResultsDialog *table = new BaseFindResultsDialog(results, parentWidget());
|
||||
table->show();
|
||||
this->close();
|
||||
}
|
||||
|
||||
void BaseFindSearchDialog::on_buttonBox_rejected()
|
||||
{
|
||||
emit cancelSearch();
|
||||
}
|
41
src/tools/basefind/BaseFindSearchDialog.h
Normal file
41
src/tools/basefind/BaseFindSearchDialog.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef BASEFIND_SEARCH_DIALOG_H
|
||||
#define BASEFIND_SEARCH_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidgetItem>
|
||||
#include <QProgressBar>
|
||||
#include <memory>
|
||||
|
||||
#include <core/Cutter.h>
|
||||
|
||||
namespace Ui {
|
||||
class BaseFindSearchDialog;
|
||||
}
|
||||
|
||||
class BaseFindSearchDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BaseFindSearchDialog(QWidget *parent = nullptr);
|
||||
~BaseFindSearchDialog();
|
||||
|
||||
void show(RzBaseFindOpt *opts);
|
||||
|
||||
public slots:
|
||||
void onProgress(BasefindCoreStatusDescription status);
|
||||
void onCompletion();
|
||||
|
||||
signals:
|
||||
void cancelSearch();
|
||||
|
||||
private slots:
|
||||
void on_buttonBox_rejected();
|
||||
|
||||
private:
|
||||
std::vector<QProgressBar *> bars;
|
||||
std::unique_ptr<Basefind> basefind;
|
||||
std::unique_ptr<Ui::BaseFindSearchDialog> ui;
|
||||
};
|
||||
|
||||
#endif // BASEFIND_SEARCH_DIALOG_H
|
112
src/tools/basefind/BaseFindSearchDialog.ui
Normal file
112
src/tools/basefind/BaseFindSearchDialog.ui
Normal file
@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>BaseFindSearchDialog</class>
|
||||
<widget class="QDialog" name="BaseFindSearchDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>582</width>
|
||||
<height>382</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Searching for base address</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="mainVerticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinimumSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeAdjustPolicy">
|
||||
<enum>QAbstractScrollArea::AdjustToContents</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>564</width>
|
||||
<height>320</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="actionRemoveItem">
|
||||
<property name="text">
|
||||
<string>Remove item</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRemoveAll">
|
||||
<property name="text">
|
||||
<string>Remove all</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Remove all</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>BaseFindSearchDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>240</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -1 +1 @@
|
||||
Subproject commit e8fc5ca1acd70fd82a2ac9ac02b0261e57703250
|
||||
Subproject commit 53b42f0854479f36170356c13d5eec4be3182444
|
@ -57,16 +57,30 @@ public:
|
||||
itemContextMenu = menu;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is set to true, the context menu will also be shown if no item
|
||||
* is currently selected.
|
||||
*/
|
||||
void setShowItemContextMenuWithoutAddress(bool val) { showItemContextMenuWithoutAddress = val; }
|
||||
|
||||
protected:
|
||||
virtual void showItemContextMenu(const QPoint &pt)
|
||||
{
|
||||
if (!itemContextMenu) {
|
||||
return;
|
||||
}
|
||||
auto index = this->currentIndex();
|
||||
if (index.isValid() && itemContextMenu) {
|
||||
if (index.isValid()) {
|
||||
auto offset = addressableModel->address(index);
|
||||
auto name = addressableModel->name(index);
|
||||
itemContextMenu->setTarget(offset, name);
|
||||
itemContextMenu->exec(this->mapToGlobal(pt));
|
||||
} else {
|
||||
if (!showItemContextMenuWithoutAddress) {
|
||||
return;
|
||||
}
|
||||
itemContextMenu->clearTarget();
|
||||
}
|
||||
itemContextMenu->exec(this->mapToGlobal(pt));
|
||||
}
|
||||
|
||||
virtual void onItemActivated(const QModelIndex &index)
|
||||
@ -90,6 +104,7 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
bool showItemContextMenuWithoutAddress = false;
|
||||
AddressableItemModelI *addressableModel = nullptr;
|
||||
AddressableItemContextMenu *itemContextMenu = nullptr;
|
||||
MainWindow *mainWindow = nullptr;
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "ClassesWidget.h"
|
||||
#include "core/MainWindow.h"
|
||||
#include "ui_ClassesWidget.h"
|
||||
#include "ui_ListDockWidget.h"
|
||||
#include "common/Helpers.h"
|
||||
#include "common/SvgIconEngine.h"
|
||||
#include "dialogs/EditMethodDialog.h"
|
||||
@ -9,6 +9,8 @@
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QInputDialog>
|
||||
#include <QShortcut>
|
||||
#include <QComboBox>
|
||||
|
||||
QVariant ClassesModel::headerData(int section, Qt::Orientation, int role) const
|
||||
{
|
||||
@ -33,6 +35,17 @@ QVariant ClassesModel::headerData(int section, Qt::Orientation, int role) const
|
||||
}
|
||||
}
|
||||
|
||||
RVA ClassesModel::address(const QModelIndex &index) const
|
||||
{
|
||||
QVariant v = data(index, OffsetRole);
|
||||
return v.isValid() ? v.toULongLong() : RVA_INVALID;
|
||||
}
|
||||
|
||||
QString ClassesModel::name(const QModelIndex &index) const
|
||||
{
|
||||
return data(index, NameRole).toString();
|
||||
}
|
||||
|
||||
BinClassesModel::BinClassesModel(QObject *parent) : ClassesModel(parent) {}
|
||||
|
||||
void BinClassesModel::setClasses(const QList<BinClassDescription> &classes)
|
||||
@ -526,12 +539,17 @@ QVariant AnalysisClassesModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
|
||||
ClassesSortFilterProxyModel::ClassesSortFilterProxyModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
: AddressableFilterProxyModel(nullptr, parent)
|
||||
{
|
||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
bool ClassesSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return true;
|
||||
|
||||
QModelIndex index = sourceModel()->index(row, 0, parent);
|
||||
return qhelpers::filterStringContains(index.data(ClassesModel::NameRole).toString(), this);
|
||||
}
|
||||
@ -576,23 +594,63 @@ bool ClassesSortFilterProxyModel::hasChildren(const QModelIndex &parent) const
|
||||
return !parent.isValid() || !parent.parent().isValid();
|
||||
}
|
||||
|
||||
ClassesWidget::ClassesWidget(MainWindow *main) : CutterDockWidget(main), ui(new Ui::ClassesWidget)
|
||||
ClassesWidget::ClassesWidget(MainWindow *main)
|
||||
: ListDockWidget(main),
|
||||
seekToVTableAction(tr("Seek to VTable"), this),
|
||||
editMethodAction(tr("Edit Method"), this),
|
||||
addMethodAction(tr("Add Method"), this),
|
||||
newClassAction(tr("Create new Class"), this),
|
||||
renameClassAction(tr("Rename Class"), this),
|
||||
deleteClassAction(tr("Delete Class"), this)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(tr("Classes"));
|
||||
setObjectName("ClassesWidget");
|
||||
|
||||
ui->classesTreeView->setIconSize(QSize(10, 10));
|
||||
ui->treeView->setIconSize(QSize(10, 10));
|
||||
|
||||
proxy_model = new ClassesSortFilterProxyModel(this);
|
||||
ui->classesTreeView->setModel(proxy_model);
|
||||
ui->classesTreeView->sortByColumn(ClassesModel::TYPE, Qt::AscendingOrder);
|
||||
ui->classesTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
setModels(proxy_model);
|
||||
|
||||
ui->classSourceCombo->setCurrentIndex(1);
|
||||
classSourceCombo = new QComboBox(this);
|
||||
// User an intermediate single-child layout to contain the combo box, otherwise
|
||||
// when the combo box is inserted directly, the entire vertical layout gets a
|
||||
// weird horizontal padding on macOS.
|
||||
QBoxLayout *comboLayout = new QBoxLayout(QBoxLayout::Direction::LeftToRight, nullptr);
|
||||
comboLayout->addWidget(classSourceCombo);
|
||||
ui->verticalLayout->insertLayout(ui->verticalLayout->indexOf(ui->quickFilterView), comboLayout);
|
||||
classSourceCombo->addItem(tr("Binary Info (Fixed)"));
|
||||
classSourceCombo->addItem(tr("Analysis (Editable)"));
|
||||
classSourceCombo->setCurrentIndex(1);
|
||||
|
||||
connect<void (QComboBox::*)(int)>(ui->classSourceCombo, &QComboBox::currentIndexChanged, this,
|
||||
connect<void (QComboBox::*)(int)>(classSourceCombo, &QComboBox::currentIndexChanged, this,
|
||||
&ClassesWidget::refreshClasses);
|
||||
connect(ui->classesTreeView, &QTreeView::customContextMenuRequested, this,
|
||||
&ClassesWidget::showContextMenu);
|
||||
|
||||
connect(&seekToVTableAction, &QAction::triggered, this,
|
||||
&ClassesWidget::seekToVTableActionTriggered);
|
||||
connect(&editMethodAction, &QAction::triggered, this,
|
||||
&ClassesWidget::editMethodActionTriggered);
|
||||
connect(&addMethodAction, &QAction::triggered, this, &ClassesWidget::addMethodActionTriggered);
|
||||
connect(&newClassAction, &QAction::triggered, this, &ClassesWidget::newClassActionTriggered);
|
||||
connect(&renameClassAction, &QAction::triggered, this,
|
||||
&ClassesWidget::renameClassActionTriggered);
|
||||
connect(&deleteClassAction, &QAction::triggered, this,
|
||||
&ClassesWidget::deleteClassActionTriggered);
|
||||
|
||||
// Build context menu like this:
|
||||
// class-related actions
|
||||
// -- classesMethodsSeparator
|
||||
// method-related actions
|
||||
// -- separator
|
||||
// default actions from AddressableItemList
|
||||
auto contextMenu = ui->treeView->getItemContextMenu();
|
||||
contextMenu->insertSeparator(contextMenu->actions().first());
|
||||
contextMenu->insertActions(contextMenu->actions().first(),
|
||||
{ &addMethodAction, &editMethodAction, &seekToVTableAction });
|
||||
classesMethodsSeparator = contextMenu->insertSeparator(contextMenu->actions().first());
|
||||
contextMenu->insertActions(classesMethodsSeparator,
|
||||
{ &newClassAction, &renameClassAction, &deleteClassAction });
|
||||
connect(contextMenu, &QMenu::aboutToShow, this, &ClassesWidget::updateActions);
|
||||
ui->treeView->setShowItemContextMenuWithoutAddress(true);
|
||||
|
||||
refreshClasses();
|
||||
}
|
||||
@ -601,7 +659,7 @@ ClassesWidget::~ClassesWidget() {}
|
||||
|
||||
ClassesWidget::Source ClassesWidget::getSource()
|
||||
{
|
||||
switch (ui->classSourceCombo->currentIndex()) {
|
||||
switch (classSourceCombo->currentIndex()) {
|
||||
case 0:
|
||||
return Source::BIN;
|
||||
default:
|
||||
@ -614,88 +672,68 @@ void ClassesWidget::refreshClasses()
|
||||
switch (getSource()) {
|
||||
case Source::BIN:
|
||||
if (!bin_model) {
|
||||
proxy_model->setSourceModel(nullptr);
|
||||
proxy_model->setSourceModel(static_cast<AddressableItemModelI *>(nullptr));
|
||||
delete analysis_model;
|
||||
analysis_model = nullptr;
|
||||
bin_model = new BinClassesModel(this);
|
||||
proxy_model->setSourceModel(bin_model);
|
||||
proxy_model->setSourceModel(static_cast<AddressableItemModelI *>(bin_model));
|
||||
}
|
||||
bin_model->setClasses(Core()->getAllClassesFromBin());
|
||||
break;
|
||||
case Source::ANALYSIS:
|
||||
if (!analysis_model) {
|
||||
proxy_model->setSourceModel(nullptr);
|
||||
proxy_model->setSourceModel(static_cast<AddressableItemModelI *>(nullptr));
|
||||
delete bin_model;
|
||||
bin_model = nullptr;
|
||||
analysis_model = new AnalysisClassesModel(this);
|
||||
proxy_model->setSourceModel(analysis_model);
|
||||
proxy_model->setSourceModel(static_cast<AddressableItemModelI *>(analysis_model));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
qhelpers::adjustColumns(ui->classesTreeView, 3, 0);
|
||||
qhelpers::adjustColumns(ui->treeView, 3, 0);
|
||||
|
||||
ui->classesTreeView->setColumnWidth(0, 200);
|
||||
ui->treeView->setColumnWidth(0, 200);
|
||||
}
|
||||
|
||||
void ClassesWidget::on_classesTreeView_doubleClicked(const QModelIndex &index)
|
||||
void ClassesWidget::updateActions()
|
||||
{
|
||||
if (!index.isValid())
|
||||
return;
|
||||
bool isAnalysis = !!analysis_model;
|
||||
newClassAction.setVisible(isAnalysis);
|
||||
addMethodAction.setVisible(isAnalysis);
|
||||
|
||||
QVariant offsetData = index.data(ClassesModel::OffsetRole);
|
||||
if (!offsetData.isValid()) {
|
||||
return;
|
||||
}
|
||||
RVA offset = offsetData.value<RVA>();
|
||||
Core()->seekAndShow(offset);
|
||||
}
|
||||
|
||||
void ClassesWidget::showContextMenu(const QPoint &pt)
|
||||
{
|
||||
if (!analysis_model) {
|
||||
// no context menu for bin classes
|
||||
return;
|
||||
}
|
||||
|
||||
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
bool rowIsAnalysisClass = false;
|
||||
bool rowIsAnalysisMethod = false;
|
||||
QModelIndex index = ui->treeView->selectionModel()->currentIndex();
|
||||
if (isAnalysis && index.isValid()) {
|
||||
auto type = static_cast<ClassesModel::RowType>(index.data(ClassesModel::TypeRole).toInt());
|
||||
|
||||
QMenu menu(ui->classesTreeView);
|
||||
|
||||
menu.addAction(ui->newClassAction);
|
||||
|
||||
if (type == ClassesModel::RowType::Class) {
|
||||
menu.addAction(ui->renameClassAction);
|
||||
menu.addAction(ui->deleteClassAction);
|
||||
rowIsAnalysisClass = type == ClassesModel::RowType::Class;
|
||||
rowIsAnalysisMethod = type == ClassesModel::RowType::Method;
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
renameClassAction.setVisible(rowIsAnalysisClass);
|
||||
deleteClassAction.setVisible(rowIsAnalysisClass);
|
||||
|
||||
menu.addAction(ui->addMethodAction);
|
||||
|
||||
if (type == ClassesModel::RowType::Method) {
|
||||
menu.addAction(ui->editMethodAction);
|
||||
classesMethodsSeparator->setVisible(rowIsAnalysisClass || rowIsAnalysisMethod);
|
||||
|
||||
editMethodAction.setVisible(rowIsAnalysisMethod);
|
||||
bool rowHasVTable = false;
|
||||
if (rowIsAnalysisMethod) {
|
||||
QString className = index.parent().data(ClassesModel::NameRole).toString();
|
||||
QString methodName = index.data(ClassesModel::NameRole).toString();
|
||||
AnalysisMethodDescription desc;
|
||||
if (Core()->getAnalysisMethod(className, methodName, &desc)) {
|
||||
if (desc.vtableOffset >= 0) {
|
||||
menu.addAction(ui->seekToVTableAction);
|
||||
rowHasVTable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu.exec(ui->classesTreeView->mapToGlobal(pt));
|
||||
seekToVTableAction.setVisible(rowHasVTable);
|
||||
}
|
||||
|
||||
void ClassesWidget::on_seekToVTableAction_triggered()
|
||||
void ClassesWidget::seekToVTableActionTriggered()
|
||||
{
|
||||
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||
QModelIndex index = ui->treeView->selectionModel()->currentIndex();
|
||||
QString className = index.parent().data(ClassesModel::NameRole).toString();
|
||||
|
||||
QList<AnalysisVTableDescription> vtables = Core()->getAnalysisClassVTables(className);
|
||||
@ -714,9 +752,9 @@ void ClassesWidget::on_seekToVTableAction_triggered()
|
||||
Core()->seekAndShow(vtables[0].addr + desc.vtableOffset);
|
||||
}
|
||||
|
||||
void ClassesWidget::on_addMethodAction_triggered()
|
||||
void ClassesWidget::addMethodActionTriggered()
|
||||
{
|
||||
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||
QModelIndex index = ui->treeView->selectionModel()->currentIndex();
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
@ -732,9 +770,9 @@ void ClassesWidget::on_addMethodAction_triggered()
|
||||
EditMethodDialog::newMethod(className, QString(), this);
|
||||
}
|
||||
|
||||
void ClassesWidget::on_editMethodAction_triggered()
|
||||
void ClassesWidget::editMethodActionTriggered()
|
||||
{
|
||||
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||
QModelIndex index = ui->treeView->selectionModel()->currentIndex();
|
||||
if (!index.isValid()
|
||||
|| index.data(ClassesModel::TypeRole).toInt()
|
||||
!= static_cast<int>(ClassesModel::RowType::Method)) {
|
||||
@ -745,7 +783,7 @@ void ClassesWidget::on_editMethodAction_triggered()
|
||||
EditMethodDialog::editMethod(className, methName, this);
|
||||
}
|
||||
|
||||
void ClassesWidget::on_newClassAction_triggered()
|
||||
void ClassesWidget::newClassActionTriggered()
|
||||
{
|
||||
bool ok;
|
||||
QString name = QInputDialog::getText(this, tr("Create new Class"), tr("Class Name:"),
|
||||
@ -755,9 +793,9 @@ void ClassesWidget::on_newClassAction_triggered()
|
||||
}
|
||||
}
|
||||
|
||||
void ClassesWidget::on_deleteClassAction_triggered()
|
||||
void ClassesWidget::deleteClassActionTriggered()
|
||||
{
|
||||
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||
QModelIndex index = ui->treeView->selectionModel()->currentIndex();
|
||||
if (!index.isValid()
|
||||
|| index.data(ClassesModel::TypeRole).toInt()
|
||||
!= static_cast<int>(ClassesModel::RowType::Class)) {
|
||||
@ -772,9 +810,9 @@ void ClassesWidget::on_deleteClassAction_triggered()
|
||||
Core()->deleteClass(className);
|
||||
}
|
||||
|
||||
void ClassesWidget::on_renameClassAction_triggered()
|
||||
void ClassesWidget::renameClassActionTriggered()
|
||||
{
|
||||
QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex();
|
||||
QModelIndex index = ui->treeView->selectionModel()->currentIndex();
|
||||
if (!index.isValid()
|
||||
|| index.data(ClassesModel::TypeRole).toInt()
|
||||
!= static_cast<int>(ClassesModel::RowType::Class)) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include "core/Cutter.h"
|
||||
#include "CutterDockWidget.h"
|
||||
#include "widgets/ListDockWidget.h"
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
@ -21,7 +22,7 @@ class ClassesWidget;
|
||||
/**
|
||||
* @brief Common abstract base class for Bin and Anal classes models
|
||||
*/
|
||||
class ClassesModel : public QAbstractItemModel
|
||||
class ClassesModel : public AddressableItemModel<>
|
||||
{
|
||||
public:
|
||||
enum Columns { NAME = 0, REAL_NAME, TYPE, OFFSET, VTABLE, COUNT };
|
||||
@ -69,10 +70,13 @@ public:
|
||||
*/
|
||||
static const int RealNameRole = Qt::UserRole + 4;
|
||||
|
||||
explicit ClassesModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {}
|
||||
explicit ClassesModel(QObject *parent = nullptr) : AddressableItemModel(parent) {}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ClassesModel::RowType)
|
||||
@ -163,7 +167,7 @@ public slots:
|
||||
void classAttrsChanged(const QString &cls);
|
||||
};
|
||||
|
||||
class ClassesSortFilterProxyModel : public QSortFilterProxyModel
|
||||
class ClassesSortFilterProxyModel : public AddressableFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -176,7 +180,7 @@ protected:
|
||||
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
|
||||
};
|
||||
|
||||
class ClassesWidget : public CutterDockWidget
|
||||
class ClassesWidget : public ListDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -185,29 +189,34 @@ public:
|
||||
~ClassesWidget();
|
||||
|
||||
private slots:
|
||||
void on_classesTreeView_doubleClicked(const QModelIndex &index);
|
||||
|
||||
void on_seekToVTableAction_triggered();
|
||||
void on_addMethodAction_triggered();
|
||||
void on_editMethodAction_triggered();
|
||||
void on_newClassAction_triggered();
|
||||
void on_deleteClassAction_triggered();
|
||||
void on_renameClassAction_triggered();
|
||||
|
||||
void showContextMenu(const QPoint &pt);
|
||||
void seekToVTableActionTriggered();
|
||||
void editMethodActionTriggered();
|
||||
void addMethodActionTriggered();
|
||||
void newClassActionTriggered();
|
||||
void renameClassActionTriggered();
|
||||
void deleteClassActionTriggered();
|
||||
|
||||
void refreshClasses();
|
||||
void updateActions();
|
||||
|
||||
private:
|
||||
enum class Source { BIN, ANALYSIS };
|
||||
|
||||
Source getSource();
|
||||
|
||||
std::unique_ptr<Ui::ClassesWidget> ui;
|
||||
|
||||
BinClassesModel *bin_model = nullptr;
|
||||
AnalysisClassesModel *analysis_model = nullptr;
|
||||
ClassesSortFilterProxyModel *proxy_model;
|
||||
|
||||
QComboBox *classSourceCombo;
|
||||
|
||||
QAction seekToVTableAction;
|
||||
QAction editMethodAction;
|
||||
QAction addMethodAction;
|
||||
QAction newClassAction;
|
||||
QAction renameClassAction;
|
||||
QAction deleteClassAction;
|
||||
QAction *classesMethodsSeparator;
|
||||
};
|
||||
|
||||
#endif // CLASSESWIDGET_H
|
||||
|
@ -1,148 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ClassesWidget</class>
|
||||
<widget class="QDockWidget" name="ClassesWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Classes</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CutterTreeView" name="classesTreeView">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">CutterTreeView::item
|
||||
{
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="expandsOnDoubleClick">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_17">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="classSourceLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Source:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="classSourceCombo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Binary Info (Fixed)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Analysis (Editable)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<action name="seekToVTableAction">
|
||||
<property name="text">
|
||||
<string>Seek to VTable</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="editMethodAction">
|
||||
<property name="text">
|
||||
<string>Edit Method</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="addMethodAction">
|
||||
<property name="text">
|
||||
<string>Add Method</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="newClassAction">
|
||||
<property name="text">
|
||||
<string>Create new Class</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="renameClassAction">
|
||||
<property name="text">
|
||||
<string>Rename Class</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="deleteClassAction">
|
||||
<property name="text">
|
||||
<string>Delete Class</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CutterTreeView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>widgets/CutterTreeView.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -22,8 +22,7 @@ void ColorThemeComboBox::updateFromConfig(bool interfaceThemeChanged)
|
||||
|
||||
clear();
|
||||
for (const QString &theme : themes) {
|
||||
if (ThemeWorker().isCustomTheme(theme)
|
||||
|| !Configuration::relevantThemes[theme]
|
||||
if (ThemeWorker().isCustomTheme(theme) || !Configuration::relevantThemes[theme]
|
||||
|| (Configuration::cutterInterfaceThemesList()[curInterfaceThemeIndex].flag
|
||||
& Configuration::relevantThemes[theme])) {
|
||||
addItem(theme);
|
||||
|
@ -128,8 +128,8 @@ void ColorOptionDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o
|
||||
painter->setPen(qApp->palette().text().color());
|
||||
|
||||
QFontMetrics fm2 = QFontMetrics(painter->font());
|
||||
QString name = fm2.elidedText(optionInfoMap__[currCO.optionName].displayingtext,
|
||||
Qt::ElideRight, optionNameRect.width());
|
||||
QString name = fm2.elidedText(optionInfoMap__[currCO.optionName].displayingtext, Qt::ElideRight,
|
||||
optionNameRect.width());
|
||||
painter->drawText(optionNameRect, name);
|
||||
|
||||
QPainterPath roundedOptionRect;
|
||||
@ -157,9 +157,9 @@ void ColorOptionDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o
|
||||
painter->fillPath(roundedColorRect, currCO.color);
|
||||
|
||||
QFontMetrics fm3 = QFontMetrics(painter->font());
|
||||
QString desc = fm3.elidedText(
|
||||
currCO.optionName + ": " + optionInfoMap__[currCO.optionName].info, Qt::ElideRight,
|
||||
descTextRect.width());
|
||||
QString desc =
|
||||
fm3.elidedText(currCO.optionName + ": " + optionInfoMap__[currCO.optionName].info,
|
||||
Qt::ElideRight, descTextRect.width());
|
||||
painter->setPen(qApp->palette().text().color());
|
||||
painter->setBrush(qApp->palette().text());
|
||||
painter->drawText(descTextRect, desc);
|
||||
|
@ -12,8 +12,7 @@ ComboQuickFilterView::ComboQuickFilterView(QWidget *parent)
|
||||
connect(debounceTimer, &QTimer::timeout, this,
|
||||
[this]() { emit filterTextChanged(ui->lineEdit->text()); });
|
||||
|
||||
connect(ui->lineEdit, &QLineEdit::textChanged, this,
|
||||
[this](const QString &text) { debounceTimer->start(150); });
|
||||
connect(ui->lineEdit, &QLineEdit::textChanged, this, [this]() { debounceTimer->start(150); });
|
||||
}
|
||||
|
||||
ComboQuickFilterView::~ComboQuickFilterView()
|
||||
|
@ -173,7 +173,7 @@ void Dashboard::on_certificateButton_clicked()
|
||||
dialog.setMinimumSize(QSize(900, 600));
|
||||
dialog.setMaximumSize(QSize(900, 600));
|
||||
dialog.setSizeGripEnabled(false);
|
||||
dialog.setWindowTitle("Certificates");
|
||||
dialog.setWindowTitle(tr("Certificates"));
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,7 @@ DecompilerWidget::DecompilerWidget(MainWindow *main)
|
||||
ui(new Ui::DecompilerWidget),
|
||||
decompilerBusy(false),
|
||||
seekFromCursor(false),
|
||||
scrollerHorizontal(0),
|
||||
scrollerVertical(0),
|
||||
historyPos(0),
|
||||
previousFunctionAddr(RVA_INVALID),
|
||||
decompiledFunctionAddr(RVA_INVALID),
|
||||
code(Decompiler::makeWarning(tr("Choose an offset and refresh to get decompiled code")),
|
||||
@ -91,6 +90,7 @@ DecompilerWidget::DecompilerWidget(MainWindow *main)
|
||||
connect(Core(), &CutterCore::varsChanged, this, &DecompilerWidget::doRefresh);
|
||||
connect(Core(), &CutterCore::functionsChanged, this, &DecompilerWidget::doRefresh);
|
||||
connect(Core(), &CutterCore::flagsChanged, this, &DecompilerWidget::doRefresh);
|
||||
connect(Core(), &CutterCore::globalVarsChanged, this, &DecompilerWidget::doRefresh);
|
||||
connect(Core(), &CutterCore::commentsChanged, this, &DecompilerWidget::refreshIfChanged);
|
||||
connect(Core(), &CutterCore::instructionChanged, this, &DecompilerWidget::refreshIfChanged);
|
||||
connect(Core(), &CutterCore::refreshCodeViews, this, &DecompilerWidget::doRefresh);
|
||||
@ -311,13 +311,6 @@ QTextCursor DecompilerWidget::getCursorForAddress(RVA addr)
|
||||
|
||||
void DecompilerWidget::decompilationFinished(RzAnnotatedCode *codeDecompiled)
|
||||
{
|
||||
bool isDisplayReset = false;
|
||||
if (previousFunctionAddr == decompiledFunctionAddr) {
|
||||
scrollerHorizontal = ui->textEdit->horizontalScrollBar()->sliderPosition();
|
||||
scrollerVertical = ui->textEdit->verticalScrollBar()->sliderPosition();
|
||||
isDisplayReset = true;
|
||||
}
|
||||
|
||||
ui->progressLabel->setVisible(false);
|
||||
ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled);
|
||||
|
||||
@ -354,10 +347,8 @@ void DecompilerWidget::decompilationFinished(RzAnnotatedCode *codeDecompiled)
|
||||
}
|
||||
}
|
||||
|
||||
if (isDisplayReset) {
|
||||
ui->textEdit->horizontalScrollBar()->setSliderPosition(scrollerHorizontal);
|
||||
ui->textEdit->verticalScrollBar()->setSliderPosition(scrollerVertical);
|
||||
}
|
||||
ui->textEdit->horizontalScrollBar()->setSliderPosition(scrollHistory[historyPos].first);
|
||||
ui->textEdit->verticalScrollBar()->setSliderPosition(scrollHistory[historyPos].second);
|
||||
}
|
||||
|
||||
void DecompilerWidget::setAnnotationsAtCursor(size_t pos)
|
||||
@ -416,11 +407,28 @@ void DecompilerWidget::cursorPositionChanged()
|
||||
updateSelection();
|
||||
}
|
||||
|
||||
void DecompilerWidget::seekChanged()
|
||||
void DecompilerWidget::seekChanged(RVA /* addr */, CutterCore::SeekHistoryType type)
|
||||
{
|
||||
if (seekFromCursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!scrollHistory.empty()) { // History is empty upon init.
|
||||
scrollHistory[historyPos] = { ui->textEdit->horizontalScrollBar()->sliderPosition(),
|
||||
ui->textEdit->verticalScrollBar()->sliderPosition() };
|
||||
}
|
||||
if (type == CutterCore::SeekHistoryType::New) {
|
||||
// Erase previous history past this point.
|
||||
if (scrollHistory.size() > historyPos + 1) {
|
||||
scrollHistory.erase(scrollHistory.begin() + historyPos + 1, scrollHistory.end());
|
||||
}
|
||||
scrollHistory.push_back({ 0, 0 });
|
||||
historyPos = scrollHistory.size() - 1;
|
||||
} else if (type == CutterCore::SeekHistoryType::Undo) {
|
||||
--historyPos;
|
||||
} else if (type == CutterCore::SeekHistoryType::Redo) {
|
||||
++historyPos;
|
||||
}
|
||||
RVA fcnAddr = Core()->getFunctionStart(seekable->getOffset());
|
||||
if (fcnAddr == RVA_INVALID || fcnAddr != decompiledFunctionAddr) {
|
||||
doRefresh();
|
||||
|
@ -53,7 +53,7 @@ private slots:
|
||||
* - Seek changed to an offset contained in the decompiled function.
|
||||
* - Auto-refresh is disabled.
|
||||
*/
|
||||
void seekChanged();
|
||||
void seekChanged(RVA /* addr */, CutterCore::SeekHistoryType type);
|
||||
void decompilationFinished(RzAnnotatedCode *code);
|
||||
|
||||
private:
|
||||
@ -72,8 +72,8 @@ private:
|
||||
bool decompilerBusy;
|
||||
|
||||
bool seekFromCursor;
|
||||
int scrollerHorizontal;
|
||||
int scrollerVertical;
|
||||
int historyPos;
|
||||
QVector<QPair<int, int>> scrollHistory;
|
||||
RVA previousFunctionAddr;
|
||||
RVA decompiledFunctionAddr;
|
||||
std::unique_ptr<RzAnnotatedCode, void (*)(RzAnnotatedCode *)> code;
|
||||
|
@ -52,6 +52,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se
|
||||
connect(Core(), &CutterCore::commentsChanged, this, &DisassemblerGraphView::refreshView);
|
||||
connect(Core(), &CutterCore::functionRenamed, this, &DisassemblerGraphView::refreshView);
|
||||
connect(Core(), &CutterCore::flagsChanged, this, &DisassemblerGraphView::refreshView);
|
||||
connect(Core(), &CutterCore::globalVarsChanged, this, &DisassemblerGraphView::refreshView);
|
||||
connect(Core(), &CutterCore::varsChanged, this, &DisassemblerGraphView::refreshView);
|
||||
connect(Core(), &CutterCore::instructionChanged, this, &DisassemblerGraphView::refreshView);
|
||||
connect(Core(), &CutterCore::breakpointsChanged, this, &DisassemblerGraphView::refreshView);
|
||||
@ -534,17 +535,16 @@ GraphView::EdgeConfiguration DisassemblerGraphView::edgeConfiguration(GraphView:
|
||||
|
||||
bool DisassemblerGraphView::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::Type::ToolTip && Config()->getGraphPreview()) {
|
||||
if ((Config()->getGraphPreview() || Config()->getShowVarTooltips())
|
||||
&& event->type() == QEvent::Type::ToolTip) {
|
||||
|
||||
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
|
||||
QPoint pointOfEvent = helpEvent->globalPos();
|
||||
QPoint point = viewToLogicalCoordinates(helpEvent->pos());
|
||||
|
||||
GraphBlock *block = getBlockContaining(point);
|
||||
|
||||
if (block == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (auto block = getBlockContaining(point)) {
|
||||
// Get pos relative to start of block
|
||||
QPoint pos = point - QPoint(block->x, block->y);
|
||||
|
||||
// offsetFrom is the address which on top the cursor triggered this
|
||||
RVA offsetFrom = RVA_INVALID;
|
||||
@ -553,14 +553,26 @@ bool DisassemblerGraphView::eventFilter(QObject *obj, QEvent *event)
|
||||
* getAddrForMouseEvent() doesn't work for jmps, like
|
||||
* getInstrForMouseEvent() with false as a 3rd argument.
|
||||
*/
|
||||
Instr *inst = getInstrForMouseEvent(*block, &point, true);
|
||||
Instr *inst = getInstrForMouseEvent(*block, &pos, true);
|
||||
if (inst != nullptr) {
|
||||
offsetFrom = inst->addr;
|
||||
}
|
||||
|
||||
// Don't preview anything for a small scale
|
||||
if (getViewScale() >= 0.8) {
|
||||
return DisassemblyPreview::showDisasPreview(this, pointOfEvent, offsetFrom);
|
||||
if (Config()->getGraphPreview()
|
||||
&& DisassemblyPreview::showDisasPreview(this, pointOfEvent, offsetFrom)) {
|
||||
return true;
|
||||
}
|
||||
if (Config()->getShowVarTooltips() && inst) {
|
||||
auto token = getToken(inst, pos.x());
|
||||
if (token
|
||||
&& DisassemblyPreview::showDebugValueTooltip(this, pointOfEvent,
|
||||
token->content, offsetFrom)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return CutterGraphView::eventFilter(obj, event);
|
||||
|
@ -128,6 +128,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main)
|
||||
|
||||
connect(Core(), &CutterCore::commentsChanged, this, [this]() { refreshDisasm(); });
|
||||
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshDisasm()));
|
||||
connect(Core(), SIGNAL(globalVarsChanged()), this, SLOT(refreshDisasm()));
|
||||
connect(Core(), SIGNAL(functionsChanged()), this, SLOT(refreshDisasm()));
|
||||
connect(Core(), &CutterCore::functionRenamed, this, [this]() { refreshDisasm(); });
|
||||
connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshDisasm()));
|
||||
@ -333,6 +334,7 @@ void DisassemblyWidget::scrollInstructions(int count)
|
||||
}
|
||||
|
||||
refreshDisasm(offset);
|
||||
topOffsetHistory[topOffsetHistoryPos] = offset;
|
||||
}
|
||||
|
||||
bool DisassemblyWidget::updateMaxLines()
|
||||
@ -629,21 +631,29 @@ bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
&& (obj == mDisasTextEdit || obj == mDisasTextEdit->viewport())) {
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
|
||||
if (mouseEvent->button() == Qt::LeftButton) {
|
||||
const QTextCursor &cursor = mDisasTextEdit->cursorForPosition(mouseEvent->pos());
|
||||
jumpToOffsetUnderCursor(cursor);
|
||||
|
||||
return true;
|
||||
} else if (Config()->getPreviewValue()
|
||||
&& event->type() == QEvent::ToolTip
|
||||
&& obj == mDisasTextEdit->viewport()) {
|
||||
}
|
||||
} else if ((Config()->getPreviewValue() || Config()->getShowVarTooltips())
|
||||
&& event->type() == QEvent::ToolTip && obj == mDisasTextEdit->viewport()) {
|
||||
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
|
||||
|
||||
auto cursorForWord = mDisasTextEdit->cursorForPosition(helpEvent->pos());
|
||||
cursorForWord.select(QTextCursor::WordUnderCursor);
|
||||
|
||||
RVA offsetFrom = DisassemblyPreview::readDisassemblyOffset(cursorForWord);
|
||||
|
||||
return DisassemblyPreview::showDisasPreview(this, helpEvent->globalPos(), offsetFrom);
|
||||
if (Config()->getPreviewValue()
|
||||
&& DisassemblyPreview::showDisasPreview(this, helpEvent->globalPos(), offsetFrom)) {
|
||||
return true;
|
||||
}
|
||||
if (Config()->getShowVarTooltips()
|
||||
&& DisassemblyPreview::showDebugValueTooltip(
|
||||
this, helpEvent->globalPos(), cursorForWord.selectedText(), offsetFrom)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return MemoryDockWidget::eventFilter(obj, event);
|
||||
@ -664,19 +674,34 @@ QString DisassemblyWidget::getWindowTitle() const
|
||||
return tr("Disassembly");
|
||||
}
|
||||
|
||||
void DisassemblyWidget::on_seekChanged(RVA offset)
|
||||
void DisassemblyWidget::on_seekChanged(RVA offset, CutterCore::SeekHistoryType type)
|
||||
{
|
||||
if (type == CutterCore::SeekHistoryType::New) {
|
||||
// Erase previous history past this point.
|
||||
if (topOffsetHistory.size() > topOffsetHistoryPos + 1) {
|
||||
topOffsetHistory.erase(topOffsetHistory.begin() + topOffsetHistoryPos + 1,
|
||||
topOffsetHistory.end());
|
||||
}
|
||||
topOffsetHistory.push_back(offset);
|
||||
topOffsetHistoryPos = topOffsetHistory.size() - 1;
|
||||
} else if (type == CutterCore::SeekHistoryType::Undo) {
|
||||
--topOffsetHistoryPos;
|
||||
} else if (type == CutterCore::SeekHistoryType::Redo) {
|
||||
++topOffsetHistoryPos;
|
||||
}
|
||||
if (!seekFromCursor) {
|
||||
cursorLineOffset = 0;
|
||||
cursorCharOffset = 0;
|
||||
}
|
||||
|
||||
if (topOffset != RVA_INVALID && offset >= topOffset && offset <= bottomOffset) {
|
||||
if (topOffset != RVA_INVALID && offset >= topOffset && offset <= bottomOffset
|
||||
&& type == CutterCore::SeekHistoryType::New) {
|
||||
// if the line with the seek offset is currently visible, just move the cursor there
|
||||
updateCursorPosition();
|
||||
topOffsetHistory[topOffsetHistoryPos] = topOffset;
|
||||
} else {
|
||||
// otherwise scroll there
|
||||
refreshDisasm(offset);
|
||||
refreshDisasm(topOffsetHistory[topOffsetHistoryPos]);
|
||||
}
|
||||
mCtxMenu->setOffset(offset);
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public slots:
|
||||
QList<DisassemblyLine> getLines();
|
||||
|
||||
protected slots:
|
||||
void on_seekChanged(RVA offset);
|
||||
void on_seekChanged(RVA offset, CutterCore::SeekHistoryType type);
|
||||
void refreshIfInRange(RVA offset);
|
||||
void instructionChanged(RVA offset);
|
||||
void refreshDisasm(RVA offset = RVA_INVALID);
|
||||
@ -88,6 +88,9 @@ private:
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
QString getWindowTitle() const override;
|
||||
|
||||
int topOffsetHistoryPos = 0;
|
||||
QList<RVA> topOffsetHistory;
|
||||
|
||||
QList<RVA> breakpoints;
|
||||
|
||||
void setupFonts();
|
||||
|
@ -234,9 +234,8 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const
|
||||
QStringList summary {};
|
||||
{
|
||||
auto seeker = Core()->seekTemp(function.offset);
|
||||
auto strings = fromOwnedCharPtr(
|
||||
rz_core_print_disasm_strings(Core()->core(), RZ_CORE_DISASM_STRINGS_MODE_FUNCTION,
|
||||
0, NULL));
|
||||
auto strings = fromOwnedCharPtr(rz_core_print_disasm_strings(
|
||||
Core()->core(), RZ_CORE_DISASM_STRINGS_MODE_FUNCTION, 0, NULL));
|
||||
summary = strings.split('\n', CUTTER_QT_SKIP_EMPTY_PARTS);
|
||||
}
|
||||
|
||||
@ -508,6 +507,7 @@ FunctionsWidget::FunctionsWidget(MainWindow *main)
|
||||
functionProxyModel = new FunctionSortFilterProxyModel(functionModel, this);
|
||||
setModels(functionProxyModel);
|
||||
ui->treeView->sortByColumn(FunctionModel::NameColumn, Qt::AscendingOrder);
|
||||
ui->treeView->setExpandsOnDoubleClick(false);
|
||||
|
||||
titleContextMenu = new QMenu(this);
|
||||
auto viewTypeGroup = new QActionGroup(titleContextMenu);
|
||||
|
228
src/widgets/GlobalsWidget.cpp
Normal file
228
src/widgets/GlobalsWidget.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
#include "GlobalsWidget.h"
|
||||
#include "ui_GlobalsWidget.h"
|
||||
#include "core/MainWindow.h"
|
||||
#include "common/Helpers.h"
|
||||
#include "dialogs/GlobalVariableDialog.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QShortcut>
|
||||
|
||||
GlobalsModel::GlobalsModel(QList<GlobalDescription> *globals, QObject *parent)
|
||||
: AddressableItemModel<QAbstractListModel>(parent), globals(globals)
|
||||
{
|
||||
}
|
||||
|
||||
int GlobalsModel::rowCount(const QModelIndex &) const
|
||||
{
|
||||
return globals->count();
|
||||
}
|
||||
|
||||
int GlobalsModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return GlobalsModel::ColumnCount;
|
||||
}
|
||||
|
||||
QVariant GlobalsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (index.row() >= globals->count()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const GlobalDescription &global = globals->at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (index.column()) {
|
||||
case GlobalsModel::AddressColumn:
|
||||
return RzAddressString(global.addr);
|
||||
case GlobalsModel::TypeColumn:
|
||||
return QString(global.type).trimmed();
|
||||
case GlobalsModel::NameColumn:
|
||||
return global.name;
|
||||
case GlobalsModel::CommentColumn:
|
||||
return Core()->getCommentAt(global.addr);
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
case GlobalsModel::GlobalDescriptionRole:
|
||||
return QVariant::fromValue(global);
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant GlobalsModel::headerData(int section, Qt::Orientation, int role) const
|
||||
{
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (section) {
|
||||
case GlobalsModel::AddressColumn:
|
||||
return tr("Address");
|
||||
case GlobalsModel::TypeColumn:
|
||||
return tr("Type");
|
||||
case GlobalsModel::NameColumn:
|
||||
return tr("Name");
|
||||
case GlobalsModel::CommentColumn:
|
||||
return tr("Comment");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
RVA GlobalsModel::address(const QModelIndex &index) const
|
||||
{
|
||||
const GlobalDescription &global = globals->at(index.row());
|
||||
return global.addr;
|
||||
}
|
||||
|
||||
QString GlobalsModel::name(const QModelIndex &index) const
|
||||
{
|
||||
const GlobalDescription &global = globals->at(index.row());
|
||||
return global.name;
|
||||
}
|
||||
|
||||
GlobalsProxyModel::GlobalsProxyModel(GlobalsModel *sourceModel, QObject *parent)
|
||||
: AddressableFilterProxyModel(sourceModel, parent)
|
||||
{
|
||||
setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
bool GlobalsProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||
{
|
||||
QModelIndex index = sourceModel()->index(row, 0, parent);
|
||||
auto global = index.data(GlobalsModel::GlobalDescriptionRole).value<GlobalDescription>();
|
||||
|
||||
return qhelpers::filterStringContains(global.name, this);
|
||||
}
|
||||
|
||||
bool GlobalsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
{
|
||||
auto leftGlobal = left.data(GlobalsModel::GlobalDescriptionRole).value<GlobalDescription>();
|
||||
auto rightGlobal = right.data(GlobalsModel::GlobalDescriptionRole).value<GlobalDescription>();
|
||||
|
||||
switch (left.column()) {
|
||||
case GlobalsModel::AddressColumn:
|
||||
return leftGlobal.addr < rightGlobal.addr;
|
||||
case GlobalsModel::TypeColumn:
|
||||
return leftGlobal.type < rightGlobal.type;
|
||||
case GlobalsModel::NameColumn:
|
||||
return leftGlobal.name < rightGlobal.name;
|
||||
case GlobalsModel::CommentColumn:
|
||||
return Core()->getCommentAt(leftGlobal.addr) < Core()->getCommentAt(rightGlobal.addr);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GlobalsWidget::editGlobal()
|
||||
{
|
||||
QModelIndex index = ui->treeView->currentIndex();
|
||||
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RVA globalVariableAddress = globalsModel->address(index);
|
||||
|
||||
GlobalVariableDialog dialog(globalVariableAddress, parentWidget());
|
||||
dialog.exec();
|
||||
}
|
||||
|
||||
void GlobalsWidget::deleteGlobal()
|
||||
{
|
||||
QModelIndex index = ui->treeView->currentIndex();
|
||||
|
||||
if (!index.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RVA globalVariableAddress = globalsModel->address(index);
|
||||
Core()->delGlobalVariable(globalVariableAddress);
|
||||
}
|
||||
|
||||
void GlobalsWidget::showGlobalsContextMenu(const QPoint &pt)
|
||||
{
|
||||
QModelIndex index = ui->treeView->indexAt(pt);
|
||||
|
||||
QMenu menu(ui->treeView);
|
||||
|
||||
if (index.isValid()) {
|
||||
menu.addAction(actionEditGlobal);
|
||||
menu.addAction(actionDeleteGlobal);
|
||||
}
|
||||
|
||||
menu.exec(ui->treeView->mapToGlobal(pt));
|
||||
}
|
||||
|
||||
GlobalsWidget::GlobalsWidget(MainWindow *main)
|
||||
: CutterDockWidget(main), ui(new Ui::GlobalsWidget), tree(new CutterTreeWidget(this))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->quickFilterView->setLabelText(tr("Category"));
|
||||
|
||||
setWindowTitle(tr("Globals"));
|
||||
setObjectName("GlobalsWidget");
|
||||
|
||||
// Add status bar which displays the count
|
||||
tree->addStatusBar(ui->verticalLayout);
|
||||
|
||||
// Set single select mode
|
||||
ui->treeView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
// Setup up the model and the proxy model
|
||||
globalsModel = new GlobalsModel(&globals, this);
|
||||
globalsProxyModel = new GlobalsProxyModel(globalsModel, this);
|
||||
ui->treeView->setModel(globalsProxyModel);
|
||||
ui->treeView->sortByColumn(GlobalsModel::AddressColumn, Qt::AscendingOrder);
|
||||
|
||||
// Setup custom context menu
|
||||
connect(ui->treeView, &QWidget::customContextMenuRequested, this,
|
||||
&GlobalsWidget::showGlobalsContextMenu);
|
||||
|
||||
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(ui->quickFilterView, &ComboQuickFilterView::filterTextChanged, globalsProxyModel,
|
||||
&QSortFilterProxyModel::setFilterWildcard);
|
||||
|
||||
connect(ui->quickFilterView, &ComboQuickFilterView::filterTextChanged, this,
|
||||
[this] { tree->showItemsNumber(globalsProxyModel->rowCount()); });
|
||||
|
||||
QShortcut *searchShortcut = new QShortcut(QKeySequence::Find, this);
|
||||
connect(searchShortcut, &QShortcut::activated, ui->quickFilterView,
|
||||
&ComboQuickFilterView::showFilter);
|
||||
searchShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||
|
||||
QShortcut *clearShortcut = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||
connect(clearShortcut, &QShortcut::activated, ui->quickFilterView,
|
||||
&ComboQuickFilterView::clearFilter);
|
||||
clearShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||
|
||||
actionEditGlobal = new QAction(tr("Edit Global Variable"), this);
|
||||
actionDeleteGlobal = new QAction(tr("Delete Global Variable"), this);
|
||||
|
||||
connect(actionEditGlobal, &QAction::triggered, [this]() { editGlobal(); });
|
||||
connect(actionDeleteGlobal, &QAction::triggered, [this]() { deleteGlobal(); });
|
||||
|
||||
connect(Core(), &CutterCore::globalVarsChanged, this, &GlobalsWidget::refreshGlobals);
|
||||
connect(Core(), &CutterCore::codeRebased, this, &GlobalsWidget::refreshGlobals);
|
||||
connect(Core(), &CutterCore::refreshAll, this, &GlobalsWidget::refreshGlobals);
|
||||
connect(Core(), &CutterCore::commentsChanged, this,
|
||||
[this]() { qhelpers::emitColumnChanged(globalsModel, GlobalsModel::CommentColumn); });
|
||||
}
|
||||
|
||||
GlobalsWidget::~GlobalsWidget() {}
|
||||
|
||||
void GlobalsWidget::refreshGlobals()
|
||||
{
|
||||
globalsModel->beginResetModel();
|
||||
globals = Core()->getAllGlobals();
|
||||
globalsModel->endResetModel();
|
||||
|
||||
qhelpers::adjustColumns(ui->treeView, GlobalsModel::ColumnCount, 0);
|
||||
}
|
89
src/widgets/GlobalsWidget.h
Normal file
89
src/widgets/GlobalsWidget.h
Normal file
@ -0,0 +1,89 @@
|
||||
#ifndef GLOBALSWIDGET_H
|
||||
#define GLOBALSWIDGET_H
|
||||
|
||||
#include <memory>
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "core/Cutter.h"
|
||||
#include "CutterDockWidget.h"
|
||||
#include "widgets/ListDockWidget.h"
|
||||
|
||||
class MainWindow;
|
||||
class QTreeWidget;
|
||||
class GlobalsWidget;
|
||||
|
||||
namespace Ui {
|
||||
class GlobalsWidget;
|
||||
}
|
||||
|
||||
class MainWindow;
|
||||
class QTreeWidgetItem;
|
||||
|
||||
class GlobalsModel : public AddressableItemModel<QAbstractListModel>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend GlobalsWidget;
|
||||
|
||||
private:
|
||||
QList<GlobalDescription> *globals;
|
||||
|
||||
public:
|
||||
enum Column { AddressColumn = 0, TypeColumn, NameColumn, CommentColumn, ColumnCount };
|
||||
enum Role { GlobalDescriptionRole = Qt::UserRole };
|
||||
|
||||
GlobalsModel(QList<GlobalDescription> *exports, QObject *parent = nullptr);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
class GlobalsProxyModel : public AddressableFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GlobalsProxyModel(GlobalsModel *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 GlobalsWidget : public CutterDockWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GlobalsWidget(MainWindow *main);
|
||||
~GlobalsWidget();
|
||||
|
||||
private slots:
|
||||
void refreshGlobals();
|
||||
|
||||
void showGlobalsContextMenu(const QPoint &pt);
|
||||
|
||||
void editGlobal();
|
||||
void deleteGlobal();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::GlobalsWidget> ui;
|
||||
|
||||
QList<GlobalDescription> globals;
|
||||
GlobalsModel *globalsModel;
|
||||
GlobalsProxyModel *globalsProxyModel;
|
||||
CutterTreeWidget *tree;
|
||||
|
||||
QAction *actionEditGlobal;
|
||||
QAction *actionDeleteGlobal;
|
||||
};
|
||||
|
||||
#endif // GLOBALSWIDGET_H
|
107
src/widgets/GlobalsWidget.ui
Normal file
107
src/widgets/GlobalsWidget.ui
Normal file
@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GlobalsWidget</class>
|
||||
<widget class="QDockWidget" name="GlobalsWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Global Variables</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CutterTreeView" name="treeView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">CutterTreeView::item
|
||||
{
|
||||
padding-top: 1px;
|
||||
padding-bottom: 1px;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="indentation">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="ComboQuickFilterView" name="quickFilterView" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<action name="actionEditGlobal">
|
||||
<property name="text">
|
||||
<string>Edit Global Variable</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Edit Global Variable</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDeleteGlobal">
|
||||
<property name="text">
|
||||
<string>Delete Global Variable</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Delete Global Variable</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CutterTreeView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>widgets/CutterTreeView.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ComboQuickFilterView</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>widgets/ComboQuickFilterView.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -438,7 +438,7 @@ void GraphView::saveAsSvg(QString path)
|
||||
generator.setFileName(path);
|
||||
generator.setSize(QSize(width, height));
|
||||
generator.setViewBox(QRect(0, 0, width, height));
|
||||
generator.setTitle("Cutter graph export");
|
||||
generator.setTitle(tr("Cutter graph export"));
|
||||
QPainter p;
|
||||
p.begin(&generator);
|
||||
paint(p, QPoint(0, 0), QRect(0, 0, width, height), 1.0, false);
|
||||
|
@ -36,8 +36,7 @@ void HeapBinsGraphView::loadCurrentGraph()
|
||||
|| QString(heapBin->type) == QString("Tcache");
|
||||
|
||||
// store info about the chunks in a vector for easy access
|
||||
CutterRzListForeach(heapBin->chunks, iter, RzHeapChunkListItem, item)
|
||||
{
|
||||
CutterRzListForeach (heapBin->chunks, iter, RzHeapChunkListItem, item) {
|
||||
GraphHeapChunk graphHeapChunk;
|
||||
graphHeapChunk.addr = item->addr;
|
||||
RzHeapChunkSimple *chunkInfo = Core()->getHeapChunk(item->addr);
|
||||
|
@ -1407,8 +1407,8 @@ void HexWidget::w_writeRandom()
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
int nbytes = QInputDialog::getInt(this, tr("Write random bytes"), tr("Number of bytes:"), size, 1,
|
||||
0x7FFFFFFF, 1, &ok);
|
||||
int nbytes = QInputDialog::getInt(this, tr("Write random bytes"), tr("Number of bytes:"), size,
|
||||
1, 0x7FFFFFFF, 1, &ok);
|
||||
if (!ok) {
|
||||
return;
|
||||
}
|
||||
|
@ -248,19 +248,24 @@ void HexdumpWidget::updateParseWindow(RVA start_address, int size)
|
||||
ut64 old_offset = core->offset;
|
||||
rz_core_seek(core, start_address, true);
|
||||
ut8 *block = core->block;
|
||||
char *digest = rz_hash_cfg_calculate_small_block_string(core->hash, "md5", block, size, &digest_size, false);
|
||||
char *digest = rz_hash_cfg_calculate_small_block_string(core->hash, "md5", block, size,
|
||||
&digest_size, false);
|
||||
ui->bytesMD5->setText(QString(digest));
|
||||
free(digest);
|
||||
digest = rz_hash_cfg_calculate_small_block_string(core->hash, "sha1", block, size, &digest_size, false);
|
||||
digest = rz_hash_cfg_calculate_small_block_string(core->hash, "sha1", block, size,
|
||||
&digest_size, false);
|
||||
ui->bytesSHA1->setText(QString(digest));
|
||||
free(digest);
|
||||
digest = rz_hash_cfg_calculate_small_block_string(core->hash, "sha256", block, size, &digest_size, false);
|
||||
digest = rz_hash_cfg_calculate_small_block_string(core->hash, "sha256", block, size,
|
||||
&digest_size, false);
|
||||
ui->bytesSHA256->setText(QString(digest));
|
||||
free(digest);
|
||||
digest = rz_hash_cfg_calculate_small_block_string(core->hash, "crc32", block, size, &digest_size, false);
|
||||
digest = rz_hash_cfg_calculate_small_block_string(core->hash, "crc32", block, size,
|
||||
&digest_size, false);
|
||||
ui->bytesCRC32->setText(QString(digest));
|
||||
free(digest);
|
||||
digest = rz_hash_cfg_calculate_small_block_string(core->hash, "entropy", block, size, &digest_size, false);
|
||||
digest = rz_hash_cfg_calculate_small_block_string(core->hash, "entropy", block, size,
|
||||
&digest_size, false);
|
||||
ui->bytesEntropy->setText(QString(digest));
|
||||
free(digest);
|
||||
rz_core_seek(core, old_offset, true);
|
||||
|
@ -2,7 +2,6 @@
|
||||
#include "ui_ListDockWidget.h"
|
||||
#include "core/MainWindow.h"
|
||||
#include "common/Helpers.h"
|
||||
#include "menus/AddressableItemContextMenu.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QResizeEvent>
|
||||
|
@ -16,7 +16,7 @@ QuickFilterView::QuickFilterView(QWidget *parent, bool defaultOn)
|
||||
[this]() { emit filterTextChanged(ui->filterLineEdit->text()); });
|
||||
|
||||
connect(ui->filterLineEdit, &QLineEdit::textChanged, this,
|
||||
[this](const QString &text) { debounceTimer->start(150); });
|
||||
[this]() { debounceTimer->start(150); });
|
||||
|
||||
if (!defaultOn) {
|
||||
closeFilter();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user