Dynamic Debug [dyndbg] 概述

本文介绍了 Linux 内核中的 DynamicDebug(dyndbg)功能,该功能允许用户动态地控制内核模块中的 debug 信息输出。文章详细阐述了 dyndbg 的开启方法、系统配置要求、控制文件使用及命令格式,并提供了实际操作示例。

Dynamic Debug功能概述

dyndbg的英文版原文连接
发现内核的很多模块都支持dyndbg的功能,可以用于打印很多debug和error信息,但是之前都不知道如何开启。特别适合在跟踪内核或者驱动的一些功能。

输出结果

那么到底开启后的结果是什么样的?有什么作用?
输出实例:[c0] sprdfb: sprdfb: [sprdfb_ioctl]: FBIO_WAITFORVSYNC
源代码的是 pr_debug(KERN_INFO “sprdfb: [%s]: BIO_WAITFORVSYNC\n”, FUNCTION);

其中C0是用户名,sprdfb是模块,%s的是文件名,以及后续的fmt的输出,如果开启了dyndbg以后,就可以将对应的debug信息输出到dmesg中。

内核代码的接口

此功能对应内核代码里面的一些接口,例如

dev_dbg
pr_debug()
print_hex_dump_debug
print_hex_dump_bytes

例如内核代码里面的: usb-apic.c line 76,78


	error = acpi_bus_set_power(port_handle, state);
	if (!error)
		dev_dbg(&port_dev->dev, "acpi: power was set to %d\n", enable);
	else
		dev_dbg(&port_dev->dev, "acpi: power failed to be set\n");

如果开启了相关的开关,则可以在执行的时候看到对应的power的状态了。

系统条件

支持dyndbg功能,需要在Kernel里面的一些配置信息,例如
CONFIG_DYNAMIC_DEBUG(全局) ,写在kernel config中

CONFIG_DYNAMIC_DEBUG_CORE(模块的宏)配置,写在模块的makefile中

检查开启

如何检查当前内核是否已经开启了对应的配置选项,可以通过查看deubg/control文件是否存在

<debugfs>/dynamic_debug/control 
实际的目录应该是
/sys/kernel/debug/dynamic_debug/control

如果存在则表示已经开启,如果不存在则应该没有开启,同时如果没有开启,可能位于的地址是:/proc/dynamic_debug/control.

Control文件详解

其中每一个entry都类似与如下的格式

drivers/cpufreq/acpi-cpufreq.c:823 [acpi_cpufreq]acpi_cpufreq_cpu_init =_ "     %cP%d: %d MHz, %d mW, %d uS\012"

文件格式

格式解释如下:path/file_name:line_number [module]function_name flags fmt,对于上述例子则是acpi-cpufreq.c的823行的apci-cpufreq模块的cpu_init函数的一段格式输出,但是当前的模式为 “_”

标志符

不同的标志符有不同的含义,例如打出来的这个"_"表示当前并没有配置,那么内核可能就不会打印出来这个debug信息,可以通过enable(+),disable(-)和设置(=)来设置不同的标志位

p	enables the pr_debug() callsite.
f    Include the function name in the printed message
l    Include line number in the printed message
m    Include module name in the printed message
t    Include thread ID in messages not generated from interrupt context
_    No flags are set. (Or'd with others on input)


-    remove the given flags
+    add the given flags
=    set the flags to the given flags

我们修改一个flag的模块可以在文件里面看到具体的修改,举例如下,将特定的entry从"_“修改为"p”,具体的修改可以参考下面的具体的command格式

oot@axxiax86-64:~#  cat /sys/kernel/debug/dynamic_debug/control |grep usb-acpi.c
drivers/usb/core/usb-acpi.c:76 [usbcore]usb_acpi_set_power_state =_ "acpi: power was set to %d\012"
root@axxiax86-64:~# echo -n "format 'power was'  +p" > /sys/kernel/debug/dynamic_debug/control
root@axxiax86-64:~#  cat /sys/kernel/debug/dynamic_debug/control |grep usb-acpi.c
drivers/usb/core/usb-acpi.c:76 [usbcore]usb_acpi_set_power_state =p "acpi: power was set to %d\012"

Control具体操作

我们希望动态的对entry进行修改甚至是添加,那么就需要修改control文件来完成此操作。对于entry修改的特定格式为
echo -n command > /sys/kernel/debug/dynamic_debug/control
其中command的格式为

command ::= match-spec* flags-spec

其中match-spec是一个通配匹配符,会对符合条件的entry进行批量的修改,flag-spec见上述章节的描述,可以针对函数、文件、模块、行数和特定fromat的格式进行匹配。具体如下

match-spec ::= 'func' string |
               'file' string |
               'module' string |
               'format' string |
               'line' line-range

line-range ::= lineno |
               '-'lineno |
               lineno'-' |
               lineno'-'lineno

lineno ::= unsigned-int

举例如下

/*特定函数usb_acpi_set_power_state 的开启*/
echo -n "func usb_acpi_set_power_state +p" > /sys/kernel/debug/dynamic_debug/control
/*特定文件usb-acpi的开启*/
echo -n "file usb-acpi.c +p" > /sys/kernel/debug/dynamic_debug/control
/*特定文件usb-acpi的部分行的开启*/
echo -n "file usb-acpi.c:12-40 +p" > /sys/kernel/debug/dynamic_debug/control
echo -n "file usb-acpi.c:76 +p" > /sys/kernel/debug/dynamic_debug/control

/*特定模块usbcore的部分行的开启*/
echo -n "module usbcore +p" > /sys/kernel/debug/dynamic_debug/control

root@axxiax86-64:~#  cat /sys/kernel/debug/dynamic_debug/control |grep usb-acpi.c
drivers/usb/core/usb-acpi.c:78 [usbcore]usb_acpi_set_power_state =_ "acpi: power failed to be set\012"
drivers/usb/core/usb-acpi.c:76 [usbcore]usb_acpi_set_power_state =_ "acpi: power was set to %d\012"
root@axxiax86-64:~# echo -n "format 'power was'  +p" > /sys/kernel/debug/dynamic_debug/control
root@axxiax86-64:~#  cat /sys/kernel/debug/dynamic_debug/control |grep usb-acpi.c
drivers/usb/core/usb-acpi.c:78 [usbcore]usb_acpi_set_power_state =_ "acpi: power failed to be set\012"
drivers/usb/core/usb-acpi.c:76 [usbcore]usb_acpi_set_power_state =p "acpi: power was set to %d\012"

需要注意的是,如果内容比较多,可以通过一个命令包含多个operation,通过;隔开。或者使用文件的方式一次性写入。而且可以使用通配符, “*“表示通配”,”?”表示单次通配。

/* 多次修改,文件,*通配   */  
echo "func pnpacpi_get_resources +p; func pnp_assign_mem +p" > <debugfs>/dynamic_debug/control
cat query-batch-file > <debugfs>/dynamic_debug/control
echo "file drivers/usb/* +p" > <debugfs>/dynamic_debug/control

功能开启
功能上应该有几种开启方式,第一个是在启动command_line中添加,第二个是built-in的模块开启,第三个是在insmod模块的时候开启

boot args

开启dynmic模块的打印信息:dynamic_debug.verbose=3
开启特定模块 btrfs.dyndbg=“+p”,特定函数等就不一一举例了。

built-in

对于内置的内核模块,可以通过修改command_line,例如增加如下的命令格式dyndbg=“file ec.c +p”
dyndbg=“func pc87360_init_device +p; func pc87360_find +p”

模块加载

modprobe foo dyndbg==pmf,记载foo驱动,并且开启模式是pmf
dyndbg里面的内容和之前的讲解的格式一致即可

或者你可以在modprobe里面config文件里对应的option

options foo dyndbg=+pt
options foo dyndbg # defaults to +p

总结

完成如上的基础知识后,大概知道了此功能的作用、开启的条件和方法,以及是否开启的加载等,如果大家需要查看更详细的信息,可以自己去参考英文的原文文档。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值