Linux: stack trace on crash

This commit is contained in:
tobtoht 2023-01-26 13:12:33 +01:00
parent a7a06d8413
commit 7f07f98f92
No known key found for this signature in database
GPG key ID: E45B10DD027D2472
7 changed files with 120 additions and 4 deletions

View 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(USE_DEVICE_TREZOR "Trezor support compilation" ON)
option(DONATE_BEG "Prompt donation window every once in a while" OFF) option(DONATE_BEG "Prompt donation window every once in a while" OFF)
option(WITH_SCANNER "Enable webcam QR scanner" ON) 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") list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
include(CheckCCompilerFlag) include(CheckCCompilerFlag)
@ -105,8 +106,8 @@ if(MINGW)
set(Boost_THREADAPI win32) set(Boost_THREADAPI win32)
endif() endif()
set(Boost_USE_MULTITHREADED ON)
find_package(Boost 1.58 REQUIRED COMPONENTS set(BOOST_COMPONENTS
system system
filesystem filesystem
thread thread
@ -118,6 +119,14 @@ find_package(Boost 1.58 REQUIRED COMPONENTS
locale 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(UNIX AND NOT APPLE)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
# https://github.com/monero-project/monero-gui/issues/3142#issuecomment-705940446 # https://github.com/monero-project/monero-gui/issues/3142#issuecomment-705940446

View file

@ -22,7 +22,7 @@ $(package)_toolset_$(host_os)=gcc
$(package)_archiver_$(host_os)=$($(package)_ar) $(package)_archiver_$(host_os)=$($(package)_ar)
$(package)_toolset_darwin=darwin $(package)_toolset_darwin=darwin
$(package)_archiver_darwin=$($(package)_libtool) $(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=-std=c++17
$(package)_cxxflags_linux=-fPIC $(package)_cxxflags_linux=-fPIC
$(package)_cxxflags_freebsd=-fPIC $(package)_cxxflags_freebsd=-fPIC

View file

@ -284,6 +284,7 @@ mkdir -p "$DISTSRC"
esac esac
;; ;;
*linux*) *linux*)
CMAKEVARS+=" -DSTACK_TRACE=ON"
case "$OPTIONS" in case "$OPTIONS" in
tails) tails)
CMAKEVARS+=" -DTOR_DIR=Off -DTOR_VERSION=Off" CMAKEVARS+=" -DTOR_DIR=Off -DTOR_VERSION=Off"

View file

@ -117,6 +117,13 @@ set_target_properties(feather PROPERTIES
LINK_FLAGS_RELEASE -s 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 target_include_directories(feather PUBLIC
${CMAKE_BINARY_DIR}/src/feather_autogen/include ${CMAKE_BINARY_DIR}/src/feather_autogen/include
${CMAKE_SOURCE_DIR}/monero/include ${CMAKE_SOURCE_DIR}/monero/include
@ -186,6 +193,10 @@ if(PLATFORM_INSTALLER)
target_compile_definitions(feather PRIVATE PLATFORM_INSTALLER=1) target_compile_definitions(feather PRIVATE PLATFORM_INSTALLER=1)
endif() endif()
if(STACK_TRACE)
target_compile_definitions(feather PRIVATE STACK_TRACE=1)
endif()
if(HAVE_SYS_PRCTL_H) if(HAVE_SYS_PRCTL_H)
target_compile_definitions(feather PRIVATE HAVE_SYS_PRCTL_H=1) target_compile_definitions(feather PRIVATE HAVE_SYS_PRCTL_H=1)
endif() endif()
@ -290,6 +301,10 @@ if(DEPENDS AND APPLE)
${CMAKE_OSX_SYSROOT}/lib/darwin/libclang_rt.osx.a) ${CMAKE_OSX_SYSROOT}/lib/darwin/libclang_rt.osx.a)
endif() endif()
if(STACK_TRACE AND CMAKE_C_COMPILER_ID STREQUAL "GNU")
target_link_libraries(feather -rdynamic)
endif()
install(TARGETS feather install(TARGETS feather
DESTINATION ${CMAKE_INSTALL_PREFIX} DESTINATION ${CMAKE_INSTALL_PREFIX}
) )

View file

@ -3,6 +3,7 @@
#include "WindowManager.h" #include "WindowManager.h"
#include <QDialogButtonBox>
#include <QInputDialog> #include <QInputDialog>
#include <QMessageBox> #include <QMessageBox>
@ -38,6 +39,8 @@ WindowManager::WindowManager(EventFilter *eventFilter)
this->initSkins(); this->initSkins();
this->showCrashLogs();
if (!config()->get(Config::firstRun).toBool() || TailsOS::detect() || WhonixOS::detect()) { if (!config()->get(Config::firstRun).toBool() || TailsOS::detect() || WhonixOS::detect()) {
this->onInitialNetworkConfigured(); 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 ######################## // ######################## DEVICE ########################
void WindowManager::onDeviceButtonRequest(quint64 code) { void WindowManager::onDeviceButtonRequest(quint64 code) {

View file

@ -69,6 +69,7 @@ private:
void buildTrayMenu(); void buildTrayMenu();
void startupWarning(); void startupWarning();
void showWarningMessageBox(const QString &title, const QString &message); void showWarningMessageBox(const QString &title, const QString &message);
void showCrashLogs();
void quitAfterLastWindow(); void quitAfterLastWindow();

View file

@ -12,6 +12,16 @@
#include "MainWindow.h" #include "MainWindow.h"
#include "utils/EventFilter.h" #include "utils/EventFilter.h"
#include "WindowManager.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) #if defined(Q_OS_WIN)
#include <windows.h> #include <windows.h>
@ -22,10 +32,35 @@
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin) Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
#endif #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[]) int main(int argc, char *argv[])
{ {
Q_INIT_RESOURCE(assets); 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) #if defined(HAS_TOR_BIN)
Q_INIT_RESOURCE(assets_tor); Q_INIT_RESOURCE(assets_tor);
#endif #endif