最近项目出现线上奔溃,解crash的过程中调试了汇编,特此记录。

奔溃日志

OS Version:      iPhone OS 9.2 (13C75)
Report Version:  104
Exception Type:  SIGSEGV
Exception Codes: SEGV_MAPERR at 0x145e4bec8
Crashed Thread:  26


Thread 26 Crashed:
0   libobjc.A.dylib    0x00000001943c80b4 objc_retain + 20
1   libobjc.A.dylib    0x00000001943c812c objc_storeStrong + 44
2   AFWealth           0x0000000101af23dc -[SPDYSession initWithOrigin:configuration:cellular:error:] + 108

系统在objc_storeStrong的时候会retain对象,当线程25正在retain的时候,却发现该对象编程野指针了,导致retain奔溃,但从crash日志中没法看出是retain哪个对象的时候发生了变化。

找出这个对象就需要使用调试汇编。

储备知识

  1. iOS Assembly Tutorial: Understanding ARM
  2. X86_Assembly

需要注意两点

  • calling convention
  • iOS的汇编代码是AT&T 语法的

汇编调试

根据crash堆栈打符号断点,命中后在objc_storeStrong打断点进行逐步调试。

id objc_storeStrong(id *object, id value) {
  value = [value retain];
  id oldValue = *object;
  *object = value;
  [oldValue release];
  return value;
}

从上述源码可以知道,objc_storeStrong有两个参数,第二个参数就是我们retain的对象。

0x1061ffb63 <+99>:   movq   %rcx, %rdi
0x1061ffb66 <+102>:  movq   %rdx, %rsi
0x1061ffb69 <+105>:  callq  0x10764e60e               ; symbol stub for: objc_storeStrong

根据FASTCALL的调用规范,我们查看rdx寄存器的值。

(lldb) x/a $rdx
0x608001e60040: 0x00000001087bf8d0 (void *)0x00000001087bf8f8: SPDYConfiguration

或者

(lldb) po [$rdx class]
SPDYConfiguration

因而得之在这里被retain的是 SPDYConfiguration对象

结论

从上面的分析知道是有个SPDYConfiguration对象有多线程问题,然后再查查源码不久就解决问题了。