iOS Crash Catch

​ iOS中的崩溃主要分为两种:oc语言抛出的异常和Mach层的异常。

img

​ 上图可以看到对于这两种异常都可以注册回调函数进行检测。在异常抛出时,将调用堆栈的信息记录下来,供之后异常分析。

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 {
// SIGABRT为例。
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]]
}
/* mstr need to store in sandbox */

origin_signal_action(signal, info, context);
}