├── .gitignore ├── test ├── widget.h ├── widget.ui ├── widget.cpp ├── main.cpp └── CMakeLists.txt ├── LICENSE ├── README.md └── .github └── workflows └── build-crashpad.yml /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeLists.txt.user 2 | CMakeCache.txt 3 | CMakeFiles 4 | CMakeScripts 5 | Testing 6 | Makefile 7 | cmake_install.cmake 8 | install_manifest.txt 9 | compile_commands.json 10 | CTestTestfile.cmake 11 | _deps 12 | crashpad/ 13 | -------------------------------------------------------------------------------- /test/widget.h: -------------------------------------------------------------------------------- 1 | #ifndef WIDGET_H 2 | #define WIDGET_H 3 | 4 | #include 5 | 6 | QT_BEGIN_NAMESPACE 7 | namespace Ui { class Widget; } 8 | QT_END_NAMESPACE 9 | 10 | class Widget : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | Widget(QWidget *parent = nullptr); 16 | ~Widget(); 17 | 18 | private slots: 19 | void on_crashBtn_clicked(); 20 | 21 | private: 22 | Ui::Widget *ui; 23 | }; 24 | #endif // WIDGET_H 25 | -------------------------------------------------------------------------------- /test/widget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Widget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 369 10 | 217 11 | 12 | 13 | 14 | test 15 | 16 | 17 | 18 | 19 | 130 20 | 90 21 | 93 22 | 28 23 | 24 | 25 | 26 | crash 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/widget.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | #include "./ui_widget.h" 3 | 4 | Widget::Widget(QWidget *parent) 5 | : QWidget(parent) 6 | , ui(new Ui::Widget) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | Widget::~Widget() 12 | { 13 | delete ui; 14 | } 15 | 16 | 17 | void Widget::on_crashBtn_clicked() 18 | { 19 | // windows上这个crash为什么捕获不到? 20 | // windows上crashpad内部使用::SetUnhandledExceptionFilter()来注册异常处理函数 21 | // 而SetUnhandledExceptionFilter不能处理所有windows上的异常: 22 | // 1. windowproc等消息处理函数中的异常 - windowproc是由系统内核回调的,系统内部使用SEH处理系统内核回调的异常,所以SetUnhandledExceptionFilter抓不到 23 | // 2. crt中有自己的异常处理机制,在某些情况下会删除任何自定义崩溃处理程序(SetUnhandledExceptionFilter(NULL)),并且我们的崩溃处理程序将永远不会被调用 24 | // 关于windows下异常处理是一个比较复杂的问题,后面有时间专门调研 25 | 26 | // 202303 update:(换了新版crashpad ad2e04可以捕获了) 27 | *(volatile int *)0 = 0; 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Barry 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cmake-crashpad 2 | cmake项目集成crashpad(win&mac平台) 3 | 4 | 当前crashpad版本:chromium 111.0.5563.99 2023年3月7日版本 -> crashpad Revision ad2e04 5 | 6 | - 支持win&mac平台 7 | - github action自动编译crashpad并生成相关产物,方便后续复用 8 | - cmake脚本引入crashpad 9 | - crashpad基示例本代码 10 | 11 | # 注意事项 12 | - 构建crashpad时,要使用和Qt项目完全相同的Visual Studio版本,否则编译出错 13 | - Qt项目不能与/MT /MTd一起使用,所以需要编译/MD /MDd版本 14 | 15 | # 参考文档 16 | - [Qt项目使用crashpad上报dump到BugSplat教程](https://docs.bugsplat.com/introduction/getting-started/integrations/cross-platform/qt/) 17 | - [Qt项目使用crashpad上报dump到BugSplat示例](https://github.com/BugSplat-Git/my-qt-crasher) 18 | - [crashpad编译官方教程](https://chromium.googlesource.com/crashpad/crashpad/+/HEAD/doc/developing.md) 19 | 20 | - [crashpad上报dump到backtrace教程](https://support.backtrace.io/hc/en-us/articles/360040516131-Crashpad-Integration-Guide#InitialIntegration) 21 | 22 | # 扩展阅读 23 | ## ~~关于windows下SetUnhandledExceptionFilter不能捕获所有异常的相关调研~~(换了新版crashpad ad2e04可以捕获了) 24 | - [windows下异常处理相关介绍](http://crashrpt.sourceforge.net/docs/html/exception_handling.html) 25 | - [stackoverflow上的相关讨论](https://stackoverflow.com/questions/13591334/what-actions-do-i-need-to-take-to-get-a-crash-dump-in-all-error-scenarios) 26 | - [SetUnhandledExceptionFilter和CRT](https://www.codeproject.com/Articles/154686/SetUnhandledExceptionFilter-and-the-C-C-Runtime-Li) 27 | - [当crash捕获不生效的时候](https://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesnt-work/) 28 | - [SEH](https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-170) 29 | -------------------------------------------------------------------------------- /.github/workflows/build-crashpad.yml: -------------------------------------------------------------------------------- 1 | name: build crashpad 2 | 3 | # 手动触发github actions 4 | on: workflow_dispatch 5 | 6 | jobs: 7 | build: 8 | strategy: 9 | matrix: 10 | os: 11 | # windows-latest会始终保持最新(目前是2022) 12 | # windows server 2019安装的是vs2019,windows server 2016安装的是vs2017 13 | # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on 14 | - windows-2019 15 | # 注意如果编译旧版crashpad使用macos-10.15,macos-11编译旧版crashpad会有这个问题 https://bugs.chromium.org/p/chromium/issues/detail?id=1265179 16 | - macos-10.15 17 | 18 | runs-on: ${{ matrix.os }} 19 | 20 | steps: 21 | - name: checkout 22 | uses: actions/checkout@v2 23 | 24 | - name: build on macOS 25 | if: runner.os == 'macOS' 26 | run: | 27 | chmod +x ./build-crashpad.sh 28 | ./build-crashpad.sh 29 | shell: bash 30 | 31 | - name: build on windows 32 | if: runner.os == 'Windows' 33 | run: | 34 | call "C:\Program Files\Git\bin\bash.EXE" --noprofile --norc -e -o pipefail build-crashpad.sh 35 | shell: cmd 36 | 37 | - uses: actions/upload-artifact@v1 38 | if: runner.os == 'macOS' 39 | with: 40 | name: Mac-x64.zip 41 | path: crashpad/Mac-x64 42 | 43 | - uses: actions/upload-artifact@v1 44 | if: runner.os == 'Windows' 45 | with: 46 | name: Windows-x64.zip 47 | path: crashpad/Windows-x64 48 | 49 | - uses: actions/upload-artifact@v1 50 | if: runner.os == 'Windows' 51 | with: 52 | name: Windows-x86.zip 53 | path: crashpad/Windows-x86 54 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include "widget.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "client/crash_report_database.h" 7 | #include "client/crashpad_client.h" 8 | #include "client/settings.h" 9 | 10 | bool initializeCrashpad(); 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | QApplication a(argc, argv); 15 | 16 | qDebug() << "initializeCrashpad:" << initializeCrashpad(); 17 | // 这个crash可以捕获到 18 | //*(volatile int *)0 = 0; 19 | 20 | Widget w; 21 | w.show(); 22 | return a.exec(); 23 | } 24 | 25 | bool initializeCrashpad() { 26 | QString exeDir = QCoreApplication::applicationDirPath(); 27 | 28 | #if defined(Q_OS_WIN) 29 | base::FilePath handleDir((exeDir + "/crashpad_handler.exe").toStdWString()); 30 | base::FilePath reportsDir(exeDir.toStdWString()); 31 | base::FilePath metricsDir(exeDir.toStdWString()); 32 | #endif 33 | 34 | #if defined(Q_OS_MAC) 35 | base::FilePath handleDir((exeDir + "/crashpad_handler").toStdString()); 36 | base::FilePath reportsDir(exeDir.toStdString()); 37 | base::FilePath metricsDir(exeDir.toStdString()); 38 | #endif 39 | 40 | // BugSplat database url 41 | QString url = "http://cmake_crashpad.bugsplat.com/post/bp/crash/crashpad.php"; 42 | // Metadata that will be posted to BugSplat 43 | QMap annotations; 44 | annotations["format"] = "minidump"; // Required: Crashpad setting to save crash as a minidump 45 | annotations["database"] = "cmake_crashpad"; // Required: BugSplat database 46 | annotations["product"] = "test"; // Required: BugSplat appName 47 | annotations["version"] = "1.0.0"; // Required: BugSplat appVersion 48 | //annotations["key"] = "Sample key"; // Optional: BugSplat key field 49 | //annotations["user"] = "fred@bugsplat.com"; // Optional: BugSplat user email 50 | //annotations["list_annotations"] = "Sample comment"; // Optional: BugSplat crash description 51 | 52 | // Disable crashpad rate limiting so that all crashes have dmp files 53 | std::vector arguments; 54 | arguments.push_back("--no-rate-limit"); 55 | 56 | // Initialize crashpad database 57 | std::unique_ptr database = crashpad::CrashReportDatabase::Initialize(reportsDir); 58 | if (database == NULL) { 59 | return false; 60 | } 61 | 62 | // Enable automated crash uploads 63 | crashpad::Settings* settings = database->GetSettings(); 64 | if (settings == NULL) { 65 | return false; 66 | } 67 | settings->SetUploadsEnabled(true); 68 | 69 | // Start crash handler 70 | crashpad::CrashpadClient* client = new crashpad::CrashpadClient(); 71 | bool status = client->StartHandler(handleDir, reportsDir, metricsDir, url.toStdString(), annotations.toStdMap(), arguments, true, false); 72 | return status; 73 | } 74 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(test LANGUAGES CXX) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | 7 | set(CMAKE_AUTOUIC ON) 8 | set(CMAKE_AUTOMOC ON) 9 | set(CMAKE_AUTORCC ON) 10 | 11 | set(CMAKE_CXX_STANDARD 17) 12 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 13 | 14 | # QtCreator supports the following variables for Android, which are identical to qmake Android variables. 15 | # Check https://doc.qt.io/qt/deployment-android.html for more information. 16 | # They need to be set before the find_package( ...) calls below. 17 | 18 | #if(ANDROID) 19 | # set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") 20 | # if (ANDROID_ABI STREQUAL "armeabi-v7a") 21 | # set(ANDROID_EXTRA_LIBS 22 | # ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so 23 | # ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so) 24 | # endif() 25 | #endif() 26 | 27 | find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED) 28 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED) 29 | 30 | set(PROJECT_SOURCES 31 | main.cpp 32 | widget.cpp 33 | widget.h 34 | widget.ui 35 | ) 36 | 37 | if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) 38 | qt_add_executable(test 39 | ${PROJECT_SOURCES} 40 | ) 41 | else() 42 | if(ANDROID) 43 | add_library(test SHARED 44 | ${PROJECT_SOURCES} 45 | ) 46 | else() 47 | add_executable(test 48 | ${PROJECT_SOURCES} 49 | ) 50 | endif() 51 | endif() 52 | 53 | target_link_libraries(test PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) 54 | 55 | # crashpad 56 | target_include_directories(test PRIVATE 57 | ${CMAKE_CURRENT_SOURCE_DIR}/../crashpad/include/crashpad 58 | ${CMAKE_CURRENT_SOURCE_DIR}/../crashpad/include/crashpad/third_party/mini_chromium/mini_chromium 59 | ${CMAKE_CURRENT_SOURCE_DIR}/../crashpad/include/crashpad/gen 60 | ) 61 | 62 | target_link_directories(test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../crashpad/lib) 63 | 64 | if(CMAKE_SYSTEM_NAME STREQUAL "Windows") 65 | target_link_libraries(test PRIVATE 66 | $<$:clientd> 67 | $<$:based> 68 | $<$:utild> 69 | $<$:commond> 70 | 71 | $<$>:client> 72 | $<$>:base> 73 | $<$>:util> 74 | $<$>:common> 75 | ) 76 | 77 | add_custom_command(TARGET test POST_BUILD 78 | COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../crashpad/bin/crashpad_handler.exe" $ 79 | ) 80 | endif() 81 | 82 | if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") 83 | target_link_libraries(test PRIVATE 84 | client 85 | base 86 | util 87 | mig_output 88 | bsm 89 | "-framework AppKit" 90 | "-framework Security" 91 | "-framework IOKit" 92 | ) 93 | 94 | add_custom_command(TARGET test POST_BUILD 95 | COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/../crashpad/bin/crashpad_handler" $ 96 | ) 97 | endif() 98 | --------------------------------------------------------------------------------