Breakpad崩溃报告系统介绍

Breakpad是Google开发的一套开源的崩溃报告系统,它是跨平台的,支持Windows、Linux、Mac等操作系统,被Chrome、Firefox等各大软件采用。最近做Chromium内核升级,需要把Breakpad升级成Crashpad,故再看看Breakpad项目的实现,写篇博客总结一下。

Breakpad的机制

breakpad

如上图所示是Breakpad的工作机制,它是参考Windows上那套崩溃处理机制。Windows上面编译器把代码编译成可执行文件,同时生成包含调试信息的PDB符号文件。程序运行发生崩溃时,将崩溃的堆栈等信息存储成一个dump文件。调试器打开dump文件并读取PDB里面的调试信息,就可以看到崩溃的堆栈。因为Breakpad是跨平台的,所以在Linux等其他平台也实现了Windows上的生成调试符号、生成dump、处理dump等功能。

Breakpad分为3个主要的模块:

  1. Client。Client模块会被编译到客户端程序中,它的职责包括捕获客户端的异常、生成崩溃的dump文件、上报dump文件到服务器。在Windows平台,我们只需要这部分就足够了。
  2. Symbol dumper。这个模块是用来读取编译器编译代码生成的调试信息,然后把这些调试信息处理存储成一个符号文件。它扮演的角色类似Windows上的编译器生成PDB文件。
  3. Processor。这个模块是根据符号文件里面的信息,处理dump文件,输出人类可读的崩溃堆栈信息。它扮演的角色类似Windows上的windbg调试器。

Minidump

在程序崩溃的时候,Breakpad会生成dump文件。Dump文件里包含许多让帮助我们定位程序崩溃原因的信息:

  • 程序运行时已经加载的模块信息。在Windows上面是指各种dll。
  • 程序崩溃时各个线程的堆栈信息,比如调用栈、栈上参数、栈上变量、CPU寄存器。
  • 进程的句柄、内存信息。

之前不同平台生成的dump文件格式是不统一的,Linux上的dump文件是core dump。Breakpad生成的dump文件格式都是跟Windows平台上的Minidump格式是一致的,原因是:

  • Linux上的core dump文件体积可能很大,不利于收集上传到服务器
  • Core dump文件格式缺乏文档
  • Windows上现有的Minidump格式很完善
  • 不同平台使用统一的格式有利于proccessor的处理

非Windows平台的开发者可能对Minidump不熟悉,这里有MSDN上关于Minidump文件的介绍https://msdn.microsoft.com/en-us/library/windows/desktop/ms680369(v=vs.85).aspx。Windows上是有个专门的Dbghelp的库来处理Minidump文件。

Breakpad代码

Breakpad项目的URL https://chromium.googlesource.com/breakpad/breakpad,还有不少文档。
Breakpad的代码获取跟Chromium很类似,用depot_tools,做过Chromium开发的人应该觉得很熟悉。Breakpad的编译系统却跟Chrmoium不一样,Breakpad使用的是make。不过还好,Windows上的实现在src/client/windows目录里面已经提供了现成的breakpad_client.sln工程文件,用VS打开就可以编译了。breakpad_client.sln,里面有个crash_generation_app工程,这个就是一个例子。通过学习这个例子可以让我们了解Breakpad的运作。

生成Dump

生成dump是Breakpad里面client模块的功能。Client模块是会编译到客户端代码里面的。Breakpad支持两种生成dump方式,以下分别介绍。

进程内生成dump

当程序发生异常的时候,就直接生成dump文件,这是一种比较简单直接的做法。在每个需要捕获异常生成dump的进程内创建一个ExceptionHandler对象即可。

进程外生成dump

进程内生成dump有两个缺点:

  1. 当进程发生异常频率崩溃的时候,进程是处于一种微弱和不稳定的状态,如果继续在进程内做生成dump的操作可能会破坏崩溃的现场,导致我们后来从dump看到的信息并非一开始导致崩溃的信息。
  2. 有些进程不支持进程内生成dump。比如renderer进程,它在沙箱中没有访问文件系统的权限,因此它自己无法生成dump。

 

google-breakpad-out-of-process-dump

因此Breakpad还支持进程外的生成dump。如上图所示,先在Server进程里面创建一个CrashGenerationServer对象,CrashGenerationServer对象会创建一个命名管道。然后Client进程里面还是会创建一个ExceptionHandler对象,ExceptionHandler里面又包含了一个CrashGenerationClient对象,它通过命名管道与Server进程里面的CrashGenerationServer通信。

Chromium 里面的Breakpad

http://dev.chromium.org/developers/crash-reports,这篇文章讲了Chomium是如何整合Breakpad的。默认情况下,Chromium是没有开启Breakpad,而Chrome在Windows上进Browser进程开启了进程内的抓dump。所以Windows上无法抓取在沙箱中的Renderer进程。不过从Chromium 49开始,开始启用新的Crashpad,以后再写博客讲这个。虽然Chromium默认没有启用Breakpad,但我们可以用过–noerrdialogs命令行参数来手动开启。

看代码的实现,Chromium在MainDllLoader::Launch里面,还未加载chrome.dll之前有这么一段代码:

这里就是初始化Breakpad的地方。而在breakpad::InitCrashReporter里面开始真正创建了一个google_breakpad::ExceptionHandler对象。

Windows版本的Chromium里面没有创建google_breakpad::CrashGenerationServer对象,这也是它为什么不支持进程外抓dump的原因。不过Chromium里面有个breakpad::CrashServer,它创建了google_breakpad::CrashGenerationServer。但是Chromium也没有创建google_breakpad::CrashServer。有个crash_service的程序,倒是创建了google_breakpad::CrashServer。

参考

  • https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/getting_started_with_breakpad.md
  • https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/client_design.md
  • http://dev.chromium.org/developers/crash-reports
  • Google Breakpad 完全解析(一) —— Windows入门篇。http://bigasp.com/archives/450
  • Google Breakpad 完全解析(二) —— Windows前台实现篇。http://bigasp.com/archives/458

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注