崩溃报告的线程状态部分列出了应用程序终止时崩溃线程的CPU寄存器及其值。了解线程状态是一个高级主题,需要了解应用程序二进制接口(ABI)。
寄存器为内存访问问题导致的崩溃提供额外信息。了解崩溃线程的寄存器将进一步讨论这种情况。
大多数崩溃报告的分析不需要考虑寄存器状态。然而,如果您正在调查一个困难的内存访问问题,寄存器会提供崩溃报告中其他地方找不到的信息。
- 内存访问是内存获取还是指令获取?
- 程序计数器、链接寄存器和堆栈指针寄存器是否在程序的地址空间中包含有效地址?
- 如果您使用atos来表示链接寄存器中的地址,它的功能是什么?该函数是否通过函数指针跳转到其他代码?
确定导致问题的内存访问类型
内存访问问题有两类:无效内存获取和无效指令获取。当代码取消引用无效指针时,会发生无效内存提取。当函数通过错误的函数指针或通过对意外对象的函数调用跳转到另一个函数时,会发生无效的指令获取。要确定哪种类型的内存访问问题导致了崩溃,请关注程序计数器,这是一个包含导致内存访问异常的指令地址的寄存器。在ARM CPU架构上,这是pc寄存器。在x86_64 CPU架构上,这是rip寄存器。
如果程序计数器寄存器与异常地址不相同,则崩溃是由于无效的内存获取。例如,考虑x86_64 CPU上的以下macOS崩溃报告:
Exception Type: SIGSEGV
Exception Codes: SEGV_MAPERR at 0x21474feae2c8
...
Thread 12 crashed with X86-64 Thread State:
rip: 0x00007fff61f5739d rbp: 0x00007000026c72c0 rsp: 0x00007000026c7248 rax: 0xe85e2965c85400b4
rbx: 0x00006000023ee2b0 rcx: 0x00007f9273022990 rdx: 0x00007000026c6d88 rdi: 0x00006000023ee2b0
rsi: 0x00007fff358aae0f r8: 0x00000000000003ff r9: 0x00006000023edbc0 r10: 0x000021474feae2b0
r11: 0x00007fff358aae0f r12: 0x000060000237af10 r13: 0x00007fff61f57380 r14: 0x00006000023ee2b0
r15: 0x0000000000000006 rflags: 0x0000000000010202 cs: 0x000000000000002b fs: 0x0000000000000000
gs: 0x0000000000000000
程序计数器寄存器(rip)为0x00007fff61f5739d,这与异常的地址0x21474feae2c8不同。此崩溃是由于无效的内存获取。
如果程序计数器寄存器与异常地址相同,则崩溃是由于无效的指令获取。例如,考虑arm64 CPU上的以下iOS崩溃报告:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000040
...
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 ??? 0x0000000000000040 0 + 64
...
Thread 0 crashed with ARM Thread State (64-bit):
x0: 0x0000000000000002 x1: 0x0000000000000040 x2: 0x0000000000000001 x3: 0x000000016dcfe080
x4: 0x0000000000000010 x5: 0x000000016dcfdc8f x6: 0x000000016dcfdd80 x7: 0x0000000000000000
x8: 0x000000010210d3c8 x9: 0x0000000000000000 x10: 0x0000000000000014 x11: 0x0000000102835948
x12: 0x0000000000000014 x13: 0x0000000000000000 x14: 0x0000000000000001 x15: 0x0000000000000000
x16: 0x000000010210c0b8 x17: 0x00000001021063b0 x18: 0x0000000000000000 x19: 0x0000000102402b80
x20: 0x0000000102402b80 x21: 0x0000000204f6b000 x22: 0x00000001f6e6f984 x23: 0x0000000000000001
x24: 0x0000000000000001 x25: 0x00000001fc47b690 x26: 0x0000000102304040 x27: 0x0000000204eea000
x28: 0x00000001f6e78fae fp: 0x000000016dcfdec0 lr: 0x00000001021063c4
sp: 0x000000016dcfdec0 pc: 0x0000000000000040 cpsr: 0x40000000
esr: 0x82000006 (Instruction Abort) Translation fault
Binary Images:
0x102100000 - 0x102107fff MyCoolApp arm64 <87760ecf8573392ca5795f0db63a44e2> /var/containers/Bundle/Application/686CA3F1-6CC5-4F84-8126-EE22D03BC161/MyCoolApp.app/MyCoolApp
在本例中,程序计数器寄存器(pc)为0x0000000000000040,它与异常子类型中报告的地址匹配,表明此崩溃是由于错误的指令获取造成的。因为这是一个错误的指令获取,所以回溯中的第0帧不包含正在运行的函数,如“???”所示而不是回溯中的符号名称。然而,链接寄存器lr包含在正常情况下代码在函数调用后返回的位置。链接寄存器中的值允许您跟踪跳转到错误指令指针的原点。
x86_64 CPU体系结构将返回地址存储在堆栈上,而不是存储在链接寄存器中,因此无法跟踪x86_64处理器上错误函数指针的来源。
链接寄存器(lr)包含0x00000001021063c4,这是应用程序进程中加载的二进制文件之一中的指令地址。崩溃报告的Binary Images部分显示该地址位于MyCoolApp二进制文件内,因为该地址位于该二进制文件列出的范围0x102100000-0x102107fff内。有了这些信息,您可以使用atos命令行工具和二进制文件的dSYM文件,并识别位于0x00000001021063c4的相应代码:
% atos -arch arm64 -o MyCoolApp.app.dSYM/Contents/Resources/DWARF/MyCoolApp -l 0x102100000 0x00000001021063c4
-[ViewController loadData] (in MyCoolApp) (ViewController.m:38)
友盟崩溃日志原文:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000
Thread 0 crashed with ARM-64 Thread State:
cpsr: 0x0000000080000000 fp: 0x000000016d79a5e0 lr: 0x000000010344156c pc: 0x0000000102fb28c0
sp: 0x000000016d79a5c0 x0: 0x000000016d79a638 x1: 0x0000000000000000 x10: 0x0000000000000000
x11: 0x00000000000007fd x12: 0x0000000000000012 x13: 0x00000000b5804054 x14: 0x00000000b5a04800
x15: 0x0000000000000009 x16: 0x00000001ef7ef100 x17: 0x0000000230c58c10 x18: 0x0000000000000000
x19: 0x00000001515082e0 x2: 0x0000000230c3f260 x20: 0x877a31c8606f7002 x21: 0x0000000000000002
x22: 0x000000014be94140 x23: 0x877a31c86075701a x24: 0x0000000000000000 x25: 0x0000000000000000
x26: 0x0000000000000000 x27: 0x0000000000000000 x28: 0x000000010410b910 x29: 0x000000016d79a5e0
x3: 0x00000001e8db62ec x4: 0x0000000000000000 x5: 0x0000000000000010 x6: 0x0000000000000079
x7: 0x0000000000000000 x8: 0x000000016d79a640 x9: 0xab84ca84cec80013
Binary Images:
0x102664000 - 0x103d53fff +XXXApp arm64 <c3e2537682e73a81a84d236feea6582c> /private/var/containers/Bundle/Application/89DB2FD2-4411-4A9F-AC8D-635559FF85E7/XXXApp.app/XXXApp
分析:
在本例中,程序计数器寄存器(pc)为0x0000000102fb28c0,这与异常的地址0x21474feae2c8不同。此崩溃是由于无效的内存获取。链接寄存器lr包含在正常情况下代码在函数调用后返回的位置。链接寄存器中的值允许您跟踪跳转到错误指令指针的原点。
链接寄存器(lr)包含0x000000010344156c,这是应用程序进程中加载的二进制文件之一中的指令地址。崩溃报告的Binary Images部分显示该地址位于XXXApp二进制文件内,因为该地址位于该二进制文件列出的范围0x102664000 - 0x103d53fff内。有了这些信息,您可以使用atos命令行工具和二进制文件的dSYM文件,并识别位于0x000000010344156c的相应代码:
% atos -o /Users/xx/Library/Developer/Xcode/Archives/2022-12-02/XXXApp\ 2022-12-2\,\ 10.31.xcarchive/dSYMs/XXXApp.app.dSYM/Contents/Resources/DWARF/XXXApp -l 0x1022ac000 0x0000000103042080
-[MobClickInternal saveAndCleanCache] (in XXXApp) + 804
由此定位到崩溃出现在友盟的SDK中
网友评论