From 10709880fca4e8b6f6ffb6ecae0e34a1bc2e0bcc Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 14 Aug 2020 18:25:12 +1000 Subject: [PATCH] preliminary google crashpad integration First attempt at automated out-of-process crash reporting. Have only updated AppVeyor script so far, so if this works (which it won't), it'll only work on Windows. --- .appveyor/build.bat | 22 +++++++-- CMakeLists.txt | 6 +++ app/CMakeLists.txt | 23 +++++++-- app/common/CMakeLists.txt | 2 + app/common/crashpadinterface.cpp | 82 ++++++++++++++++++++++++++++++++ app/common/crashpadinterface.h | 34 +++++++++++++ app/main.cpp | 16 +++++-- cmake/FindGoogleCrashpad.cmake | 82 ++++++++++++++++++++++++++++++++ 8 files changed, 255 insertions(+), 12 deletions(-) create mode 100644 app/common/crashpadinterface.cpp create mode 100644 app/common/crashpadinterface.h create mode 100644 cmake/FindGoogleCrashpad.cmake diff --git a/.appveyor/build.bat b/.appveyor/build.bat index e2c6b553f..51211c585 100644 --- a/.appveyor/build.bat +++ b/.appveyor/build.bat @@ -30,8 +30,17 @@ curl https://ffmpeg.zeranoe.com/builds/win64/shared/%FFMPEG_VER%-shared.zip > %F 7z x %FFMPEG_VER%-dev.zip 7z x %FFMPEG_VER%-shared.zip -REM Add Qt and FFmpeg directory to path -set PATH=%PATH%;C:\Qt\5.13.2\msvc2017_64\bin;%APPVEYOR_BUILD_FOLDER%\%FFMPEG_VER%-dev +REM Acquire Google Crashpad +git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git +set PATH=%PATH%;%APPVEYOR_BUILD_FOLDER%\depot_tools +fetch crashpad +cd crashpad +gn gen out/Default +ninja -C out/Default +cd .. + +REM Add Qt, FFmpeg, and Crashpad to path +set PATH=%PATH%;C:\Qt\5.13.2\msvc2017_64\bin;%APPVEYOR_BUILD_FOLDER%\%FFMPEG_VER%-dev;%APPVEYOR_BUILD_FOLDER%\crashpad;%APPVEYOR_BUILD_FOLDER%\crashpad\out\Default REM Run cmake cmake -G "Ninja" . -DCMAKE_TOOLCHAIN_FILE=c:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo @@ -42,12 +51,18 @@ ninja.exe || exit /B 1 REM If this is a pull request, no further packaging/deploying needs to be done if NOT "%APPVEYOR_PULL_REQUEST_NUMBER%" == "" goto end +REM Create Crashpad symbol file and upload it +wget https://github.com/google/breakpad/blob/master/src/tools/windows/binaries/dump_syms.exe?raw=true -O dump_syms.exe +dump_syms app\olive-editor.pdb > olive-editor.sym +curl -F symfile=@olive-editor.sym https://olivevideoeditor.org/crashpad/symbols.php + REM Start building package mkdir olive-editor cd olive-editor copy ..\app\olive-editor.exe . copy ..\app\olive-editor.pdb . copy ..\app\crashhandler.exe . +copy ..\crashpad\out\Default\crashpad_handler.exe . windeployqt olive-editor.exe copy ..\%FFMPEG_VER%-shared\bin\*.dll . copy C:\Tools\vcpkg\installed\x64-windows\bin\OpenColorIO.dll . @@ -85,9 +100,6 @@ REM Create portable copy nul olive-editor\portable 7z a %PKGNAME%.zip olive-editor -REM We're ready to upload, but we only upload *sometimes* -REM set PATH=%PATH%;C:\msys64\usr\bin - REM If this was a tagged build, upload if "%APPVEYOR_REPO_TAG%"=="true" GOTO upload diff --git a/CMakeLists.txt b/CMakeLists.txt index 95a3ef62d..3c0f423c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,12 @@ find_package(FFMPEG 3.0 REQUIRED swresample ) +find_package(GoogleCrashpad) + +if (NOT GoogleCrashpad_FOUND) + message(" Automatic crash reporting will be disabled.") +endif() + if(EXISTS "${CMAKE_SOURCE_DIR}/.git") find_package(Git) if(GIT_FOUND) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 931702964..714a5e01d 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -79,9 +79,6 @@ if(APPLE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9") endif() -# Set compiler definitions -target_compile_definitions(${OLIVE_TARGET} PRIVATE ${OLIVE_DEFINITIONS}) - # Set compiler options if(MSVC) target_compile_options( @@ -171,6 +168,26 @@ elseif (APPLE) ) endif() +# Enable Crashpad if found +if (GoogleCrashpad_FOUND) + set(OLIVE_DEFINITIONS ${OLIVE_DEFINITIONS} USE_CRASHPAD) + + target_include_directories( + ${OLIVE_TARGET} + PRIVATE + ${CRASHPAD_INCLUDE_DIRS} + ) + + target_link_libraries( + ${OLIVE_TARGET} + PRIVATE + ${CRASHPAD_LIBRARIES} + ) +endif() + +# Set compiler definitions +target_compile_definitions(${OLIVE_TARGET} PRIVATE ${OLIVE_DEFINITIONS}) + set(OLIVE_TS_FILES # FIXME: Empty variable ) diff --git a/app/common/CMakeLists.txt b/app/common/CMakeLists.txt index 295027196..0ee6714aa 100644 --- a/app/common/CMakeLists.txt +++ b/app/common/CMakeLists.txt @@ -23,6 +23,8 @@ set(OLIVE_SOURCES common/clamp.h common/crashhandler.h common/crashhandler.cpp + common/crashpadinterface.cpp + common/crashpadinterface.h common/debug.h common/debug.cpp common/define.h diff --git a/app/common/crashpadinterface.cpp b/app/common/crashpadinterface.cpp new file mode 100644 index 000000000..85cf37fad --- /dev/null +++ b/app/common/crashpadinterface.cpp @@ -0,0 +1,82 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "crashpadinterface.h" + +#ifdef USE_CRASHPAD + +#include +#include +#include + +#include "filefunctions.h" + +// Copied from base::FilePath to match its macro +#if defined(OS_POSIX) + // On most platforms, native pathnames are char arrays, and the encoding + // may or may not be specified. On Mac OS X, native pathnames are encoded + // in UTF-8. + #define TO_BASE_STRING_TYPE(x) x.toStdString() +#elif defined(OS_WIN) + // On Windows, for Unicode-aware applications, native pathnames are wchar_t + // arrays encoded in UTF-16. + #define TO_BASE_STRING_TYPE(x) x.toStdWString() +#endif // OS_WIN + +bool InitializeCrashpad() +{ + QString exe_dir = QCoreApplication::applicationDirPath(); + + // FIXME: On Linux, probably should put this in a subdir so that it doesn't conflict with + // anything else in /usr/bin + + base::FilePath handler(TO_BASE_STRING_TYPE(QDir(exe_dir).filePath(QStringLiteral("crashpad_handler.exe")))); + + base::FilePath reports_dir(TO_BASE_STRING_TYPE(QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath("reports"))); + + base::FilePath metrics_dir(TO_BASE_STRING_TYPE(QDir(OLIVE_NAMESPACE::FileFunctions::GetTempFilePath()).filePath("metrics"))); + + std::string url = "https://olivevideoeditor.org/crashpad/report.php"; + + // Metadata that will be posted to the server with the crash report map + std::map annotations; + + // Disable crashpad rate limiting so that all crashes have dmp files + std::vector arguments; + arguments.push_back("--no-rate-limit"); + arguments.push_back("--no-upload-gzip"); + + // Initialize Crashpad database + std::unique_ptr database = crashpad::CrashReportDatabase::Initialize(reports_dir); + if (database == NULL) return false; + + // Enable automated crash uploads + crashpad::Settings *settings = database->GetSettings(); + if (settings == NULL) return false; + settings->SetUploadsEnabled(true); + + // Start crash handler + crashpad::CrashpadClient *client = new crashpad::CrashpadClient(); + bool status = client->StartHandler(handler, reports_dir, metrics_dir, + url, annotations, arguments, true, true); + return status; +} + +#endif // USE_CRASHPAD diff --git a/app/common/crashpadinterface.h b/app/common/crashpadinterface.h new file mode 100644 index 000000000..26bd17b65 --- /dev/null +++ b/app/common/crashpadinterface.h @@ -0,0 +1,34 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef CRASHPAD_INTERFACE_H +#define CRASHPAD_INTERFACE_H + +#ifdef USE_CRASHPAD + +#include +#include +#include + +bool InitializeCrashpad(); + +#endif // USE_CRASHPAD + +#endif // CRASHPAD_INTERFACE_H diff --git a/app/main.cpp b/app/main.cpp index 0026395f0..d58b65ebf 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -32,17 +32,18 @@ extern "C" { } #include + #include #include #include "core.h" -#include "common/crashhandler.h" #include "common/debug.h" -int main(int argc, char *argv[]) { - signal(SIGSEGV, OLIVE_NAMESPACE::crash_handler); - signal(SIGABRT, OLIVE_NAMESPACE::crash_handler); +#ifdef USE_CRASHPAD +#include "common/crashpadinterface.h" +#endif // USE_CRASHPAD +int main(int argc, char *argv[]) { // Set OpenGL display profile (3.2 Core) QSurfaceFormat format; format.setVersion(3, 2); @@ -86,5 +87,12 @@ int main(int argc, char *argv[]) { avfilter_register_all(); #endif + // Enable Google Crashpad if compiled with it +#ifdef USE_CRASHPAD + if (!InitializeCrashpad()) { + qWarning() << "Failed to initialize Crashpad handler"; + } +#endif // USE_CRASHPAD + return OLIVE_NAMESPACE::Core::instance()->execute(&a); } diff --git a/cmake/FindGoogleCrashpad.cmake b/cmake/FindGoogleCrashpad.cmake new file mode 100644 index 000000000..4a5f2f2a9 --- /dev/null +++ b/cmake/FindGoogleCrashpad.cmake @@ -0,0 +1,82 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +include(FindPackageHandleStandardArgs) + +# Try to find include files +find_path(CRASHPAD_CLIENT_INCLUDE_DIR + client/crashpad_client.h + HINTS + "${CRASHPAD_LOCATION}" + "$ENV{CRASHPAD_LOCATION}" + "${CRASHPAD_BASE_DIR}" +) +list(APPEND CRASHPAD_INCLUDE_DIRS ${CRASHPAD_CLIENT_INCLUDE_DIR}) + +find_path(CRASHPAD_BASE_INCLUDE_DIR + base/files/file_path.h + HINTS + "${CRASHPAD_LOCATION}" + "$ENV{CRASHPAD_LOCATION}" + "${CRASHPAD_BASE_DIR}" + PATH_SUFFIXES + "third_party/mini_chromium/mini_chromium" +) +list(APPEND CRASHPAD_INCLUDE_DIRS ${CRASHPAD_BASE_INCLUDE_DIR}) + +# Try to find build files +if (WIN32) + find_path(CRASHPAD_LIBRARY_DIRS + obj/client/client.lib + HINTS + "${CRASHPAD_LOCATION}" + "$ENV{CRASHPAD_LOCATION}" + "${CRASHPAD_BASE_DIR}" + ) +elseif(UNIX) + # Assuming macOS works this way, don't actually know + find_path(CRASHPAD_LIBRARY_DIRS + obj/client/libclient.a + HINTS + "${CRASHPAD_LOCATION}" + "$ENV{CRASHPAD_LOCATION}" + "${CRASHPAD_BASE_DIR}" + ) +endif() + +# Find the libraries we need +set (_crashpad_components + client/client + util/util + third_party/mini_chromium/mini_chromium/base/base) +foreach (COMPONENT ${_crashpad_components}) + string(REGEX MATCH "^(.*[\\\/])" SUBDIR ${COMPONENT}) + string(REGEX MATCH "([^\/]+$)" SHORT_COMPONENT ${COMPONENT}) + string(TOUPPER ${SHORT_COMPONENT} UPPERCOMPONENT) + + find_library(CRASHPAD_${UPPERCOMPONENT}_LIB + ${SHORT_COMPONENT} + HINTS "${CRASHPAD_LIBRARY_DIRS}/obj/${SUBDIR}" + ) + + list(APPEND CRASHPAD_LIBRARIES ${CRASHPAD_${UPPERCOMPONENT}_LIB}) +endforeach() + +find_package_handle_standard_args(GoogleCrashpad + REQUIRED_VARS + CRASHPAD_LIBRARIES + CRASHPAD_INCLUDE_DIRS +)