1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
| // // YCSymbolTracker.m // YCSymbolTracker // // Created by ycpeng on 2020/6/10. //
#import "YCSymbolTracker.h"
#import <stdint.h> #import <stdio.h> #import <sanitizer/coverage_interface.h> #import <libkern/OSAtomic.h> #import <dlfcn.h> #import <os/lock.h>
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { static uint64_t N; // Counter for the guards. if (start == stop || *start) return; // Initialize only once. // printf("INIT: %p %p\n", start, stop); for (uint32_t *x = start; x < stop; x++) *x = (uint32_t)++N; // Guards should start from 1. }
void printInfo(void *PC) { Dl_info info; dladdr(PC, &info); printf("fnam:%s \n fbase:%p \n sname:%s \n saddr:%p \n", info.dli_fname, info.dli_fbase, info.dli_sname, info.dli_saddr); }
static OSQueueHead symbolList = OS_ATOMIC_QUEUE_INIT; static BOOL finished; static NSMutableDictionary *mappings; static os_unfair_lock lock;
typedef struct { void *pc; void *next; } SymbolNode;
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { // if (!*guard) return; // Duplicate the guard check. if (finished) { return; } static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ mappings = [NSMutableDictionary dictionaryWithCapacity:1000]; lock = OS_UNFAIR_LOCK_INIT; }); void *PC = __builtin_return_address(0); int64_t pcw = (int64_t)PC; int32_t pch = (pcw & 0xFFFFFFFF00000000) >> 32; os_unfair_lock_lock(&lock); NSMutableDictionary *sub = [mappings objectForKey:@(pch)]; if (sub && sub[@(pcw)]) { os_unfair_lock_unlock(&lock); return; } if (!sub) { sub = [NSMutableDictionary dictionaryWithCapacity:10000]; mappings[@(pch)] = sub; } sub[@(pcw)] = @1; os_unfair_lock_unlock(&lock); SymbolNode * node = malloc(sizeof(SymbolNode)); *node = (SymbolNode){PC, NULL}; OSAtomicEnqueue(&symbolList, node, offsetof(SymbolNode, next));
// printInfo(PC); }
@implementation YCSymbolTracker
+ (BOOL)exportSymbolsWithFilePath:(nonnull NSString *)filePath { finished = YES; NSMutableArray <NSString *>* symbolNames = [NSMutableArray array]; while (YES) { SymbolNode *node = OSAtomicDequeue(&symbolList, offsetof(SymbolNode, next)); if (node == NULL) { break; } Dl_info info; dladdr(node->pc, &info); NSString * name = @(info.dli_sname); BOOL isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["]; // Objective-C method do nothing NSString * symbolName = isObjc? name : [@"_" stringByAppendingString:name]; // c function with "_" [symbolNames addObject:symbolName]; } NSEnumerator * emt = [symbolNames reverseObjectEnumerator]; NSMutableArray<NSString*>* funcs = [NSMutableArray arrayWithCapacity:symbolNames.count]; NSString * name; while (name = [emt nextObject]) { if (![funcs containsObject:name]) { [funcs addObject:name]; } } // remove current method symbol (not necessary when launch) [funcs removeObject:[NSString stringWithFormat:@"%s", __FUNCTION__]]; NSString *funcStr = [funcs componentsJoinedByString:@"\n"]; NSData * fileContents = [funcStr dataUsingEncoding:NSUTF8StringEncoding]; if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil]; } return [[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil]; }
@end
|
Comments