如何根据oops函数偏移快速定位源码?
如何根据函数偏移快速定位源码?
在内核栈的输出中,你一定注意到每一个函数的输出格式都是函数名+偏移量
,而这儿的偏移就是调用下一个函数的位置。那么,能不能根据函数名+偏移量
直接定位源码的位置呢?
答案是肯定的。这是因为,不仅是我们这些 eBPF 学习者想要这种工具,内核开发者为了方便问题的排查,也经常需要根据内核栈,快速定位导致问题发生的代码位置。所以,Linux 内核维护了一个 faddr2line 脚本,根据函数名+偏移量
输出源码文件名和行号。你可以点击这里,把它下载到本地,然后执行下面的命令加上可执行权限:
$chmod +x faddr2line
注意内核编译配置需要启用CONFIG_DEBUG_INFO!!
在使用这个脚本之前,你还需要注意两个前提条件:
-
第一,带有调试信息的内核文件,一般名字为 vmlinux(注意,/boot 目录下面的 vmlinz 是压缩后的内核,不可以直接拿来使用)。
-
第二,系统中需要安装 awk、readelf、addr2line、size、nm 等命令。
对于第二个条件,这些命令都包含在 binutils 软件包中,只需要执行 apt 或者 dnf 命令安装即可。
而对第一个条件中的内核调试信息,各个主要的发行版也都提供了相应的软件仓库,你可以根据文档进行安装。比如,对于 Ubuntu 来说,你可以执行下面的命令安装调试信息:
codename=$(lsb_release -cs)
sudo tee /etc/apt/sources.list.d/ddebs.list << EOF
deb http://ddebs.ubuntu.com/ ${codename} main restricted universe multiverse
deb http://ddebs.ubuntu.com/ ${codename}-updates main restricted universe multiverse
EOF
sudo apt-get install -y ubuntu-dbgsym-keyring
sudo apt-get update
sudo apt-get install -y linux-image-$(uname -r)-dbgsym
就可以执行下面的命令,对刚才内核栈中的 __ip_local_out+219
进行定位:
$faddr2line /usr/lib/debug/boot/vmlinux-5.13.0-22-generic __ip_local_out+219
命令执行后,可以得到下面的输出:
__ip_local_out+219/0x150:
nf_hook at include/linux/netfilter.h:256
(inlined by) __ip_local_out at net/ipv4/ip_output.c:115
- 第二行表示
nf_hook
的定义位置在netfilter.h
的156行。 - 第三行表示
net/ipv4/ip_output.c
的 115行调用了kfree_skb
函数。但是,由于nf_hook
是一个内联函数,所以行号115实际上是内联函数 nf_hook 的调用位置。
make -C /lib/modules/$(uname -r)/build M=/lib/modules/$(uname -r)/kernel/drivers/my_module modules