iOS中的崩溃主要分为两种:oc语言抛出的异常和Mach层的异常。
上图可以看到对于这两种异常都可以注册回调函数进行检测。在异常抛出时,将调用堆栈的信息记录下来,供之后异常分析。
Objective-C Exception 1 2 3 4 void NSSetUncaughtExceptionHandler(NSUncaughtExceptionHandler *); description: Changes the top-level error handler. Sets the top-level error-handling function where you can perform last-minute logging before the program terminates.
1 2 3 4 5 6 7 8 - (void)installOCExceptionHandle { NSSetUncaughtExceptionHandler(&oc_exception_handler); } static void oc_exception_handler(NSException *exception) { NSLog(@"%@", exception); NSLog(@"%@", [exception callStackSymbols]); }
apple文档中描述中可以看到top-level的handler只能有一个,即多次通过该函数注册handler会有覆盖现象。
覆盖的问题的解决方案是将原本的handler函数赋值给一个全局变量,在自己的handler函数末尾再调用这个函数。这样就能使原本的handler不失效。
1 2 3 4 5 6 7 8 9 10 11 static void (*origin_exception_handler) (NSException *);- (void )installOCExceptionHandle { orgin_exception_handler = NSGetUncaughtExceptionHandler (); NSSetUncaughtExceptionHandler (&oc_exception_handler); } static void oc_exception_handler(NSException *exception) { NSLog (@"%@" , exception); NSLog (@"%@" , [exception callStackSymbols]); (*origin_exception_handler)(exception); }
XNU Exception xnu的异常捕捉同oc的异常捕捉同理,都需要注册一个handler函数。额外注意的一点,在DEBUG模式下xcode会优先捕捉异常,所以不能连着xcode进行调试。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 static void origin_signal_action(int signal, siginfo_t* info, void context);- (void )installXNUExceptionHandler { struct sigaction old_action; sigaction(SIGABRT, NULL , &old_action); if (old_action.sa_flags & SA_SIGINFO) { origin_signal_action = old_action.sa_sigaction; } struct sigaction action; action.sa_sigaction = signal_exception_handler; action.sa_flags = SA_NODEFER | SA_SIGINFO; sigemptyset(&action.sa_mask); sigaction(SIGABRT, &action, 0 ); } static void signal_exception_handler(int signal, siginfo_t* info, void context) { NSMutableString *mstr = [NSMutableString new]; void *callstack[120 ]; int i, frames = backtrace(callstack, 120 ); char ** strs = backtrace_symbols(callstack, frames); for (i = 0 ; i < frames; i++) { [mstr appendString:@"%s\n" , strs[i]] } origin_signal_action(signal, info, context); }