Skip to content

Instantly share code, notes, and snippets.

@michaeleisel
Created January 15, 2019 16:39
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save michaeleisel/111fed9bf8dc46d2c08a0a30b940171e to your computer and use it in GitHub Desktop.
Save michaeleisel/111fed9bf8dc46d2c08a0a30b940171e to your computer and use it in GitHub Desktop.
//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];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment