├── .gitmodules ├── LICENSE ├── README.md ├── doc └── jpnaude.md ├── qt-breakpad.pri ├── qt_breakpad.cpp └── qt_breakpad.h /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/breakpad"] 2 | path = vendor/breakpad 3 | url = https://github.com/google/breakpad.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Credit goes to [JPNaude](https://github.com/JPNaude/dev_notes/wiki/Using-Google-Breakpad-with-Qt) 2 | 3 | # Qt Breakpad 4 | 5 | A little wrapper around [Google's 6 | Breakpad](https://chromium.googlesource.com/breakpad/breakpad/) to 7 | be used in [Qt5](http://www.qt.io/) projects, to make it platform-independent. 8 | 9 | For now, only supports Linux and Windows (please open an issue, or even better, 10 | a pull request, to support other OSes). 11 | 12 | ## Usage 13 | 14 | Checkout this repo in your app's folder, e.g. (but not 15 | necessarily) as a submodule (and the path is up to you, too): 16 | 17 | ```bash 18 | git submodule add git@github.com:wk8/qt-breakpad.git qt-breakpad 19 | git submodule update --init --recursive 20 | ``` 21 | 22 | In your Qt project's `*.pro` file, include `qt-breakpad`'s `pri` file: 23 | ``` 24 | include(qt-breakpad/qt-breakpad.pri) 25 | ``` 26 | 27 | In your application's `main`, before doing anything else, initialize the handler: 28 | 29 | ```cpp 30 | #include "qt_breakpad.h" 31 | 32 | int main(int argc, char *argv[]) { 33 | QString reportPath = QDir::current().absolutePath(); // or whatever else you want, but it must exist 34 | QtBreakpad::init(reportPath); 35 | 36 | // ... your app's code starts here 37 | 38 | return 0; 39 | } 40 | ``` 41 | 42 | Now if your app crashes, a `dmp` file will be generated in the given path. 43 | 44 | If you want to send the said dump to some server, you can do 45 | that by passing a 46 | `google_breakpad::ExceptionHandler::MinidumpCallback` to 47 | `QtBreakpad::init`; or keep reading! 48 | 49 | ## Real-life example 50 | 51 | We also provide a wrapper around 52 | `google_breakpad::ExceptionHandler::MinidumpCallback`s in the 53 | usual case where you simply want to access the minidump file to 54 | send it; that's 55 | ```cpp 56 | typedef bool (*QMinidumpCallback)(QFile& minidumpFile, void* context); 57 | ``` 58 | that can be passed a second argument to `QtBreakpad::init`. 59 | 60 | It should return `true` if and only if it has successfully done 61 | its job (in which case no further Breakpad handlers that might 62 | have been defined will be called). 63 | 64 | A more complicated example than above, that uses context object, 65 | and retrieves the contents of the minidump file and encodes it to 66 | base 64: 67 | 68 | ```cpp 69 | #include "qt_breakpad.h" 70 | 71 | class MyContext 72 | { 73 | public: 74 | QDateTime appStartedAt; 75 | } 76 | 77 | bool myQtBreakpadCallback(QFile &minidumpFile, void* context) 78 | { 79 | MyContext* myContext = (MyContext*) context; 80 | 81 | QFileInfo fileInfo(minidumpFile); 82 | 83 | qDebug("From myQtBreakpadCallback; minidump file at " + fileInfo.absoluteFilePath()); 84 | qDebug("My app had started at " + myContext->appStartedAt.toString()); 85 | 86 | minidumpFile.open(QIODevice::ReadOnly); 87 | QByteArray rawMinidumpContent = minidumpFile.readAll(); 88 | QString minidumpContent = rawMinidumpContent.toBase64(); 89 | 90 | // ... actually upload it somewhere 91 | 92 | return true; 93 | } 94 | 95 | int main(int argc, char *argv[]) { 96 | QString reportPath = QDir::current().absolutePath(); // or whatever else you want, but it must exist 97 | 98 | MyContext myContext; 99 | myContext.appStartedAt = QDateTime::currentDateTimeUtc(); 100 | 101 | QtBreakpad::init(reportPath, myQtBreakpadCallback, &myContext); 102 | 103 | // ... your app's code starts here 104 | 105 | return 0; 106 | } 107 | ``` 108 | 109 | ## Analyzing the dumps 110 | 111 | See [here](https://github.com/JPNaude/dev_notes/wiki/Using-Google-Breakpad-with-Qt). 112 | -------------------------------------------------------------------------------- /doc/jpnaude.md: -------------------------------------------------------------------------------- 1 | This is only a backup of https://github.com/JPNaude/dev_notes/wiki/Using-Google-Breakpad-with-Qt, in case that repo would get deleted. 2 | 3 | --- 4 | 5 | # Introduction 6 | 7 | Google Breakpad is a cross platform crash handler which generates minidumps when your application crash. Users can send these minidumps to you and it contains valuable information allowing you to figure out why it crashed on them. More information on the [Google Breakpad](https://code.google.com/p/google-breakpad/) project page. 8 | 9 | This page contains notes I made while implementing a Google Breakpad based crash handler for a Qt 5.1.1 C++ application. The implementation was done and tested on both Windows 7 (MSVC Express 2010) and Linux (Ubuntu 12.0.4 and CentOs 5.6) using SVN revision 1281 of the Google Breakpad repository. 10 | 11 | The implementation is roughly based on [this blog post](http://blog.inventic.eu/2012/08/qt-and-google-breakpad/) so its a good reference to fall back to if this page is unclear. All references to other operating systems were removed (Mac etc.). 12 | 13 | If something is wrong in the article or if I am not understanding something correctly, please file a bug against this article or feel free to edit the wiki page. 14 | 15 | # Integration into the Qt application 16 | 17 | * Svn checkout the Google Breakpad sources: 18 | 19 | `svn checkout http://google-breakpad.googlecode.com/svn/trunk/ google-breakpad-read-only` 20 | 21 | * Create a directory called `crashhandler` in your application's source directory. 22 | * Create a new class called `CrashHandler` in this directory. The header and source file contents looks like this: 23 | 24 | `crash_handler.h` 25 | ```C++ 26 | #pragma once 27 | #include 28 | 29 | namespace Breakpad { 30 | class CrashHandlerPrivate; 31 | class CrashHandler 32 | { 33 | public: 34 | static CrashHandler* instance(); 35 | void Init(const QString& reportPath); 36 | 37 | void setReportCrashesToSystem(bool report); 38 | bool writeMinidump(); 39 | 40 | private: 41 | CrashHandler(); 42 | ~CrashHandler(); 43 | Q_DISABLE_COPY(CrashHandler) 44 | CrashHandlerPrivate* d; 45 | }; 46 | } 47 | ``` 48 | 49 | `crash_handler.cpp` 50 | ```C++ 51 | #include "crash_handler.h" 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #if defined(Q_OS_LINUX) 58 | #include "client/linux/handler/exception_handler.h" 59 | #elif defined(Q_OS_WIN32) 60 | #include "client/windows/handler/exception_handler.h" 61 | #endif 62 | 63 | namespace Breakpad { 64 | /************************************************************************/ 65 | /* CrashHandlerPrivate */ 66 | /************************************************************************/ 67 | class CrashHandlerPrivate 68 | { 69 | public: 70 | CrashHandlerPrivate() 71 | { 72 | pHandler = NULL; 73 | } 74 | 75 | ~CrashHandlerPrivate() 76 | { 77 | delete pHandler; 78 | } 79 | 80 | void InitCrashHandler(const QString& dumpPath); 81 | static google_breakpad::ExceptionHandler* pHandler; 82 | static bool bReportCrashesToSystem; 83 | }; 84 | 85 | google_breakpad::ExceptionHandler* CrashHandlerPrivate::pHandler = NULL; 86 | bool CrashHandlerPrivate::bReportCrashesToSystem = false; 87 | 88 | /************************************************************************/ 89 | /* DumpCallback */ 90 | /************************************************************************/ 91 | #if defined(Q_OS_WIN32) 92 | bool DumpCallback(const wchar_t* _dump_dir,const wchar_t* _minidump_id,void* context,EXCEPTION_POINTERS* exinfo,MDRawAssertionInfo* assertion,bool success) 93 | #elif defined(Q_OS_LINUX) 94 | bool DumpCallback(const google_breakpad::MinidumpDescriptor &md,void *context, bool success) 95 | #endif 96 | { 97 | Q_UNUSED(context); 98 | #if defined(Q_OS_WIN32) 99 | Q_UNUSED(_dump_dir); 100 | Q_UNUSED(_minidump_id); 101 | Q_UNUSED(assertion); 102 | Q_UNUSED(exinfo); 103 | #endif 104 | qDebug("BreakpadQt crash"); 105 | 106 | /* 107 | NO STACK USE, NO HEAP USE THERE !!! 108 | Creating QString's, using qDebug, etc. - everything is crash-unfriendly. 109 | */ 110 | return CrashHandlerPrivate::bReportCrashesToSystem ? success : true; 111 | } 112 | 113 | void CrashHandlerPrivate::InitCrashHandler(const QString& dumpPath) 114 | { 115 | if ( pHandler != NULL ) 116 | return; 117 | 118 | #if defined(Q_OS_WIN32) 119 | std::wstring pathAsStr = (const wchar_t*)dumpPath.utf16(); 120 | pHandler = new google_breakpad::ExceptionHandler( 121 | pathAsStr, 122 | /*FilterCallback*/ 0, 123 | DumpCallback, 124 | /*context*/ 125 | 0, 126 | true 127 | ); 128 | #elif defined(Q_OS_LINUX) 129 | std::string pathAsStr = dumpPath.toStdString(); 130 | google_breakpad::MinidumpDescriptor md(pathAsStr); 131 | pHandler = new google_breakpad::ExceptionHandler( 132 | md, 133 | /*FilterCallback*/ 0, 134 | DumpCallback, 135 | /*context*/ 0, 136 | true, 137 | -1 138 | ); 139 | #endif 140 | } 141 | 142 | /************************************************************************/ 143 | /* CrashHandler */ 144 | /************************************************************************/ 145 | CrashHandler* CrashHandler::instance() 146 | { 147 | static CrashHandler globalHandler; 148 | return &globalHandler; 149 | } 150 | 151 | CrashHandler::CrashHandler() 152 | { 153 | d = new CrashHandlerPrivate(); 154 | } 155 | 156 | CrashHandler::~CrashHandler() 157 | { 158 | delete d; 159 | } 160 | 161 | void CrashHandler::setReportCrashesToSystem(bool report) 162 | { 163 | d->bReportCrashesToSystem = report; 164 | } 165 | 166 | bool CrashHandler::writeMinidump() 167 | { 168 | bool res = d->pHandler->WriteMinidump(); 169 | if (res) { 170 | qDebug("BreakpadQt: writeMinidump() success."); 171 | } else { 172 | qWarning("BreakpadQt: writeMinidump() failed."); 173 | } 174 | return res; 175 | } 176 | 177 | void CrashHandler::Init( const QString& reportPath ) 178 | { 179 | d->InitCrashHandler(reportPath); 180 | } 181 | } 182 | ``` 183 | 184 | * Create a new .pri file for the required files in this directory. I did not explore the other ways of building breakpad on its own. Instead just adding the required files to a .pri and then adding this .pri to the Qt application proved very easy and clean. Note that more required files will probably be needed for other platform which I did not test, but any missing files can easily be added. The resulting pri looks like this: 185 | 186 | ``` 187 | # *************************************************************************** 188 | # Implemented using http://blog.inventic.eu/2012/08/qt-and-google-breakpad/ 189 | # as a the reference. 190 | # 191 | # Get Google Breakpad here: https://code.google.com/p/google-breakpad/ 192 | # 193 | # The required breakpad sources have been copied into /src in order to make 194 | # integration with the application smooth and easy. 195 | # 196 | # To use source from Google Breakpad SVN checkout instead, change $$PWD/src 197 | # to path where it was checked out. 198 | # 199 | # *************************************************************************** 200 | 201 | HEADERS += $$PWD/crash_handler.h 202 | SOURCES += $$PWD/crash_handler.cpp 203 | 204 | INCLUDEPATH += $$PWD 205 | INCLUDEPATH += $$PWD/src 206 | 207 | # Windows 208 | win32:HEADERS += $$PWD/src/common/windows/string_utils-inl.h 209 | win32:HEADERS += $$PWD/src/common/windows/guid_string.h 210 | win32:HEADERS += $$PWD/src/client/windows/handler/exception_handler.h 211 | win32:HEADERS += $$PWD/src/client/windows/common/ipc_protocol.h 212 | win32:HEADERS += $$PWD/src/google_breakpad/common/minidump_format.h 213 | win32:HEADERS += $$PWD/src/google_breakpad/common/breakpad_types.h 214 | win32:HEADERS += $$PWD/src/client/windows/crash_generation/crash_generation_client.h 215 | win32:HEADERS += $$PWD/src/common/scoped_ptr.h 216 | win32:SOURCES += $$PWD/src/client/windows/handler/exception_handler.cc 217 | win32:SOURCES += $$PWD/src/common/windows/string_utils.cc 218 | win32:SOURCES += $$PWD/src/common/windows/guid_string.cc 219 | win32:SOURCES += $$PWD/src/client/windows/crash_generation/crash_generation_client.cc 220 | 221 | # Linux 222 | unix:HEADERS += $$PWD/src/client/linux/minidump_writer/cpu_set.h 223 | unix:HEADERS += $$PWD/src/client/linux/minidump_writer/proc_cpuinfo_reader.h 224 | unix:HEADERS += $$PWD/src/client/linux/handler/exception_handler.h 225 | unix:HEADERS += $$PWD/src/client/linux/crash_generation/crash_generation_client.h 226 | unix:HEADERS += $$PWD/src/client/linux/handler/minidump_descriptor.h 227 | unix:HEADERS += $$PWD/src/client/linux/minidump_writer/minidump_writer.h 228 | unix:HEADERS += $$PWD/src/client/linux/minidump_writer/line_reader.h 229 | unix:HEADERS += $$PWD/src/client/linux/minidump_writer/linux_dumper.h 230 | unix:HEADERS += $$PWD/src/client/linux/minidump_writer/linux_ptrace_dumper.h 231 | unix:HEADERS += $$PWD/src/client/linux/minidump_writer/directory_reader.h 232 | unix:HEADERS += $$PWD/src/client/linux/log/log.h 233 | unix:HEADERS += $$PWD/src/client/minidump_file_writer-inl.h 234 | unix:HEADERS += $$PWD/src/client/minidump_file_writer.h 235 | unix:HEADERS += $$PWD/src/common/linux/linux_libc_support.h 236 | unix:HEADERS += $$PWD/src/common/linux/eintr_wrapper.h 237 | unix:HEADERS += $$PWD/src/common/linux/ignore_ret.h 238 | unix:HEADERS += $$PWD/src/common/linux/file_id.h 239 | unix:HEADERS += $$PWD/src/common/linux/memory_mapped_file.h 240 | unix:HEADERS += $$PWD/src/common/linux/safe_readlink.h 241 | unix:HEADERS += $$PWD/src/common/linux/guid_creator.h 242 | unix:HEADERS += $$PWD/src/common/linux/elfutils.h 243 | unix:HEADERS += $$PWD/src/common/linux/elfutils-inl.h 244 | unix:HEADERS += $$PWD/src/common/linux/elf_gnu_compat.h 245 | unix:HEADERS += $$PWD/src/common/using_std_string.h 246 | unix:HEADERS += $$PWD/src/common/memory.h 247 | unix:HEADERS += $$PWD/src/common/basictypes.h 248 | unix:HEADERS += $$PWD/src/common/memory_range.h 249 | unix:HEADERS += $$PWD/src/common/string_conversion.h 250 | unix:HEADERS += $$PWD/src/common/convert_UTF.h 251 | unix:HEADERS += $$PWD/src/google_breakpad/common/minidump_format.h 252 | unix:HEADERS += $$PWD/src/google_breakpad/common/minidump_size.h 253 | unix:HEADERS += $$PWD/src/google_breakpad/common/breakpad_types.h 254 | unix:HEADERS += $$PWD/src/common/scoped_ptr.h 255 | unix:HEADERS += $$PWD/src/third_party/lss/linux_syscall_support.h 256 | unix:SOURCES += $$PWD/src/client/linux/crash_generation/crash_generation_client.cc 257 | unix:SOURCES += $$PWD/src/client/linux/handler/exception_handler.cc 258 | unix:SOURCES += $$PWD/src/client/linux/handler/minidump_descriptor.cc 259 | unix:SOURCES += $$PWD/src/client/linux/minidump_writer/minidump_writer.cc 260 | unix:SOURCES += $$PWD/src/client/linux/minidump_writer/linux_dumper.cc 261 | unix:SOURCES += $$PWD/src/client/linux/minidump_writer/linux_ptrace_dumper.cc 262 | unix:SOURCES += $$PWD/src/client/linux/log/log.cc 263 | unix:SOURCES += $$PWD/src/client/minidump_file_writer.cc 264 | unix:SOURCES += $$PWD/src/common/linux/linux_libc_support.cc 265 | unix:SOURCES += $$PWD/src/common/linux/file_id.cc 266 | unix:SOURCES += $$PWD/src/common/linux/memory_mapped_file.cc 267 | unix:SOURCES += $$PWD/src/common/linux/safe_readlink.cc 268 | unix:SOURCES += $$PWD/src/common/linux/guid_creator.cc 269 | unix:SOURCES += $$PWD/src/common/linux/elfutils.cc 270 | unix:SOURCES += $$PWD/src/common/string_conversion.cc 271 | unix:SOURCES += $$PWD/src/common/convert_UTF.c 272 | #breakpad app need debug info inside binaries 273 | unix:QMAKE_CXXFLAGS+=-g 274 | ``` 275 | 276 | * (Optional) If you prefer to check the breakpad sources into your main code repository to make building on multiple machines easier, only the above files are required instead of checking in everything contained in the breakpad repository. The tree under our _crashhandler _directory should look like this: 277 | 278 | ``` 279 | . 280 | ├── crash_handler.cpp 281 | ├── crash_handler.h 282 | ├── crash_handler.pri 283 | └── src 284 | ├── client 285 | │   ├── linux 286 | │   │   ├── crash_generation 287 | │   │   │   ├── crash_generation_client.cc 288 | │   │   │   └── crash_generation_client.h 289 | │   │   ├── handler 290 | │   │   │   ├── exception_handler.cc 291 | │   │   │   ├── exception_handler.h 292 | │   │   │   ├── minidump_descriptor.cc 293 | │   │   │   └── minidump_descriptor.h 294 | │   │   ├── log 295 | │   │   │   ├── log.cc 296 | │   │   │   └── log.h 297 | │   │   └── minidump_writer 298 | │   │   ├── cpu_set.h 299 | │   │   ├── directory_reader.h 300 | │   │   ├── line_reader.h 301 | │   │   ├── linux_dumper.cc 302 | │   │   ├── linux_dumper.h 303 | │   │   ├── linux_ptrace_dumper.cc 304 | │   │   ├── linux_ptrace_dumper.h 305 | │   │   ├── minidump_writer.cc 306 | │   │   ├── minidump_writer.h 307 | │   │   └── proc_cpuinfo_reader.h 308 | │   ├── minidump_file_writer.cc 309 | │   ├── minidump_file_writer.h 310 | │   ├── minidump_file_writer-inl.h 311 | │   └── windows 312 | │   ├── common 313 | │   │   ├── auto_critical_section.h 314 | │   │   └── ipc_protocol.h 315 | │   ├── crash_generation 316 | │   │   ├── crash_generation_client.cc 317 | │   │   └── crash_generation_client.h 318 | │   └── handler 319 | │   ├── exception_handler.cc 320 | │   └── exception_handler.h 321 | ├── common 322 | │   ├── basictypes.h 323 | │   ├── convert_UTF.c 324 | │   ├── convert_UTF.h 325 | │   ├── linux 326 | │   │   ├── eintr_wrapper.h 327 | │   │   ├── elf_gnu_compat.h 328 | │   │   ├── elfutils.cc 329 | │   │   ├── elfutils.h 330 | │   │   ├── elfutils-inl.h 331 | │   │   ├── file_id.cc 332 | │   │   ├── file_id.h 333 | │   │   ├── guid_creator.cc 334 | │   │   ├── guid_creator.h 335 | │   │   ├── ignore_ret.h 336 | │   │   ├── linux_libc_support.cc 337 | │   │   ├── linux_libc_support.h 338 | │   │   ├── memory_mapped_file.cc 339 | │   │   ├── memory_mapped_file.h 340 | │   │   ├── safe_readlink.cc 341 | │   │   └── safe_readlink.h 342 | │   ├── memory.h 343 | │   ├── memory_range.h 344 | │   ├── memory_range_unittest.cc 345 | │   ├── scoped_ptr.h 346 | │   ├── string_conversion.cc 347 | │   ├── string_conversion.h 348 | │   ├── using_std_string.h 349 | │   └── windows 350 | │   ├── guid_string.cc 351 | │   ├── guid_string.h 352 | │   ├── string_utils.cc 353 | │   └── string_utils-inl.h 354 | ├── google_breakpad 355 | │   └── common 356 | │   ├── breakpad_types.h 357 | │   ├── minidump_cpu_amd64.h 358 | │   ├── minidump_cpu_arm64.h 359 | │   ├── minidump_cpu_arm.h 360 | │   ├── minidump_cpu_mips.h 361 | │   ├── minidump_cpu_ppc64.h 362 | │   ├── minidump_cpu_ppc.h 363 | │   ├── minidump_cpu_sparc.h 364 | │   ├── minidump_cpu_x86.h 365 | │   ├── minidump_exception_linux.h 366 | │   ├── minidump_exception_mac.h 367 | │   ├── minidump_exception_ps3.h 368 | │   ├── minidump_exception_solaris.h 369 | │   ├── minidump_exception_win32.h 370 | │   ├── minidump_format.h 371 | │   └── minidump_size.h 372 | └── third_party 373 | └── lss 374 | └── linux_syscall_support.h 375 | ``` 376 | 377 | * Add `crash_handler.pri` to the Qt application's .pro file. 378 | * Add the required files to the Qt application's main file: 379 | 380 | ```C++ 381 | #include "crash_handler.h" 382 | #include 383 | 384 | int buggyFunc() { 385 | delete reinterpret_cast(0xFEE1DEAD); 386 | return 0; 387 | } 388 | 389 | int main(int argc, char *argv[]) { 390 | QCoreApplication a(argc, argv); 391 | 392 | // We put the dumps in the user's home directory for this example: 393 | Breakpad::CrashHandler::instance()->Init(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)); 394 | 395 | buggyFunc(); 396 | 397 | return 0; 398 | } 399 | ``` 400 | 401 | * Run the application. It will crash and produce crash dump file in the path specified during the Init call. 402 | * The above dump file + the symbol file (see next section) is used to debug the crash (see last section). 403 | 404 | # Exporting the application's symbols 405 | 406 | Exporting of the application symbols is OS dependent as far as I can tell. 407 | 408 | ## Windows 409 | 410 | * In the breakpad checkout, go to `src\tools\windows\binaries`. The `dump_syms.exe` application does the exporting for us. I had numerous issues in order to get `dump_syms` to work, especially for older versions. Finally I managed to get it working with the latest rev. 1291 of Breakpad repository. 411 | 412 | * If you don't have MSVC 2013 available on you system (more specifically msdia120.dll) you will be greeded with the following output when attempting to use dump_syms: `CoCreateInstance CLSID_DiaSource failed (msdia*.dll unregistered?)` 413 | 414 | To fix it, download MSVC 2013 Express Edition and install it. For older versions of `dump_syms` you will require older versions of `msdia*.dll` as well. To get older version to work, following the steps below: 415 | 416 | 1. Download a copy of [msdia80.dll](http://www.dllme.com/download/dll-file/205365c3e4aa138c800936bdeca56c0f/msdia80.dll) and put it in `c:\Program Files\Common Files\Microsoft Shared\VC`. 417 | 2. Download a version of dump_syms built against MSVC9 [here](https://bug669384.bugzilla.mozilla.org/attachment.cgi?id=545295) into the `binaries` directory and rename the file to `dump_sums_vc9.exe`. It is also possible to build dump_syms manually, but I did not attempt it. 418 | 3. Also download the following files and place them into the `binaries` directory as well: [cygstdc++-6.dll](http://hg.mozilla.org/build/tools/raw-file/755e58ebc9d4/breakpad/win32/cygstdc++-6.dll), [cyggcc_s-1.dll](http://hg.mozilla.org/build/tools/raw-file/755e58ebc9d4/breakpad/win32/cyggcc_s-1.dll) and [cygwin1.dll](http://hg.mozilla.org/build/tools/raw-file/755e58ebc9d4/breakpad/win32/cygwin1.dll). 419 | 4. Next register all copies of msdia on the computer. I registered the following 3 files: 420 | 421 | ``` 422 | c:\Windows\system32\regsvr32 "c:\Program Files\Common Files\Microsoft Shared\VC\msdia80.dll" 423 | c:\Windows\system32\regsvr32 "c:\Program Files\Common Files\Microsoft Shared\VC\msdia90.dll" 424 | c:\Windows\system32\regsvr32 "c:\Program Files\Common Files\Microsoft Shared\VC\msdia100.dll" 425 | ``` 426 | 427 | * The symbol export process basically converts the .pdb file generated by MSVC into a .sym file used by Breakpad. Run the following command from the `binaries` directory: 428 | 429 | `dump_syms_vc9.exe \foo.pdb > foo.sym` 430 | 431 | * That's it. This .sym file will be used when analyzing the minidump. 432 | 433 | ## Linux 434 | 435 | For this I used the "Get the debugging symbols" section on [http://www.chromium.org/developers/decoding-crash-dumps](http://www.chromium.org/developers/decoding-crash-dumps) as a reference. 436 | 437 | The following steps were required from the breakpad checkout directory: 438 | 439 | * `./configure` 440 | * `make` 441 | * `cd src/tools/linux/dump_syms` 442 | * `./dump_syms /foo.so > foo.sym` 443 | 444 | This command produced some warning, although it did not seem to break anything downstream. 445 | 446 | ``` 447 | /foo.so, section '.eh_frame': the call frame entry at offset 0x18 uses a DWARF expression to describe how to recover register '.cfa', but this translator cannot yet translate DWARF expressions to Breakpad postfix expressions 448 | ``` 449 | 450 | * That's it. This .sym file will be used when analyzing the minidump. 451 | 452 | Note that dump_syms uses a library, not the main application. 453 | 454 | # Analyzing the minidump 455 | 456 | ## Windows 457 | 458 | I'm not sure if it is possible to properly analyze the dumps using the build in dump analysis applications found in the Debugging Tools for Windows set of tools since as far as I could figure out the Windows dump and Breakpad formats does not match exactly. 459 | 460 | Breakpad does however contains a small application which is intended to make sense out of the dump files. 461 | 462 | * Download `minidump_stackwalk.exe` from [here](http://hg.mozilla.org/build/tools/raw-file/755e58ebc9d4/breakpad/win32/minidump_stackwalk.exe) 463 | * Note that this .exe needs the same cygwin dependencies mentioned in the Windows section of "Exporting the application's symbols". 464 | * Launch the `minidump_stackwalk.exe` with the dump file and pipe the output to `foo.txt`: 465 | 466 | ` minidump_stackwalk.exe foo.dmp symbols > foo.txt 2>&1` 467 | 468 | * The above command prints a bunch of very useful information to help debug crashes (loaded modules, details of OS on which crash happened, reason for the crash, stack traces for all active threads). I noticed that the stack trace did not contain line numbers which indicates that the debug symbols was not correctly loaded. Inspecting the top part of the output I found this line: 469 | 470 | `2014-02-26 11:49:53: simple_symbol_supplier.cc:171: INFO: No symbol file at foo.sym/foo.pdb/BD6D3E40BCF34C77861B0EADF13A901C69/foo.sym` 471 | 472 | * To fix it you need to place the symbols in a specific directory structure. For example: 473 | 474 | 1. Create directory in the `binaries` directory called `foo.pdb`. 475 | 2. Inside this new directory, create another directory called (notice that I tood the hex characters from the above message) `BD6D3E40BCF34C77861B0EADF13A901C69`. 476 | 3. Copy the symbol file into this new directory. 477 | 4. Rerun the stack walk application like this: `minidump_stackwalk.exe ./foo.dmp .` 478 | 479 | See "Notes on the directory structure required in order to use minidump_stackwalk" at the end of this document for more information on the required symbols directory structure. 480 | 481 | * Looking at the output of `minidump_stackwalk.exe` now shows correct file numbers for the code in the Qt application. 482 | 483 | ## Linux 484 | 485 | For this I used the "Get the debugging symbols" section on [http://www.chromium.org/developers/decoding-crash-dumps](http://www.chromium.org/developers/decoding-crash-dumps) as a reference. 486 | 487 | The following steps were required from within the breakpad checkout directory: 488 | 489 | * `./configure && make` 490 | * `minidump_stackwalk` can be found in /src/processor 491 | 492 | After building, you can run `minidump_stackwalk` providing it with the .dmp file as well as the path to the symbols. For example: 493 | 494 | ``` 495 | minidump_stackwalk foo.dmp ./symbols 2>&1 > foo_stackwalk.txt 496 | ``` 497 | 498 | See "Notes on the directory structure required in order to use minidump_stackwalk" at the end of this document for more information on the required symbols directory structure. 499 | 500 | # General Notes 501 | 502 | * When using this approach to get crash reports from end users which will use release builds, we need to make sure the .pdb files on Windows are generated in order to do symbol exporting on the release libraries etc. To ensure that this happens, add the following to the .pro files or all libraries and executables: 503 | 504 | ``` 505 | # The following makes sure .pdb files are generated in release mode in order to analyze crash reports: 506 | win32-msvc* { 507 | QMAKE_LFLAGS_RELEASE += /MAP 508 | QMAKE_CFLAGS_RELEASE += /Zi 509 | QMAKE_LFLAGS_RELEASE += /debug /opt:ref 510 | } 511 | ``` 512 | 513 | * Notes on the directory structure required in order to use minidump_stackwalk: 514 | 515 | In order to use these symbols with the `minidump_stackwalk` tool, you will need to place them in a specific directory structure. To see where they should be placed, you can do the following (note that you need to run it from within the symbols directory otherwise it does not work): 516 | 517 | ``` 518 | $ cd 519 | $ /src/processor/minidump_stackwalk foo.dmp . 2>&1 | grep "No symbol" 520 | ``` 521 | 522 | This will produce output like the following: 523 | 524 | ``` 525 | 2014-03-20 12:41:17: simple_symbol_supplier.cc:196: INFO: No symbol file at ./libxcb.so.1/33466400C1C9785E1FADDFEA24D0D5F60/libxcb.so.1.sym 526 | 2014-03-20 12:41:17: simple_symbol_supplier.cc:196: INFO: No symbol file at ./libqxcb.so/37BD6BAC43D805F32EB4F3537000E40E0/libqxcb.so.sym 527 | 2014-03-20 12:41:17: simple_symbol_supplier.cc:196: INFO: No symbol file at ./ld-2.5.so/2D6E32C01DB690E6E6113D736D9B45AC0/ld-2.5.so.sym 528 | 2014-03-20 12:41:17: simple_symbol_supplier.cc:196: INFO: No symbol file at ./libqca-ossl.so/0EA2F5969C8B7B163AA67668688AEED30/libqca-ossl.so.sym 529 | 2014-03-20 12:41:17: simple_symbol_supplier.cc:196: INFO: No symbol file at ./libtcl8.4.so/F3E473507067ACA9672BF6E5DAF41ADC0/libtcl8.4.so.sym 530 | 2014-03-20 12:41:17: simple_symbol_supplier.cc:196: INFO: No symbol file at ./libstdc++.so.6/9366DEB563B557872C7CDA1F54FD78A90/libstdc++.so.6.sym 531 | 2014-03-20 12:41:17: simple_symbol_supplier.cc:196: INFO: No symbol file at ./gconv-modules.cache/000000000000000000000000000000000/gconv-modules.cache.sym 532 | ``` 533 | 534 | The system libraries can be ignored, and only the libraries for your application are of interest. Instead creating the required symbol tree structure manually, we can automate the process. 535 | 536 | The first line of the symbol file contains the information you need to produce this directory structure, for example (your output will vary): 537 | 538 | ``` 539 | $ head -n1 test.sym 540 | MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test 541 | $ mkdir -p ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830 542 | $ mv test.sym ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830 543 | ``` 544 | 545 | Obviously it makes sense to automate the process for bigger applications where multiple symbol files are involved. The bash script below will move all .sym files found in the directory from which it is called to the correct places: 546 | 547 | ``` 548 | for symbol_file in *.sym 549 | do 550 | file_info=$(head -n1 $symbol_file) 551 | IFS=' ' read -a splitlist <<< "${file_info}" 552 | basefilename=${symbol_file:0:${#symbol_file} - 4} 553 | dest_dir=$basefilename/${splitlist[3]} 554 | mkdir -p $dest_dir 555 | mv $symbol_file $dest_dir 556 | echo "$symbol_file -> $dest_dir/$symbol_file" 557 | done 558 | ``` 559 | 560 | Note that a couple of things can go wrong here: 561 | 1. First of all, when exporting your symbols make sure to specify the actual library paths to `dump_syms`, not any symbolic links. 562 | 2. For me, the hex code in the first line of some libraries was different to the hex code which was actually listed in the `grep "No symbols"` output and I had to manually fix it. Not sure why this is the case. -------------------------------------------------------------------------------- /qt-breakpad.pri: -------------------------------------------------------------------------------- 1 | HEADERS += $$PWD/qt_breakpad.h 2 | SOURCES += $$PWD/qt_breakpad.cpp 3 | 4 | INCLUDEPATH += $$PWD 5 | INCLUDEPATH += $$PWD/vendor/breakpad/src 6 | 7 | # Windows 8 | win32:HEADERS += $$PWD/vendor/breakpad/src/common/windows/string_utils-inl.h 9 | win32:HEADERS += $$PWD/vendor/breakpad/src/common/windows/guid_string.h 10 | win32:HEADERS += $$PWD/vendor/breakpad/src/client/windows/handler/exception_handler.h 11 | win32:HEADERS += $$PWD/vendor/breakpad/src/client/windows/common/ipc_protocol.h 12 | win32:HEADERS += $$PWD/vendor/breakpad/src/google_breakpad/common/minidump_format.h 13 | win32:HEADERS += $$PWD/vendor/breakpad/src/google_breakpad/common/breakpad_types.h 14 | win32:HEADERS += $$PWD/vendor/breakpad/src/client/windows/crash_generation/crash_generation_client.h 15 | win32:HEADERS += $$PWD/vendor/breakpad/src/common/scoped_ptr.h 16 | win32:SOURCES += $$PWD/vendor/breakpad/src/client/windows/handler/exception_handler.cc 17 | win32:SOURCES += $$PWD/vendor/breakpad/src/common/windows/string_utils.cc 18 | win32:SOURCES += $$PWD/vendor/breakpad/src/common/windows/guid_string.cc 19 | win32:SOURCES += $$PWD/vendor/breakpad/src/client/windows/crash_generation/crash_generation_client.cc 20 | 21 | # Linux 22 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/cpu_set.h 23 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/proc_cpuinfo_reader.h 24 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/handler/exception_handler.h 25 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/crash_generation/crash_generation_client.h 26 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/handler/minidump_descriptor.h 27 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/minidump_writer.h 28 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/line_reader.h 29 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/linux_dumper.h 30 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.h 31 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/directory_reader.h 32 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/linux/log/log.h 33 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/minidump_file_writer-inl.h 34 | unix:HEADERS += $$PWD/vendor/breakpad/src/client/minidump_file_writer.h 35 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/linux_libc_support.h 36 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/eintr_wrapper.h 37 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/ignore_ret.h 38 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/file_id.h 39 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/memory_mapped_file.h 40 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/safe_readlink.h 41 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/guid_creator.h 42 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/elfutils.h 43 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/elfutils-inl.h 44 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/linux/elf_gnu_compat.h 45 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/using_std_string.h 46 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/memory.h 47 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/basictypes.h 48 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/memory_range.h 49 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/string_conversion.h 50 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/convert_UTF.h 51 | unix:HEADERS += $$PWD/vendor/breakpad/src/google_breakpad/common/minidump_format.h 52 | unix:HEADERS += $$PWD/vendor/breakpad/src/google_breakpad/common/minidump_size.h 53 | unix:HEADERS += $$PWD/vendor/breakpad/src/google_breakpad/common/breakpad_types.h 54 | unix:HEADERS += $$PWD/vendor/breakpad/src/common/scoped_ptr.h 55 | unix:SOURCES += $$PWD/vendor/breakpad/src/client/linux/crash_generation/crash_generation_client.cc 56 | unix:SOURCES += $$PWD/vendor/breakpad/src/client/linux/handler/exception_handler.cc 57 | unix:SOURCES += $$PWD/vendor/breakpad/src/client/linux/handler/minidump_descriptor.cc 58 | unix:SOURCES += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/minidump_writer.cc 59 | unix:SOURCES += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/linux_dumper.cc 60 | unix:SOURCES += $$PWD/vendor/breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc 61 | unix:SOURCES += $$PWD/vendor/breakpad/src/client/linux/log/log.cc 62 | unix:SOURCES += $$PWD/vendor/breakpad/src/client/minidump_file_writer.cc 63 | unix:SOURCES += $$PWD/vendor/breakpad/src/common/linux/linux_libc_support.cc 64 | unix:SOURCES += $$PWD/vendor/breakpad/src/common/linux/file_id.cc 65 | unix:SOURCES += $$PWD/vendor/breakpad/src/common/linux/memory_mapped_file.cc 66 | unix:SOURCES += $$PWD/vendor/breakpad/src/common/linux/safe_readlink.cc 67 | unix:SOURCES += $$PWD/vendor/breakpad/src/common/linux/guid_creator.cc 68 | unix:SOURCES += $$PWD/vendor/breakpad/src/common/linux/elfutils.cc 69 | unix:SOURCES += $$PWD/vendor/breakpad/src/common/string_conversion.cc 70 | unix:SOURCES += $$PWD/vendor/breakpad/src/common/convert_UTF.c 71 | 72 | ## breakpad needs debug info inside binaries 73 | 74 | win32-msvc* { 75 | # generate the symbol file 76 | QMAKE_LFLAGS_RELEASE += /MAP /debug /opt:ref 77 | QMAKE_CFLAGS_RELEASE += -Zi 78 | QMAKE_CXXFLAGS_RELEASE += -Zi 79 | } 80 | 81 | unix:QMAKE_CFLAGS += -g 82 | unix:QMAKE_CXXFLAGS += -g 83 | 84 | # prevent undue optimization, which ruins breakpad's backtrace 85 | QMAKE_CFLAGS_RELEASE -= -O 86 | QMAKE_CFLAGS_RELEASE -= -O1 87 | QMAKE_CFLAGS_RELEASE -= -O2 88 | QMAKE_CXXFLAGS_RELEASE -= -O 89 | QMAKE_CXXFLAGS_RELEASE -= -O1 90 | QMAKE_CXXFLAGS_RELEASE -= -O2 91 | -------------------------------------------------------------------------------- /qt_breakpad.cpp: -------------------------------------------------------------------------------- 1 | #include "qt_breakpad.h" 2 | 3 | QtBreakpad* QtBreakpad::_instance = NULL; 4 | 5 | void QtBreakpad::init(const QString& reportPath, 6 | google_breakpad::ExceptionHandler::FilterCallback filterCallBack, 7 | google_breakpad::ExceptionHandler::MinidumpCallback minidumpCallback, 8 | void* callbackContext) 9 | { 10 | QtBreakpad::replaceInstance(new QtBreakpad(reportPath, filterCallBack, 11 | minidumpCallback, callbackContext)); 12 | } 13 | 14 | void QtBreakpad::init(const QString& reportPath, 15 | QMinidumpCallback qMinidumpCallback, 16 | void* callbackContext) 17 | { 18 | QtBreakpad::replaceInstance(new QtBreakpad(reportPath, qMinidumpCallback, callbackContext)); 19 | } 20 | 21 | QtBreakpad::QtBreakpad(const QString& reportPath, 22 | google_breakpad::ExceptionHandler::FilterCallback filterCallBack, 23 | google_breakpad::ExceptionHandler::MinidumpCallback minidumpCallback, 24 | void* callbackContext) 25 | { 26 | this->buildBreakpadHandler(reportPath, filterCallBack, minidumpCallback, callbackContext); 27 | } 28 | 29 | void QtBreakpad::buildBreakpadHandler(const QString& reportPath, 30 | google_breakpad::ExceptionHandler::FilterCallback filterCallBack, 31 | google_breakpad::ExceptionHandler::MinidumpCallback minidumpCallback, 32 | void* callbackContext) 33 | { 34 | #if defined(Q_OS_WIN32) 35 | std::wstring pathAsStr = (const wchar_t*)reportPath.utf16(); 36 | this->_breakpad_handler = new google_breakpad::ExceptionHandler( 37 | pathAsStr, 38 | filterCallBack, 39 | minidumpCallback, 40 | callbackContext, 41 | true 42 | ); 43 | #elif defined(Q_OS_LINUX) 44 | std::string pathAsStr = reportPath.toStdString(); 45 | google_breakpad::MinidumpDescriptor md(reportPath); 46 | this->_breakpad_handler = new google_breakpad::ExceptionHandler( 47 | md, 48 | filterCallBack, 49 | minidumpCallback, 50 | callbackContext, 51 | true, 52 | -1 53 | ); 54 | #endif 55 | } 56 | 57 | QtBreakpad::QtBreakpad(const QString& reportPath, 58 | QMinidumpCallback qMinidumpCallback, 59 | void* callbackContext) 60 | { 61 | this->_qMinidumpContextWrapper = new QtBreakpad::QMinidumpContextWrapper(qMinidumpCallback, callbackContext); 62 | 63 | this->buildBreakpadHandler(reportPath, 64 | NULL, // filter callback 65 | reinterpret_cast(&QtBreakpad::qMinidumpWrapper), 66 | this->_qMinidumpContextWrapper); 67 | } 68 | 69 | #if defined(Q_OS_WIN32) 70 | bool QtBreakpad::qMinidumpWrapper(const wchar_t* dump_path, 71 | const wchar_t* minidump_id, 72 | QMinidumpContextWrapper* contextWrapper, 73 | EXCEPTION_POINTERS* exinfo, 74 | MDRawAssertionInfo* assertion, 75 | bool succeeded) 76 | { 77 | Q_UNUSED(exinfo); 78 | Q_UNUSED(assertion); 79 | #elif defined(Q_OS_LINUX) 80 | bool QtBreakpad::qMinidumpWrapper(const MinidumpDescriptor& descriptor, 81 | QMinidumpContextWrapper* contextWrapper, 82 | bool succeeded) 83 | { 84 | #endif 85 | // if there's no dump file, not much to do 86 | if (!succeeded) { return false; } 87 | 88 | QMinidumpCallback qMinicudmpCallback = contextWrapper->qMinicudmpCallback; 89 | void* context = contextWrapper->context; 90 | 91 | QString minidumpFileName; 92 | 93 | #if defined(Q_OS_WIN32) 94 | QDir minidumpDir = QDir(QString::fromWCharArray(dump_path)); 95 | minidumpFileName = minidumpDir.absoluteFilePath(QString::fromWCharArray(minidump_id) + ".dmp"); 96 | #elif defined(Q_OS_LINUX) 97 | minidumpFileName = descriptor.path(); 98 | #endif 99 | 100 | QFile minidumpFile(minidumpFileName); 101 | 102 | return qMinicudmpCallback(minidumpFile, context); 103 | } 104 | 105 | void QtBreakpad::replaceInstance(QtBreakpad* newInstance) 106 | { 107 | // there can only be one handler 108 | delete QtBreakpad::_instance; 109 | 110 | QtBreakpad::_instance = newInstance; 111 | } 112 | 113 | QtBreakpad::~QtBreakpad() 114 | { 115 | delete this->_breakpad_handler; 116 | delete this->_qMinidumpContextWrapper; 117 | } 118 | -------------------------------------------------------------------------------- /qt_breakpad.h: -------------------------------------------------------------------------------- 1 | #ifndef QT_BREAKPAD_H 2 | #define QT_BREAKPAD_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if defined(Q_OS_WIN32) 11 | // breakpad includes windows.h, so we must include QT's qt_windows.h beforehand 12 | // to avoid breaking other QT headers 13 | #include 14 | 15 | #include "vendor/breakpad/src/client/windows/handler/exception_handler.h" 16 | 17 | #elif defined(Q_OS_LINUX) 18 | #include "vendor/breakpad/src/client/linux/handler/exception_handler.h" 19 | 20 | #endif // OS-specific includes 21 | 22 | class QtBreakpad 23 | { 24 | public: 25 | static void init(const QString& reportPath, 26 | google_breakpad::ExceptionHandler::FilterCallback filterCallBack = NULL, 27 | google_breakpad::ExceptionHandler::MinidumpCallback minidumpCallback = NULL, 28 | void* callbackContext = NULL); 29 | 30 | typedef bool (*QMinidumpCallback)(QFile& minidumpFile, void* context); 31 | 32 | static void init(const QString& reportPath, 33 | QMinidumpCallback qMinidumpCallback, 34 | void* callbackContext = NULL); 35 | 36 | private: 37 | Q_DISABLE_COPY(QtBreakpad) 38 | static QtBreakpad* _instance; 39 | static void replaceInstance(QtBreakpad* newInstance); 40 | 41 | class QMinidumpContextWrapper 42 | { 43 | public: 44 | QMinidumpContextWrapper(QMinidumpCallback qMinicudmpCallback, void* context) 45 | { 46 | this->qMinicudmpCallback = qMinicudmpCallback; 47 | this->context = context; 48 | } 49 | 50 | ~QMinidumpContextWrapper() { } 51 | 52 | QMinidumpCallback qMinicudmpCallback; 53 | void* context; 54 | }; 55 | 56 | QtBreakpad(const QString& reportPath, 57 | google_breakpad::ExceptionHandler::FilterCallback filterCallBack, 58 | google_breakpad::ExceptionHandler::MinidumpCallback minidumpCallback, 59 | void* callbackContext); 60 | QtBreakpad(const QString& reportPath, 61 | QMinidumpCallback qMinidumpCallback, 62 | void* callbackContext); 63 | ~QtBreakpad(); 64 | 65 | google_breakpad::ExceptionHandler* _breakpad_handler; 66 | void buildBreakpadHandler(const QString& reportPath, 67 | google_breakpad::ExceptionHandler::FilterCallback filterCallBack, 68 | google_breakpad::ExceptionHandler::MinidumpCallback minidumpCallback, 69 | void* callbackContext); 70 | 71 | QMinidumpContextWrapper* _qMinidumpContextWrapper; 72 | #if defined(Q_OS_WIN32) 73 | static bool qMinidumpWrapper(const wchar_t* dump_path, 74 | const wchar_t* minidump_id, 75 | QMinidumpContextWrapper* context, 76 | EXCEPTION_POINTERS* exinfo, 77 | MDRawAssertionInfo* assertion, 78 | bool succeeded); 79 | #elif defined(Q_OS_LINUX) 80 | static bool qMinidumpWrapper(const MinidumpDescriptor& descriptor, 81 | QMinidumpContextWrapper* context, 82 | bool succeeded); 83 | #endif 84 | }; 85 | 86 | #endif // QT_BREAKPAD_H 87 | --------------------------------------------------------------------------------