Kernel之debug调试信息
Kernel之debug调试信息
背景
平时我们在调试内核或驱动的时候,需要打开或增加调试信息,最常见的比如dev_dbg()
、pr_debug()
等
以内核v5.15为例,我们先来看一下上面2个日志打印函数在内核里面的大致定义:
dev_dbg()
[include/linux/dev_printk.h
]#if defined(CONFIG_DYNAMIC_DEBUG) || \ (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE)) #define dev_dbg(dev, fmt, ...) \ dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__) #elif defined(DEBUG) #define dev_dbg(dev, fmt, ...) \ dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__) #else #define dev_dbg(dev, fmt, ...) \ ({ \ if (0) \ dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \ }) #endif
pr_debug()
[include/linux/printk.h
]
从上面的代码可以看出,默认情况下, 这些调试信息是不会打印的,如果需要输出,则要我们手动打开,主要有2种方式:/* If you are writing a driver, please use dev_dbg instead */ #if defined(CONFIG_DYNAMIC_DEBUG) || \ (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE)) #include <linux/dynamic_debug.h> /** * pr_debug - Print a debug-level message conditionally * @fmt: format string * @...: arguments for the format string * * This macro expands to dynamic_pr_debug() if CONFIG_DYNAMIC_DEBUG is * set. Otherwise, if DEBUG is defined, it's equivalent to a printk with * KERN_DEBUG loglevel. If DEBUG is not defined it does nothing. * * It uses pr_fmt() to generate the format string (dynamic_pr_debug() uses * pr_fmt() internally). */ #define pr_debug(fmt, ...) \ dynamic_pr_debug(fmt, ##__VA_ARGS__) #elif defined(DEBUG) #define pr_debug(fmt, ...) \ printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) #else #define pr_debug(fmt, ...) \ no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) #endif
- 动态调试(DYNAMIC DEBUG)
- 静态调试(DEBUG)
动态调试(DYNAMIC DEBUG)
确认内核是否已打开动态调试:
/proc/dynamic_debug/control
, 若存在,说明已打开打开内核动态调试,配置打开以下选项即可:
CONFIG_DYNAMIC_DEBUG=y # build catalog, enables CORE CONFIG_DYNAMIC_DEBUG_CORE=y # enable mechanics only, skip catalog
说明:
如果你不想全局使用动态调试(比如一些嵌入式系统),你可以只打开CONFIG_DYNAMIC_DEBUG_CORE
这个配置来支持基本的动态调试,
然后当任何模块需要动态调试时,只要在其Makefile
中添加ccflags := -DDYNAMIC_DEBUG_MODULE
就行主要支持的函数:
pr_debug() dev_dbg() print_hex_dump_debug() print_hex_dump_bytes()
如何使用:
可以控制文件、函数的打印日志方式一: 添加启动参数
在cmdline
中添加启动参数dyndbg="file drivers/usb/* +p"
能输出drviers/usb
下所有文件的debug日志;方式二: 动态开关
适用于调试非启动时的情况#切换su #mount -t debugfs none /sys/kernel/debug 这一步可省略 #打开 hub_event 函数的调试信息 echo -n 'func hub_event +p' > /sys/kernel/debug/dynamic_debug/control #关闭 echo -n 'func hub_event -p' > /sys/kernel/debug/dynamic_debug/control
静态调试(DEBUG)
在需要调试的驱动文件最开头定义DEBUG宏,如下面的例子:
#define DEBUG
#include <xxx.h>
...
但这个有个弊端,只能一个个源码文件添加DEBUG宏,如果同时有多个文件,可以通过C编译器选项来传递,即通过ccflags
传递DEBUG,在makefile中定义:ccflags += -DDEBUG
即可
提高日志等级
以上2种调试日志打印都需要提高日志等级,大于等于7即可
有以下几种方式:
- 动态修改,适用于调试非启动时的情况
echo 7 > /proc/sys/kernel/printk
- 修改内核配置,比较暴力
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
- 在cmdline添加启动参数:
loglevel=7
参考
内核官方文档
Documentation/admin-guide/dynamic-debug-howto.rst
(注:不同的内核版本可能文档名或路径不一样)- https://www.kernel.org/doc/html/v5.15/admin-guide/dynamic-debug-howto.html
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 DD'Notes!
评论