]> Nutra Git (v2) - gamesguru/feather.git/commitdiff
Linux: stack trace on crash
authortobtoht <tob@featherwallet.org>
Thu, 26 Jan 2023 12:12:33 +0000 (13:12 +0100)
committertobtoht <tob@featherwallet.org>
Thu, 26 Jan 2023 14:18:12 +0000 (15:18 +0100)
CMakeLists.txt
contrib/depends/packages/boost.mk
contrib/guix/libexec/build.sh
src/CMakeLists.txt
src/WindowManager.cpp
src/WindowManager.h
src/main.cpp

index f217b7d18b5b8b03a1cf2b89ee9f841ac1820448..d0143615f90130996a252823afa307fb0151cb5e 100644 (file)
@@ -26,6 +26,7 @@ option(PLATFORM_INSTALLER "Built-in updater fetches installer (windows-only)" OF
 option(USE_DEVICE_TREZOR "Trezor support compilation" ON)
 option(DONATE_BEG "Prompt donation window every once in a while" OFF)
 option(WITH_SCANNER "Enable webcam QR scanner" ON)
+option(STACK_TRACE "Dump stack trace on crash (Linux only)" OFF)
 
 list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
 include(CheckCCompilerFlag)
@@ -105,8 +106,8 @@ if(MINGW)
     set(Boost_THREADAPI win32)
 endif()
 
-set(Boost_USE_MULTITHREADED ON)
-find_package(Boost 1.58 REQUIRED COMPONENTS
+
+set(BOOST_COMPONENTS
         system
         filesystem
         thread
@@ -116,7 +117,15 @@ find_package(Boost 1.58 REQUIRED COMPONENTS
         serialization
         program_options
         locale
-        )
+)
+
+if(STACK_TRACE AND UNIX AND NOT APPLE)
+    list(APPEND BOOST_COMPONENTS
+            stacktrace_basic)
+endif()
+
+set(Boost_USE_MULTITHREADED ON)
+find_package(Boost 1.58 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
 
 if(UNIX AND NOT APPLE)
     if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
index e77e27820194679c246ca6c0289d2c9fde76ff31..ae5bacddcdf972357461db1e987d6088e454a9db 100644 (file)
@@ -22,7 +22,7 @@ $(package)_toolset_$(host_os)=gcc
 $(package)_archiver_$(host_os)=$($(package)_ar)
 $(package)_toolset_darwin=darwin
 $(package)_archiver_darwin=$($(package)_libtool)
-$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale
+$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale,stacktrace
 $(package)_cxxflags=-std=c++17
 $(package)_cxxflags_linux=-fPIC
 $(package)_cxxflags_freebsd=-fPIC
index edcb336a8f68a845dd1b11427b9871006e56bdf4..5393853c30a18f5bd0de2c604c386d9b3c59f1f3 100755 (executable)
@@ -284,6 +284,7 @@ mkdir -p "$DISTSRC"
             esac
             ;;
         *linux*)
+            CMAKEVARS+=" -DSTACK_TRACE=ON"
             case "$OPTIONS" in
                 tails)
                     CMAKEVARS+=" -DTOR_DIR=Off -DTOR_VERSION=Off"
index 59014fcf7cd3114f217eab5814802a3309480ab0..03e4fbcbf87ca2940dd0b2f7721112fe9051dbf5 100644 (file)
@@ -117,6 +117,13 @@ set_target_properties(feather PROPERTIES
         LINK_FLAGS_RELEASE -s
 )
 
+if(STACK_TRACE)
+    message(STATUS "Stack Trace Enabled")
+    if (STATIC)
+        set_property(TARGET feather APPEND PROPERTY LINK_FLAGS "-Wl,--wrap=__cxa_throw")
+    endif()
+endif()
+
 target_include_directories(feather PUBLIC
         ${CMAKE_BINARY_DIR}/src/feather_autogen/include
         ${CMAKE_SOURCE_DIR}/monero/include
@@ -186,6 +193,10 @@ if(PLATFORM_INSTALLER)
     target_compile_definitions(feather PRIVATE PLATFORM_INSTALLER=1)
 endif()
 
+if(STACK_TRACE)
+    target_compile_definitions(feather PRIVATE STACK_TRACE=1)
+endif()
+
 if(HAVE_SYS_PRCTL_H)
     target_compile_definitions(feather PRIVATE HAVE_SYS_PRCTL_H=1)
 endif()
@@ -290,6 +301,10 @@ if(DEPENDS AND APPLE)
             ${CMAKE_OSX_SYSROOT}/lib/darwin/libclang_rt.osx.a)
 endif()
 
+if(STACK_TRACE AND CMAKE_C_COMPILER_ID STREQUAL "GNU")
+    target_link_libraries(feather -rdynamic)
+endif()
+
 install(TARGETS feather
         DESTINATION ${CMAKE_INSTALL_PREFIX}
 )
index ec0fda7180164e71f6568a0ba0f8e4ce2537b433..e6758ad081e44a80bbda5c9db78473724bb26719 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "WindowManager.h"
 
+#include <QDialogButtonBox>
 #include <QInputDialog>
 #include <QMessageBox>
 
@@ -38,6 +39,8 @@ WindowManager::WindowManager(EventFilter *eventFilter)
 
     this->initSkins();
 
+    this->showCrashLogs();
+
     if (!config()->get(Config::firstRun).toBool() || TailsOS::detect() || WhonixOS::detect()) {
         this->onInitialNetworkConfigured();
     }
@@ -410,6 +413,58 @@ void WindowManager::displayWalletErrorMessage(const QString &message) {
     }
 }
 
+void WindowManager::showCrashLogs() {
+    QString crashLogPath{Config::defaultConfigDir().path() + "/crash_report.txt"};
+    QFile crashLogFile{crashLogPath};
+
+    if (!crashLogFile.exists()) {
+        return;
+    }
+
+    bool r = crashLogFile.open(QIODevice::ReadOnly);
+    if (!r) {
+        qWarning() << "Unable to open crash log file: " << crashLogPath;
+        return;
+    }
+
+    QTextStream log(&crashLogFile);
+    QString logString = log.readAll();
+    crashLogFile.close();
+
+    bool renamed = false;
+    for (int i = 1; i < 999; i++) {
+        QString name{QString("/crash_report_%1.txt").arg(QString::number(i))};
+        if (crashLogFile.rename(Config::defaultConfigDir().path() + name)) {
+            renamed = true;
+            break;
+        }
+    }
+
+    if (!renamed) {
+        crashLogFile.remove();
+    }
+
+    QDialog dialog(nullptr);
+    dialog.setWindowTitle("Crash report");
+
+    QVBoxLayout layout;
+    QLabel msg{"Feather encountered an unrecoverable error.\n\nPlease send a copy of these logs to the developers. Logs are not automatically reported.\n"};
+    QTextEdit logs;
+    logs.setText(logString);
+
+    layout.addWidget(&msg);
+    layout.addWidget(&logs);
+    QDialogButtonBox buttons(QDialogButtonBox::Ok);
+    layout.addWidget(&buttons);
+    dialog.setLayout(&layout);
+    QObject::connect(&buttons, &QDialogButtonBox::accepted, [&dialog]{
+        dialog.close();
+    });
+    dialog.exec();
+
+    exit(0);
+}
+
 // ######################## DEVICE ########################
 
 void WindowManager::onDeviceButtonRequest(quint64 code) {
index 6df35db3c71f6f4ffa3bdb3579925e2f2db63ab7..4d3c7c02bd2c1a0d30e53aad753b8a6a8005acba 100644 (file)
@@ -69,6 +69,7 @@ private:
     void buildTrayMenu();
     void startupWarning();
     void showWarningMessageBox(const QString &title, const QString &message);
+    void showCrashLogs();
 
     void quitAfterLastWindow();
 
index d3e2bcfffa95ffb079e448cbaea38ec0bfcf77b3..ab89fc7b63dda6d756d309e563bb0bed863ff8f1 100644 (file)
 #include "MainWindow.h"
 #include "utils/EventFilter.h"
 #include "WindowManager.h"
+#include "config.h"
+
+#if defined(Q_OS_LINUX) && defined(STACK_TRACE)
+#define BOOST_STACKTRACE_LINK
+#include <signal.h>
+#include <boost/stacktrace.hpp>
+#include <fstream>
+#endif
+
+#include <QObject>
 
 #if defined(Q_OS_WIN)
 #include <windows.h>
 Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
 #endif
 
+#if defined(Q_OS_LINUX) && defined(STACK_TRACE)
+void signal_handler(int signum) {
+    ::signal(signum, SIG_DFL);
+    std::stringstream keyStream;
+    keyStream << boost::stacktrace::stacktrace();
+    std::cout << keyStream.str();
+
+    // Write stack trace to disk
+    QString crashLogPath{Config::defaultConfigDir().path() + "/crash_report.txt"};
+    std::ofstream out(crashLogPath.toStdString());
+    out << keyStream.str();
+    out.close();
+
+    // Make a last ditch attempt to restart the application
+    QProcess::startDetached(qApp->arguments()[0], qApp->arguments());
+
+    ::raise(SIGABRT);
+}
+#endif
+
 int main(int argc, char *argv[])
 {
     Q_INIT_RESOURCE(assets);
 
+#if defined(Q_OS_LINUX) && defined(STACK_TRACE)
+    ::signal(SIGSEGV, &signal_handler);
+    ::signal(SIGABRT, &signal_handler);
+#endif
+
 #if defined(HAS_TOR_BIN)
     Q_INIT_RESOURCE(assets_tor);
 #endif