考虑以下 Linux 内核转储堆栈跟踪;例如,您可以通过调用
panic("debugging a Linux kernel panic");
: 从内核源代码触发恐慌
[<001360ac>] (unwind_backtrace+0x0/0xf8) from [<00147b7c>] (warn_slowpath_common+0x50/0x60)
[<00147b7c>] (warn_slowpath_common+0x50/0x60) from [<00147c40>] (warn_slowpath_null+0x1c/0x24)
[<00147c40>] (warn_slowpath_null+0x1c/0x24) from [<0014de44>] (local_bh_enable_ip+0xa0/0xac)
[<0014de44>] (local_bh_enable_ip+0xa0/0xac) from [<0019594c>] (bdi_register+0xec/0x150)
unwind_backtrace+0x0/0xf8
中,+0x0/0xf8
代表什么?unwind_backtrace+0x0/0xf8
的C代码?这只是一个普通的回溯。这些函数以相反的顺序调用;列出的第一个函数被下一个函数调用。下面我添加了
[was called]
以进一步澄清:
(unwind_backtrace+0x0/0xf8) [was called] from (warn_slowpath_common+0x50/0x60)
(warn_slowpath_common+0x50/0x60) [was called] from (warn_slowpath_null+0x1c/0x24)
(warn_slowpath_null+0x1c/0x24) [was called] from (local_bh_enable_ip+0xa0/0xac)
(local_bh_enable_ip+0xa0/0xac) [was called] from (bdi_register+0xec/0x150)
bdi_register+0xec/0x150
是符号+偏移/长度。有关此内容的更多信息,请参阅了解内核 Oops 以及如何调试内核 oops。另外,还有关于“调试内核”的优秀教程。
注意:按照 Eugene 下面的建议,您可能想先尝试 addr2lineaddr2line -e vmlinux_with_debug_info 0019594c(+offset)
addr2line
。假设您拥有正确的目标工具链,您可以执行以下操作之一:
使用objdump
:
vmlinux
或
.ko
文件,然后反汇编目标文件:objdump -dS vmlinux > /tmp/kernel.s
/tmp/kernel.s
。使用文本编辑器,例如
vim
。去
unwind_backtrace+0x0/0xf8
,即搜索unwind_backtrace
+offset
的地址。最后,您在源代码中找到了有问题的部分。
gdb
:
gdb
。假设您的主机上有合适的工具链:
运行gdb <path-to-vmlinux>
list *(unwind_backtrace+0x10)
unwind_backtrace+0x0/0xf8
中,
代表什么? 第一个数字 (+0x0/0xf8
+0x0
) 是距函数开头的
偏移量(在本例中为
unwind_backtrace
)。第二个数字 (0xf8
) 是函数的总长度。有了这两条信息,如果您已经预感到错误发生的位置,这可能足以证实您的怀疑(您可以(大致)知道您在函数中进行了多远)。 要获取相应指令的确切源代码行(通常比预感更好),请使用
addr2line
或其他答案中的其他方法。