Clang 原理
Clang文档 clang.llvm.org/docs/Saniti…
苹果提供的一个代码跟踪的功能, Tracing PCs
1、将-fsanitize-coverage=func,trace-pc-guard
添加到xcode中
注意这里的 func
,代表仅拦截方法。
2、运行的时候会报错,因为有两个方法还未定义
__sanitizer_cov_trace_pc_guard_init
__sanitizer_cov_trace_pc_guard
复制代码
这是回调,,需要按照文档的要求在项目中定义。
查看内存的命令:x 0x100000
以下将方法、block、函数等统称方法。
__sanitizer_cov_trace_pc_guard_init
可以获取所有方法的个数。
__sanitizer_cov_trace_pc_guard
hook所有的方法,并且可以得到所有这些方法的调用顺序。
扫描二维码关注公众号,回复:
13785793 查看本文章
就是在每一个方法的实现的部分添加了一句代码,调用该方法,相当于修改了二进制文件。
这个方法也就是Clang插桩的原理。
获取符号并存储
通过下面的方法打印所有符号:
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
void *PC = __builtin_return_address(0);
Dl_info info;
dladdr(PC,&info);
printf(@"%s\n",info.dli_sname);
}
复制代码
上述回调方法是多线程的,也就是说子线程里面的函数,这个方法就会在子线程执行。
因此,需要用一种线程安全的方式,来存储符号,也就是放在一个线程安全的原子队列中。
#include <stdint.h>
#include <stdio.h>
#include <sanitizer/coverage_interface.h>
#import <dlfcn.h>
#import <libkern/OSAtomic.h>
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
void *PC = __builtin_return_address(0);
Dl_info info;
dladdr(PC,&info);
printf(@"%s\n",info.dli_sname);
//创建结构体
SYNode * node = malloc(sizeof(SYNode));
*node = (SYNode){PC,NULL};
//结构体入栈
OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, next));
}
//生成order文件!!
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//定义数组
NSMutableArray<NSString *> * symbleNames = [NSMutableArray array];
while (YES) {//循环体内!进行了拦截!!
SYNode * node = OSAtomicDequeue(&symbolList, offsetof(SYNode,next));
if (node == NULL) {
break;
}
Dl_info info;
dladdr(node->pc, &info);
NSString * name = @(info.dli_sname);//转字符串
//给函数名称添加 _
BOOL isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["];
NSString * symbolName = isObjc ? name : [@"_" stringByAppendingString:name];
[symbleNames addObject:symbolName];
}
//反向遍历数组
// symbleNames = (NSMutableArray<NSString *> *)[[symbleNames reverseObjectEnumerator] allObjects];
// NSLog(@"%@",symbleNames);
NSEnumerator * em = [symbleNames reverseObjectEnumerator];
NSMutableArray * funcs = [NSMutableArray arrayWithCapacity:symbleNames.count];
NSString * name;
//去重
while (name = [em nextObject]) {
if (![funcs containsObject:name]) {
[funcs addObject:name];
}
}
//去掉自己!touchesBegan
[funcs removeObject:[NSString stringWithFormat:@"%s",__func__]];
//写入文件
//1.编程字符串
NSString * funcStr = [funcs componentsJoinedByString:@"\n"];
NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"dd.order"];
NSData * file = [funcStr dataUsingEncoding:NSUTF8StringEncoding];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:file attributes:nil];
NSLog(@"%@",funcStr);
}
复制代码
swift符号覆盖
1、创建一个swift文件
2、添加 Other Swift Flags
这样 swift 的方法也就加进去了。