崩溃进程的每个线程都被捕获为回溯,记录进程终止时线程上运行的代码。回溯与使用调试器暂停进程时看到的类似。由语言异常引起的崩溃包括位于第一个线程之前的附加回溯,即最后一个异常回溯。
友盟崩溃日志原文:
Thread 0 Crashed: 0 libobjc.A.dylib 0x00000001cd9cae20 objc_retain + [ : 16] 1 XXXApp 0x0000000103042080 ReachabilityCallback + [ : 40] 2 SystemConfiguration 0x00000001de6076c4 reachPerformAndUnlock + [ : 620] 3 CoreFoundation 0x00000001d46e622c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + [ : 28] 4 CoreFoundation 0x00000001d46f2614 __CFRunLoopDoSource0 + [ : 176] 5 CoreFoundation 0x00000001d467657c __CFRunLoopDoSources0 + [ : 340] 6 CoreFoundation 0x00000001d468beb8 __CFRunLoopRun + [ : 836] 7 CoreFoundation 0x00000001d46911e4 CFRunLoopRunSpecific + [ : 612] 8 GraphicsServices 0x000000020d4b1368 GSEventRunModal + [ : 164] 9 UIKitCore 0x00000001d6b40d88 -[UIApplication _run] + [ : 888] 10 UIKitCore 0x00000001d6b409ec UIApplicationMain + [ : 340] 11 XXXApp 0x0000000102470efc main + [main.m : 16] 12 (null) 0x00000001f29b5948 0x0 + 8365234504 Thread 1 name: JavaScriptCore libpas scavenger Thread 1: 0 libsystem_kernel.dylib 0x0000000210cfc41c __psynch_cvwait + [ : 8] 1 libsystem_pthread.dylib 0x0000000220f4006c _pthread_cond_wait + [ : 1232] 2 JavaScriptCore 0x00000001e7a03c70 0x1e7910000 + 998512 3 libsystem_pthread.dylib 0x0000000220f396cc _pthread_start + [ : 148] Thread 2: 0 libsystem_kernel.dylib 0x0000000210cfc050 __workq_kernreturn + [ : 8] 1 libsystem_pthread.dylib 0x0000000220f38e44 _pthread_wqthread + [ : 364]
分析:
每个回溯的第一行列出线程编号和线程名称。出于隐私考虑,通过Xcode中的崩溃管理器提交的崩溃报告不包含线程名称。此示例显示了三个线程的回溯;线程0崩溃,并通过其名称标识为应用程序的主线程。
在线程号之后,回溯的每一行表示回溯中的堆栈帧。
0 libobjc.A.dylib 0x00000001cd9cae20 objc_retain + [ : 16]
堆栈帧的每一列都包含有关崩溃时执行的代码的信息。下面的列表使用了上面示例中堆栈帧0的组件。
- 0 堆栈帧编号。堆栈帧按调用顺序排列,其中帧0是执行停止时正在执行的函数。帧1是调用帧0中的函数的函数,依此类推。
- libobjc.A.dylib 包含正在执行的函数的二进制文件的名称。
- 0x00000001cd9cae20 正在执行的机器指令的地址。对于每个回溯中的帧0,这是进程终止时线程上执行的机器指令的地址。对于其他堆栈帧,这是在控制返回到该堆栈帧之后执行的第一条机器指令的地址。
- objc_retain 在完全符号化的崩溃报告中,是正在执行的函数的名称。出于隐私考虑,函数名有时仅限于前100个字符。
- [ : 16] +后面的数字是从函数的入口点到函数中当前指令的字节偏移量。
如果二进制文件有dSYM文件,则包含代码的文件名和行号。
在某些情况下,文件名或行号信息与原始源代码不符:
- 如果源文件名为<compiler generated>,则编译器为该帧创建了代码,而代码不在源文件中。如果这是崩溃线程中的顶部帧,请查看前面的几个堆栈帧以获取线索。
- 如果源文件的行号为0,这意味着回溯不会映射到原始代码中的特定代码行。这是因为编译器优化了代码,例如通过内联函数,并且在崩溃时执行的代码与原始代码中的一行不一致。在这种情况下,框架的函数名仍然是一个线索。