1. 为什么你需要Crash和ftrace这对“黄金搭档”?
搞Android内核开发或者系统底层优化的朋友,肯定都遇到过那种让人头皮发麻的瞬间:系统毫无征兆地重启了,或者某个关键服务突然卡死,logcat里只留下一堆似是而非的错误码,根本找不到根因。这时候,你需要的不是漫无目的地翻代码,而是一套能直接“透视”内核运行状态的“手术刀”。Crash和ftrace,就是我最常用的两把。
简单来说,Crash 是内核“死后验尸”的专家。当内核发生严重错误(比如空指针解引用、内存越界)导致崩溃(Kernel Panic)时,系统会通过kdump等机制保存下崩溃瞬间的完整内存镜像,也就是vmcore文件。Crash工具能加载这个“案发现场”的快照,让你像法医一样,检查崩溃时每一个进程的状态、内核栈、内存分配、寄存器值,精准定位是哪一行代码捅了娄子。
而 ftrace 则是内核“实时心电图”监测仪。它可以在系统运行时,以极低的性能开销,动态追踪内核函数的调用流程、耗时、中断开关情况、调度器决策等。当遇到性能抖动、死锁、响应延迟这类“慢性病”时,ftrace能帮你看到函数执行的来龙去脉,找到那个拖慢全场的“慢函数”或诡异的执行路径。
那么,为什么要把它们结合起来用呢?我举个真实的例子。有一次,我们的设备在播放高清视频时,会间歇性地发生系统重启。用Crash分析抓到的vmcore,发现崩溃点总是在一个音频驱动的中断处理函数里,提示是某个内核链表被破坏了。但Crash只能告诉你“尸体”的最终状态,无法还原“凶案”发生的过程:这个链表是谁、在什么时候、怎么被破坏的?这时候,我就需要ftrace出场了。我在复现问题前,先用ftrace设置好对相关内存操作函数(如kfree、kmalloc)和链表操作函数的追踪。等下次崩溃发生、Crash再次抓到现场后,我结合Crash分析出的可疑对象地址,去ftrace的海量追踪日志里,按时间线搜索对该地址的内存操作记录。果然,我发现另一个网络协议栈的线程,在错误的时机释放了这个本属于音频驱动的内存块。你看,Crash给了你“结果”(哪里坏了),ftrace还原了“过程”(怎么坏的),两者一结合,真相大白。
这套组合拳,特别适合处理那些随机复现、与并发竞态条件相关、或者涉及多个模块交互的复杂内核问题。如果你还在为一些玄学问题熬夜,强烈建议你花点时间掌握它。
2. 搭建你的内核调试“手术室”:环境与工具准备
工欲善其事,必先利其器。在开始联合调试之前,我们需要把“手术室”——也就是调试环境——搭建好。这里面的坑我踩过不少,总结下来,最关键的就是版本一致性。
2.1 获取并编译匹配的Crash工具
Crash工具是开源的,但你不能随便从软件仓库安装一个了事。你必须使用与你的目标内核版本相匹配的Crash源码进行编译。因为Crash内部需要解析内核数据结构,不同内核版本的数据结构布局可能有差异,版本不匹配会导致解析错误甚至工具崩溃。
第一步:获取Crash源码。 直接去其官方GitHub仓库(https://github.com/crash-utility/crash)克隆或下载稳定版本。我通常使用最新的稳定tag。
第二步:安装编译依赖。 Crash依赖ncurses(用于终端界面)和zlib(可能用于处理压缩的转储文件)。在Ubuntu/Debian上,一条命令搞定:
sudo apt-get update
sudo apt-get install libncurses5-dev zlib1g-dev
第三步:针对你的目标架构编译。 这是关键步骤。你需要确认你的Android设备内核是ARM 32位还是ARM 64位(现在基本都是64位了)。进入源码目录:
cd crash-8.0.1 # 以8.0.1版本为例
对于ARM 64位内核(AArch64):
make target=ARM64
编译成功后,当前目录会生成名为crash的可执行文件。为了节省空间,可以去掉调试符号:
strip -s crash
我建议将编译好的crash重命名为类似crash_arm64_v8.0.1的名字,并放入你的工具路径(如~/bin/),方便管理不同版本。
2.2 准备不可或缺的调试符号文件:vmlinux
这是新手最容易出错的地方!千万不能用你随手从/proc/kallsyms获取的符号,或者从系统镜像里提取的压缩内核映像(如Image.gz)。Crash分析必须使用编译内核时生成的、包含完整调试符号的 vmlinux 文件。
这



被折叠的 条评论
为什么被折叠?



