通过寄存器信息分析iOS crash

2,924 阅读2分钟

日常遇到一些crash,最终调用到objc_msgSendobjc_retain...等,产生在Object-C方法调用或者系统方法调用,经常束手无措归根于系统的问题,这时候可以通过crash日志上的寄存器和符号表信息找到一些真正的线索,一次函数的调用会被记录在寄存器中。这里主要说实践操作。

寄存器信息

以bugly上的一条crash的寄存器信息为例:

  1. 下图中x0~x28fplr等表示寄存器的指令,冒号后面的代表在寄存器上的地址。
  2. 第1行:crash的线程、寄存器信息的描述,这里是子线程thread32ARM64
  3. 第2、3行:x0x7记录的是当前函数的参数和返回值(x0一般为返回),以objc_msgSend为例,x0表示接受者,x1表示对应的@selector()
  4. 第8行:fpsp:分别代表栈底、栈顶寄存器,lr是链接寄存器,代表上一级调用函数的地址(假设当前函数B,A函数中调用B函数,寄存器信息上的lr表示A函数地址)。
  5. 第12行:App base addr模块基准地址,可以理解为此次app启动在寄存器的起始地址,这个信息很重要,查找寄存器的时候需要用到。

读懂了寄存器可以获得更多crash信息,接下来可以通过符号表和寄存器上的函数地址,获取符号化后的函数名来定位问题

image.png

以下常见的一些寄存器指令:

image.png

查看符号表

将以上地址信息带入到命令行参数,执行命令:atos -o 符号表路径 -l 模块基准地址 函数地址

atos -o /Users/xxx/Desktop/xxapp.app.dSYM/xxapp.app.dSYM/Contents/Resources/DWARF/xxapp -l 0x000000010079c000 0x00000001025cbfd4
  1. 当前crash是系统函数,对我们有用的是crash函数的入参和上一级调用的函数,也就是x0~x28和lr后面的地址信息。
  2. 借助atos命令行工具解析函数地址,能获取到具体的函数名、代码行数、类名信息
  3. 再结合代码逻辑基本都能定位到大概的问题所在。