-
-
Save annidy/bad51b21184767a64bce1693349aad64 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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]; | |
} | |
NSOrderedSet *set = [NSOrderedSet orderedSetWithArray:functions]; | |
return [[set reverseObjectEnumerator] allObjects];} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment