之前没有用过addr2line和gdb等内核调试工具定位问题代码,这里记录一下在将某个网络驱动从4.9内核移植到5.7内核时出现内核崩溃起不来的问题。

4.9内核到5.7内核改动了大量代码,在将驱动移植到5.7上编译到内核里时出现了很多错误,按照错误提示都解决之后(网络相关函数有变动),编译通过,系统起到一半内核崩溃,错误提示如下

[    2.547487] ------------[ cut here ]------------
[    2.547508] WARNING: CPU: 3 PID: 54 at ethtool_check_ops+0x18/0x38
[    2.552581] Modules linked in:
[    2.555601] CPU: 3 PID: 54 Comm: kworker/3:1 Tainted: GW  5.7.0-dirty #30
[    2.564398] Hardware name: Khadas VIM3 (DT)
[    2.568539] Workqueue: events deferred_probe_work_func
[    2.573627] pstate: 80000005 (Nzcv daif -PAN -UAO)
[    2.578370] pc : ethtool_check_ops+0x18/0x38
[    2.582596] lr : register_netdevice+0x60/0x440
[    2.586994] sp : ffff8000101d3760
[    2.590272] x29: ffff8000101d3760 x28: ffff0000f26a0000 
[    2.595533] x27: 0000000000010009 x26: 0000000000000000 
[    2.600794] x25: ffff80001256c000 x24: ffff0000f26a0a90 
[    2.606056] x23: ffff0000f26a0d80 x22: ffff800012483140 
[    2.611317] x21: ffff8000123e9000 x20: ffff8000123e9000 
[    2.616578] x19: ffff0000f26a0000 x18: ffffffffffffffff 
[    2.621839] x17: 0000000094d2982f x16: 00000000bbcb3772 
[    2.627101] x15: ffff8000123e9848 x14: ffff0000f26a1cd0 
[    2.632362] x13: ffff0000f26a1cba x12: 0000000000000000 
[    2.637623] x11: ffff8000101d37d0 x10: ffff8000101d37d0 
[    2.642884] x9 : 00000000ffffffd8 x8 : 0000000000000204 
[    2.648146] x7 : 0000000000000204 x6 : ffff800014b00000 
[    2.653407] x5 : 0000000000000000 x4 : ffff0000f3209c80 
[    2.658668] x3 : 0000000000000000 x2 : 0000000000000000 
[    2.663929] x1 : 0000000000000000 x0 : 0000000000000000 
[    2.669191] Call trace:

1.通过addr2line定位

首先找出函数地址,在源码编译目录下的System.map中可以找到,这里错误函数是ethtool_check_ops,在System.map文件找到地址是  

ffff800011ad4310 T ethtool_check_ops

加上0x18后地址就是FFFF800011AD4328。

我用的编译链是aarch64-linux-gnu-,所以addr2line前面也要加这个前缀,这里一开始有个问题,我使用addr2line的时候没有输出代码行号,只输出两个"??",后来查了资料才知道内核配置项CONFIG_DEBUG_INFO没有勾选,勾选之后重新编译,发现vmlinux这个文件变得很大了,有260M左右了,重新输入以下命令输出以下信息

linux#  aarch64-linux-gnu-addr2line -e vmlinux FFFF800011AD4328
net/ethtool/common.c:346

定位问题代码在net/ethtool/common.c的346行。

2.通过gdb定位

使用 aarch64-linux-gnu-gdb vmlinux 命令进入gdb调试行,输入以下命令

(gdb) b*(0xFFFF800011AD4328)
Breakpoint 1 at 0xffff800011ad4328: file net/ethtool/common.c, line 346

可以看到两种方法定位到的代码问题行是一样的,接下去查看这行代码


int ethtool_check_ops(const struct ethtool_ops *ops)
{
        if (WARN_ON(ops->set_coalesce && !ops->supported_coalesce_params))  //346
                return -EINVAL;
        /* NOTE: sufficiently insane drivers may swap ethtool_ops at runtime,
         * the fact that ops are checked at registration time does not
         * mean the ops attached to a netdev later on are sane.
         */
        return 0;
}

定位到网卡驱动的ethtool中的ops这里有问题,查看驱动中ethtool_ops这个结构体中缺少supported_coalesce_params,看了其他像intel网卡驱动中的ethtool.c文件中都有这个值,于是在该结构体中添加

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS,
#endif

编译完成后没有错误,系统启动正常内核不再崩溃。

如果觉得我的文章对你有用,请随意赞赏