步骤一:添加 Build Setting 设置
Target -> Build Setting -> Custom Complier Flags ->
Other C Flags 添加
-fsanitize-coverage=func,trace-pc-guard
Other Swift Flags 添加
-sanitize-coverage=func
-sanitize=undefined
步骤二:添加代码
添加到启动最早的那个 ViewController 即可。
#import "dlfcn.h"
#import <libkern/OSAtomic.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 = ++N; // Guards should start from 1.
}
//初始化原子队列
static OSQueueHead list = OS_ATOMIC_QUEUE_INIT;
//定义节点结构体
typedef struct {
void *pc; //存下获取到的PC
void *next; //指向下一个节点
} Node;
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
void *PC = __builtin_return_address(0);
Node *node = malloc(sizeof(Node));
*node = (Node){PC, NULL};
// offsetof() 计算出列尾,OSAtomicEnqueue() 把 node 加入 list 尾巴
OSAtomicEnqueue(&list, node, offsetof(Node, next));
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSMutableArray *arr = [NSMutableArray array];
while(1){
//有进就有出,这个方法和 OSAtomicEnqueue() 类比使用
Node *node = OSAtomicDequeue(&list, offsetof(Node, next));
//退出机制
if (node == NULL) {
break;
}
//获取函数信息
Dl_info info;
dladdr(node->pc, &info);
NSString *sname = [NSString stringWithCString:info.dli_sname encoding:NSUTF8StringEncoding];
printf("%s \n", info.dli_sname);
//处理c函数及block前缀
BOOL isObjc = [sname hasPrefix:@"+["] || [sname hasPrefix:@"-["];
//c函数及block需要在开头添加下划线
sname = isObjc ? sname: [@"_" stringByAppendingString:sname];
//去重
if (![arr containsObject:sname]) {
//因为入栈的时候是从上至下,取出的时候方向是从下至上,那么就需要倒序,直接插在数组头部即可
[arr insertObject:sname atIndex:0];
}
}
//去掉 touchesBegan 方法 启动的时候不会用到这个
[arr removeObject:[NSString stringWithFormat:@"%s",__FUNCTION__]];
//数组合成字符串
NSString * funcStr = [arr componentsJoinedByString:@"\n"];
//写入文件
NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"link.order"];
NSData * fileContents = [funcStr dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@", filePath);
[[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil];
}
步骤三:取出 order file
在步骤二的代码NSLog(@"%@", filePath); 断点
如果页面无法触发点击,viewDidLoad里面调用touchesBegan:withEvent:也可以
运行代码后记录 link.order 的路径
Finder 前往路径取出 order file
步骤四:设置 order file
把 link.order 的路径放到工程根目录
Target -> Build Setting -> Linking -> Order File 设置路径
步骤五:编译代码
把步骤一 order file 的设置还原
把步骤二添加代码删除
clean 以后编译代码
参考链接:
https://juejin.im/post/6844904165773328392