内核动态打印

Posted Li-Yongjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内核动态打印相关的知识,希望对你有一定的参考价值。

活动地址:CSDN21天学习挑战赛

简介

调试过内核或驱动的小伙伴肯定都用过 printk(),不过 printk() 有个不好的地方,使用打印等级控制其打印,一旦开了某个打印等级,内核和驱动中满足该等级的打印都会打印出来,影响阅读。那有没有什么办法,能够让程序员控制只打印某个文件、某个模块、某个函数的调试信息?有的,那就是内核动态打印。

pr_debug()、dev_dbg()

首先,在内核代码中使用如下函数添加打印信息:

pr_debug()
dev_dbg()
netdev_dbg()
...

net/core/dev.c

static int xmit_one(struct sk_buff *skb, struct net_device *dev,
		    struct netdev_queue *txq, bool more)

	unsigned int len;
	int rc;

	if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
		dev_queue_xmit_nit(skb, dev);

	len = skb->len;

	/* 动态打印 */
	netdev_dbg(dev, "[xmit_one] skb->len = %d\\n", skb->len);

	trace_net_dev_start_xmit(skb, dev);
	rc = netdev_start_xmit(skb, dev, txq, more);
	trace_net_dev_xmit(skb, rc, dev, len);

	return rc;

CONFIG_DYNAMIC_DEBUG

其次,要打开内核 CONFIG_DYNAMIC_DEBUG 编译选项

# CONFIG_DYNAMIC_DEBUG is not set
CONFIG_DYNAMIC_DEBUG=y

查看

编译、运行后,使用如下命令查看内核中都包含了哪些动态打印语句

root@ATK-IMX6U:~# cat /sys/kernel/debug/dynamic_debug/control | grep net/core/dev.c
net/core/dev.c:5095 [dev]__netdev_adjacent_dev_remove =_ "%s to %s ref_nr-- = %d\\012"
net/core/dev.c:5108 [dev]__netdev_adjacent_dev_remove =_ "dev_put for %s, because link removed from %s to %s\\012"
net/core/dev.c:6013 [dev]rollback_registered_many =_ "unregister_netdevice: device %s/%p never was registered\\012"
net/core/dev.c:5047 [dev]__netdev_adjacent_dev_insert =_ "dev_hold for %s, because of link added from %s to %s\\012"
net/core/dev.c:5227 [dev]__netdev_upper_dev_link =_ "Interlinking %s with %s, non-neighbour\\012"
net/core/dev.c:5237 [dev]__netdev_upper_dev_link =_ "linking %s's upper device %s with %s\\012"
net/core/dev.c:5246 [dev]__netdev_upper_dev_link =_ "linking %s's lower device %s with %s\\012"
net/core/dev.c:2651 [dev]xmit_one =_ "[xmit_one] skb->len = %d\\012"
net/core/dev.c:6105 [dev]netdev_fix_features =_ "Dropping TSO features since no SG feature.\\012"
net/core/dev.c:6111 [dev]netdev_fix_features =_ "Dropping TSO features since no CSUM feature.\\012"
net/core/dev.c:6118 [dev]netdev_fix_features =_ "Dropping TSO6 features since no CSUM feature.\\012"
net/core/dev.c:6128 [dev]netdev_fix_features =_ "Dropping NETIF_F_GSO since no SG feature.\\012"
net/core/dev.c:6139 [dev]netdev_fix_features =_ "Dropping NETIF_F_UFO since no checksum offload features.\\012"
net/core/dev.c:6145 [dev]netdev_fix_features =_ "Dropping NETIF_F_UFO since no NETIF_F_SG feature.\\012"
net/core/dev.c:6179 [dev]__netdev_update_features =_ "Features changed: %pNF -> %pNF\\012"

由于内核原生包含的动态打印语句就很多,所以我们过滤了一下,在 net/core/dev.c 看到了我们添加的打印语句,上面第 9 行。

生效

注意,刚才查看到的动态打印语句默认是不生效的,也就是说,使用 dmesg 是看不到这些打印输出的。要使用如下命令使其生效

root@ATK-IMX6U:~# echo -n "file net/core/dev.c +p" > /sys/kernel/debug/dynamic_debug/control
root@ATK-IMX6U:~# cat /sys/kernel/debug/dynamic_debug/control | grep core/dev.c
net/core/dev.c:5095 [dev]__netdev_adjacent_dev_remove =p "%s to %s ref_nr-- = %d\\012"
net/core/dev.c:5108 [dev]__netdev_adjacent_dev_remove =p "dev_put for %s, because link removed from %s to %s\\012"
net/core/dev.c:6013 [dev]rollback_registered_many =p "unregister_netdevice: device %s/%p never was registered\\012"
net/core/dev.c:5047 [dev]__netdev_adjacent_dev_insert =p "dev_hold for %s, because of link added from %s to %s\\012"
net/core/dev.c:5227 [dev]__netdev_upper_dev_link =p "Interlinking %s with %s, non-neighbour\\012"
net/core/dev.c:5237 [dev]__netdev_upper_dev_link =p "linking %s's upper device %s with %s\\012"
net/core/dev.c:5246 [dev]__netdev_upper_dev_link =p "linking %s's lower device %s with %s\\012"
net/core/dev.c:2650 [dev]xmit_one =p "[1xmit_one] skb->len = %d\\012"
net/core/dev.c:2651 [dev]xmit_one =p "[2xmit_one] skb->len = %d\\012"
net/core/dev.c:6105 [dev]netdev_fix_features =p "Dropping TSO features since no SG feature.\\012"
net/core/dev.c:6111 [dev]netdev_fix_features =p "Dropping TSO features since no CSUM feature.\\012"
net/core/dev.c:6118 [dev]netdev_fix_features =p "Dropping TSO6 features since no CSUM feature.\\012"
net/core/dev.c:6128 [dev]netdev_fix_features =p "Dropping NETIF_F_GSO since no SG feature.\\012"
net/core/dev.c:6139 [dev]netdev_fix_features =p "Dropping NETIF_F_UFO since no checksum offload features.\\012"
net/core/dev.c:6145 [dev]netdev_fix_features =p "Dropping NETIF_F_UFO since no NETIF_F_SG feature.\\012"
net/core/dev.c:6179 [dev]__netdev_update_features =p "Features changed: %pNF -> %pNF\\012"

可以看到从刚才的 =_ 变成了 =p,这样就生效了。

打印

root@ATK-IMX6U:~# dmesg | tail 
[  190.284130] fec 20b4000.ethernet eth0: [xmit_one] skb->len = 85
[  190.284277] fec 20b4000.ethernet eth0: [xmit_one] skb->len = 105
[  190.292195] lo: [xmit_one] skb->len = 85
[  193.254611] fec 20b4000.ethernet eth0: [xmit_one] skb->len = 42
[  206.169663] fec 20b4000.ethernet eth0: [xmit_one] skb->len = 94

可以看到刚才添加的打印语句 netdev_dbg(dev, "[xmit_one] skb->len = %d\\n", skb->len); 生效了。

以上是关于内核动态打印的主要内容,如果未能解决你的问题,请参考以下文章

如何在内核中打印当前时间?

带有 kmalloc 的 Linux 内核模块中的动态数组

今天打印文档记

module_param 用于动态开启/关闭 驱动打印信息

linux内核内存泄露检测

Linux内核的基础设施:工作队列等待队列