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
总结
完成如上的基础知识后,大概知道了此功能的作用、开启的条件和方法,以及是否开启的加载等,如果大家需要查看更详细的信息,可以自己去参考英文的原文文档。
本文介绍了 Linux 内核中的 DynamicDebug(dyndbg)功能,该功能允许用户动态地控制内核模块中的 debug 信息输出。文章详细阐述了 dyndbg 的开启方法、系统配置要求、控制文件使用及命令格式,并提供了实际操作示例。

被折叠的 条评论
为什么被折叠?



