iOS底层优化(33) - 启动优化之clang插桩

Clang 原理

Clang文档 clang.llvm.org/docs/Saniti…

苹果提供的一个代码跟踪的功能, Tracing PCs

1、将-fsanitize-coverage=func,trace-pc-guard添加到xcode中

image.png

注意这里的 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所有的方法,并且可以得到所有这些方法的调用顺序。

就是在每一个方法的实现的部分添加了一句代码,调用该方法,相当于修改了二进制文件。

这个方法也就是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

image.png

这样 swift 的方法也就加进去了。

猜你喜欢

转载自juejin.im/post/7085638984126169095