前言
版本:1.15.18
这一篇主要介绍如何捕获异常的,由于KSCrash做了反调试,阅读起来有点麻烦,只能一步一步的阅读源码来探寻原理
Monitors
这个目录下面对crash的类型进行了分类处理,挑几个重点的来看
- KSCrashMonitor_NSException
#import "KSCrash.h" #import "KSCrashMonitor_NSException.h" #import "KSStackCursor_Backtrace.h" #include "KSCrashMonitorContext.h" #include "KSID.h" #include "KSThread.h" #import <Foundation/Foundation.h> //#define KSLogger_LocalLevel TRACE #import "KSLogger.h" // ============================================================================ #pragma mark - Globals - // ============================================================================ static volatile bool g_isEnabled = 0; static KSCrash_MonitorContext g_monitorContext; /** The exception handler that was in place before we installed ours. */ static NSUncaughtExceptionHandler* g_previousUncaughtExceptionHandler; // ============================================================================ #pragma mark - Callbacks - // ============================================================================ /** Our custom excepetion handler. * Fetch the stack trace from the exception and write a report. * * @param exception The exception that was raised. */ /* 捕获到crash之后 1.暂停所有线程 保护现场 2.获取堆栈 3.保存信息(符号化之后) 4.唤醒线程 5.将crash抛给原先的处理函数 */ static void handleException(NSException* exception, BOOL currentSnapshotUserReported) { KSLOG_DEBUG(@"Trapped exception11111 %@", exception); if(g_isEnabled) { ksmc_suspendEnvironment(); kscm_notifyFatalExceptionCaptured(false); KSLOG_DEBUG(@"Filling out context."); NSArray* addresses = [exception callStackReturnAddresses]; NSUInteger numFrames = addresses.count; uintptr_t* callstack = malloc(numFrames * sizeof(*callstack)); for(NSUInteger i = 0; i < numFrames; i++) { callstack[i] = (uintptr_t)[addresses[i] unsignedLongLongValue]; } char eventID[37]; ksid_generate(eventID); KSMC_NEW_CONTEXT(machineContext); ksmc_getContextForThread(ksthread_self(), machineContext, true); KSStackCursor cursor; kssc_initWithBacktrace(&cursor, callstack, (int)numFrames, 0); KSCrash_MonitorContext* crashContext = &g_monitorContext; memset(crashContext, 0, sizeof(*crashContext)); crashContext->crashType = KSCrashMonitorTypeNSException; crashContext->eventID = eventID; crashContext->offendingMachineContext = machineContext; crashContext->registersAreValid = false; crashContext->NSException.name = [[exception name] UTF8String]; crashContext->NSException.userInfo = [[NSString stringWithFormat:@"%@", exception.userInfo] UTF8String]; crashContext->exceptionName = crashContext->NSException.name; crashContext->crashReason = [[exception reason] UTF8String]; crashContext->stackCursor = &cursor; crashContext->currentSnapshotUserReported = currentSnapshotUserReported; KSLOG_DEBUG(@"Calling main crash handler."); kscm_handleException(crashContext); free(callstack); if (currentSnapshotUserReported) { ksmc_resumeEnvironment(); } if (g_previousUncaughtExceptionHandler != NULL) { KSLOG_DEBUG(@"Calling original exception handler."); g_previousUncaughtExceptionHandler(exception); } } } static void handleCurrentSnapshotUserReportedException(NSException* exception) { handleException(exception, true); } static void handleUncaughtException(NSException* exception) { handleException(exception, false); } // ============================================================================ #pragma mark - API - // ============================================================================ //授权开关 static void setEnabled(bool isEnabled) { NSLog(@"************KSCrashMonitor_NSException isEnabled :%d",isEnabled); if(isEnabled != g_isEnabled) { g_isEnabled = isEnabled; if(isEnabled) { KSLOG_DEBUG(@"Backing up original handler."); g_previousUncaughtExceptionHandler = NSGetUncaughtExceptionHandler(); KSLOG_DEBUG(@"Setting new handler."); NSSetUncaughtExceptionHandler(&handleUncaughtException); KSCrash.sharedInstance.uncaughtExceptionHandler = &handleUncaughtException; KSCrash.sharedInstance.currentSnapshotUserReportedExceptionHandler = &handleCurrentSnapshotUserReportedException; } else { KSLOG_DEBUG(@"Restoring original handler."); NSSetUncaughtExceptionHandler(g_previousUncaughtExceptionHandler); } } } static bool isEnabled() { return g_isEnabled; } //是否已对KSCrashMonitor_NSException进行授权 KSCrashMonitorAPI* kscm_nsexception_getAPI() { static KSCrashMonitorAPI api = { .setEnabled = setEnabled, .isEnabled = isEnabled }; return &api; }