diff options
-rw-r--r-- | linux/makepkg/PKGBUILD | 29 | ||||
-rw-r--r-- | meson.build | 10 | ||||
-rw-r--r-- | src/crashhandler.cpp | 44 | ||||
-rw-r--r-- | src/crashhandler.h | 38 | ||||
-rw-r--r-- | src/main.cpp | 32 | ||||
-rw-r--r-- | src/meson.build | 4 | ||||
-rw-r--r-- | tools/src/crashhandler/main.go | 4 |
7 files changed, 97 insertions, 64 deletions
diff --git a/linux/makepkg/PKGBUILD b/linux/makepkg/PKGBUILD index debf2f1..59c7eee 100644 --- a/linux/makepkg/PKGBUILD +++ b/linux/makepkg/PKGBUILD @@ -26,11 +26,11 @@ sha512sums=('SKIP' #validgpgkeys=(BB1C090188E3E32B375C13FD095DE26BC16D2E98) # Aqua-sama <aqua@iserlohn-fortress.net> -## Build Options +## not-use flags Options # Enable plugin signing: -# meson/ninja will generate the privateKey.pem and publicKey.pem in the $builddir -# Because this embeds the public key into the executable, enabling this option will break reproducible builds. _signPlugins= +# Enable breakpad integraton: +_enableBreakpad= prepare() { cd $srcdir/smolbote @@ -53,6 +53,7 @@ build() { mkdir $srcdir/build fi cd $srcdir/smolbote + KCONFIG_CONFIG=linux/.config alldefconfig # For a list of configureable options, check smolbote/meson_options.txt, or # run `meson configure` in $srcdir/build @@ -65,13 +66,15 @@ build() { # b_lto: Use link time optimization meson --buildtype=plain --wrap-mode=nodownload \ --prefix=/usr/local --auto-features=disabled \ - -Db_pie=true -Db_lto=true -Dcpp_link_args="-fuse-ld=gold" \ + -Db_pie=true -Db_lto=true \ -Dmanpage=enabled \ $srcdir/build - # uncomment to enable crashhandler - #meson configure -Dcrashhandler=enabled $srcdir/build - #KCONFIG_CONFIG=linux/.config setconfig USEBREAKPAD=y + if [ -n $_enableBreakpad ]; then + msg2 "Enabling crashhandler" + meson configure -Ddebug=true -Dcrashhandler=enabled $srcdir/build + KCONFIG_CONFIG=linux/.config setconfig USEBREAKPAD=y + fi # Run menuconfig #KCONFIG_CONFIG=linux/.config menuconfig @@ -88,10 +91,16 @@ package() { if [ -n $_signPlugins ]; then msg "Signing plugins" for so in $pkgdir/usr/local/lib/smolbote/plugins/*.so; do + msg2 "Signed $(basename $so)" openssl dgst -sha256 -sign $srcdir/build/privateKey.pem -out $so.sig $so - # If the sigs were in another location, use - #install -m644 -t $pkgdir/usr/local/lib/smolbote/plugins $so.sig done - fi # _signPlugins + fi + + if [ -n $_enableBreakpad ]; then + msg "Installing debug symbols" + ninja -C $srcdir/build linux/poi.sym + install -dm644 $pkgdir/usr/local/lib/smolbote/symbols/poi/$(head -n1 linux/poi.sym | awk '{ print $(NF-1) }') + install -m644 -t $pkgdir/usr/local/lib/smolbote/symbols/poi/$(head -n1 linux/poi.sym | awk '{ print $(NF-1) }') $srcdir/build/linux/poi.sym + fi } diff --git a/meson.build b/meson.build index 6a7518b..009ec91 100644 --- a/meson.build +++ b/meson.build @@ -38,6 +38,7 @@ add_project_arguments(cxx.get_supported_arguments([ '-Wdate-time', # Warn when using __TIME__ and __DATE__ macros '-Wimplicit-fallthrough', ]), language: 'cpp') + add_project_link_arguments(cxx.get_supported_link_arguments([ '-fuse-ld=gold' ]), language: 'cpp') @@ -51,9 +52,14 @@ dep_qt5 = dependency('qt5', dep_spdlog = dependency('spdlog', fallback: ['spdlog', 'spdlog_dep'], version: '>=1.3.1') optional_deps = [] +poi_cpp_args = [] dep_breakpad = dependency('breakpad-client', include_type: 'system', required: get_option('crashhandler')) dep_threads = dependency('threads', include_type: 'system', required: get_option('crashhandler')) +if dep_breakpad.found() + poi_cpp_args += '-DHAVE_BREAKPAD' +endif + dep_gtest = dependency('gtest', required: false, disabler: true) # Generate config header @@ -89,10 +95,10 @@ subdir('test/conf') ssconfig = poi_sourceset.apply(cdata) poi_exe = executable(get_option('poi'), - cpp_args: ['-DQAPPLICATION_CLASS=QApplication'], + cpp_args: ['-DQAPPLICATION_CLASS=QApplication', poi_cpp_args], sources: [ssconfig.sources()], include_directories: [include, include_directories('src')], - dependencies: [dep_qt5, dep_spdlog, dep_SingleApplication, dep_args, optional_deps, dep_about, dep_bookmarks, dep_configuration, dep_downloads, dep_pluginloader, dep_urlfilter], + dependencies: [dep_qt5, dep_spdlog, dep_SingleApplication, dep_args, optional_deps, dep_about, dep_bookmarks, dep_configuration, dep_downloads, dep_pluginloader, dep_urlfilter, ssconfig.dependencies()], install: true, ) diff --git a/src/crashhandler.cpp b/src/crashhandler.cpp index 194d04b..0c2fec7 100644 --- a/src/crashhandler.cpp +++ b/src/crashhandler.cpp @@ -8,31 +8,49 @@ #include "crashhandler.h" #include "version.h" - -#ifdef BREAKPAD - -//#ifdef Q_OS_LINUX +#include <QByteArray> +#include <client/linux/handler/exception_handler.h> #include <unistd.h> -//#endif // Q_OS_LINUX - -bool CrashHandler::dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor, void *context, bool succeeded) +// bool filter_callback (void*) +// --> true: continue processing and write a minidump +static bool minidumpCb(const google_breakpad::MinidumpDescriptor &descriptor, void *context, bool succeeded) { printf("Dump path: %s\n", descriptor.path()); - auto *ctx = static_cast<BreakpadContext *>(context); + auto *ctx = static_cast<CrashHandler::Context *>(context); if(ctx != nullptr) { - if(ctx->handler != nullptr) { + if(!ctx->handler.empty()) { // fork and run 'handler master:commit path.dmp' pid_t pid = fork(); if(pid == 0) { - char buffer[256]; - snprintf(buffer, 256, "%s %s %s", ctx->handler, poi_Version, descriptor.path()); - execlp("/bin/sh", "/bin/sh", "-c", buffer, (char *)nullptr); + // pathname program argument ... nullptr + execlp(ctx->handler.c_str(), + ctx->handler.c_str(), "--crashd", ctx->dumppath.c_str(), "-c", descriptor.path(), poi_Version, + (char *)nullptr); } } } return succeeded; } -#endif + +bool CrashHandler::install_handler(CrashHandler::Context &ctx) +{ + if(ctx.dumppath.empty()) + return false; + + // Disable Chromium's crash handler so breakpad can capture crashes instead. + // This has to be done before QtWebEngine gets initialized. + const auto chromiumFlags = qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"); + if(!chromiumFlags.contains("disable-in-process-stack-traces")) { + qputenv("QTWEBENGINE_CHROMIUM_FLAGS", chromiumFlags + " --disable-in-process-stack-traces"); + } + + google_breakpad::MinidumpDescriptor descriptor(ctx.dumppath.c_str()); + + // minidump descriptor, filter callback, minidump callback, callback_context, install handler, server_fd + auto *eh = new google_breakpad::ExceptionHandler(descriptor, nullptr, minidumpCb, &ctx, true, -1); + + return true; +} diff --git a/src/crashhandler.h b/src/crashhandler.h index e7f7fa1..9b79ecc 100644 --- a/src/crashhandler.h +++ b/src/crashhandler.h @@ -9,26 +9,28 @@ #ifndef SMOLBOTE_CRASHHANDLER_H #define SMOLBOTE_CRASHHANDLER_H -#ifdef BREAKPAD -//#ifdef Q_OS_LINUX -#include <client/linux/handler/exception_handler.h> -#endif +#include <string> -class CrashHandler +namespace CrashHandler { - -public: - struct BreakpadContext { - char *handler = nullptr; - }; - - // bool filter_callback (void*) - // --> true: continue processing and write a minidump - -#ifdef BREAKPAD - static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor, void *context, bool succeeded); +struct Context { + const std::string dumppath; + const std::string handler; + + explicit Context(const std::string &path, const std::string &crashhandler) + : dumppath(path) + , handler(crashhandler) + { + } +}; + +bool install_handler(Context &ctx) +#ifndef HAVE_BREAKPAD +{ + return false; +} #endif - -}; // CrashHandler +; +}; #endif // SMOLBOTE_CRASHHANDLER_H diff --git a/src/main.cpp b/src/main.cpp index f4f2b78..f6a5b17 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -148,26 +148,20 @@ int main(int argc, char **argv) // set this, otherwise the webview becomes black when using a stylesheet app.setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true); -#ifdef CONFIG_USEBREAKPAD - const std::string crashpath = config->value<std::string>("browser.crash.path").value_or("/tmp"); - assert(!crashpath.empty()); - - CrashHandler::BreakpadContext ctx; - google_breakpad::MinidumpDescriptor descriptor(crashpath.c_str()); - - const auto crashHandler = config->value<std::string>("browser.crash.handler"); - if(crashHandler) { - const int length = crashHandler.value().length() + 1; - ctx.handler = new char[length]; - crashHandler.value().copy(ctx.handler, length - 1); - ctx.handler[length - 1] = '\0'; - } - - // minidump descriptor, filter callback, minidump callback, callback_context, install handler, server_fd - google_breakpad::ExceptionHandler eh(descriptor, nullptr, CrashHandler::dumpCallback, &ctx, true, -1); + { + Configuration conf; + if(conf.value<bool>("usebreakpad").value()) { + CrashHandler::Context ctx( + conf.value<std::string>("path.crashdump").value(), + conf.value<std::string>("path.crashhandler").value()); - spdlog::debug("Installed breakpad exception handler (path {})", crashpath); -#endif // CONFIG_USEBREAKPAD + if(CrashHandler::install_handler(ctx)) { + spdlog::info("Installed breakpad crash handler: {}", ctx.dumppath); + } else { + spdlog::warn("Failed to install breakpad crash handler: {}", ctx.dumppath); + } + } + } const auto profile = []() { Configuration c; diff --git a/src/meson.build b/src/meson.build index 25f94f0..956c41b 100644 --- a/src/meson.build +++ b/src/meson.build @@ -20,7 +20,7 @@ poi_sourceset.add(mod_qt5.preprocess( )) poi_sourceset.add(files( - 'main.cpp', 'builtins.cpp', 'crashhandler.cpp', + 'main.cpp', 'builtins.cpp', 'browser.cpp', 'util.cpp', 'util.h', @@ -53,3 +53,5 @@ poi_sourceset.add(files( interfaces_moc, version_h, poi_settings_h ) +poi_sourceset.add(when: [dep_breakpad, dep_threads], if_true: files('crashhandler.cpp')) + diff --git a/tools/src/crashhandler/main.go b/tools/src/crashhandler/main.go index 00ce0cd..7b1717f 100644 --- a/tools/src/crashhandler/main.go +++ b/tools/src/crashhandler/main.go @@ -67,7 +67,7 @@ func main() { return } - fmt.Printf("[%s]\n", dumpPath) + fmt.Printf(" [%s]\n", dumpPath) c, err := dumps(dumpPath) if err != nil { panic(err) @@ -75,5 +75,7 @@ func main() { for _, d := range c { fmt.Printf("\t- %s\n", d.Name) } + fmt.Println(" To analyze a crashdump, use the minidump_stackwalk tool:") + fmt.Println("minidump_stackwalk <minidump-file> [symbol-path]") } |