环境
macOS Mojave 10.14.3
Xcode10.1
iPhone6S 10.0.1
获得崩溃日志 方式一:Xcode
菜单 > Window
> Devices and Simulators
选择设备并查看设备日志(View Device Logs
)
方式二:手机 设置 > 隐私 > 诊断与用量 > 诊断与用量数据
崩溃日志的结构
Incident Identifier
: 崩溃日志的唯一标识
CrashReporter Key
: 匿名的设备标识
Process
:进程名
Path
:二进制文件路径
Identifier
:包名
Version
:应用版本号
Code Type
: 目标架构
Role
:进程终止时进程被赋予的task_role
枚举值 …
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Incident Identifier: F21EC10C-018D-494F-997D-E9C9D82B2F7F CrashReporter Key: ab7fcdf6938542fd82446362e0481f7fddba141f Hardware Model: iPhone6,2 Process: JACrash [27195] Path: /private/var/containers/Bundle/Application/EDDDCB8E-75CE-4638-84CA-5B7971F6EFE0/JACrash.app/JACrash Identifier: com.ishepherdme.JACrash Version: 1 (1.0) Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] Coalition: com.ishepherdme.JACrash [4182] Date/Time: 2019-02-08 13:03:58.7771 +0800 Launch Time: 2019-02-08 13:03:58.3811 +0800 OS Version: iPhone OS 10.0.1 (14A403) Report Version: 104
Triggered by Thread
: 产生崩溃的线程
Exception Type
: 崩溃类型 …
1 2 3 4 Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Triggered by Thread: 0
其他诊断信息
Application Specific Information
:在进程终止时框架捕获的错误信息 …
1 2 3 4 5 Application Specific Information: abort() called Filtered syslog: None found
线程回溯 罗列崩溃时每个线程的调用栈情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 libsystem_kernel.dylib 0x000000018af0e014 __pthread_kill + 8 1 libsystem_pthread.dylib 0x000000018afd5460 pthread_kill + 112 2 libsystem_c.dylib 0x000000018ae823f4 abort + 140 3 libc++abi.dylib 0x000000018a94d2d4 __cxa_bad_cast + 0 4 libc++abi.dylib 0x000000018a96acc0 default_unexpected_handler+ 126144 () + 0 5 libobjc.A.dylib 0x000000018a978844 _objc_terminate+ 34884 () + 124 6 libc++abi.dylib 0x000000018a96766c std::__terminate(void (*)+ 112236 ()) + 16 7 libc++abi.dylib 0x000000018a967234 __cxa_rethrow + 144 8 libobjc.A.dylib 0x000000018a97871c objc_exception_rethrow + 44 9 CoreFoundation 0x000000018be1a0bc CFRunLoopRunSpecific + 560 10 UIKit 0x0000000191df37cc -[UIApplication _run] + 608 11 UIKit 0x0000000191dee550 UIApplicationMain + 208 12 JACrash 0x000000010007de90 0x100078000 + 24208 13 libdyld.dylib 0x000000018adfc5b8 start + 4
线程状态 列出崩溃线程的线程状态。这是一个寄存器列表及其执行停止时的值。在阅读崩溃报告时,无需了解线程状态,但可以使用此信息更好地了解崩溃的情况。
1 2 3 4 5 6 7 8 9 10 Thread 0 crashed with ARM Thread State (64-bit): x0: 0x0000000000000000 x1: 0x0000000000000000 x2: 0x0000000000000000 x3: 0x00000001740e9737 x4: 0x000000018a96bbc3 x5: 0x000000016fd87520 x6: 0x000000000000006e x7: 0xffffffffffffffec x8: 0x0000000008000000 x9: 0x0000000004000000 x10: 0x000000000000000b x11: 0x0000000000000010 x12: 0x000000018ae99792 x13: 0x0000000000000000 x14: 0x0000030000000300 x15: 0x0000000000000000 x16: 0x0000000000000148 x17: 0x0000000000000000 x18: 0x0000000000000000 x19: 0x0000000000000006 x20: 0x00000001b0bf8c40 x21: 0x000000016fd87520 x22: 0x00000001b0bffbb8 x23: 0x0000000000000001 x24: 0x0000000170011110 x25: 0x0000000000000000 x26: 0x0000000000000001 x27: 0x0000000000000000 x28: 0x000000016fd87b80 fp: 0x000000016fd87480 lr: 0x000000018afd5460 sp: 0x000000016fd87460 pc: 0x000000018af0e014 cpsr: 0x00000000
二进制镜像 进程二进制文件加载的地址区间,动态库加载的地址区间
1 2 3 4 5 6 7 Binary Images: 0x100078000 - 0x10007ffff JACrash arm64 <2fd461c16e7239489a037c6c1141c134> /var/containers/Bundle/Application/A55333A1-CD62-41A2-AE96-F3411ECD3447/JACrash.app/JACrash 0x10009c000 - 0x10009ffff MobileSubstrate.dylib arm64 <3134cfb2f722310ea2c742ae4dc131ab> /Library/MobileSubstrate/MobileSubstrate.dylib 0x1000a8000 - 0x1000affff libswiftCoreFoundation.dylib arm64 <47deeaa1967b3e339dfcb48535a994e1> /var/containers/Bundle/Application/A55333A1-CD62-41A2-AE96-F3411ECD3447/JACrash.app/Frameworks/libswiftCoreFoundation.dylib 0x1000bc000 - 0x1000cbfff libswiftCoreGraphics.dylib arm64 <25fe91aa901b3cf6a443b498012ab5af> /var/containers/Bundle/Application/A55333A1-CD62-41A2-AE96-F3411ECD3447/JACrash.app/Frameworks/libswiftCoreGraphics.dylib 0x1000f0000 - 0x1000f7fff libswiftCoreImage.dylib arm64 ....
关于异常类型(Exception Type
) 野指针(Bad Memory Access [EXC_BAD_ACCESS // SIGSEGV // SIGBUS]
) 尝试访问了非法的内存地址,或访问了受保护的地址
1 2 3 4 5 6 Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Subtype: KERN_INVALID_ADDRESS at 0x000000064229beb8 Termination Signal: Segmentation fault: 11 Termination Reason: Namespace SIGNAL, Code 0xb Terminating Process: exc handler [0] Triggered by Thread: 0
比如在MRC
环境下尝试发送消息给已释放的对象,调用栈的特点是objc_msgSend
/objc_release
在调用栈顶
异常退出(Abnormal Exit [EXC_CRASH // SIGABRT]
) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @implementation ViewController - (void )viewDidLoad { [super viewDidLoad]; [self callCrashMethod]; } - (void )callCrashMethod { [self arrayOutOfBounds]; } - (void )arrayOutOfBounds { NSArray *arr = @[@"0" ,@"1" ]; NSLog (@"%@" ,arr[2 ]); } @end
1 2 3 4 Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Triggered by Thread: 0
崩溃会直接到main
,因为调用栈中包含objc_exception_rethrow
栈帧,根据参考1 ,进行如下的配置,设置异常的断点
The Exception Breakpoint So how do you find the line in the code that made the app crash? Well, whenever you get a stacktrace like this, an exception was thrown by the app. (You can tell because one of the functions in the call stack is named objc_exception_rethrow.)
追踪陷阱(Trace Trap [EXC_BREAKPOINT // SIGTRAP]
) 这个异常是为调试器提供在进程执行的特定点中断进程的机会。
1 2 3 4 5 6 Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000010006e588 Termination Signal: Trace/BPT trap: 5 Termination Reason: Namespace SIGNAL, Code 0x5 Terminating Process: exc handler [0] Triggered by Thread: 0
非法指令(Illegal Instruction
) 进程试图执行非法或未定义指令。这个进程可能试图通过一个配置错误的函数指针,跳到一个无效的地址。
1 2 3 4 5 6 7 Exception Type: EXC_CRASH (SIGILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Termination Signal: Illegal instruction: 4 Termination Reason: Namespace SIGNAL, Code 0x4 Terminating Process: neteasemusic [6562] Triggered by Thread: 0
被杀死(Killed[SIGKILL]
) 1 2 3 4 5 Exception Type: EXC_CRASH (SIGKILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Note: EXC_CORPSE_NOTIFY Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d Triggered by Thread: 0
资源限制(Resource Limit [EXC_RESOURCE]
) 这个进程超出了资源消耗的限制。
符号化
来自参考3
方式一:dSYM
文件 DWARF
即Debugging with Attributed Record Formats
,Xcode
使用它来生成符号表,生成的符号表放在.dSYM
文件中,在Debug
模式下,默认不会生成.dSYM
文件,可以在Build Settings
中进行设置
编译后,在工程中Product
目录下,选择应用程序,Show in Finder
,会发现生成了应用的.dSYM
文件
获取UUID
1 2 Binary Images: 0x1000f8000 - 0x1000fffff JACrash arm64 <2fd461c16e7239489a037c6c1141c134> /var/containers/Bundle/Application/7B72F18F-930E-42CB-B69C-FED75161A03F/JACrash.app/JACrash
UUID:2fd461c16e7239489a037c6c1141c134
1 2 3 % dwarfdump --uuid path/to/Your.app.dSYM/Contents/Resources/DWARF/JACrash ... UUID: 2FD461C1-6E72-3948-9A03-7C6C1141C134 (arm64) /Users/Jason/Library/Developer/Xcode/DerivedData/JACrash-bntjxfwsvrraeuevozrbvraorxqv/Build/Products/Debug-iphoneos/JACrash.app.dSYM/Contents/Resources/DWARF/JACrash
两者UDID
一致即可
定位崩溃地址 1 2 3 % atos -o path/to/Your.app.dSYM/Contents/Resources/DWARF/Your -arch arm64 -l 0x1000f8000 0x1000fdda8 -[ViewController arrayOutOfBounds] (in JACrash) (ViewController.m:33)
0x1000f8000
: 运行时应用基地址0x1000fdda8
: 运行时崩溃地址(待符号化的地址)
支持bitcode
支持bitcode
的情况下,因为最终的二进制文件由Apple Store
后台生成,本地是没有对应的.dSYM
文件,可以从Xcode
或iTunes Connect
上下载
方式二:崩溃日志 + Hopper
如果没有.dSYM
文件,但有崩溃日志的情况时
崩溃地址 = 基地址 + ASLR
+ 方法偏移地址
方法相对基地址的偏移地址是不变的 ,因此只要把ASLR
从崩溃地址中移除,再加上方法的偏移地址即可
用hopper
找出基地址,再加上方法偏移地址
异常捕获监听 1 2 3 4 5 typedef void NSUncaughtExceptionHandler (NSException *exception);FOUNDATION_EXPORT NSUncaughtExceptionHandler * _Nullable NSGetUncaughtExceptionHandler (void ); FOUNDATION_EXPORT void NSSetUncaughtExceptionHandler (NSUncaughtExceptionHandler * _Nullable);
在程序启动时加上一个异常捕获监听,用来处理程序崩溃时的回调动作
1 2 3 4 5 6 7 8 9 10 11 12 void exceptionHandler(NSException *exception) { NSLog (@"%@" , [exception reason]); NSLog (@"%@" , [exception userInfo]); NSLog (@"%@" , [exception callStackSymbols]); } int main(int argc, char * argv[]) { NSSetUncaughtExceptionHandler (&exceptionHandler); @autoreleasepool { return UIApplicationMain (argc, argv, nil , NSStringFromClass ([AppDelegate class ])); } }
参考
My App Crashed, Now What? – Part 1
手动解析CrashLog之—-方法篇
Understanding and Analyzing Application Crash Reports
Address space layout randomization
NSSetUncaughtExceptionHandler not catch all errors on iPhone