breakpad概述
时间:2022-07-26
本文章向大家介绍breakpad概述,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
breakpad是什么
- google开源的一套实现
崩溃报告
系统的客户端和服务端组件 - C++语言实现
- 现在已经被广泛运用在google的一系列产品及其它公司的桌面程序上,如chrome,piscal,firefox等。
- github地址
- 官方网站
功能特性
- 崩溃转储
- 崩溃分析
- 跨平台:windows、mac、linux
- 可以运行于一系列架构的cpu上
主要组件
- client:集成到应用程序源码中,用于抓取崩溃信息,并生成minidmp文件
- symbol dumper:读取编译器生成的调试信息(pdb),生成symbol文件
- processor:读取minidump文件,并结合symbol文件,生成可读的堆栈调用信息
各组件关系示意图
工作原理图
崩溃转储文件
coredump文件
- Coredump叫做核心转储,它是进程运行时在突然崩溃的那一刻的一个内存快照。
- linux内核提供的功能
- 操作系统在程序发生异常而异常在进程内部又没有被捕获的情况下,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在一个文件里
coredump生成的条件
- 条件一:需要有信号产生:进程中止前肯定有信号产生,
内核根据信号类型来决定是否产生core文件
- 条件二:需要编译器支持:需要把当前进程镜像以某种格式dump到文件中,比如:gcc/g++的
-g
选型 - 条件三:环境参数支持:
- 通过 ulimit –a 查看 core file size 是否为 0 ,如果为 0 则不能产生 core 文件。
- 通过 ulimit –c unlimited 可以系统能支持的产生足够大的 core 文件,也可以设置为具体值
coredump的局限性
- 文件巨大,不利于保存和传输
- 有些情况崩溃导致堆栈被破坏,堆栈信息不准确
- 一些信号导致崩溃,不会产生core文件
- 不能实时产生崩溃文件,必须进程终止时
minidump文件
- minidump文件格式是由微软开发的用于崩溃上传
各个组件详解
client
- client模块作为一个
静态库
将会与使用者的程序编译在一块 - 它的主要作用是在程序崩溃后,接管程序的异常处理
- 主要做了两方面的事情:
- 响应程序崩溃时接收到的
signal
- 获取程序崩溃那一刻的运行时信息,保存为一个minidump格式的文件
- 响应程序崩溃时接收到的
- 内部原理:
- 崩溃时线程可以异常了,通过克隆子进程,并通过ptrace与父进程交互,读取相关信息
- 有两种异常处理模式:进程内、进程外
symbole dumper
- 从可执行程序中提取与符号相关的信息,并保存为一种特定格式的文件
- symbol file中全部内容都是ascii文本。
- symbol file的内容以行单位,每一行称作一条记录,每条记录中有多个字段,每个字段以空格分开
- 每条记录的开头是一个串字符,这个字符标记这条记录是什么类型的记录。(Line record除外,这种类型的记录,默认省略掉标记符)
- 记录中有些字段是10进制或16进制的字符串,16进制也没有以0x开头,要分清某个数字具体是哪种进制,就要看这些数字是在哪种记录里,属于哪个字段,这些都是规定死了的
symbole文件格式
样例:
MODULE windows x86 3AA3B2229C144C24AEBEF3D971F32D711 GMTSJWorker.pdb
FILE 18430 d:winmain.public.x86fresdkincrpcdce.h
FUNC b7990 49 0 `dynamic initializer for 'std::_Error_objects::_Generic_object''
b7990 49 611 282
FUNC c2a70 327 0 boost::algorithm::detail::process_segment_helper<0>::operator() >,std::basic_string,std::allocator >,std::_String_iterator > > >(std::deque > &,std::basic_string,std::allocator > &,std::_String_iterator > >,std::_String_iterator > >,std::_String_iterator > >)
c2a70 53 63 6337
c2ac3 62 71 6337
STACK WIN 4 207410 f 3 0 0 0 0 0 1 $T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =
- MODULE:第一条记录,用来描述当前这个模块文件
- FILE:记录源文件,包含有文件名及路径信息。会被分配一个整形符号来作标记,然后在别的记录中可能会引用它。
- FUNC:这种记录用来描述一个函数,包含函数名,函数在可执行文件中的地址等信息
- Line:这种记录没有类型,描述一个给定范围的机器指令对应哪个源文件的哪一行。行记录总是跟在FUNC记录后面,从而描述每个函数里的指令对应在源码里的位置。
- PUBLIC: 这种记录用来描述每一个链接符号的地址,如汇编函数里的各个入口点
- STACK WIN: 这种记录用来描述函数调用时,函数帧(stack frame)的布局。有了这个记录,给定一特定的函数帧F,就可以找到哪个函数帧调用了F
- STACK CFI:CFI, 就是Call Frame Info,这种记录用来表述当执行到某条指令的时候,怎样去查看当前的函数调用栈。
关于符号信息,linux环境:编译非release版本的程序时(如,gcc 开了-g选项),编译器通常会将带有符号相关的信息以某种格式(DWARF,STABS)组织起来,存放在可执行文件的某个段位里。windows环境:脱离可执行文件,放在单独的pdb中
processor
- 根据coredump及symbol file,构建出可读的call stack
- 针对每一个线程进行分析,根据不同的cpu,构建出当前线程的top frame,也就是函数调用的最顶一层。然后从top frame开始,对整个调用栈的栈帧进行解析。
解析包含的内容
1. 查找模块
根据当前帧的eip(x86)来调用 CodeModules::GetModuleForAddress()返回当前frame所属的模块信息
2. 定位符号
前面找到模块后,找到只是二进制相关的信息。要找到这个模块相应的名字及模块里其它函数,变量的名字等,还需要用到之前symbole file.
3. 查找符号
根据某个地址,查找出对应的符号名字,如,输入一个函数地址,返回函数的名字。
4. 查找出当前帧的调用帧
- 当前帧解析完后,需要继续去解析调用当前帧的父帧
- symbol file中有二种记录类型:stack win,stack cfi。
- 这两种类型的记录完整的描述了各类函数调用的栈帧布局,因此借助这些记录理论上就可以找回当前帧的调用帧
参考文档
- 很多人比较纠结的约束和索引的关系(r7笔记第75天)
- JavaWeb09-Servlet(Java真正的全栈开发)
- JavaWeb08-XML,tomcat,HTTP轻松入门
- JavaWeb07-JDBC(Java真正的全栈开发)
- 编程思想 之「操作符」
- Hyperledger fabric Chaincode 开发详解
- 字节码文件的内部结构之谜
- 基因功能富集分析-R语言
- CRM, C4C和Hybris的工作流简介
- 想进大厂?50个多线程面试题,你会多少?(一)
- golang 几种字符串的连接方式
- Go Template学习笔记
- Go语言实现控制台贪吃蛇
- 容灾半自动化的实现思路(二) (r7笔记第93天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 搞它!!!linux配置本地yum源
- JAVA网络编程TCP通信
- 使用ExecutorService实现线程池
- 搞它!!!linux服务器硬件及RAID 配置实战
- 认识XML
- 基于oracle的sql(结构化查询语言)指令
- oracle约束条件
- oracle常用函数介绍
- 搞它!!!Linux系统中查看进程和计划任务管理
- 搞它!!!深入了解linux文件系统底层原理及日志文件介绍
- 搞它!!!Linux系统MBR分区和GPT分区的区别
- oracle补充
- 搞它!!!Linux系统LVM原理及磁盘配额(PV、VG、LV、PE的关系,手把手教你,嘴对嘴的传达)
- 搞它!!!linux网络服务基本设置命令合集
- 搞它!!!Linux系统上DHCP服务器的配置(理论加实验,分分钟搞定!!!)