前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Google Breakpad 来助力解决程序崩溃

使用 Google Breakpad 来助力解决程序崩溃

作者头像
HelloWorld杰少
发布2022-12-17 16:04:18
1.9K0
发布2022-12-17 16:04:18
举报
文章被收录于专栏:HelloWorld杰少HelloWorld杰少

背景

作为一名程序,最头疼的莫过于项目上线后收到程序崩溃的通知,若能够在手头重现出该问题,那相对来说项目能够及时的修复并更新;如果无法重现外网崩溃的问题,那就十分的"头疼"了。要是能够实时的采集到项目的崩溃信息,那该多好啊!这并不是一种什么奢望,目前就有现成的技术解决方案。这段时间,我一直在帮项目开发程序崩溃的采集功能,其中用到的技术方案就是 Google 开发的 Breakpad。

Google Breakpad是什么?

Google Breakpad 是 Google 开发的一个跨平台的崩溃采集库。利用这个库可以在 Windows, Mac, Linux, iOS 和 Android 平台上对程序的崩溃进行捕获,并生成 dump 文件供后期分析。也是目前最成熟运用最广的开源库,并且这个库现在依然在更新和维护。

它主要包括三个部分:

  • dumpSyms 负责读取用户开发应用中的debug信息,并生成特定的符号文件。
  • client 在崩溃系统中负责抓取当前线程和当前载入的库生成 minidump 文件。
  • processor 通过 minidump_stackwalk 读取 minidump 文件 找到合适的符号文件产生一个可读的 c/c++ 调用栈。

breakpad原理图

image

在默认情况下,当程序崩溃时 breakpad 会生成一个 minidump 文件,它在不同平台上的实现机制不一样,解释如下:

  • 在 Windows 平台上,使用微软提供的 SetUnhandledExceptionFilter() 方法来实现。
  • 在 OS X 平台上,通过创建一个线程来监听 Mach Exception port 来实现。
  • 在 Linux 平台上,通过设置一个信号处理器来监听 SIGILL SIGSEGV 等异常信号。

Breakpad 在所有的平台上都使用 minidump 文件格式,minidump 文件格式是由微软开发的用于崩溃上传,它包括:

  • 当 dump 生成时进程中一系列 executable 和 shared libraries, 包括这些文件的文件名和版本号。
  • 进程中的线程列表,对于每个线程,minidump 包含它在寄存器中的状态,线程的 stack memory 内容。这些数据都是未解析的字节流,Breakpad client 通常没有调试信息能生成函数名,行号,甚至无法确定 stack frame 的边界。
  • 其他收集关于系统的信息,如处理器,操作系统高版本,dump 的原因等等。

breakpad的使用

在 Github 上将 Breakpad 源码下载到本地:https://github.com/google/breakpad。

编译

打开终端,cd 到源码路径,编译源码:

./configure && make

编译之前请先在电脑上通过homebrew安装cmake工具,否则会报错。

生成 dump_syms

找到路径 /breakpad-main/src/tools/mac/dump_syms/dump_syms.xcodeproj,然后通过 Xcode 编译生成 dump_syms。

生成 libBreakpad.a

本文通过在 iOS 平台上集成 Breakpad 来演示崩溃采集,所以这里我们只会去编译供 iOS 应用使用的 .a 库。

找到路径 /breakpad-main/src/client/ios/Breakpad.xcodeproj,然后通过 Xcode 打开它,然后编译成 libBreakpad.a。

好了,到这里我们的准备工作就做好了,接下来就来看看如何去解析崩溃吧!

项目集成

首先创建一个 iOS App 的测试工程,然后在工程中依赖我们上面编译生成的 libBreakpad.a 库。

然后在 didFinishLaunchingWithOptions 方法里加入

[[BreakpadController sharedInstance] start: YES];

在 applicationWillTerminate 方法时加入

[[BreakpadController sharedInstance] stop];

代码如下:

代码语言:javascript
复制
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    [[BreakpadController sharedInstance] start:YES];
    return YES;
}


- (void)applicationWillTerminate:(UIApplication *)application{
    [[BreakpadController sharedInstance] stop];
}

除了依赖库之外,我们还得在工程中加入一些配置,这也是 Breakpad 所要求的,否则 Breakpad 在初始化的时候就会初始化失败。

打开我们的测试工程的 plist,然后为其加上以下内容:

代码语言:javascript
复制
 <key>BreakpadProduct</key>
    <string>Google_Notifier_Mac</string>
    <key>BreakpadProductDisplay</key>
    <string>${PRODUCT_NAME}</string>
    <key>BreakpadURL</key>
    <string>这里请填入您自己要上传的服务器地址</string>
    <key>BreakpadReportInterval</key>
    <string>30</string>

这些配置做完了以后,接下来我们就要来模拟一次崩溃啦!这还不容易吗?直接写一个数组越界的逻辑就可以模拟 Crash 啦!

代码如下:

代码语言:javascript
复制
- (IBAction)Triger:(id)sender {
    NSArray *array = [[NSArray alloc] initWithObjects:@"1", @"2", @"3", nil];
    
    NSString *value = [array objectAtIndex:8];
}

当我们点击这个按钮事件的时候,就会触发这次崩溃。

Breakpad 在捕获到这次崩溃时,会在我们 App 的 Library/Caches 路径下创建 Breakpad 文件夹,并将生成的 dmp 文件保存在里面,如图:

image

现在有了 dmp 文件,我们暂时还无法去解析它,为什么?因为我们还缺少符号文件去符号化这个 dmp。

那我们去哪里找这个符号文件呢?打包时,iOS App 的符号文件默认情况下都存放在 xcarchive 文件中。

打开 Xcode 的 Window -> Organizer, 然后找到对应的 archive 包,右键 Show in Finder, 文件夹 dSYMs 里即为我们的符号文件。

image

分析崩溃文件

在上面我们已经编译好了 dump_syms 和 minidump_stackwalk ,接下来用这两个工具生成 symbols 文件和堆栈文件。

在你合适的目录中新建一个文件夹,名称按照个人喜好即可,然后将 dump_syms,minidump_stackwalk,dmp 和 .dSYM 文件拖进来。

生成Symbols文件:

cd 到该目录,执行如下命令:

$ ./dump_syms -a arm64 TTTT.app.dSYM > TTTT.sym

❝解释下,命令中的架构可以是 armv7, armv7s 等等,主要还是看你的应用是支持的什么架构,像我的这个测试工程,它就只支持 arm64,所以我这边就只生成 arm64 的 Symbols 文件。另外,TTTT.app.dSYM 是我这边打包生成的,需要替换你自己的 .dSYM 文件,然后生成的 .sym 文件,文件名必须与之前的 TTTT 保持一致,否则 dmp 文件就不能符号化。 ❞

查看 TTTT.sym 文件内容,执行如下:

head -n1 TTTT.sym

头部会有

MODULE mac arm64 6DD6178D3EF53F21A61BE8B5D9E294D00 TTTT

这样的字符串。

继续执行命令

mkdir -p symbols/TTTT/6DD6178D3EF53F21A61BE8B5D9E294D00 /

mv TTTT.sym symbols/TTTT/6DD6178D3EF53F21A61BE8B5D9E294D00 /

./minidump_stackwalk xxxx-xxxx-xxxx-xxx.dmp symbols > crashed.log

这样我们就把 dmp 给分析出来了,符号化的数据都保存在 crashed.log 中。

image

根据图上的内容,我们可以发现程序的崩溃发生在 ViewController.m 的第24行。回到我们的测试工程中,发现确实在 24 行,这里发生了数组越界。

image

由此说明,Breakpad 帮助我们找到了程序崩溃的地方,本次实验就成功啦!

最后

好了,本篇教程到此就结束了。总体来说 Breakpad 使用起来并不麻烦,崩溃采集的结果也很准确,相信对很多想把产品做好的公司来说是一把利器。本篇仅是简单的讲解了一下 Google Breakpad 的使用以及 dump 解析,如果真正想把这一块做好的话还需要下一点功夫,譬如说崩溃文件压缩上传,以及服务器崩溃日志解析等工作都需要自动化完成,本篇就不再赘述了,如果你有什么好的 idea,欢迎与我交流。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HelloWorld杰少 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • Google Breakpad是什么?
    • breakpad原理图
    • breakpad的使用
      • 编译
        • 生成 dump_syms
          • 生成 libBreakpad.a
          • 项目集成
          • 分析崩溃文件
            • 生成Symbols文件:
            • 最后
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档