From 92e94a0f7ac933510c10a9ba21e4e8b388a33919 Mon Sep 17 00:00:00 2001 From: Igor Sirotin Date: Mon, 4 Nov 2024 12:30:57 +0000 Subject: [PATCH] WIP --- Makefile | 50 ++++++++++++- src/backend/general.nim | 17 +++++ ui/StatusQ/CMakeLists.txt | 2 - vendor/DOtherSide/lib/CMakeLists.txt | 4 ++ vendor/DOtherSide/lib/src/DOtherSide.cpp | 90 ++++++++++++++++++++++-- 5 files changed, 155 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 396f4546ec..dec9c8b459 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,7 @@ ifneq ($(detected_OS),Windows) endif # some manually installed Qt5 instances have wrong paths in their *.pc files, so we pass the right one to the linker here ifeq ($(detected_OS),Darwin) - NIM_PARAMS += -L:"-framework Foundation -framework AppKit -framework Security -framework IOKit -framework CoreServices -framework LocalAuthentication" + NIM_PARAMS += -L:"-framework Foundation -framework AppKit -framework Security -framework IOKit -framework CoreServices -framework LocalAuthentication -lbsm" # Fix for failures due to 'can't allocate code signature data for' NIM_PARAMS += --passL:"-headerpad_max_install_names" NIM_PARAMS += --passL:"-F$(QT5_LIBDIR)" @@ -405,6 +405,7 @@ $(DOTHERSIDE_CMAKE_CACHE): | deps -DCMAKE_BUILD_TYPE=$(COMMON_CMAKE_BUILD_TYPE) \ -DENABLE_DOCS=OFF \ -DENABLE_TESTS=OFF \ + -DSENTRY_INTEGRATION_QT=YES \ $(COMMON_CMAKE_CONFIG_PARAMS) \ $(DOTHERSIDE_CMAKE_CONFIG_PARAMS) \ -B $(DOTHERSIDE_BUILD_PATH) \ @@ -556,8 +557,35 @@ else NIM_STATUS_CLIENT := bin/nim_status_client endif +export SENTRY_LIB := vendor/DOtherSide/build/lib/sentry-native/libsentry.$(LIBSTATUS_EXT) +export SENTRY_LIBDIR := "$(shell pwd)/$(shell dirname "$(SENTRY_LIB)")" + +export CRASHPAD_CLIENT_LIB := vendor/DOtherSide/build/lib/sentry-native/crashpad_build/client/libcrashpad_client.$(LIBSTATUS_EXT) +export CRASHPAD_CLIENT_LIBDIR := "$(shell pwd)/$(shell dirname "$(CRASHPAD_CLIENT_LIB)")" + +export CRASHPAD_HANDLER_LIB := vendor/DOtherSide/build/lib/sentry-native/crashpad_build/handler/libcrashpad_handler_lib.$(LIBSTATUS_EXT) +export CRASHPAD_HANDLER_LIBDIR := "$(shell pwd)/$(shell dirname "$(CRASHPAD_HANDLER_LIB)")" + +export CRASHPAD_MINIDUMP_LIB := vendor/DOtherSide/build/lib/sentry-native/crashpad_build/minidump/libcrashpad_minidump.$(LIBSTATUS_EXT) +export CRASHPAD_MINIDUMP_LIBDIR := "$(shell pwd)/$(shell dirname "$(CRASHPAD_MINIDUMP_LIB)")" + +export CRASHPAD_SNAPSHOT_LIB := vendor/DOtherSide/build/lib/sentry-native/crashpad_build/snapshot/libcrashpad_snapshot.$(LIBSTATUS_EXT) +export CRASHPAD_SNAPSHOT_LIBDIR := "$(shell pwd)/$(shell dirname "$(CRASHPAD_SNAPSHOT_LIB)")" + +export CRASHPAD_TOOLS_LIB := vendor/DOtherSide/build/lib/sentry-native/crashpad_build/tools/libcrashpad_tools.$(LIBSTATUS_EXT) +export CRASHPAD_TOOLS_LIBDIR := "$(shell pwd)/$(shell dirname "$(CRASHPAD_TOOLS_LIB)")" + +export CRASHPAD_UTIL_LIB := vendor/DOtherSide/build/lib/sentry-native/crashpad_build/util/libcrashpad_util.$(LIBSTATUS_EXT) +export CRASHPAD_UTIL_LIBDIR := "$(shell pwd)/$(shell dirname "$(CRASHPAD_UTIL_LIB)")" + +export CRASHPAD_MINICHROMIUM_LIB := vendor/DOtherSide/build/lib/sentry-native/crashpad_build/third_party/mini_chromium/libmini_chromium.$(LIBSTATUS_EXT) +export CRASHPAD_MINICHROMIUM_LIBDIR := "$(shell pwd)/$(shell dirname "$(CRASHPAD_MINICHROMIUM_LIB)")" + +bin/crashpad_handler: + cp vendor/DOtherSide/build/lib/sentry-native/crashpad_build/handler/crashpad_handler bin/ + $(NIM_STATUS_CLIENT): NIM_PARAMS += $(RESOURCES_LAYOUT) -$(NIM_STATUS_CLIENT): $(NIM_SOURCES) | statusq dotherside check-qt-dir $(STATUSGO) $(STATUSKEYCARDGO) $(QRCODEGEN) $(FLEETS) rcc compile-translations deps +$(NIM_STATUS_CLIENT): $(NIM_SOURCES) | statusq dotherside check-qt-dir $(STATUSGO) $(STATUSKEYCARDGO) $(QRCODEGEN) $(FLEETS) rcc compile-translations deps bin/crashpad_handler echo -e $(BUILD_MSG) "$@" $(ENV_SCRIPT) nim c $(NIM_PARAMS) \ --passL:"-L$(STATUSGO_LIBDIR)" \ @@ -566,8 +594,25 @@ $(NIM_STATUS_CLIENT): $(NIM_SOURCES) | statusq dotherside check-qt-dir $(STATUSG --passL:"-lStatusQ" \ --passL:"-L$(STATUSKEYCARDGO_LIBDIR)" \ --passL:"-lkeycard" \ + --passL:"-L$(SENTRY_LIBDIR)" \ + --passL:"-lsentry" \ + --passL:"-L$(CRASHPAD_CLIENT_LIBDIR)" \ + --passL:"-lcrashpad_client" \ + --passL:"-L$(CRASHPAD_HANDLER_LIBDIR)" \ + --passL:"-lcrashpad_handler_lib" \ + --passL:"-L$(CRASHPAD_MINIDUMP_LIBDIR)" \ + --passL:"-lcrashpad_minidump" \ + --passL:"-L$(CRASHPAD_SNAPSHOT_LIBDIR)" \ + --passL:"-lcrashpad_snapshot" \ + --passL:"-L$(CRASHPAD_TOOLS_LIBDIR)" \ + --passL:"-lcrashpad_tools" \ + --passL:"-L$(CRASHPAD_UTIL_LIBDIR)" \ + --passL:"-lcrashpad_util" \ + --passL:"-L$(CRASHPAD_MINICHROMIUM_LIBDIR)" \ + --passL:"-lmini_chromium" \ --passL:"$(QRCODEGEN)" \ --passL:"-lm" \ + --passL:"-lcurl" \ $(NIM_EXTRA_PARAMS) src/nim_status_client.nim ifeq ($(detected_OS),Darwin) install_name_tool -change \ @@ -686,6 +731,7 @@ $(STATUS_CLIENT_DMG): nim_status_client $(DMG_TOOL) mkdir -p $(MACOS_OUTER_BUNDLE)/Contents/Resources cp Info.plist $(MACOS_OUTER_BUNDLE)/Contents/ cp bin/nim_status_client $(MACOS_OUTER_BUNDLE)/Contents/MacOS/ + cp bin/crashpad_handler $(MACOS_OUTER_BUNDLE)/Contents/MacOS/ cp status.icns $(MACOS_OUTER_BUNDLE)/Contents/Resources/ cp status-macos.svg $(MACOS_OUTER_BUNDLE)/Contents/ cp -R resources.rcc $(MACOS_OUTER_BUNDLE)/Contents/ diff --git a/src/backend/general.nim b/src/backend/general.nim index 113e2b8afa..04b55cf548 100644 --- a/src/backend/general.nim +++ b/src/backend/general.nim @@ -79,7 +79,24 @@ proc initKeystore*(keystoreDir: string): RpcResponse[JsonNode] = error "error", methodName = "initKeystore", exception=e.msg raise newException(RpcException, e.msg) +type + Node = ref object + value: int + proc backupData*(): RpcResponse[JsonNode] = + echo "<<< ABOUT TO CRASH" + + # FIXME: Force a crash to test the crash reporting + + var n: Node = nil + echo n.value + + let p = cast[ptr int](0x1) # Point to an invalid address + echo p[] # Attempt to access it + + # var arr = cast[ptr array[1, int]](nil) # Array pointer with no valid memory + # echo arr[1] # Out-of-bounds access + let payload = %* [] result = callPrivateRPC("backupData".prefix, payload) diff --git a/ui/StatusQ/CMakeLists.txt b/ui/StatusQ/CMakeLists.txt index e59e100fc5..0794b6b380 100644 --- a/ui/StatusQ/CMakeLists.txt +++ b/ui/StatusQ/CMakeLists.txt @@ -35,7 +35,6 @@ endif() add_subdirectory(../../vendor/SortFilterProxyModel SortFilterProxyModel) add_subdirectory(../../vendor/qzxing/src qzxing) -add_subdirectory(../../vendor/sentry-native sentry-native) target_compile_options(qzxing PRIVATE -w) target_compile_options(SortFilterProxyModel PRIVATE -w) @@ -187,7 +186,6 @@ target_link_libraries(StatusQ PRIVATE Qt5::QuickControls2 SortFilterProxyModel qzxing - sentry::sentry ) if (CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/vendor/DOtherSide/lib/CMakeLists.txt b/vendor/DOtherSide/lib/CMakeLists.txt index 6e060b14d9..f6cdc40c53 100644 --- a/vendor/DOtherSide/lib/CMakeLists.txt +++ b/vendor/DOtherSide/lib/CMakeLists.txt @@ -9,6 +9,8 @@ if(MONITORING) include(../../../ui/MonitoringSources.cmake) endif() +add_subdirectory(../../sentry-native sentry-native) + # Macro for merging common code between static and shared macro(add_target name type) find_package(Qt5 COMPONENTS Core Qml Gui Quick QuickControls2 Widgets Network Multimedia WebView REQUIRED) @@ -68,6 +70,8 @@ macro(add_target name type) target_link_libraries(${name} PRIVATE Qt5::QuickControls2) set(PC_REQUIRES "${PC_REQUIRES}, Qt5QuickControls2") endif() + + target_link_libraries(${name} PUBLIC sentry::sentry) endmacro() set(major 0) diff --git a/vendor/DOtherSide/lib/src/DOtherSide.cpp b/vendor/DOtherSide/lib/src/DOtherSide.cpp index e8e0ff0263..572a3ab3d9 100644 --- a/vendor/DOtherSide/lib/src/DOtherSide.cpp +++ b/vendor/DOtherSide/lib/src/DOtherSide.cpp @@ -81,6 +81,8 @@ #include "StatusDesktop/Monitoring/Monitor.h" #endif +#include + namespace { void register_meta_types() @@ -189,6 +191,24 @@ void dos_qguiapplication_try_enable_threaded_renderer() static MessageHandlerCallback messageHandlerCallback = nullptr; +sentry_level_t qtLevelToSentry(int type) +{ + switch (type) { + case QtDebugMsg: + return SENTRY_LEVEL_DEBUG; + case QtInfoMsg: + return SENTRY_LEVEL_INFO; + case QtWarningMsg: + return SENTRY_LEVEL_WARNING; + case QtCriticalMsg: + return SENTRY_LEVEL_ERROR; + case QtFatalMsg: + return SENTRY_LEVEL_FATAL; + default: + return SENTRY_LEVEL_INFO; + } +} + // This catches the QT and QML logs and outputs them. // This is necessary on Windows, because otherwise we do not get any logs at all void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) @@ -205,6 +225,16 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS int messageType = int(type); messageHandlerCallback(messageType, message, category, file, function, context.line); + + // if (type == QtDebugMsg || type == QtInfoMsg) { + // return; + // } + + // sentry_capture_event(sentry_value_new_message_event( + // /* level */ convertToSentryLevel(type), + // /* logger */ "", + // /* message */ message + // )); } void dos_installMessageHandler(MessageHandlerCallback messageHandler) @@ -213,19 +243,39 @@ void dos_installMessageHandler(MessageHandlerCallback messageHandler) qInstallMessageHandler(myMessageOutput); } +static sentry_value_t on_crash_callback( + const sentry_ucontext_t *uctx, // provides the user-space context of the crash + sentry_value_t event, // used the same way as in `before_send` + void *closure // user-data that you can provide at configuration time +) +{ + // Do contextual clean-up before the crash is sent to sentry's backend infrastructure + + qInfo() << "on_crash_callback"; + + /* ... */ + + // tell the backend to retain the event (+ dump) + // or to discard it, you could free the event and return a `null`: + // sentry_value_decref(event); + // return sentry_value_new_null(); + return event; +} + void dos_qguiapplication_create() { + qInfo() << "dos_qguiapplication_create"; + sentry_options_t *options = sentry_options_new(); - // sentry_options_set_dsn(options, "https://fecdd38f76baa59481dd8b643bd54022@sentry.infra.status.im/8"); // This is also the default-path. For further information and recommendations: // https://docs.sentry.io/platforms/native/configuration/options/#database-path sentry_options_set_database_path(options, ".sentry-native"); - sentry_options_set_release(options, "status-desktop@x.y.z"); + sentry_options_set_release(options, "status-desktop@test-1"); sentry_options_set_debug(options, 1); + sentry_options_set_on_crash(options, on_crash_callback, NULL); sentry_init(options); - // Make sure everything flushes - auto sentryClose = qScopeGuard([] { sentry_close(); }); + qInfo() << "sentry initialized" << sentry_options_get_dsn(options); // The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, // and retain their last-stored values between program startup and program termination. @@ -362,6 +412,9 @@ void dos_qguiapplication_download_imageByUrl(const char *url, const char *filePa void dos_qguiapplication_delete() { delete qGuiApp; + + // Make sure everything flushes + sentry_close(); } void dos_qguiapplication_exec() @@ -1887,3 +1940,32 @@ void dos_app_make_it_active(::DosQQmlApplicationEngine* vptr) } } } + +// sentry_level_t chroniclesLevelToSentry(const char* type) +// { +// switch (type) { +// case "DEBUG": +// return SENTRY_LEVEL_DEBUG; +// case "INFO": +// return SENTRY_LEVEL_INFO; +// case "WARN": +// return SENTRY_LEVEL_WARNING; +// case "ERROR": +// return SENTRY_LEVEL_ERROR; +// default: +// return SENTRY_LEVEL_INFO; +// } +// } + +// void report_sentry_event(const char* type, const char* message) { +// const int sentryLevel = convertToSentryLevel(type); +// if (sentryLevel == SENTRY_LEVEL_DEBUG || type == SENTRY_LEVEL_INFO) { +// return; +// } + +// sentry_capture_event(sentry_value_new_message_event( +// /* level */ sentryLevel, +// /* logger */ "", +// /* message */ message +// )); +// }