https://mp.weixin.qq.com/s/LSj63THjgt2XKxkapAQpCg
首先在other C flag中增加下面这段:-fsanitize-coverage=func,trace-pc-guard
#import <dlfcn.h> #import <libkern/OSAtomicQueue.h> #import <pthread.h> typedef struct { void *ptr; NSInteger number; } CLRCall; static OSQueueHead sQueueData = OS_ATOMIC_QUEUE_INIT; static OSQueueHead *sQueue = &sQueueData; static BOOL sStopCollecting = NO; static BOOL sInitDidOccur = NO; typedef struct { void *pointer; void *next; } PointerNode; void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { sInitDidOccur = YES; for (uint32_t *x = start; x < stop; x++) { *x = 1; } } void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { // If initialization has not occurred yet (meaning that guard is uninitialized), that means that initial functions like +load are being run. These functions will only be run once anyways, so we should always allow them to be recorded and ignore guard if (sStopCollecting || (!(*guard) && sInitDidOccur)) { return; } *guard = 0; void *pointer = __builtin_return_address(0); PointerNode *node = malloc(sizeof(PointerNode)); *node = (PointerNode){pointer, NULL}; OSAtomicEnqueue(sQueue, node, offsetof(PointerNode, next)); } extern NSArray <NSString *> *CLRCollectCalls(void) { sStopCollecting = YES; __sync_synchronize(); // Hopefully, any other threads for which sStopCollecting was NO when they entered and are still preempted will get to preempt // during this sleep and finish up sleep(1); NSMutableArray <NSString *> *functions = [NSMutableArray array]; while (YES) { PointerNode *node = OSAtomicDequeue(sQueue, offsetof(PointerNode, next)); if (node == NULL) { break; } Dl_info info = {0}; dladdr(node->pointer, &info); NSString *name = @(info.dli_sname); BOOL isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["]; NSString *symbolName = isObjc ? name : [@"_" stringByAppendingString:name]; [functions addObject:symbolName]; } return [[functions reverseObjectEnumerator] allObjects]; }