当捕获到crash以后,捕获到的其实是一堆内存地址,需要将其转化为可读的符号,才能定位问题。
说到堆栈的符号化,我们很容易联想到DSYM
文件,在Xcode build setting
有个Debug Infomation Format
的选项,如下图所示:
可以看到Debug
模式下,符号表文件会存入到可执行文件中,而Release
模式则会生成出DSYM
文件。由于符号表在内存中,这为我们实时符号化堆栈提供了可能性。
1、线程的调用堆栈
如上图所示,一个函数的调用栈是由若干个栈帧组成,每个栈帧通过FP
和SP
划分界线。所以只要知道当前栈帧的 Stack Pointer 和 Frame Pointer,就能知道上一个栈帧的 Stack Pointer 和 Frame Pointer,从而递归的获取栈底的帧。
2、获取线程的SP、FP(寄存器值)
thread_get_state
函数可以获得当前线程的使用的各个寄存器的信息
thread_get_state(thread, BS_THREAD_STATE, (thread_state_t)&machineContext->__ss, &state_count);
machineContext
的类型是_STRUCT_MCONTEXT
结构体,_STRUCT_MCONTEXT
在不同的 cpu 架构会有所不同。以ARM64为例,_STRUCT_MCONTEXT
结构体如下图所示:
可以发现__ss
是保存线程的状态,进入_STRUCT_ARM_THREAD_STATE64
结构体继续查看
可以发现_STRUCT_ARM_THREAD_STATE64
结构体里面保存了重要的寄存器值,我们最关心的SP
和FP
也存在这里,其它的还有PC
程序计算器,L