Linux 内核问题调试手段

源代码定位方法

我们经常需要根据内核错误日志,在源代码中比较精确地定位到发生错误的那一行。一般而言,我们通过错误发生的地址来定位对应的源代码:(链接

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

参考材料:

内核早期启动过程打印

当前内核的启动日志默认是从 console 初始化完毕后开始的,因此不包括 console 初始化之前的早期(early)启动过程。该过程包含如 CPU 多核的使能、虚拟内存的建立,以及其他一些体系结构相关的初始化过程。如需调试这部分功能,可以通过添加以下内核启动参数,让内核打印早期启动过程的相关日志:

1console=ttyAMA0 earlycon earlyprintk

参考资料:

单独编译某个 .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
    

  1. 对该格式的解释:<偏移>/<长度>。第一个值是相对函数起始地址的偏移,第二个值是函数的长度。见参考材料。 ↩︎


Linux 内核问题调试手段——QEMU 专题
【C++ 小问答】5:对结构体成员字符数组的访问