mac下利用Breakpad的dump文件进行调试

一、前情回顾

最近把公司的一个视频处理程序更新了一个版本,准备提交测试的发现了崩溃的情况。这个程序采用Qt和ffmpeg技术栈开发,主要用于对视频进行渲染拼接处理,在Windows和mac两个平台同时进行发布。在windows上测试完一切正常,然而就在我以为一切大功告成的时候,测试的同事直接给我来了个当头棒喝,程序崩溃了!没有道理啊,同一套代码在Windows上安然无恙,在Mac上为何直接崩溃?好消息是程序在崩溃的时候保存了dump文件。

这得感谢前段时间集成的Google Breakpad了。Google Breakpad是Google开发的一个跨平台异常捕获和dump文件(准确的说是mini dump)生成的开发库。利用这个库可以在Windows, Mac, Linux, iOS, Android平台上对程序异常崩溃进行捕获,并生成dump文件供后期调试。据说Google Chrome, Chromium, Firefox都使用了这套机制,因此其可用性是经得起考验的,并且这个库现在依然更新的很频繁。

 如此强大的东西,怎么使用呢?好在网上关于breakpad的资料是还是挺多的,只不过都不是很完整很简洁。要么就只介绍了实现原理、或者只介绍了怎么编译、或者就只介绍了怎么集成,对于新手使用非常不友善。这里就根据我在Windows和Mac两个平台的使用经验来总结下吧。

二、breakpad的使用

 breakpad以源代码的形式发布,所以首先要从仓库中把代码下下来:

git clone https://chromium.googlesource.com/breakpad/breakpad  

这个是Google的代码仓库,基于国内的环境需要把VPN打开。下载下来的代码包含了windows, mac, linux三个平台所有的文件了,也包含了各个平台的工具源码。没错,breakpad的工具需要自己编译。

假设源代码下载到了E:/breakpad,那么进入到这个目录运行make命令:

./configure
make

在Windows上需要用gyp工具来编译,所以还得下载gyp非常麻烦。在mac上就非常简单了,直接运行上述命令即可生成静态库文件。但是工具的话需要进入到tools目录,里面有个已经配置好的xcode工程,直接打开即可编译。

不过要注意的是,最新的breakpad源码在编译工具的时候会报错:

Undefined symbols for architecture x86_64:
  "google_breakpad::BaseName(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
      google_breakpad::DumpSymbols::CreateEmptyModule(google_breakpad::scoped_ptr<google_breakpad::Module>&) in dump_syms.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

解决办法是:

 在这一步中我们编译源码主要是为了得到两个工具:minidump_stackwalkdump_syms。这两个分别有什么用呢?dump_syms用于从可执行程序中抽取出调试符号保存到syms符号文件中,而minidump_stackwalk则根据syms文件来分析mini dump文件,得到一个可读性强的崩溃调用堆栈。由于我的工程是基于Qt的,所以我直接利用了Github上面的一个开源项目进行编译。这个项目针对Qt剔除了一些无用的头文件,并对源代码做了稍微的调整。

基于QMake的工程,可以直接用Qt Creator打开编译。在Windows上和Mac上无缝支持。编译即可得到我们需要的lib文件了。这个在我们后面集成工程中链接需要用到。当然也可以直接将源代码集成到工程去。

接下来就讲讲如何集成吧。集成步骤其实非常简单,直接上代码:

#ifdef _WINDOWS
#include <client/windows/handler/exception_handler.h>
#else
#include <client/mac/handler/exception_handler.h>
#endif

#ifdef _WINDOWS
bool minidumpCB(const wchar_t *dump_path, const wchar_t *id, void *context, EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion, bool succeeded) {
#else
bool minidumpCB(const char* dump_path, const char* id, void* context, bool succeeded) {
#endif
    if (succeeded) {
        std::wcout << "Mini Dump file: " << id << ".dump Path: " << dump_path << std::endl;
    }  
    return succeeded;
}

int main() {
#ifdef NDEBUG  // 只在Release模式下启用Breakpad
#ifdef _WINDOWS
    google_breakpad::ExceptionHandler eh(dumpLocation.toStdWString(), NULL, minidumpCB, NULL, google_breakpad::ExceptionHandler::HANDLER_ALL);
#else
    google_breakpad::ExceptionHandler eh(dumpLocation.toStdString(), NULL, minidumpCB, NULL, true, NULL);
#endif
#endif
}

接口非常简单,只要定义一个回调函数minidumpCB()。当程序崩溃被捕捉到的时候就会调用这个函数,这里只是输出了mini dump文件保存的位置。如果第一张截图中的红框所示。

三、dump文件如何利用

 生成的dump文件如何利用?如何转换成我们能看得懂的调用堆栈信息?其实有上面编译出来的两个工具,接下来的工作分三个步骤:

  • 使用dump_syms生成符号表: ./dump_syms ~/Test/Caputre > Capture.syms
  • 创建有层次的调试符号文件夹: head -n1 Capture.syms // 查看文件层次 mkdir -p ./symbols/PanoramaCapture/3EXXXXXX/ //这一步根据上面的输出来 mv Capture.syms ./symbols/PanoramaCapture/3EXXXXX/ // 将符号文件移动进去
  • 利用minidump_stackwalk分析dump文件: ./minidump_stackwalk minidump.dmp ./symbols

   最后一步将输出详细的堆栈信息:

  相信有了这些信息,找出代码中潜伏的bug不是什么难事了。而我也正是根据这些信息,成功解决了这次的崩溃问题。再提一句,不管在Windows上还是Mac上,编译Release的时候最好把调试符号文件保存好。这样利用breakpad来分析的时候才能事半功倍,breakpad方才能展现其强大的一面。

四、参考链接

1. https://www.jianshu.com/p/295ebf42b05b

2. https://github.com/google/breakpad

3. https://groups.google.com/forum/#!topic/google-breakpad-discuss/fierVnIAv1M

4. https://github.com/gyunaev/google-breakpad-qt

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏涤生的博客

服务框架之注册中心,你不知道的内幕

前一篇服务框架技术栈粗略分析了服务框架需要的各个核心模块,首先提到的就是注册中心,注册中心实现了服务注册和发现的功能,在服务框架中也发挥着重要的作用。今天主要围...

1062
来自专栏FreeBuf

一种新型的Web缓存欺骗攻击技术

为了减少WEB响应时延并减小WEB服务器负担,现在WEB缓存技术已经用的非常普遍了,除了专门的CDN,负载均衡以及反向代理现在也会缓存一部分的网页内容。这里我要...

1164
来自专栏FreeBuf

Redis未授权访问配合SSH key文件利用分析

1.更新情况 ? 2.漏洞概述 Redis默认情况下,会绑定在0.0.0.0:6379,这样将会将Redis服务暴露到公网上,如果在没有开启认证的情况下,可以导...

2806
来自专栏Seebug漏洞平台

DeDeCMS v5.7 密码修改漏洞分析

织梦内容管理系统(DedeCms)以简单、实用、开源而闻名,是国内最知名的PHP开源网站管理系统,也是使用用户最多的PHP类CMS系统,在经历多年的发展,目前的...

4628
来自专栏卡少编程之旅

手机adb命令学习

3778
来自专栏Rainbond开源「容器云平台」

好雨云帮每周更新日志(2017.02.27-2017.03.12)

1133
来自专栏Java技术栈

两张趣图助你理解 HTTP 状态码!

HTTP状态码(HTTP Status Code)是用以表示网页服务器HTTP响应状态的3位数字代码。

1133
来自专栏java一日一条

JVM 开发者必看:傻瓜式编译 OpenJDK 7

LZ经过一个星期断断续续的研究,终于成功的搞定了JDK的成功编译与调试。尽管网络上的教程也有不少,包括源码中也有自带的编译步骤说明,但真正自己动手的话,还是会遇...

952
来自专栏星汉技术

虚拟机:Linux系统安装

2557
来自专栏idba

基于consul的Redis高可用方案

这几天在研究如何做Redis的高可用容灾方案,查询了资料和咨询DBA同行,了解到Redis可以基于consul和sentinel实现读写分离以及HA高可用方案。...

2281

扫码关注云+社区