| //Copyright (c) 2018 Michael Eisel. All rights reserved. | |
| #import "CLRCallRecorder.h" | |
| #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]; | |
| } |