GoogleBreakpad库生成Dump文件
文章目录
一、软件奔溃捕获的意义
二、Breakpad介绍
三、Qt工程中加入breakpad库的方法
四、测试是否可以生成dump崩溃文件
五、软件奔溃dump文件上报处理
六、根据dump文件获取Stack Trace
七、编译工具“dump_syms”的方法
八、编译工具"minidump_stackwalk"的方法
九、示例工程中的源码等资源获取
十、参考文章列表
一、软件奔溃捕获的意义
应用程序发布后,不能保证百分百没有bug并引发崩溃。因此,在出现崩溃的情况下需要记录崩溃详情并给用户弹出崩溃提示对话框,提示用户重启软件以及上报(上传)崩溃。
这样做意义是:
能保证软件在使用过程中发现的bug都能被收集起来,并根据崩溃详情修改bug,然后发布修复bug的版本。如果软件在使用过程中直接闪退没有任何提示,不仅用户体验不好,还无法获取崩溃的原因。之后更具用户反馈的口头描述来找bug就会非常头疼了。
二、Breakpad介绍
breakpad简介
Breakpad是Google公司开发的开源多平台C++崩溃检测库。Breakpad可以捕获发布给用户的应用程序的崩溃,并记录软件崩溃的调试信息到“minidump”文件中。调试信息包括错误行号,报错详情,堆栈错误(stack traces)。软件崩溃时候把生成的“minidump”上传到自己的服务器上就可已方便的获取足够细致崩溃详情。
支持平台:
windows、linux、mac、ios、solaris、android ndkbreakpad实现原理简单了解
在不同平台下使用平台特有的函数以及方式实现异常捕获:
Windows:通过SetUnhandledExceptionFilter()设置崩溃回掉函数
Max OS:监听 Mach Exception Port 获取崩溃事件
Linux:监听 SIGILL SIGSEGV 等异常信号 获取崩溃事件MiniDump文件格式
minidump是由微软开发的崩溃记录文件格式。minidump为二进制文件,体积小。为了保持统一,breakpad在其他系统下也选择生成minidump文件。BreakPad工作原理示意图
示意图要表达的意思如下:
a. 包含了breakpad客户端(静态库)的应用程序在发布Release版本的时候。在编译的时候选择保留调试信息。
b. 使用Breakpad提供的dump_syms工具根据release版本程序生成“symbols文件”。“symbols文件”包括程序之前保留的调试信息。
c. 发布给用户的release版本程序发生崩溃后包含在程序内“breakpad客户端”会捕捉崩溃并生成“minidump文件”。
d. “minidump文件”被应用程序发送到你指定的服务器,或通过其他方式收到用户软件崩溃产生的“minidump文件”。
e. 收到“minidump文件”后,结合发布应用的所对应的 “symbols文件”,通过“minidump_stackwalk” 工具来转换生成文本格式的“stack trace 文件”。这个文件内的信息就是程序员可以直接阅读的崩溃堆栈详情。从而准确的找到触发崩溃的bug。
三、Qt工程中加入breakpad库的方法
breakpad可以先编译生成lib文件,然后在加入到自己的qt工程,也可以直接使用源码加入到自己的qt工程中。
为了方便在Qt中加入breakpad并且方便在多个平台编译,这里使用“源码添加breakpad库“的方式。
在Qt工程加入Breakpad的步骤如下:
下载源码:https://github.com/google/breakpad
把源码放置到自己工程目录里面,我这里使用的目录是:third_libs/breakpad/thirdparty
编写“breakpad.pri”文件用于在工程中引入所需要的breakpad源文件,把文件放置到和breakpad源码相同的目录。
编写多平台封装类。breakpad在不同系统中有不同的崩溃回调函数。为了实现跨平台使用breakpad,需要做一个封装类,然后对外提供一个唯一的接口。编写一个封装类为“BreakpadHandler”,放置在third_libs/breakpad/src目录中。
接着编写自己封装类的引入文件“breakpadsrc.pri”。并放置在third_libs/breakpad目录中。此配置文件还包括一些编译参数设置,从而包在各个平台的编译生成的release版本中包含调试信息。同时此文件相当于把整个breakpad相关的文件和配置整理到了一起。从而形成一个跨平台的breakpad模块。在自己的Qt工程中直接引入此模块,即可使用所有Breakpad的功能。
完成以上所有步骤,最终形成的目录结构如下图所示:
由于引入文件“breakpad.pri”、“breakpadsrc.pri”和“BreakpadHandler封装类”中的内容很长,因此不便在这里列出。请参考本文第九节中所列出的源码地址。源码中不仅集成了breakpad库,并且包含完整使用示例。
四、测试是否可以生成dump崩溃文件
为了演示上一节所制作的Brakpad库的使用方法。本文专门编写了一个示例工程“BreakpadDemo”。工程的编写过程如下:
使用Qt Creater新建一个工程,叫做“BreakpadDemo”
在工程的pro文件中引入之前编写好的brakpad模块
QT += core gui network //本例子包含网络上传代码# link qBreakpad libraryinclude($$PWD/third_libs/breakpad/breakpadsrc.pri)
在工程的main.cpp文件编写如下代码:
#include <QApplication>#include "BreakpadHandler.h"void crash() { volatile int* a = (int*)(NULL); *a = 1; }int main(int argc, char *argv[]){ QApplication app (argc, argv); //those settings are need by QStandardPaths and breakpad QCoreApplication::setApplicationName("BreakpadDemo"); QCoreApplication::setApplicationVersion("0.0.1"); QCoreApplication::setOrganizationName("OrgName"); QCoreApplication::setOrganizationDomain("name.org"); BreakpadHandler *breakpad_instance = BreakpadHandler::GetInstance(); QStringList path_list2 = QStandardPaths::standardLocations(QStandardPaths::DataLocation); QString std_base_path = path_list2[0]; QString my_crash_path = std_base_path + "/crashs"; breakpad_instance->SetupBreakPad(my_crash_path);//or just using "crashes" //run app DemoDialog w; w.show(); crash(); return app.exec();}
编译运行此工程。查看应用程序调试输出窗口,看是否有dump文件生成。如果生成则,表示你集成成功。程序奔溃后在输入窗口的输入如下图所示:(注:本示例代码以第九节所示源码为准)
五、软件奔溃dump文件上报处理
既然生成了崩溃dump文件。就需要把这个文件传递给开发者才能最终解决bug。那么收集dump文件的方法更具不同平台,不同使用场合,可以有不同的dump文件反馈方式:
有崩溃上报服务器处理方法
在服务器软件中加入崩溃文件上传接口。软件这边通过联网并调用这个接口上传即可,本例子中包含上传崩溃文件的示例的代码。无崩溃上报服务器处理方法
有些软件处于无网络连接的使用环境,因此通过网络上传便不再可行。那么应该提供一个良好的引导界面,引导用户把崩溃的dump文件,通过其他可行方式反馈给软件开发公司。
在本示例工程“BreakpadDemo”中,编写了一个崩溃引导界面,作为崩溃反馈的主要示例方法。因为这个方法不用配合服务器软件,可以独立展示和测试。
测试崩溃引导过程如下:
a. 编译并启动BreakpadDemo,点击窗口中的“Crash”按钮来触发一个软件崩溃。b. 再次启动BreakpadDemo,软件会弹出一个“引导窗口”,窗口提示用户把接下来弹出的文件发送给售后。
c. 点击“引导窗口”中的“Ok”按钮会弹出崩溃生成的dmp文件。
六、根据dump文件获取Stack Trace
生成包含调试信息的Release版本软件
根具之前介绍的breakpad的原理可知,发送给用户的release版本的软件需要包含调试信息。否则收到dunmp文件也不能获取到报错信息的详情。让发布的release版本软件包含调试信息的方法如下。其实在第三节总提到的“breakpadsrc.pri”文件中就已经包含了这个配置。不用你再次配置。这里是拿出来做一个专门的强调。也方便你了解这些配置的作用。
在MacOS、Linux和windows-mingw环境下编译包含调试信息的release软件:
* { QMAKE_CFLAGS_RELEASE += -g QMAKE_CXXFLAGS_RELEASE += -g QMAKE_CFLAGS_RELEASE -= -O2 QMAKE_CXXFLAGS_RELEASE -= -O2 #QMAKE_LFLAGS_RELEASE = -mthreads -Wl}
注意:在以上编译环境下,调试信息就在编译好的软件本身中。
在Windows-msvc环境下,编译包含调试信息的release软件:
# for generate dpb files at windowswin32-msvc* { QMAKE_LFLAGS_RELEASE += /MAP QMAKE_CFLAGS_RELEASE += /Zi QMAKE_LFLAGS_RELEASE += /debug /opt:ref}
注意:在windows-msvc下软件的调试信息在单独的*.pdb文件中(msvc指编译器)
生成“Stack Trace”所用到了命令工具介绍
“dump_syms”或“dump_syms.exe”
用户提取调试信息到一个单独的文件“*.sym”中,给“minidump_stackalk”命令使用。“minidump_stackwalk"或"minidump_stackwalk.exe”
结合“*.sym”和用户反馈的奔溃dump文件生成“Stack Trace”。包含报错的详情
“dump_syms”和命令"minidump_stackalk"的使用方法
使用环境
在讲命令的使用方法之前先介绍一下命令的使用环境
MacOS、Linux
直接使用系统自带的命令行工具即可。
windows
下载Git软件,使用“Git Bash”执行以下命令。因为接下来要运行一个shell脚本,为了方便只使用一个脚本,且windows下无法执行shell脚本。所以使用Git软件所带的Bash运行环境。(如果有需要,你可以根据这个shell脚本编写出对应的windows下的bat脚本)。
Git软件下载官网:https://git-scm.com/book/zh/v2/起步-安装-Git
使用的Git的工具如下图所示:编写生成“Stack Trace”的脚本
由于这两个命令需要配合使用,且在使用过程中会需要手工创建一些特定名称的文件夹,因此编写了一个shell脚本。由于在windows下需要对脚本稍做修改。因此下面分别贴出2个脚本:
MacOS、Linux和windows-mingw下的使用脚本
#!/bin/bashif [ $# != 2 ] ; then echo "USAGE: $0 EXE_NAME DMP_NAME" echo " e.g.: $0 test 3872B2CF-983B-4963-AFA9-C8534DFD4C44.dmp" exit 1; fi #get input paramexe_file_name=$1dmp_file_name=$2getSymbol() { echo "@getSymbol: start get symbol" ./dump\_syms ./$exe_file_name > $exe_file_name'.sym'}getStackTrace() { echo "@getStackTrace: start get StackTrace" sym_file_name=$exe_file_name'.sym' #get first line of $sym_file_name line1=`head -n1 $sym_file_name` #echo $line1 #get version number form string of first line OIFS=$IFS; IFS=" "; set -- $line1; aa=$1;bb=$2;cc=$3;dd=$4; IFS=$OIFS #echo $dd version_number=$dd #make standard dir and move *.sym in it mkdir -p ./symbols/$exe_file_name/$version_number mv $sym_file_name ./symbols/$exe_file_name/$version_number #print stack trace at std output ./minidump_stackwalk $dmp_file_name ./symbols 2> /dev/null #print stack trace at a file #./minidump_stackwalk $dmp_file_name ./symbols 2>/dev/null >result.txt}main() { getSymbol if [ $? == 0 ] then getStackTrace fi}# run mainmain
在windows-msvc下的使用的脚本
为了增强阅读体验,windows-msvc所用的脚本不在此列出,在第九节中的源码中统一提供。
脚本使用方法
MacOS、Linux和windows-mingw下的使用方法
注意:BreakpadDemo为编译后的可执行文件(macos平台下注意右键打开包正文/Contents/MacOS下获取)
命令、脚本、dmp文件、可执行文件等文件如下图目录所示
sh ./process_dump.sh BreakpadDemo 928703D7-EA7B-4050-8DF5-667958A502F0.dmp
在windows-msvc下的使用方法
注意:在windows-msvc环境下,需要使用从编译生成的pdb文件中获取调试信息
命令、脚本、dmp文件、可执行文件等文件如下图目录所示
sh ./process_dump.sh BreakpadDemo.pdb ee4962a8-0bf4-419a-8830-8230e26488cc.dmp
如果出现以下报错请参考,第七小节
CoCreateInstance CLSID_DiaSource failed (msdia*.dll unregistered?)
脚本执行结果中“Stack Trace”的报错详情截图如下:
对脚本所做操作的解释
脚本相当于以下命令依次执行:
#生成symbols文件,生成的文件名字指定为:“test.sym”./dump\_syms ./test > test.sym #得到test.sym这个文本文件的第一行,如下#MODULE mac x86_64 887D1A2C356F3401ABCCA76B666B3A810 testhead -n1 test.sym#依照上面一行中的id名字创建目录mkdir -p ./symbols/test/887D1A2C356F3401ABCCA76B666B3A810#把生成的test.sym符号文件复制到刚刚创建的目录mv test.sym ./symbols/LedStripEditor/887D1A2C356F3401ABCCA76B666B3A810#使用minidump_stackwalk命令生成“stack trace”到result.txt,把处理过程输出到process.txt#当然,在正式脚本中,为了方便查看,直接把“stack trace”输出到了stdout./minidump_stackwalk xxx.dmp ./symbols > result.txt 2> process.txt
七、编译工具“dump_syms”的方法
Linux系统下
安装G++编辑器,编译唯一的一个c++代码即可。未经实际测试。在MacOS下:
安装XCode作为编译工具
找到breakpad的源码目录,在源码的"src/tools/mac/dump_syms"目录中,找到dump_syms.xcodeproj这个文件用XCode编译即可获得macos平台下的dump_syms工具。在Windows系统下:
安装Visual Studio 2017(并选择Vritual C++编程环境)作为编译工具,不一定是2017版本,任何版本都可以
找到breakpad的源码目录,在源码的"src/tools/windows/dump_syms"目录中,找到dump_syms.vcproj这个文件用Visual Studio编译即可获得windows平台下的dump_syms工具。
注意:由于是开源代码源代码不停更新,经过测试,从github下载的源代码会导致此工具编译失败。因此建议使用本示例所使用的breakpad源码。源码在第九节的源码中包含,目录为:BreakpadDemo/third_libs/breakpad/thirdparty/breakpad在windows下编译遇到问题解答
问题1:
使用Visual Studio导入工程后,编译的时候,报错提示“找不到Windows SDK 8.1”,如下图所示:解答问题1:
下载并安装Windows Sdk。然后在Visual Studio中的“dump_syms”工程,右键“属性”,修改Sdk为你安装的Sdk。如下图所示:问题2:
dump_syms.exe已经编译好了,但是使用命令导出调试信息的时候,出现以下错误输出:
CoCreateInstance CLSID_DiaSource failed (msdia*.dll unregistered?)
错误截图如下:
解答问题2:
错误提示为:msdia*.dll这个dll未注册。解决办法如下:
从网上下载“msdia80.dll”、“msdia100.dll”,“msdia120.dll”这几个dll,实际上只用其中的一个dll。具体用到了那个dll,应该是依据的开发环境所定。这里是把可能用到的都下载了。本文测试环境为win7_32位,因此下载的dll也应该是32位的。这三个Dll本文在第九节的源码中会提供。
把准备好的三个dll放置到以下目录:
c:\Program Files\Common Files\Microsoft Shared\VC
如下图所示:
然后编写一个bat脚本来注册这几个dll。脚本内容如下:
c:\Windows\system32\regsvr32 "c:\Program Files\Common Files\Microsoft Shared\VC\msdia80.dll"c:\Windows\system32\regsvr32 "c:\Program Files\Common Files\Microsoft Shared\VC\msdia100.dll"c:\Windows\system32\regsvr32 "c:\Program Files\Common Files\Microsoft Shared\VC\msdia140.dll"
执行脚本
注意这个脚本直接运行会出现如下图所示错误:
应该选中脚本文件,右键“以管理员身份运行”,即可依次弹出成功消息如下图所示:
八、编译工具"minidump_stackwalk"的方法
MaccOS、Linux系统下编译:
使用命令行切换到brakpad的源码目录。执行以下命令
./configure && make
编译完成之后,breakpad源码目录中的"src/processor/"中可以找到“minidump_stackwalk”这个编译好的工具。
windows系统下编译:
由于windows下不具有configure和make等工具。而breakpad的源码中也没有整体的visual studio工程文件。因此选用另一种编译模式,即模拟linux环境的编译模式(类似Qt-mingw编译模式)。操作方式如下:
配置编译器
下载windows版本的Qt,并断网安装(避免注册)。安装的时候选择安装mingw-32编译器。其他安装选项按需选择。这个步骤主要是为了保证你安装有mingw-32编译器(当然同时你可以在windows下使用Qt Creater编译BreakpadDemo来测试)。
Qt的下载地址为:http://download.qt.io/archive/qt/5.12/5.12.5/
安装好后,把需要添加环境变量,用于之后在命令行编译的时候能找到编译工具。本文的测试环境中,需要添加的环境变量为:
C:\Qt\Qt5.12.5\Tools\mingw730_32\bin;
配置编译工具
前面提到要以Linux的方式编译工程。因此需要使用“Git Bash”,这个软件除了作为管理git的代码,还提供了一个标准的shell执行环境。
Git软件下载官网:https://git-scm.com/book/zh/v2/起步-安装-Git
这里有一个注意点,不能安装在默认安装目录,不然windows系统的“Program Files”这个目录中的空格会给之后的编译造成问题。编译会报错为:“/usr/bin/sh: C:/Program: No such file or directory”。本文是安装在C盘根目录。正式编译
使用configure先生成makefile
./configure
正确配置完成以后,执行make命令
mingw32-make
编译完成之后,breakpad源码目录中的"src/processor/"中可以找到“minidump_stackwalk.exe”这个编译好的工具。
九、示例工程中的源码等资源获取
源码中包含以下内容:
BreadpadDemo源码(在MacOS和Windows7下测试验证通过)
用于MaxOS的“dump_syms”和“minidump_stackwalk”工具集合(包含脚本)
用于Windows的“dump_syms”和“minidump_stackwalk”工具集合(包含脚本)
用于在wiindows下编译“dump_syms”的msdia_dll
源码地址为:
点此获取源码