iOS 符号化方法

介绍 iOS 堆栈符号化常用的方法。

符号化可以将上面的得到的代码内存地址转为可读的函数签名信息,包括函数名、文件名、行数等等,方便我们快速定位问题。

符号化常用方法

使用 backtrace_symbols_fd 方法进行运行时符号化

backtrace_symbols_fd 函数能够将从backtrace 中得到的原始堆栈信息进行符号化,并输出到控制台。

vm_address_t *stacks_2[128];
int depth = backtrace((void **)stacks_2, 128);
backtrace_symbols_fd((void **)stacks_2, depth, STDOUT_FILENO);     // STDOUT_FILENO 表示向屏幕输出
💡
注意,这里用的是 backtrace_symbols_fd 而不是 backtrace_symbols。backtrace_symbols 内部实现也有 alloc/malloc 相关的调用,在 malloc_logger 里面调用会陷入递归死循环

使用 atos 和 dSYM 对堆栈信息符号化

假设我们的崩溃日志系统收集到了下面这样的崩溃日志:

"0 libsystem_kernel.dylib 0x1b00df000 0x1b00e1d0c" "1 libsystem_kernel.dylib 0x1b00df000 0x1b00ffe70" "2 Keep 0x104584000 0x10704e864" "3 Keep 0x104584000 0x10704ac5c" "4 libsystem_malloc.dylib 0x192e77000 0x192e89b4c" "5 Keep 0x104584000 0x10a1d9c2c" "6 Keep 0x104584000 0x10a209ba4" "7 Keep 0x104584000 0x10a209e48" "8 Keep 0x104584000 0x108c877b8" "9 Keep 0x104584000 0x108c86c04" "10 Keep 0x104584000 0x108c6c8d0" "11 Keep 0x104584000 0x108c68938" "12 Keep 0x104584000 0x108c664d8" "13 Keep 0x104584000 0x108c66d5c" "14 Keep 0x104584000 0x108c66ee8" "15 libdispatch.dylib 0x183f33000 0x183f932b0" "16 libdispatch.dylib 0x183f33000 0x183f94298" "17 libdispatch.dylib 0x183f33000 0x183f3ca40" "18 libdispatch.dylib 0x183f33000 0x183f3d518" "19 libdispatch.dylib 0x183f33000 0x183f46fac" "20 libsystem_pthread.dylib 0x1cc79e000 0x1cc7a95bc" 

我们需要先拿到 App 的 dSYM 文件。之后在终端使用 xcrun atos 进行符号化。

xcrun atos -arch arm64 -o Keep.app.dSYM/Contents/Resources/DWARF/Keep -l 0x104584000
0x108c66ee8
# 第一行指令输入一次即可,随后可以逐次输入调用方法的内存地址

逐次输入各个调用方法的内存地址后,控制台会输出相应的解析结果。

符号化

动态库堆栈符号化

iOS 静态库是在程序编译的时候就进行了链接,拷贝到了 App 的可执行文件里。而动态库并不会在编译时置入 App 中,而是在 App 运行的时候去动态查找动态库并进行链接。

静态库代码发生崩溃时,堆栈信息也是和 App 放在一起的,内存加载地址一致,可以用 dSYM 解析。

但是动态库堆栈信息无法使用 dSYM 解析,需要利用动态库的 framework 进行解析。

堆栈信息:

"0 libdispatch.dylib 0x1210e4000 0x1210eabb8" "5 KPlayerCore 0x121f48000 0x121f61134" "6 KPlayerCore 0x121f48000 0x121f954a8" "7 KPlayerCore 0x121f48000 0x121f95634" "8 KPlayerCore 0x121f48000 0x121f74e5c" "9 libsystem_pthread.dylib 0x213dcc000 0x213dcd6b8"

找到工程使用的动态库 framework:

img.png

使用 atos 工具解析堆栈:

img.png

Read more

2025 年度总结

2025 年度总结

今天是 2026 年 1 月 1 号,又是新的一年。这个元旦没有安排出行任务,就在家里休息休息,或者出门溜达溜达。昨天休了一天全薪病假,做了体检,写了年终绩效总结,晚上干了一顿烤肉,没有时间写个人的年度总结。今天起早写写总结。 以下「今年」指 2025 年。 职业发展 算起来,我已经毕业工作四年多了。职业发展整体上还算稳定,没有碰到过糟心事,遇到的领导们也都对我关怀有加。今年又晋升一次,薪资迈上新的台阶。越往上升,越觉得离职业生涯的终点越近,逼迫自己赶紧找个靠谱稳定的副业,到 35 岁没人要的时候能养活自己。 最近两年 AI 大模型的崛起,提高了许多行业的可替代性。码农虽然不是首当其冲的,但危机感已经弥漫在各个论坛博客公共平台上面。没有人能准确预测到未来发展,但做好两手准备是很有必要的。码农不能再只低着头守着自己的键盘和屏幕,也要往外看,接触社会上的各种信息,打破信息壁垒。掌握的信息越多,出路就越多。

By Gray
联通 FTTR 宽带从路由器设置自动重启和穿墙功率

联通 FTTR 宽带从路由器设置自动重启和穿墙功率

几个月前把家里宽带换成了联通的千兆 FTTR 宽带,包含一主一从两个点位。配套光猫设备是华为的星光 F50 尊享版。 主点位放置在客厅茶几上,方便连接电视。从点位放在卧室门口,那里恰好有一个不耽误过路的小拐角可以放路由器。平常我们基本不在客厅活动,其他区域最近的 Wi-Fi 信号源是从路由器,因此我们大多数的设备连接的都是从路由器。从路由器的工作负荷很大。 从路由器个头小主路由器很多,散热不咋地。工作时间久了发热就容易发生数据包堵塞,丢包延迟高。需要把它电源拔掉重启。从宽带开通到现在,数据包堵塞影响网络的情况每个月会发生一次。有一次还影响了居家办公的视频会议。宽带维修师傅也给不出有效的法子,建议就是定期插拔从路由器电源。 从路由器和书房之间隔了两堵墙。信号到我书桌那个位置时,千兆网速已经衰减到只有 400-500Mbps 了,折损将近一半。叠加路由器发热的 debuff,书桌位置的网速最差的时候几乎和百兆宽带差不多。 我尝试过在光猫后台管理将路由器功率设置到「穿墙」模式,但没有任何作用。今天在后台研究了一番发现,原来我之前设置的功率是仅对主路由器生效,从路由器还是标准功率。要修

By Gray