源代码定位方法
我们经常需要根据内核错误日志,在源代码中比较精确地定位到发生错误的那一行。一般而言,我们通过错误发生的地址来定位对应的源代码:(链接 )
1# 注意:这里的 vmlinux 需要带有调试信息
2addr2line -f -e vmlinux <asm_addr>
然而在内核错误日志中,调用栈常以形如 bdi_register+0xec/0x150
的形式1展示函数调用地址,而 addr2line
无法解读这样的格式。此时我们可以使用 GDB 来解析该地址:
1# In `gdb vmlinux`, compiled with CONFIG_DEBUG_INFO=y
2
3list *(bdi_register+0xec)
4
5x/20i bdi_register+0xec
**注意:**对于交叉编译的内核(如在 x86 平台上编译出来的 arm64 内核),解析时应使用 gdb-multiarch
。
参考材料:
- StackOverflow: How to read, understand, analyze, and debug a Linux kernel panic?
- Newbedev: How to read, understand, analyze, and debug a Linux kernel panic?
内核早期启动过程打印
当前内核的启动日志默认是从 console 初始化完毕后开始的,因此不包括 console 初始化之前的早期(early)启动过程。该过程包含如 CPU 多核的使能、虚拟内存的建立,以及其他一些体系结构相关的初始化过程。如需调试这部分功能,可以通过添加以下内核启动参数,让内核打印早期启动过程的相关日志:
1console=ttyAMA0 earlycon earlyprintk
参考资料:
- Stefan’s blog: ARM Linux Kernel early startup code debugging
- Linux Kernel documentation: The kernel’s command-line parameters
单独编译某个 .c 文件
-
单独编译、预编译、汇编某个 .c 文件(详见
make help
):1make security/selinux/avc.o 2make security/selinux/avc.i 3make security/selinux/avc.s
-
查看编译某个 .c 文件的详细过程(链接 ):
1make CFLAGS_KERNEL="-v" security/selinux/avc.o 2make CFLAGS_MODULE="-v" drivers/gpu/drm/i915/display/intel_ddi.o
-
对该格式的解释:
<偏移>/<长度>
。第一个值是相对函数起始地址的偏移,第二个值是函数的长度。见参考材料。 ↩︎