mirror of
https://github.com/rizinorg/cutter.git
synced 2024-11-23 04:49:49 +00:00
Add crash handling system using Breakpad (#1439)
This commit is contained in:
parent
b6406e6ac6
commit
1cb314d674
@ -45,10 +45,11 @@ install:
|
||||
|
||||
before_build:
|
||||
- cmd: git submodule update --init
|
||||
- scripts\prepare_breakpad.bat
|
||||
|
||||
# Build config
|
||||
build_script:
|
||||
- cmd: if defined QMAKE ( call prepare_r2.bat && call build.bat CUTTER_APPVEYOR_R2DEC=true CUTTER_ENABLE_PYTHON=true CUTTER_ENABLE_PYTHON_BINDINGS=true SHIBOKEN_EXECUTABLE="%CUTTER_DEPS_DIR%\pyside\bin\shiboken2.exe" SHIBOKEN_INCLUDEDIR="%CUTTER_DEPS_DIR%/pyside/include/shiboken2" SHIBOKEN_LIBRARY="%CUTTER_DEPS_DIR%/pyside/lib/shiboken2.lib" PYSIDE_INCLUDEDIR="%CUTTER_DEPS_DIR%/pyside/include/PySide2" PYSIDE_LIBRARY="%CUTTER_DEPS_DIR%/pyside/lib/pyside2.lib" PYSIDE_TYPESYSTEMS="%CUTTER_DEPS_DIR%/pyside/share/PySide2/typesystems")
|
||||
- cmd: if defined QMAKE ( call prepare_r2.bat && call build.bat CUTTER_APPVEYOR_R2DEC=true CUTTER_ENABLE_CRASH_REPORTS=true CUTTER_ENABLE_PYTHON=true CUTTER_ENABLE_PYTHON_BINDINGS=true SHIBOKEN_EXECUTABLE="%CUTTER_DEPS_DIR%\pyside\bin\shiboken2.exe" SHIBOKEN_INCLUDEDIR="%CUTTER_DEPS_DIR%/pyside/include/shiboken2" SHIBOKEN_LIBRARY="%CUTTER_DEPS_DIR%/pyside/lib/shiboken2.lib" PYSIDE_INCLUDEDIR="%CUTTER_DEPS_DIR%/pyside/include/PySide2" PYSIDE_LIBRARY="%CUTTER_DEPS_DIR%/pyside/lib/pyside2.lib" PYSIDE_TYPESYSTEMS="%CUTTER_DEPS_DIR%/pyside/share/PySide2/typesystems")
|
||||
- cmd: if defined MESON ( python meson.py --release --dist=%ARTIFACT_PATH% --backend=%BACKEND% --python )
|
||||
|
||||
after_build:
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -71,3 +71,5 @@ compile_commands.json
|
||||
|
||||
# cutter-deps
|
||||
/cutter-deps
|
||||
|
||||
/breakpad
|
||||
|
18
.travis.yml
18
.travis.yml
@ -68,8 +68,14 @@ addons:
|
||||
install:
|
||||
- scripts/fetch_deps.sh
|
||||
- source cutter-deps/env.sh
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export PATH=/usr/local/opt/llvm/bin:$PATH; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export LD_LIBRARY_PATH="`llvm-config --libdir`:$LD_LIBRARY_PATH"; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
export PATH=/usr/local/opt/llvm/bin:$PATH;
|
||||
source scripts/prepare_breakpad_macos.sh;
|
||||
fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||
export LD_LIBRARY_PATH="`llvm-config --libdir`:$LD_LIBRARY_PATH";
|
||||
source scripts/prepare_breakpad_linux.sh;
|
||||
fi
|
||||
|
||||
before_script:
|
||||
- git submodule init ; git submodule update
|
||||
@ -84,11 +90,13 @@ before_script:
|
||||
script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- export PKG_CONFIG_PATH="$CUSTOM_BREAKPAD_PREFIX/lib/pkgconfig:$CUSTOM_PYTHON_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||
if [[ "$BUILD_SYSTEM" == "qmake" ]]; then
|
||||
qmake
|
||||
CUTTER_ENABLE_PYTHON=true
|
||||
CUTTER_ENABLE_PYTHON_BINDINGS=true
|
||||
CUTTER_ENABLE_CRASH_REPORTS=true
|
||||
PREFIX=/usr
|
||||
APPIMAGE=1
|
||||
../src &&
|
||||
@ -101,6 +109,7 @@ script:
|
||||
-DPYTHON_EXECUTABLE="$CUTTER_DEPS_PYTHON_PREFIX/bin/python3"
|
||||
-DCUTTER_ENABLE_PYTHON=ON
|
||||
-DCUTTER_ENABLE_PYTHON_BINDINGS=ON
|
||||
-DCUTTER_ENABLE_CRASH_REPORTS=ON
|
||||
../src &&
|
||||
make -j4;
|
||||
fi
|
||||
@ -110,7 +119,9 @@ script:
|
||||
CUTTER_ENABLE_PYTHON=true
|
||||
CUTTER_ENABLE_PYTHON_BINDINGS=true
|
||||
CUTTER_BUNDLE_R2_APPBUNDLE=true
|
||||
CUTTER_ENABLE_CRASH_REPORTS=true
|
||||
PYTHON_FRAMEWORK_DIR=$CUTTER_DEPS_PYTHON_FRAMEWORK_DIR
|
||||
BREAKPAD_FRAMEWORK_DIR=$BREAKPAD_FRAMEWORK_DIR
|
||||
../src &&
|
||||
make -j4;
|
||||
elif [[ "$BUILD_SYSTEM" == "cmake" ]]; then
|
||||
@ -121,6 +132,8 @@ script:
|
||||
-DPYTHON_EXECUTABLE="$CUTTER_DEPS_PYTHON_PREFIX/bin/python3"
|
||||
-DCUTTER_ENABLE_PYTHON=ON
|
||||
-DCUTTER_ENABLE_PYTHON_BINDINGS=ON
|
||||
-DCUTTER_ENABLE_CRASH_REPORTS=ON
|
||||
-DBREAKPAD_FRAMEWORK_DIR="$BREAKPAD_FRAMEWORK_DIR"
|
||||
../src &&
|
||||
make -j4;
|
||||
fi
|
||||
@ -135,6 +148,7 @@ after_success:
|
||||
macdeployqt Cutter.app -executable=Cutter.app/Contents/MacOS/Cutter -libpath="../Frameworks" &&
|
||||
macdeployqt Cutter.app -executable=Cutter.app/Contents/MacOS/Cutter -libpath="../Frameworks" &&
|
||||
cp -a "$QTDIR/lib/QtDBus.framework" "$QTDIR/lib/QtPrintSupport.framework" Cutter.app/Contents/Frameworks &&
|
||||
cp -a "$BREAKPAD_FRAMEWORK_DIR/Breakpad.framework" Cutter.app/Contents/Frameworks &&
|
||||
"$TRAVIS_BUILD_DIR/scripts/appbundle_embed_python.sh" "$CUTTER_DEPS_PYTHON_FRAMEWORK_DIR/Python.framework" Cutter.app Cutter.app/Contents/MacOS/Cutter &&
|
||||
mv Cutter.app/Contents/MacOS/Cutter Cutter.app/Contents/MacOS/Cutter.bin &&
|
||||
cp ../src/macos/Cutter.sh Cutter.app/Contents/MacOS/Cutter &&
|
||||
|
10
build.bat
10
build.bat
@ -1,5 +1,6 @@
|
||||
@ECHO off
|
||||
SETLOCAL ENABLEDELAYEDEXPANSION
|
||||
SETLOCAL ENABLEEXTENSIONS
|
||||
|
||||
IF "%VisualStudioVersion%" == "14.0" ( IF NOT DEFINED Platform SET "Platform=X86" )
|
||||
FOR /F %%i IN ('powershell -c "\"%Platform%\".toLower()"') DO SET PLATFORM=%%i
|
||||
@ -11,6 +12,7 @@ IF !ERRORLEVEL! NEQ 0 (
|
||||
|
||||
SET "R2DIST=r2_dist_%PLATFORM%"
|
||||
SET "BUILDDIR=build_%PLATFORM%"
|
||||
SET "BREAKPAD_SOURCE_DIR=%CD%\src\breakpad\src\src"
|
||||
|
||||
ECHO Preparing directory
|
||||
RMDIR /S /Q %BUILDDIR%
|
||||
@ -21,8 +23,12 @@ FOR %%i in (src\translations\*.ts) DO lrelease %%i
|
||||
|
||||
CD %BUILDDIR%
|
||||
|
||||
IF NOT DEFINED CUTTER_ENABLE_CRASH_REPORTS (
|
||||
SET "CUTTER_ENABLE_CRASH_REPORTS=false"
|
||||
)
|
||||
|
||||
ECHO Building cutter
|
||||
qmake %* ..\src\cutter.pro -config release
|
||||
qmake BREAKPAD_SOURCE_DIR=%BREAKPAD_SOURCE_DIR% CUTTER_ENABLE_CRASH_REPORTS=%CUTTER_ENABLE_CRASH_REPORTS% %* ..\src\cutter.pro -config release
|
||||
IF !ERRORLEVEL! NEQ 0 EXIT /B 1
|
||||
nmake
|
||||
IF !ERRORLEVEL! NEQ 0 EXIT /B 1
|
||||
@ -34,3 +40,5 @@ XCOPY /S /I ..\%R2DIST%\radare2 cutter\radare2
|
||||
COPY ..\%R2DIST%\*.dll cutter\
|
||||
windeployqt cutter\cutter.exe
|
||||
FOR %%i in (..\src\translations\*.qm) DO MOVE "%%~fi" cutter\translations
|
||||
|
||||
ENDLOCAL
|
||||
|
13
build.sh
13
build.sh
@ -6,7 +6,7 @@
|
||||
ERR=0
|
||||
|
||||
#### User variables ####
|
||||
BUILD="build"
|
||||
BUILD="`pwd`/build"
|
||||
QMAKE_CONF=""
|
||||
ROOT_DIR=`pwd`
|
||||
|
||||
@ -63,6 +63,16 @@ find_gmake() {
|
||||
echo "$gmakepath"
|
||||
}
|
||||
|
||||
prepare_breakpad() {
|
||||
if [[ $OSTYPE == "linux-gnu" ]]; then
|
||||
source $ROOT_DIR/scripts/prepare_breakpad_linux.sh
|
||||
export PKG_CONFIG_PATH="$CUSTOM_BREAKPAD_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
elif [[ $OSTYPE == "darwin" ]]; then
|
||||
source $ROOT_DIR/scripts/prepare_breakpad_macos.sh
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Build radare2
|
||||
check_r2
|
||||
if [ $? -eq 1 ]; then
|
||||
@ -86,6 +96,7 @@ fi
|
||||
$(find_lrelease) ./src/Cutter.pro
|
||||
|
||||
# Build
|
||||
prepare_breakpad
|
||||
mkdir -p "$BUILD"
|
||||
cd "$BUILD" || exit 1
|
||||
$(find_qmake) ../src/Cutter.pro $QMAKE_CONF
|
||||
|
@ -11,9 +11,11 @@ The “official” way to build Cutter is by using qmake, but there are two
|
||||
alternatives – cmake and meson.
|
||||
|
||||
In any case, there are obviously some requirements:
|
||||
- Radare2 installed from submodule
|
||||
- Qt 5.9 or above
|
||||
- Python3.6
|
||||
|
||||
* Radare2 installed from submodule
|
||||
* Qt 5.9 or above
|
||||
* Python3.6
|
||||
* Breakpad installed using script (optional, disabled by default)
|
||||
|
||||
Before compiling, note that we also provide binaries available for
|
||||
windows/linux/MacOS `here <https://github.com/radareorg/cutter/releases>`_.
|
||||
@ -23,9 +25,33 @@ windows/linux/MacOS `here <https://github.com/radareorg/cutter/releases>`_.
|
||||
Building options
|
||||
----------------
|
||||
|
||||
Note that there are two major building options available:
|
||||
- ``CUTTER_ENABLE_PYTHON`` compile with Python support
|
||||
- ``CUTTER_ENABLE_PYTHON_BINDINGS`` automatically generate Python Bindings with Shiboken2, required for Python plugins!
|
||||
Note that there are three major building options available:
|
||||
|
||||
* ``CUTTER_ENABLE_PYTHON`` compile with Python support
|
||||
* ``CUTTER_ENABLE_PYTHON_BINDINGS`` automatically generate Python Bindings with Shiboken2, required for Python plugins!
|
||||
* ``CUTTER_ENABLE_CRASH_REPORTS`` is used to compile Cutter with crash handling system enabled (Breakpad)
|
||||
|
||||
--------------
|
||||
|
||||
Preparing Breakpad
|
||||
-------------------
|
||||
|
||||
If you want to build Cutter with crash handling system, you want prepare Breakpad before.
|
||||
For this simply run one of the scripts (according to your OS) from root Cutter directory:
|
||||
|
||||
.. code:: sh
|
||||
|
||||
source scripts/prepare_breakpad_linux.sh # Linux
|
||||
source scripts/prepare_breakpad_macos.sh # MacOS
|
||||
scripts/prepare_breakpad.bat # Windows
|
||||
|
||||
Then if you are building on Linux you want to change ``PKG_CONFIG_PATH`` environment variable
|
||||
so it contains ``$CUSTOM_BREAKPAD_PREFIX/lib/pkgconfig``. For this simply run
|
||||
|
||||
.. code:: sh
|
||||
|
||||
export PKG_CONFIG_PATH="$CUSTOM_BREAKPAD_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
|
||||
|
||||
--------------
|
||||
|
||||
@ -73,12 +99,12 @@ Building on Linux
|
||||
The root for CMake is in src/. In-source builds are **not allowed**, so
|
||||
you **must** run CMake from a separate directory:
|
||||
|
||||
::
|
||||
.. code:: sh
|
||||
|
||||
cd src
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
cmake .. # Don't forget to provide build options
|
||||
|
||||
If all went well, you should now have a working Makefile in your build
|
||||
directory:
|
||||
|
32
docs/source/crash-handling-system.rst
Normal file
32
docs/source/crash-handling-system.rst
Normal file
@ -0,0 +1,32 @@
|
||||
Crash Handling System
|
||||
=====================
|
||||
|
||||
Cutter uses `Breakpad <https://github.com/google/breakpad>`__ as backend
|
||||
for crash handling.
|
||||
|
||||
Crash Handling System is disabled by default to do not interfere developers from debugging.
|
||||
To enable this system there is building option ``CUTTER_ENABLE_CRASH_REPORTS``.
|
||||
|
||||
Solution description
|
||||
--------------------
|
||||
|
||||
There are only 2 source files:
|
||||
|
||||
* ``CrashHandler.h``
|
||||
* ``CrashHandler.cpp``
|
||||
|
||||
And API is very simple: only one function - ``initCrashHandler()`` that enables Crash Handling System if
|
||||
``CUTTER_ENABLE_CRASH_REPORTS`` is true, otherwise does nothing.
|
||||
|
||||
As soon as signal is raised ``crashHandler(int signum)`` is called with signal's code as argument.
|
||||
This function first of all writes crash dump to OS's Temp directory to catch core and memory state
|
||||
as it was at the crash moment.
|
||||
|
||||
Then crash dialog is shown:
|
||||
|
||||
.. image :: images/crash-dialog.png
|
||||
|
||||
If user chose to create crash dump, prepared dump is moved to directory specified by user.
|
||||
And then success dialog is shown:
|
||||
|
||||
.. image :: images/success-dump-dialog.png
|
BIN
docs/source/images/crash-dialog.png
Normal file
BIN
docs/source/images/crash-dialog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
docs/source/images/success-dump-dialog.png
Normal file
BIN
docs/source/images/success-dump-dialog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
34
scripts/breakpad_client.gyp
Normal file
34
scripts/breakpad_client.gyp
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
'includes': [
|
||||
'../../build/common.gypi'
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'build_all',
|
||||
'type': 'none',
|
||||
'dependencies': [
|
||||
'./crash_generation/crash_generation.gyp:*',
|
||||
'./handler/exception_handler.gyp:*',
|
||||
'./sender/crash_report_sender.gyp:*',
|
||||
]
|
||||
},
|
||||
{
|
||||
'target_name': 'common',
|
||||
'type': 'static_library',
|
||||
'include_dirs': [
|
||||
'<(DEPTH)',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'<(DEPTH)',
|
||||
]
|
||||
},
|
||||
'sources': [
|
||||
'<(DEPTH)/common/windows/guid_string.cc',
|
||||
'<(DEPTH)/common/windows/guid_string.h',
|
||||
'<(DEPTH)/common/windows/http_upload.h',
|
||||
'<(DEPTH)/common/windows/string_utils.cc',
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
1377
scripts/breakpad_macos.patch
Normal file
1377
scripts/breakpad_macos.patch
Normal file
File diff suppressed because it is too large
Load Diff
17
scripts/dump_syms.gyp
Normal file
17
scripts/dump_syms.gyp
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
'includes': [
|
||||
'../../../build/common.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'dump_syms',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'dump_syms.cc',
|
||||
],
|
||||
'dependencies': [
|
||||
'../../../common/windows/common_windows.gyp:common_windows_lib',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
29
scripts/prepare_breakpad.bat
Normal file
29
scripts/prepare_breakpad.bat
Normal file
@ -0,0 +1,29 @@
|
||||
@ECHO OFF
|
||||
SET ROOT_DIR=%CD%
|
||||
|
||||
powershell -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; wget https://storage.googleapis.com/chrome-infra/depot_tools.zip -OutFile depot_tools.zip "
|
||||
7z -bd x %ROOT_DIR%\depot_tools.zip -odepot_tools
|
||||
powershell -Command "depot_tools\update_depot_tools"
|
||||
SET BUFF_PATH=%PATH%
|
||||
SET DEPOT_TOOLS=%ROOT_DIR%\depot_tools
|
||||
set PATH=%DEPOT_TOOLS%;%BUFF_PATH%
|
||||
|
||||
mkdir %ROOT_DIR%\src\breakpad
|
||||
CD %ROOT_DIR%\src\breakpad
|
||||
powershell -Command "fetch breakpad"
|
||||
powershell -Command "gclient sync"
|
||||
|
||||
CD %ROOT_DIR%\src\breakpad\src\src\client\windows
|
||||
DEL %CD%\breakpad_client.gyp
|
||||
DEL %CD%\breakpad_client.sln
|
||||
DEL %CD%\common.vcxproj
|
||||
DEL %CD%\common.vcxproj.filters
|
||||
DEL %CD%\build_all.vcxproj
|
||||
COPY %ROOT_DIR%\scripts\breakpad_client.gyp %CD%
|
||||
|
||||
CD %ROOT_DIR%\src\breakpad\src\src
|
||||
powershell -Command "tools\gyp\gyp.bat --no-circular-check client\windows\breakpad_client.gyp -Dwin_release_RuntimeLibrary=2 -Dwin_debug_RuntimeLibrary=2 -Dplatform=%ARCH% -Dconfiguration=release"
|
||||
|
||||
set PATH=%BUFF_PATH%
|
||||
msbuild /m %CD%\client\windows\breakpad_client.sln /p:Configuration=release /p:Platform=%ARCH%
|
||||
CD %ROOT_DIR%
|
9
scripts/prepare_breakpad_linux.sh
Executable file
9
scripts/prepare_breakpad_linux.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
git clone https://github.com/google/breakpad.git
|
||||
cd breakpad
|
||||
git clone https://chromium.googlesource.com/linux-syscall-support src/third_party/lss
|
||||
CFLAGS=-w CXXFLAGS=-w ./configure --prefix=`pwd`/prefix && make -j4 && make install || exit 1
|
||||
|
||||
export CUSTOM_BREAKPAD_PREFIX="`pwd`/prefix"
|
||||
cd ..
|
22
scripts/prepare_breakpad_macos.sh
Executable file
22
scripts/prepare_breakpad_macos.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")")
|
||||
|
||||
DIR="$SCRIPTPATH/.."
|
||||
cd "$DIR" || exit 1
|
||||
BREAKPAD_FRAMEWORK_DIR="$DIR/breakpad/framework"
|
||||
BREAKPAD_DUMP_SYMS_DIR="$DIR/breakpad/bin"
|
||||
git clone https://github.com/google/breakpad.git || exit 1
|
||||
mkdir $BREAKPAD_FRAMEWORK_DIR
|
||||
mkdir $BREAKPAD_DUMP_SYMS_DIR
|
||||
cd breakpad || exit 1
|
||||
git checkout 4d550cceca107f36c4bc1ea1126b7d32cc50f424 || exit 1
|
||||
git apply "$SCRIPTPATH/breakpad_macos.patch" || exit 1
|
||||
cd src/client/mac/ && xcodebuild -sdk macosx || exit 1
|
||||
cp -R build/Release/Breakpad.framework "$BREAKPAD_FRAMEWORK_DIR" || exit 1
|
||||
|
||||
cd $DIR/breakpad || exit 1
|
||||
cp -R src/. framework/Breakpad.framework/Headers || exit 1
|
||||
|
||||
export BREAKPAD_FRAMEWORK_DIR=$BREAKPAD_FRAMEWORK_DIR
|
||||
cd $DIR
|
@ -10,6 +10,7 @@ set(CUTTER_PYTHON_MIN 3.5)
|
||||
|
||||
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_CRASH_REPORTS "Enable crash report system. Unused if CUTTER_ENABLE_CRASH_REPORTS=OFF" OFF)
|
||||
|
||||
if(NOT CUTTER_ENABLE_PYTHON)
|
||||
set(CUTTER_ENABLE_PYTHON_BINDINGS OFF)
|
||||
@ -93,6 +94,7 @@ message(STATUS "Building Cutter version ${CUTTER_VERSION_FULL}")
|
||||
message(STATUS "Options:")
|
||||
message(STATUS "- Python: ${CUTTER_ENABLE_PYTHON}")
|
||||
message(STATUS "- Python Bindings: ${CUTTER_ENABLE_PYTHON_BINDINGS}")
|
||||
message(STATUS "- Crash Handling: ${CUTTER_ENABLE_CRASH_REPORTS}")
|
||||
message(STATUS "")
|
||||
|
||||
|
||||
@ -134,6 +136,24 @@ endif()
|
||||
add_executable(Cutter MACOSX_BUNDLE ${UI_FILES} ${QRC_FILES} ${SOURCE_FILES} ${HEADER_FILES} ${BINDINGS_SOURCE})
|
||||
set_target_properties(Cutter PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/macos/Info.plist")
|
||||
|
||||
if(CUTTER_ENABLE_CRASH_REPORTS)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(Cutter Threads::Threads)
|
||||
|
||||
add_definitions(-DCUTTER_ENABLE_CRASH_REPORTS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g ")
|
||||
if(DEFINED BREAKPAD_FRAMEWORK_DIR)
|
||||
include_directories("${BREAKPAD_FRAMEWORK_DIR}/Breakpad.framework/Headers")
|
||||
set_target_properties(Cutter PROPERTIES LINK_FLAGS "-Wl,-F${BREAKPAD_FRAMEWORK_DIR}")
|
||||
target_link_libraries(Cutter "-framework Breakpad")
|
||||
else()
|
||||
find_package(Breakpad REQUIRED)
|
||||
include_directories(${BREAKPAD_INCLUDE_DIRS})
|
||||
target_link_libraries(Cutter ${BREAKPAD_LINK_LIBRARIES})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(Cutter Qt5::Core Qt5::Widgets Qt5::Gui Qt5::Svg Qt5::Network)
|
||||
target_link_libraries(Cutter ${RADARE2_LIBRARIES})
|
||||
if(CUTTER_ENABLE_PYTHON)
|
||||
|
@ -32,6 +32,8 @@ QT += core gui widgets svg network
|
||||
QT_CONFIG -= no-pkg-config
|
||||
CONFIG += c++11
|
||||
|
||||
!defined(CUTTER_ENABLE_CRASH_REPORTS, var) CUTTER_ENABLE_CRASH_REPORTS=false
|
||||
equals(CUTTER_ENABLE_CRASH_REPORTS, true) CONFIG += CUTTER_ENABLE_CRASH_REPORTS
|
||||
!defined(CUTTER_ENABLE_PYTHON, var) CUTTER_ENABLE_PYTHON=false
|
||||
equals(CUTTER_ENABLE_PYTHON, true) CONFIG += CUTTER_ENABLE_PYTHON
|
||||
|
||||
@ -49,6 +51,13 @@ equals(CUTTER_BUNDLE_R2_APPBUNDLE, true) CONFIG += CUTTER_BUNDLE_R2_APPBU
|
||||
!defined(CUTTER_APPVEYOR_R2DEC, var) CUTTER_APPVEYOR_R2DEC=false
|
||||
equals(CUTTER_APPVEYOR_R2DEC, true) CONFIG += CUTTER_APPVEYOR_R2DEC
|
||||
|
||||
CUTTER_ENABLE_CRASH_REPORTS {
|
||||
message("Crash report support enabled.")
|
||||
DEFINES += CUTTER_ENABLE_CRASH_REPORTS
|
||||
} else {
|
||||
message("Crash report support disabled.")
|
||||
}
|
||||
|
||||
CUTTER_ENABLE_PYTHON {
|
||||
message("Python enabled.")
|
||||
DEFINES += CUTTER_ENABLE_PYTHON
|
||||
@ -188,6 +197,29 @@ CUTTER_ENABLE_PYTHON {
|
||||
}
|
||||
}
|
||||
|
||||
CUTTER_ENABLE_CRASH_REPORTS {
|
||||
QMAKE_CXXFLAGS += -g
|
||||
defined(BREAKPAD_FRAMEWORK_DIR, var)|defined(BREAKPAD_SOURCE_DIR, var) {
|
||||
defined(BREAKPAD_FRAMEWORK_DIR, var) {
|
||||
INCLUDEPATH += $$BREAKPAD_FRAMEWORK_DIR/Breakpad.framework/Headers
|
||||
LIBS += -F$$BREAKPAD_FRAMEWORK_DIR -framework Breakpad
|
||||
}
|
||||
defined(BREAKPAD_SOURCE_DIR, var) {
|
||||
INCLUDEPATH += $$BREAKPAD_SOURCE_DIR
|
||||
win32 {
|
||||
LIBS += -L$$quote($$BREAKPAD_SOURCE_DIR\\client\\windows\\release\\lib) -lexception_handler -lcrash_report_sender -lcrash_generation_server -lcrash_generation_client -lcommon
|
||||
}
|
||||
unix:LIBS += -L$$BREAKPAD_SOURCE_DIR/client/linux -lbreakpad-client
|
||||
macos:error("Please use scripts\prepare_breakpad_macos.sh script to provide breakpad framework.")
|
||||
}
|
||||
} else {
|
||||
CONFIG += link_pkgconfig
|
||||
!packagesExist(breakpad-client) {
|
||||
error("ERROR: Breakpad could not be found. Make sure it is available to pkg-config.")
|
||||
}
|
||||
PKGCONFIG += breakpad-client
|
||||
}
|
||||
}
|
||||
|
||||
macx:CUTTER_BUNDLE_R2_APPBUNDLE {
|
||||
message("Using r2 rom AppBundle")
|
||||
@ -310,6 +342,8 @@ SOURCES += \
|
||||
dialogs/LinkTypeDialog.cpp \
|
||||
common/UpdateWorker.cpp \
|
||||
widgets/MemoryDockWidget.cpp \
|
||||
common/CrashHandler.cpp \
|
||||
common/BugReporting.cpp \
|
||||
common/HighDpiPixmap.cpp \
|
||||
widgets/GraphGridLayout.cpp
|
||||
|
||||
@ -421,6 +455,7 @@ HEADERS += \
|
||||
common/RunScriptTask.h \
|
||||
common/Json.h \
|
||||
dialogs/EditMethodDialog.h \
|
||||
common/CrashHandler.h \
|
||||
dialogs/LoadNewTypesDialog.h \
|
||||
widgets/SdbWidget.h \
|
||||
common/PythonManager.h \
|
||||
@ -429,6 +464,7 @@ HEADERS += \
|
||||
common/UpdateWorker.h \
|
||||
dialogs/LinkTypeDialog.h \
|
||||
widgets/MemoryDockWidget.h \
|
||||
common/BugReporting.h \
|
||||
common/HighDpiPixmap.h \
|
||||
widgets/GraphLayout.h \
|
||||
widgets/GraphGridLayout.h
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "core/MainWindow.h"
|
||||
#include "common/UpdateWorker.h"
|
||||
#include "CutterConfig.h"
|
||||
#include "common/CrashHandler.h"
|
||||
|
||||
/**
|
||||
* @brief Migrate Settings used before Cutter 1.8
|
||||
@ -20,6 +21,8 @@ static void migrateSettings(QSettings &newSettings)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
initCrashHandler();
|
||||
|
||||
qRegisterMetaType<QList<StringDescription>>();
|
||||
qRegisterMetaType<QList<FunctionDescription>>();
|
||||
|
||||
|
46
src/cmake/FindBreakpad.cmake
Normal file
46
src/cmake/FindBreakpad.cmake
Normal file
@ -0,0 +1,46 @@
|
||||
# - Find Breakpad
|
||||
#
|
||||
# BREAKPAD_FOUND - True if Breakpad has been found.
|
||||
# BREAKPAD_INCLUDE_DIRS - Breakpad include directory
|
||||
# BREAKPAD_LIBRARIES - List of libraries when using Breakpad.
|
||||
# BREAKPAD_LIBRARY_DIRS - Breakpad library directories
|
||||
|
||||
if(WIN32)
|
||||
find_path(BREAKPAD_INCLUDE_DIRS
|
||||
HINTS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/breakpad/prefix/include/breakpad")
|
||||
|
||||
set(BREAKPAD_LIBRARY_NAMES
|
||||
BREAKPAD_CLIENT
|
||||
BREAKPAD)
|
||||
|
||||
set(BREAKPAD_LIBRARIES "")
|
||||
set(BREAKPAD_LIBRARIES_VARS "")
|
||||
foreach(libname ${BREAKPAD_LIBRARY_NAMES})
|
||||
find_library(BREAKPAD_LIBRARY_${libname}
|
||||
${libname}
|
||||
HINTS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/breakpad/prefix/lib")
|
||||
|
||||
list(APPEND BREAKPAD_LIBRARIES ${BREAKPAD_LIBRARY_${libname}})
|
||||
list(APPEND BREAKPAD_LIBRARIES_VARS "BREAKPAD_LIBRARY_${libname}")
|
||||
endforeach()
|
||||
|
||||
set(BREAKPAD_LIBRARY_DIRS "")
|
||||
else()
|
||||
set(BREAKPAD_CMAKE_PREFIX_PATH_TEMP ${CMAKE_PREFIX_PATH})
|
||||
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/breakpad/prefix")
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(BREAKPAD REQUIRED breakpad-client)
|
||||
|
||||
# reset CMAKE_PREFIX_PATH
|
||||
set(CMAKE_PREFIX_PATH ${BREAKPAD_CMAKE_PREFIX_PATH_TEMP})
|
||||
mark_as_advanced(BREAKPAD_CMAKE_PREFIX_PATH_TEMP)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(BREAKPAD REQUIRED_VARS BREAKPAD_LIBRARIES BREAKPAD_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(BREAKPAD_LIBRARIES_VARS)
|
||||
|
45
src/common/BugReporting.cpp
Normal file
45
src/common/BugReporting.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "BugReporting.h"
|
||||
|
||||
#include "Cutter.h"
|
||||
#include <QUrl>
|
||||
#include <QJsonObject>
|
||||
#include "CutterConfig.h"
|
||||
#include <QDesktopServices>
|
||||
|
||||
void openIssue()
|
||||
{
|
||||
QString url, osInfo, format, arch, type;
|
||||
//Pull in info needed for git issue
|
||||
osInfo = QSysInfo::productType() + " " +
|
||||
(QSysInfo::productVersion() == "unknown"
|
||||
? ""
|
||||
: QSysInfo::productVersion());
|
||||
QJsonDocument docu = Core()->getFileInfo();
|
||||
QJsonObject coreObj = docu.object()["core"].toObject();
|
||||
QJsonObject binObj = docu.object()["bin"].toObject();
|
||||
if (!binObj.QJsonObject::isEmpty()) {
|
||||
format = coreObj["format"].toString();
|
||||
arch = binObj["arch"].toString();
|
||||
if (!binObj["type"].isUndefined()) {
|
||||
type = coreObj["type"].toString();
|
||||
} else {
|
||||
type = "N/A";
|
||||
}
|
||||
} else {
|
||||
format = coreObj["format"].toString();
|
||||
arch = "N/A";
|
||||
type = "N/A";
|
||||
}
|
||||
url =
|
||||
"https://github.com/radareorg/cutter/issues/new?&body=**Environment information**\n* Operating System: "
|
||||
+ osInfo + "\n* Cutter version: " + CUTTER_VERSION_FULL +
|
||||
"\n* File format: " + format + "\n * Arch: " + arch + "\n * Type: " + type +
|
||||
"\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\n"
|
||||
"Steps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n"
|
||||
"4. See error\n\n**Expected behavior**\n"
|
||||
"A clear and concise description of what you expected to happen.\n\n"
|
||||
"**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n"
|
||||
"**Additional context**\nAdd any other context about the problem here.";
|
||||
|
||||
QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
|
||||
}
|
10
src/common/BugReporting.h
Normal file
10
src/common/BugReporting.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef CRASHREPORTING_H
|
||||
#define CRASHREPORTING_H
|
||||
|
||||
/**
|
||||
* @brief Opens issue on Cutter's github page
|
||||
* with current file and system information.
|
||||
*/
|
||||
void openIssue();
|
||||
|
||||
#endif // CRASHREPORTING_H
|
229
src/common/CrashHandler.cpp
Normal file
229
src/common/CrashHandler.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
#include "CrashHandler.h"
|
||||
|
||||
#ifdef CUTTER_ENABLE_CRASH_REPORTS
|
||||
#include "BugReporting.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QFileDialog>
|
||||
#include <signal.h>
|
||||
#include <QString>
|
||||
#include <QTime>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QMap>
|
||||
|
||||
#if defined (Q_OS_LINUX)
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
#elif defined (Q_OS_WIN32)
|
||||
#include "client/windows/handler/exception_handler.h"
|
||||
#elif defined (Q_OS_MACOS)
|
||||
#include "client/mac/handler/exception_handler.h"
|
||||
#endif // Q_OS
|
||||
|
||||
|
||||
|
||||
// Here will be placed crash dump at the first place
|
||||
// and then moved if needed
|
||||
#if defined (Q_OS_LINUX) || defined (Q_OS_MACOS)
|
||||
static std::string tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString();
|
||||
#else
|
||||
static std::wstring tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdWString();
|
||||
#endif
|
||||
|
||||
static const QMap<int, QString> sigNumDescription = {
|
||||
#ifdef SIGSEGV
|
||||
{ SIGSEGV, "SIGSEGV" },
|
||||
#endif // SIGSEGV
|
||||
#ifdef SIGILL
|
||||
{ SIGILL, "SIGILL" },
|
||||
#endif // SIGILL
|
||||
#ifdef SIGFPE
|
||||
{ SIGFPE, "SIGFPE" },
|
||||
#endif // SIGFPE
|
||||
#ifdef SIGABRT
|
||||
{ SIGABRT, "SIGABRT" },
|
||||
#endif // SIGABRT
|
||||
#ifdef SIGBUS
|
||||
{ SIGBUS, "SIGBUS" },
|
||||
#endif // SIGBUS
|
||||
#ifdef SIGPIPE
|
||||
{ SIGPIPE, "SIGPIPE" },
|
||||
#endif // SIGPIPE
|
||||
#ifdef SIGSYS
|
||||
{ SIGSYS, "SIGSYS" }
|
||||
#endif // SIGSYS
|
||||
};
|
||||
|
||||
static QString dumpFileFullPath = "";
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
// Called if crash dump was successfully created
|
||||
// Saves path to file
|
||||
bool callback(const wchar_t *_dump_dir,
|
||||
const wchar_t *_minidump_id,
|
||||
void *context, EXCEPTION_POINTERS *exinfo,
|
||||
MDRawAssertionInfo *assertion,
|
||||
bool success)
|
||||
{
|
||||
QString dir = QString::fromWCharArray(_dump_dir);
|
||||
QString id = QString::fromWCharArray(_minidump_id);
|
||||
dumpFileFullPath = QDir(dir).filePath(id + ".dmp");
|
||||
return true;
|
||||
}
|
||||
#elif defined (Q_OS_LINUX)
|
||||
// Called if crash dump was successfully created
|
||||
// Saves path to file
|
||||
bool callback(const google_breakpad::MinidumpDescriptor &md, void *context, bool b)
|
||||
{
|
||||
dumpFileFullPath = md.path();
|
||||
return true;
|
||||
}
|
||||
#elif defined (Q_OS_MACOS)
|
||||
// Called if crash dump was successfully created
|
||||
// Saves path to file
|
||||
bool callback(const char *dump_dir, const char *minidump_id, void *context, bool succeeded)
|
||||
{
|
||||
QString dir = QString::fromUtf8(dump_dir);
|
||||
QString id = QString::fromUtf8(minidump_id);
|
||||
dumpFileFullPath = QDir(dir).filePath(id + ".dmp");
|
||||
return true;
|
||||
}
|
||||
#endif // Q_OS
|
||||
|
||||
|
||||
/**
|
||||
* @brief Writes minidump and put its name in dumpFileFullPath.
|
||||
* @return true on succes
|
||||
*/
|
||||
bool writeMinidump()
|
||||
{
|
||||
bool ok;
|
||||
#if defined (Q_OS_LINUX) || defined (Q_OS_MACOS)
|
||||
ok = google_breakpad::ExceptionHandler::WriteMinidump(tmpLocation,
|
||||
callback,
|
||||
nullptr);
|
||||
#elif defined (Q_OS_WIN32)
|
||||
ok = google_breakpad::ExceptionHandler::WriteMinidump(tmpLocation,
|
||||
callback,
|
||||
nullptr);
|
||||
#endif // Q_OS
|
||||
return ok;
|
||||
}
|
||||
|
||||
[[noreturn]] void crashHandler(int signum)
|
||||
{
|
||||
// As soon as Cutter crashed, crash dump is created, so core and memory state
|
||||
// is not changed by all stuff with user interation going on below.
|
||||
bool ok = writeMinidump();
|
||||
|
||||
QString err = sigNumDescription.contains(signum) ?
|
||||
sigNumDescription[signum] :
|
||||
QObject::tr("undefined");
|
||||
|
||||
|
||||
QMessageBox mb;
|
||||
mb.setWindowTitle(QObject::tr("Cutter encountered a problem"));
|
||||
mb.setText(QObject::tr("Cutter received a <b>%1</b> it can't handle and will close.<br/>"
|
||||
"Would you like to create a crash dump for bug report?"
|
||||
).arg(err));
|
||||
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
mb.button(QMessageBox::Yes)->setText(QObject::tr("Create a crash dump"));
|
||||
mb.button(QMessageBox::No)->setText(QObject::tr("Do not report"));
|
||||
mb.setDefaultButton(QMessageBox::Yes);
|
||||
|
||||
int ret = mb.exec();
|
||||
if (ret == QMessageBox::Yes) {
|
||||
QString dumpSaveFileName;
|
||||
int placementFailCounter = 0;
|
||||
do {
|
||||
placementFailCounter++;
|
||||
if (placementFailCounter == 4) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
dumpSaveFileName = QFileDialog::getSaveFileName(nullptr,
|
||||
QObject::tr("Choose a directory to save the crash dump in"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::HomeLocation) +
|
||||
QDir::separator() +
|
||||
"Cutter_crash_dump_"
|
||||
+ QDate().currentDate().toString("dd.MM.yy") + "_"
|
||||
+ QTime().currentTime().toString() + ".dmp",
|
||||
QObject::tr("Dump files (*.dmp)"));
|
||||
|
||||
if (dumpSaveFileName.isEmpty()) {
|
||||
exit(3);
|
||||
}
|
||||
if (QFile::rename(dumpFileFullPath, dumpSaveFileName)) {
|
||||
break;
|
||||
}
|
||||
QMessageBox::critical(nullptr,
|
||||
QObject::tr("Error"),
|
||||
QObject::tr("Error occured during writing to the %1.<br/>"
|
||||
"Please, make sure you have access to that directory "
|
||||
"and try again.").arg(QFileInfo(dumpSaveFileName).dir().path()));
|
||||
} while (true);
|
||||
|
||||
if (ok) {
|
||||
QMessageBox info;
|
||||
info.setWindowTitle(QObject::tr("Success"));
|
||||
info.setText(QObject::tr("<a href=\"%1\">Crash dump</a> was successfully created.")
|
||||
.arg(QFileInfo(dumpSaveFileName).dir().path()));
|
||||
info.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
info.button(QMessageBox::Yes)->setText(QObject::tr("Open an issue"));
|
||||
info.button(QMessageBox::No)->setText(QObject::tr("Exit Cutter"));
|
||||
info.setDefaultButton(QMessageBox::Yes);
|
||||
|
||||
int ret = info.exec();
|
||||
if (ret == QMessageBox::Yes) {
|
||||
openIssue();
|
||||
}
|
||||
} else {
|
||||
QMessageBox::critical(nullptr,
|
||||
QObject::tr("Error!"),
|
||||
QObject::tr("Error occured during crash dump creation."));
|
||||
}
|
||||
} else {
|
||||
QFile f(dumpFileFullPath);
|
||||
f.remove();
|
||||
}
|
||||
|
||||
_exit(3);
|
||||
}
|
||||
|
||||
void initCrashHandler()
|
||||
{
|
||||
#ifdef SIGSEGV
|
||||
signal(SIGSEGV, crashHandler);
|
||||
#endif // SIGSEGV
|
||||
#ifdef SIGILL
|
||||
signal(SIGILL, crashHandler);
|
||||
#endif // SIGILL
|
||||
#ifdef SIGFPE
|
||||
signal(SIGFPE, crashHandler);
|
||||
#endif // SIGFPE
|
||||
#ifdef SIGABRT
|
||||
signal(SIGABRT, crashHandler);
|
||||
#endif // SIGABRT
|
||||
#ifdef SIGBUS
|
||||
signal(SIGBUS, crashHandler);
|
||||
#endif // SIGBUS
|
||||
#ifdef SIGPIPE
|
||||
signal(SIGPIPE, crashHandler);
|
||||
#endif // SIGPIPE
|
||||
#ifdef SIGSYS
|
||||
signal(SIGSYS, crashHandler);
|
||||
#endif // SIGSYS
|
||||
}
|
||||
|
||||
#else // CUTTER_ENABLE_CRASH_REPORTS
|
||||
|
||||
void initCrashHandler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#endif // CUTTER_ENABLE_CRASH_REPORTS
|
13
src/common/CrashHandler.h
Normal file
13
src/common/CrashHandler.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef CRASH_HANDLER_H
|
||||
#define CRASH_HANDLER_H
|
||||
|
||||
/**
|
||||
* @fn void initCrashHandler()
|
||||
*
|
||||
* If CUTTER_ENABLE_CRASH_REPORTS is true, initializes
|
||||
* crash handling and reporting, otherwise does nothing.
|
||||
*/
|
||||
void initCrashHandler();
|
||||
|
||||
|
||||
#endif // CRASH_HANDLER_H
|
@ -9,6 +9,7 @@
|
||||
#include <QList>
|
||||
#include <QStringList>
|
||||
#include <QMetaType>
|
||||
#include "core/CutterCommon.h"
|
||||
|
||||
struct FunctionDescription {
|
||||
RVA offset;
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "ui_MainWindow.h"
|
||||
|
||||
// Common Headers
|
||||
#include "common/BugReporting.h"
|
||||
#include "common/Highlighter.h"
|
||||
#include "common/HexAsciiHighlighter.h"
|
||||
#include "common/Helpers.h"
|
||||
@ -1112,34 +1113,10 @@ void MainWindow::on_actionAbout_triggered()
|
||||
a->setAttribute(Qt::WA_DeleteOnClose);
|
||||
a->open();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionIssue_triggered()
|
||||
{
|
||||
QString url, osInfo, format, arch, type;
|
||||
//Pull in info needed for git issue
|
||||
osInfo = QString(QSysInfo::productType()) + " " + QString(QSysInfo::productVersion());
|
||||
QJsonDocument docu = Core()->getFileInfo();
|
||||
QJsonObject coreObj = docu.object()["core"].toObject();
|
||||
QJsonObject binObj = docu.object()["bin"].toObject();
|
||||
if (!binObj.QJsonObject::isEmpty()) {
|
||||
format = coreObj["format"].toString();
|
||||
arch = binObj["arch"].toString();
|
||||
if (!binObj["type"].isUndefined()) {
|
||||
type = coreObj["type"].toString();
|
||||
} else {
|
||||
type = "N/A";
|
||||
}
|
||||
} else {
|
||||
format = coreObj["format"].toString();
|
||||
arch = "N/A";
|
||||
type = "N/A";
|
||||
}
|
||||
url =
|
||||
"https://github.com/radareorg/cutter/issues/new?&body=**Environment information**\n* Operating System: "
|
||||
+ osInfo + "\n* Cutter version: " + CUTTER_VERSION_FULL +
|
||||
"\n* File format: " + format + "\n * Arch: " + arch + "\n * Type: " + type +
|
||||
"\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Additional context**\nAdd any other context about the problem here.";
|
||||
|
||||
QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
|
||||
openIssue();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionRefresh_Panels_triggered()
|
||||
|
Loading…
Reference in New Issue
Block a user