breakpad是Google开源的一套跨平台工具,用于dump的处理。很全的一套东西,我这里只简单涉及breakpad客户端,不涉及纯文本符号生成,不涉及dump解析。

一、使用

  最简单的是使用进程内dump捕获,使用者只需要跟ExceptionHandler打交道,在自己的程序里定义一个ExceptionHandler对象,ExceptionHandler会挂上异常处理、CRT参数错误处理、purecall错误处理,当发生crash时,breakpad会写好dump,然后回调通知使用者。进程内dump并不推荐,但也不算太差,它在程序启动时就开启了一个“Handler thread”,等到有crash,触发该线程去写dump,写完回调使用者,从google的久未更新的ClientDesign文档可以猜到以前是只有进程内写dump的,它已经符合了让dump尽可能真实而设置下的规定。以前所在团队在chromium上做二次开发,使用的是进程内dump,没发现有问题。现在我安装的chrome浏览器,没发现有crash_server进程,估计要么是没抓dump,要么是进程内dump,我看到有文章说有一个GoogleCrashHandler.exe进程,但我这里没有发现,可能是后来修改掉了吧,之前我还一直以为是对crash_server.exe重命名了。

进程外写dump,使用者一样要定义一个ExceptionHandler对象,这对象有管道名称。另外还需要写一个server进程,server进程负责:写dump、上传dump,当客户进程发生crash时,只需要通过Event置位通知服务进程。server进程只需要定义一个breakpad提供的CrashGenerationServer类对象。客户进程和服务进程是通过管道通信的,通信可以只发生在客户进程初始化阶段,server进程要先于客户进程启动,否则客户进程就会因为管道连接不上而使用进程内dump捕获。

  进程内、外dump捕获,都是异步而阻塞的,异步具体是说,进程内dump会让写dump、回调通知使用者写dump完成在另一个安全的线程中做;进程外dump会让写dump在另一个进程中做、回调通知写dump完成在crash线程中做、dump上传可以放到另一个进程中做。阻塞具体是说,虽然发生crash的线程把dump相关的工作扔给别人做了,但是它会等待别人的工作做完才继续完下走。

二、内部实现 

  ExceptionHandler部分。

当使用进程内dump时,会有一个handler thread,该线程启动之后,等待semaphore触发写dump行为,进程外dump则没有该线程。另外,异常处理初始化是在ExceptionHandler对象构造中做的,如果没有进程外dump的需求,那么只需要ExceptionHandler就可以搞定,不需要CrashGenerationClient 和 CrashGenerationServer。

     生成dump的流程在ExceptionHandler里面跑的很杂,还提供了非崩溃产生dump的接口。画个流程图出来(流程图只是函数的罗列,块与块之间可能存在包含关系):
     CrashGenerationClient 和 CrashGenerationServer。
     这两个类主要用于进程间通信,包括:管道数据传输、Event通知。跟ExceptionHandler有关联的就是CrashGenerationClient,这里的client可以当作管道的client来理解。ExceptionHandler已经做了异常处理初始化,而进程外dump的生成是另外的进程做的,所以CrashGenerationClient,并不涉及异常、dump生成,它只是为了进程间通信而存在。

以CrashGenerationClient为主线来介绍客户进程服务进程间的交互。CrashGenerationClient对外提供Register、RequestDump、RequestUpload。
1、Register
     1-1 客户进程连接上服务进程:连接上管道,设置管道状态
     1-2 客户进程向服务进程注册:通过TransactNamedPipe,将客户进程的信息传递给服务进程,也从服务进程读取到数据。
         客户进程传递的数据包括:服务进程ID、dump类型、crash线程id的地址、EXCEPTION_POINTERS指针的地址、参数异常和纯虚函数异常的断言信息地址、客户进程信息。服务进程会监控客户进程的退出。
         客户进程接收的数据包括:客户进程用于触发生成dump的Event Handle;客户进程用于监听的dump生成完毕Event Handle;客户进程用于监听的服务进程活着Mutex handle;服务进程进程id(后面没用上)。
         这里Handle,都是服务进程通过DuplicateHandle API 复制到客户进程的,为什么不使用命名Handle呢?这样子两个进程只需要约定名字就好,不需要DuplicateHandle,然后再通过管道传递。我的理解:命名Handle之所以不用,是因为服务进程要为多个客户进程提供dump服务,如果使用命名Handle,那么命名会是一个很麻烦的事情,再则,约定名字也增加了耦合,breakpad现在的做法使得客户和服务的耦合只有管道名、管道数据协议。
     客户进程在TransactNamePipe函数执行完毕之后,再执行了一次WriteFile操作,发送MESSAGE_TAG_REGISTRATION_ACK消息给服务进程,服务进程收到该ACK消息时,关闭跟客户进程的连接。服务进程对管道的操作顺序为:读-->写-->读,第二次读是客户进程通知服务进程关闭管道。
2、RequestDump
     当发生crash时,或者是在非crash状态下要求生成dump,就需要调用RequestDump函数。客户进程触发之前从服务进程收到的崩溃Event Handle,等待dump完成Event和服务进程Event处于触发状态,release下最多等15秒,debug下无限等待,异步阻塞,为了不让现场被破坏。
     服务进程通过RegisterWaitForSingleObject注册了崩溃Event Handle的回调函数。回调函数里做了这么几件事情:(1)、通过ReadProcessMemory读取客户进程的信息;(2)、生成dump;(3)、触发dump生成事件,通知客户进程,复位触发dump事件。
3、RequestUpload
     首先客户进程连接上服务进程,接着客户进程写MESSAGE_TAG_UPLOAD_REQUEST消息到管道,写完关闭管道。
     服务进程读取数据,发现是MESSAGE_TAG_UPLOAD_REQUEST消息,则调用创建服务进程时注册的上传回调函数。注意到chromium并没有使用这个通道,而是在服务进程生成dump的回调里做了dump上传操作,这样子似乎更好,减少了crash时两进程的沟通。客户进程、服务进程、breakpad客户端之间的联系图:

可以看到breakpad客户端主要包含了CrashGenerationServer\ExceptionHandler\CrashGenerationClient三部分,另外有dump上传未画出。

三、从代码中学到的

学习breakpad_client的代码,不是为了在工作上使用,以前的、现在的团队都已经有成熟的dump捕获、dump分析工具。学习它,是为了体会它的优点和缺点。

   breakpad_client的层次划分很好,使用者不需要知道进程间通信的存在,通过回调实现层次间的通知。(这种比较简单,一般人都可以做到。)

crash之后崩溃线程尽可能少的操作,在客户进程初始化时就把崩溃时服务进程需要用的全局数据的地址通知服务进程,崩溃时,只需要触发Event。(我之前的做法是在crash的时候再把崩溃信息通知服务进程,现在看来是不合理的。)

API的使用。RegisterWaitForSingleObject的使用,这个API是我之前没用过的,非常方便,直到前阵子才通过QueueUserWorkItem API(chromium通过它异步上传dump)知道windows有自带线程池的存在;进程间通信对管道+Event的善用(管道的异步操作 + RegisterWaitForSingleObject 非常漂亮);dump生成的各种处理,不仅仅是MiniDumpWriteDump。(这可以说是我知识面不广带来的惊喜。)

  阅读ClientDesign文档,虽然文档可能老了,但引导我明白了为什么进程内dump会导致现场破坏,最直接的理解是:因为堆坏了导致的崩溃,这时候异常处理函数里又干了堆内存分配的事情,那肯定就又继续crash。

  breakpad_client对使用者的通知是用回调函数做的,回调函数是在对象初始化时传递的函数指针,有一个函数有三个回调函数指针(客户进程连接、客户进程崩溃、客户进程要求上传dump), 我更喜欢用抽象类指针,这样子只需要一个指针就够了,参数不需要那么多,而且代码更像C++。(这是目前唯一能想到的不喜欢。)

四、资料推荐

http://code.google.com/p/google-breakpad/wiki

五、杂
 (1)、获取breakpad_client 代码及其demo。
     breakpad代码所在svn:http://google-breakpad.googlecode.com/svn/trunk 
     生成sln:D:\breakpad\src\tools\gyp>gyp.bat --no-circular-check "../../client/windows/breakpad_client.gyp"
     需要先安装python,使用2.7.4版本python正常生成sln文件,2.4.3、3.3.2版本均生成失败。搜索发现,\src\client\windows\build\common.gypi文件下有 'python_ver%': '2.5',,不确定是否要依据它来确定python使用的版本。因为我是在可以编译chromium的环境下使用breakpad_client的,所以不需要对编译环境做处理。 
 (2)、chromium在breakpad_client的使用上,做了些值得看的事情。譬如:log、crash之后的处理...
 (3)、相比之下,之前分析的windows下捕获dump,真是简单到极点的入门级demo。
 (4)、breakpad服务端dump处理的开源代码:https://github.com/mozilla/socorro(我没看,不确定是否靠谱)
 (5)、breakpad官网的文档估计比较旧了,但是思路还是正确的。符号文件部分没有看,因为比较深,而我目前又没有深究它的需要,看breakpad里有pdb文件生成为纯文本格式后的样子,估计是为了统一各个平台吧。(又是一个《纯文本的威力》?)
 
http://blog.csdn.net/flyingleo1981/article/details/51543687

windows下捕获dump之Google breakpad_client的更多相关文章

  1. windows下捕获dump之Google breakpad_client的理解

    breakpad是Google开源的一套跨平台工具,用于dump的处理.很全的一套东西,我这里只简单涉及breakpad客户端,不涉及纯文本符号生成,不涉及dump解析. 一.使用 最简单的是使用进程 ...

  2. windows下捕获dump之守护进程

    一两个月前为产品写了一个独立的exe,由于产品使用的捕获dump是一个现成的进程外exe,如果以资源的方式集成它容易出现安全警告,由于时间关系没有寻求新的解决方法,还是遵循旧方案,不捕获dump. 最 ...

  3. windows下捕获dump

         一般要捕获异常只需要两个函数:SetUnhandledExceptionFilter截获异常:MiniDumpWriteDump写dump文件.但是由于CRT函数可能会在内部调用SetUnh ...

  4. Google Breakpad 在 windows下捕获程序崩溃报告

    http://blog.csdn.net/goforwardtostep/article/details/56304285

  5. Windows下获取Dump文件以及进程下各线程调用栈的方法总结(转)

    1. Dump文件的用途 Dump文件, 主要用于诊断一个进程的运行状态,尤其是碰到崩溃(Crash)或者挂起(hang)不响应时,需要分析它的工作状态.  除了平时常见的attach到这个进程, 分 ...

  6. windows下捕获本地回环网络中的报文RawCap

    一.下载地址: 官网地址:https://www.netresec.com/?page=RawCap 百度云:链接:https://pan.baidu.com/s/1mWCOTRF5XicuJitBA ...

  7. google protobuf学习笔记:windows下环境配置

    欢迎转载,转载请注明原文地址:http://blog.csdn.net/majianfei1023/article/details/45371743 protobuf的使用和原理,请查看:http:/ ...

  8. CEF中文教程(google chrome浏览器控件) -- Windows下编译Chromium

    CEF中文教程(google chrome浏览器控件) -- CEF简介 2013-04-10 16:48 42928人阅读 评论(4) 收藏 举报  分类: CEF(2)    目录(?)[+]   ...

  9. libjingler-0.6.2在windows和ubuntu 10.04下的编译(Google Talk)

    Libjingle版本:0.6.2 所需的资源:         gtest-1.6.0.zip         http://download.csdn.net/detail/cl_gamer/48 ...

随机推荐

  1. [Grid Layout] Use auto-fill and auto-fit if the number of repeated grid tracks is not to be def

    What about the situation in which we aren’t specifying the number of columns or rows to be repeated? ...

  2. C#基础readonly 与const

    readonly 与 const readonly是运行时常量,const是编译期常量(在编译过程中已经把使用该值的都用值替代,不分配内存)readonly灵活性高,const效率高 readonly ...

  3. Linux中vim中出现H不能正常编辑的问题

    使用Linux中,由于是远程操作,我使用crt,由于有的文档有乱码,我就设置了一下session的字符... vim出现问题,下方出现H,导致不能正常编辑... 耗费一下午的时间,在高人的指点之下,终 ...

  4. MOCHIWEB与COWBOY使用JSON

    http://4096.info/2014/05/28/mochiweb%E4%B8%8Ecowboy%E4%BD%BF%E7%94%A8json/ 服务器原来的socket实现机制更改为ranch了 ...

  5. 【codeforces 779C】Dishonest Sellers

    [题目链接]:http://codeforces.com/contest/779/problem/C [题意] 有n个商品; 打折前买和打折后买的价格不一样; 且必须有至少k个商品在打折前买; 问你买 ...

  6. 对Java JVM中类加载几点解释

    1.用到类的时候,类加载到方法区,同时方法区会存放static的内容(包括静态方法和静态变量),随类的加载而加载 2当new的时候,会在堆中创建一个对象,在其中会开辟其中的实例变量内存并初始化,堆中变 ...

  7. request.getSession().getServletContext().getRealPath()的一些坑

    今天是学校机房的服务器上对之前的一个网站升级时发现了一个bug,我自己的机器上用的tomcat8,机房上是tomcat7,结果一运行就开始报找不到文件,最后发现是文件分隔符的问题 原来在代码中涉及到路 ...

  8. 【16.52%】【codeforces 733C】Epidemic in Monstropolis

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  9. 聊聊QPS/TPS/并发量/系统吞吐量的概念

    原文:聊聊QPS/TPS/并发量/系统吞吐量的概念 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/cainiao_user/article/deta ...

  10. go-wingui 2018 全新 v2.0 版本发布,包含重大更新!

    go-wingui 2018 全新 v2.0 版本发布,包含重大更新!使用新版CEF内核Chromium 63.0.3239.109,页面可以使用最新的css3,html5技术.使用delphi7重写 ...