如何根据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

posted @ 2022-08-21 13:50  沐多  阅读(609)  评论(0编辑  收藏  举报