OpenHarmony Faultloggerd 模块 libunwinder 回栈库解析
unwinder 库概览
- unwinder 库代码结构
1 | unwinder |
- 功能
- 内存与寄存器访问
- elf解析
- arm_exidx 节回栈表解析
- eh_frame_hdr / eh_frame 节Dwarf回栈表解析
- minidebug_info 节解析
- 支持Hap包 CompressNativeLibs 方案的elf解析
- QUT回栈方案实现
- FP回栈方案实现
- unwind 接口封装
内存与寄存器读写
DfxAccessors 数据访问抽象
DfxAccessors
类是unwinder库中抽象出的数据访问类。
根据不同类型的回栈,实现有 DfxAccessorsLocal
、DfxAccessorsRemote
、DfxAccessorsCustomize
子类,分别对应本地回栈、远程回栈和自定义回栈(自定义内存寄存器访问方式,例如离线回栈场景)。
对于数据访问的类型,DfxAccessors
类抽象出了三个方法:
1 | class DfxAccessors { |
DfxAccessorsLocal
类:本地回栈数据访问实现
- AccessMem: 先通过判断地址是否在栈空间内来校验地址合法性,直接采用地址解引用的方式来读取内存。
- AccessReg: 直接基于context通过寄存器下标来读取寄存器值,其中context是内部定义的
UnwindContext
结构体。
1 | struct UnwindContext { |
- FindUnwindTable: 通过
dl_iterate_phdr
接口来遍历当前进程的program header
的方式来找到 unwindtable 的地址,具体实现由DfxELF::FindUnwindTableLocal
静态函数实现。
arm32 架构的回栈表有 .arm_exidx 表承载,arm64 架构的回栈表由 .eh_frame_hdr 表和 .eh_frame 表承载。
DfxAccessorsRemote
类:远程回栈数据访问实现
- AccessMem:通过
ptrace
系统调用的PTRACE_PEEKDATA
来读取目标进程的内存(一次只能读4字节),需要额外判断在arm64场景下需要读两次,同时根据大小端来进行拼接。 - AccessReg: 同local方式,基于内部
UnwindContext
结构体对象进行访问。 - FindUnwindTable: 基于内部
UnwindContext
结构体对象解析map
对应的elf
对象来找到 unwindtable 的地址。
1 | auto elf = ctx->map->GetElf(); |
DfxAccessorsCustomize
类:自定义回栈数据访问实现由实例化时传入UnwindAccessors
数据访问抽象结构体对象来承载。
如下代码所示,即所有的访问由用户自定义。
1 | struct UnwindAccessors { |
DfxMemory 内存访问实现
DfxMemory
类是 unwinder 库中定义的内存访问类,需要传入 DfxAccessors
类对象进行实例化,提供了对 DfxAccessors
管理的内存读写源数据的多样化访问方式。
1 | class DfxMemory { |
【说明】
ReadXXX(uintptr_t& addr, XXX *val, bool incre = false)
系列接口的incre
参数决定是否自增addr
- DWARF Exception Header Encoding 参考:https://refspecs.linuxfoundation.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
DfxMmap 文件读写实现
DfxMmap
类继承自 DfxMemory
类,提供对指定文件的读写功能,同时管理着通过 mmap
指定文件或地址的数据。
疑问:目前看
DfxMmap
类似乎并不需要继承DfxMemory
类。
当前 DfxMmap
主要用作加载 Elf 文件或数据,根据文件或数据的格式的不同,分为基础 Elf 文件(包含hap文件中的elf文件形式)、minidebuginfo
节解压后 Elf 格式数据。
1 | class DfxMmap : public DfxMemory { |
ELF 基础解析
libunwinder 库中基于 DfxElf
类和 ElfParser
类来完成 Elf 文件的基础解析,其中 DfxElf
是抽象出的 Elf 文件对象,ElfParser
是用于解析 Elf 文件的工具类。
公共定义
1 | struct ElfLoadInfo { // elf load段定义 |
DfxElf 文件对象
类成员对象
1 | class DfxElf final { |
重要类成员函数
- 初始化函数
1 | static std::shared_ptr<DfxElf> Create(const std::string& file); // 通用场景下的elf创建 |
- 常用工具函数
1 | bool Read(uintptr_t pos, void *buf, size_t size); // elf读取函数,指定偏移和大小 |
ElfParser 如何解析Elf文件
Elf文件解析由 ElfParser
基类和 ElfParser32
、ElfParser64
子类构成,支持对arm32和arm64的Elf文件解析。
Todo
arm_exidx 节回栈表解析
TODO
eh_frame_hdr / eh_frame 节Dwarf回栈表解析
TODO
minidebug_info 节解析
TODO
支持Hap包 CompressNativeLibs 方案的elf解析
TODO
QUT回栈方案实现
TODO
FP回栈方案实现
TODO
unwind 接口封装
TODO