iOS堆栈日志线上符号化方案调研

从手机导出.ips或者.crash文件都可以很容易获取到符号化后的堆栈日志, 但是线上大量的的crash,总不可能让用户自己导出crash文件发给开发者的,这个就需要线上符号化的一个能力, 才能更有效的治理线上崩溃问题,未符号化的日志大概率是看不出问题所在的,堆栈日志符号化是势在必行,行之有效的途径~

比如bugly,友盟,看云等三方平台,他们都可以实现事后上传DSYM文件进行翻译匹配对应的堆栈日志,其实都是同一套代码打出来的包,只是区分了CPU架构的不同,可能会有几种可能的堆栈,但是除此之外机型一样的话数据就存在冗余,因为执行脚本翻译堆栈这个过程,时间长则需要耗费几秒钟的时间,最好的做法就是把符号表做成缓存,拿到堆栈直接取地址去读表,表里没有的再去查,查了后把结果映射关系等再进行缓存~ .... 之前看过字节大佬的直播分享好像就是这么干的

找到虚拟内存的起始地址 vmaddr 运算会用到 也就是加上偏移量就是 符号表中的相对位置

otool -l  DSYM/xxx/xxx二进制  | grep __TEXT -C 5

dwarfdump iOSTest.app.dSYM --lookup 0xxxxx  //vmaddr + 偏移 可以查到符号中的信息

找出.app/二进制和dsym文件的uuid进行比对 看是否一致,避免做无用功

dwarfdump --uuid Project.app/Project
dwarfdump --uuid Project.app.dSYM

atos -arch cpu架构 -o dSYM文件 -l 基地址  运行时崩溃地址=(基地址+偏移) -i  //-i是显示内联信息

示例

未符号化的样子

    3  CoreFoundation           0x254b5949 0x253aa000 + 1096008
    4  CoreFoundation           0x253e6b68 _CF_forwarding_prep_0 + 24
    5  SuperSDKTest             0x0010143b 0x000ef000 + 74808  //且看这一条

符号化后的样子

    3   CoreFoundation          0x254b5949 <redacted> + 712   //该类是缺少系统库符号 被系统优化了 实在需要解析需要找出对应库的符号表进行翻译
    4   CoreFoundation          0x253e6b68 _CF_forwarding_prep_0 + 24
    5   SuperSDKTest            0x0010143b -[ViewController didTriggerClick:] + 58

其中 0x0010143b 为函数崩溃时的地址 它的值会等于 ( 0x000ef000为函数加载的基地址 + 74808 为偏移量)

所以翻译代码可以这么写 两个地址 第一个是未偏移前的, 第二个是加上偏移后的也就是崩溃的那个地址

$ xcrun atos -o SuperSDKTest.app.dSYM/Contents/Resources/DWARF/SuperSDKTest -arch arm64 -l 0x000ef000 
0x0010143b
-[ViewController didTriggerClick:] (in SuperSDKTest) (ViewController.m:35)

附上获取堆栈代码

#include <execinfo.h>
#import <dlfcn.h>
#import <cxxabi.h>


//获取线程的堆栈
NSLog(@"[NSThread callStackSymbols] = %@",[NSThread callStackSymbols]);


- (NSArray *)backtrace {
    void *callStack[128];//堆栈方法数组
    int frames = backtrace(callStack, 128);//获取错误堆栈方法指针数组,返回数目
    char **strs = backtrace_symbols(callStack, frames);//符号化
    NSMutableArray *symbolsBackTrace = [NSMutableArray arrayWithCapacity:frames];
    unsigned long count = frames > 20? 20 : frames;//限制取20条
    for (int i = 0; i < count; i++) {
        if (i > 0) {
            //过滤当前这个方法的符号
            [symbolsBackTrace addObject:[NSString stringWithUTF8String:strs[i]]];
        }
    }
    free(strs);
    return symbolsBackTrace;
}


//通过Dl_info获取调用栈
- (NSArray<NSString *> *)symbolicateBacktrace {
    void *callStack[128];
    int frames = backtrace(callStack, sizeof(callStack)/sizeof(*callStack));
    NSMutableArray *symbols = [NSMutableArray arrayWithCapacity:frames];
    
    for (int i = 0; i < frames; i++) {
        @autoreleasepool {
            Dl_info info;
            if (dladdr(callStack[i], &info) == 0) {
                [symbols addObject:@"[Unknown]"];
                continue;
            }
            
            // 计算符号偏移量(考虑地址可能小于基址的情况)
            const uintptr_t address = (uintptr_t)callStack[i];
            const uintptr_t baseAddress = (uintptr_t)info.dli_saddr;
            const ptrdiff_t offset = address - baseAddress;
            
            // 解析符号名称
            char *demangled = NULL;
            const char *symbolName = info.dli_sname;
            if (symbolName) {
                demangled = abi::__cxa_demangle(symbolName, NULL, 0, NULL);
            }
            
            // 安全处理模块名称
            const char *fname = info.dli_fname ?: "";
            NSString *module = [[[NSString stringWithUTF8String:fname] lastPathComponent] stringByDeletingPathExtension];
            
            // 构建符号信息
            NSString *symbol = [NSString stringWithFormat:@"%-3d %-20@ 0x%016lx %-40s + %td",
                                i,
                                module,
                                (uintptr_t)info.dli_fbase,
                                (demangled ?: symbolName ?: "???"),
                                offset];
            [symbols addObject:symbol];
            
            if (demangled) free(demangled);
        }
    }
    return [symbols copy];
}

来自大厂们的精彩分享:

我看了大厂分享的文章,逼格都比较高,要图有图,要数据有数据的,就是有点不接地气,具体实操主要还是参考CoderStar大佬的 iOS 符号化浅析 - CoderStar 文章来吧

posted @ 2024-01-03 23:04  CoderWGB  阅读(237)  评论(0)    收藏  举报