如何根据oops函数偏移快速定位源码?
如何根据函数偏移快速定位源码?
启用所有cpu的backtrace:
echo 1 > /proc/sys/kernel/oops_all_cpu_backtrace
在内核栈的输出中,你一定注意到每一个函数的输出格式都是函数名+偏移量,而这儿的偏移就是调用下一个函数的位置。那么,能不能根据函数名+偏移量直接定位源码的位置呢?
答案是肯定的。这是因为,不仅是我们这些 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
有时候faddr2line也不好用可用直接使用addr2line:
# 通用格式(本地编译内核,用系统 addr2line)
addr2line -e vmlinux -f -C __usb_hcd_giveback_urb+0x80
# 交叉编译内核(需用工具链中的 addr2line,如 ARM 架构)
# 示例:arm-linux-gnueabihf-addr2line -e vmlinux -f -C __usb_hcd_giveback_urb+0x80
GNU C预定义了一系列的宏,这些宏都是以双下划线开始的
查看内置宏的命令
gcc -dM -E - < /dev/null

浙公网安备 33010602011771号