为了收集程序崩溃时的dump信息,之前接入了Google的BreakPad,但一直没有起到太大的作用--因为定位不到具体的代码,这次仔细研究了一下这个问题,做一下记录。 首先BreakPad的代码已经迁移到Git上了(git clone https://chromium.googlesource.com/breakpad/breakpad),而且按Google的说法已经新出了一个CrashPad--但暂时还是用BreakPad吧。
然后BreakPad在Windows上的接入有两种方式:1. 直接将其代码放到你的项目里面,同项目一起编译; 2. 先将其编译为静态链接库.lib,然后在项目中使用其头文件和lib文件即可,这种方式的优点是编译你的工程时不用再编译BreakPad了。
先说第一种方式,直接参考 https://github.com/JPNaude/dev_notes/wiki/Using-Google-Breakpad-with-Qt 即可,从BreakPad的源码里面拷出代码来按文件夹组织好即可同项目一起编译。 第二种方式就复杂一点了,先安装好Python 2.7并设置好环境变量,然后:
- 把Chromium的项目管理工具 GYP Clone下来,把gyp.bat设置到环境变更Path中;
- 编辑breakpad\src\client\windows\breakpad_client.gyp,注释掉 targets : dependencies 列表中的最后三个和 test 有关的依赖引用;
- 在breakpad的目录下启动命令行,用 SET GYP_MSVS_VERSION=2013 设置目标 Visual Studio 工程的版本,后面的2013根据你的VS可设成2010、2015之类的;
- 运行 gyp.bat --no-circular-check src\client\windows\breakpad_client.gyp -Dwin_release_RuntimeLibrary=2 -Dwin_debug_RuntimeLibrary=3;最后两个参数设置的是 /MT(d) 还是 /MD(d) (0:/MT,1:/MTd, 2:/MD, 3:/MDd),一般情况下是使用MD和MDd;
- 生成的项目文件在目录 src\client\windows 中,直接用VS打开编译即可;
编译完成后,还得从BreakPad中把头文件提取出来,目录结构如下: 1
2
3
4
5
6
7
8
9
10
11
12|--google_breakpad
|---processor
|---common
|--common
|---windows
|---scoped_ptr.h
|---client
|---windows
|---crash_generation
|---sender
|---handler
|---common
接入的示例代码如下:
1 | google_breakpad::ExceptionHandler *pHandler = new google_breakpad::ExceptionHandler( |
接入BreakPad后,若程序发生崩溃,BreadPad会向dumps文件夹中写入dump文件,把dump文件和应用程序的pdb放在一起,用VS打开dump文件即可进行调试,一般情况下可定位到出现问题的代码处。
再说遇到的几个问题,一是如果是用GCC(MingW),该如何生成pdb呢? 得加入“-g”让gcc生成调试信息,还需要关闭优化,再用一个叫cv2pdb的工具从最后编译出来的exe、dll中提取出pdb来,以Qt的工程文件为例,相关的编译器开关如下:
1 | win32-g++ { |
第二个问题就是定位不到正确的堆栈和代码了,在研究过程中发现了以下现象,如果把以下代码作为崩溃触发点,则debug和release模式下的程序都可以正常生成dump文件,并且VS都可以分析: 1
2
3
4
5
6
7int buggyFunc()
{
int* p = NULL;
*p = 13;
return 0;
}1
2
3
4
5
6int buggyFunc()
{
delete reinterpret_cast<QString*>(0xFEE1DEAD);
return 0;
}
那么还有一个问题,为什么生成的dump文件VS定位不到代码? 我先尝试了用 https://github.com/JPNaude/dev_notes/wiki/Using-Google-Breakpad-with-Qt 这篇文章里面提到的dump_syms.exe来转换pdb为sym,再用minidump_stackwalk.exe来进行分析,结果比VS好一点,但全定位到BreakPad的代码上去了... 最后终于从这里(http://stackoverflow.com/questions/33939009/useless-dumps-in-google-breakpad)找到了原因,那就是Windows下的minidump_stackwalk不好使,得在linux下自己编译一个来用! 经实验,在linux下用breakpad源码编译的minidump_stackwalk可以正常地分析这种情况下的dump文件。
最后,还推荐一下这几天找到的CrashRpt(http://crashrpt.sourceforge.net/),一个实现了UI和打包上传的崩溃处理类库,在发生崩溃时还能进行截屏,然后打包dump文件、日志等一起上传。经实验,对于上面的那个特例,在Qt的Release模式下CrashRpt也可以生成dump,而且VS对dump文件也无法正确定位,至于linux下的minidump_stackwalk能不能分析,暂时还没有实验过。
参考资料: * http://zxstudio.org/blog/2014/10/28/integrating-google-breakpad/ * https://kingsamchen.github.io/2016/09/24/build-and-integrate-the-newest-version-of-breakpad-on-windows/