1. printk
打印级别控制:/proc/sys/kernel/printk
printk_index:/sys/kernel/debug/printk/index/
2. pr_fmt和dev_fmt
在阅读Linux
内核或其他开源代码时,在文件的开始部分,通常能看到类似如下代码。但是代码中又没有看到使用的地方。
1#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2
3#include <...>
4#include <...>
其实pr_fmt
是通常和大名鼎鼎的printk
一起来合作实现其他宏,比较常见的就是pr_*()
系列宏,另外一些模块或驱动中也会利用pr_fmt
来输出日志信息。使用pr_fmt
可以在要输出的信息前再添加额外的信息。
如果在#include <linux/printk.h>
之前没有定义pr_fmt
,include/linux/printk.h
中会将pr_fmt(fmt)
定义为fmt
,也就是输出信息的原始格式。如果在#include <linux/printk.h>
之后定义pr_fmt
,编译时就会提示重复定义警告或错误。所以通常来说,对pr_fmt
的定义都是放到了文件的最前端。
1/// include/linux/printk.h
2/**
3 * pr_fmt - used by the pr_*() macros to generate the printk format string
4 * @fmt: format string passed from a pr_*() macro
5 *
6 * This macro can be used to generate a unified format string for pr_*()
7 * macros. A common use is to prefix all pr_*() messages in a file with a common
8 * string. For example, defining this at the top of a source file:
9 *
10 * #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 *
12 * would prefix all pr_info, pr_emerg... messages in the file with the module
13 * name.
14 */
15#ifndef pr_fmt
16#define pr_fmt(fmt) fmt
17#endif
dev_fmt
与pr_fmt
类似,也是用来定义打印信息的前缀。
1/// include/linux/dev_printk.h
2#ifndef dev_fmt
3#define dev_fmt(fmt) fmt
4#endif
3. 常见pr_*()接口
接口定义在include/linux/printk.h
。
三种类型的接口说明如下:
- pr_xxx:按照
pr_fmt(fmt)
指定的格式输出日志。 - pr_xxx_once:日志只输出一次。
- pr_xxx_ratelimited:通常来说终端是慢速设备,
pr_xxx_ratelimited
可以限制日志输出速率,避免信息过多导致CPU阻塞。
pr_xxx | pr_xxx_once | pr_xxx_ratelimited | loglevel | description |
---|---|---|---|---|
pr_emerg | pr_emerg_once | pr_emerg_ratelimited | KERN_EMERG | system is unusable |
pr_alert | pr_alert_once | pr_alert_ratelimited | KERN_ALERT | action must be taken immediately |
pr_crit | pr_crit_once | pr_crit_ratelimited | KERN_CRIT | critical conditions |
pr_err | pr_err_once | pr_err_ratelimited | KERN_ERR | error conditions |
pr_warn | pr_warn_once | pr_warn_ratelimited | KERN_WARNING | warning conditions |
pr_notice | pr_notice_once | pr_notice_ratelimited | KERN_NOTICE | normal but significant condition |
pr_info | pr_info_once | pr_info_ratelimited | KERN_INFO | informational |
pr_devel | pr_devel_once | pr_devel_ratelimited | KERN_DEBUG | debug-level message conditionally |
pr_debug | pr_debug_once | pr_debug_ratelimited | KERN_DEBUG/dynamic | (dynamic) debug-level message conditionally |
对于驱动代码,内核提供了dev_xxx
函数来方便打印调试信息,这些函数的实现都是调用printk
。include/linux/dev_printk.h
dev_xxx | dev_xxx_once | dev_xxx_ratelimited | loglevel | description |
---|---|---|---|---|
dev_emerg | dev_emerg_once | dev_emerg_ratelimited | KERN_EMERG | system is unusable |
dev_alert | dev_alert_once | dev_alert_ratelimited | KERN_ALERT | action must be taken immediately |
dev_crit | dev_crit_once | dev_crit_ratelimited | KERN_CRIT | critical conditions |
dev_err | dev_err_once | dev_err_ratelimited | KERN_ERR | error conditions |
dev_warn | dev_warn_once | dev_warn_ratelimited | KERN_WARNING | warning conditions |
dev_notice | dev_notice_once | dev_notice_ratelimited | KERN_NOTICE | normal but significant condition |
dev_info | dev_info_once | dev_info_ratelimited | KERN_INFO | informational |
dev_dbg | dev_dbg_once | dev_dbg_ratelimited | KERN_DEBUG/dynamic | (dynamic) debug-level message conditionally |
1/// include/linux/dev_printk.h
2#ifdef VERBOSE_DEBUG
3#define dev_vdbg dev_dbg
4#else
5#define dev_vdbg(dev, fmt, ...) \
6({ \
7 if (0) \
8 dev_printk(KERN_DEBUG, dev, dev_fmt(fmt), ##__VA_ARGS__); \
9})
10#endif
除此之外,还有netdev_xxx
和netif_xxx
系列接口,另外提供了netdev_vdbg
、netif_vdbg
和netif_cond_dbg
等宏来实现更精细化的输出。
3.1. pr_devel和pr_debugbug`
pr_*()
中比较特殊的是pr_devel
和pr_debug
,它们需要在特定条件下才会有实际作用。
pr_devel
在没有定义DEBUG
的情况下不做任何工作。pr_debug
在pr_devel
的基础上增加了动态调试部分,如果使能了动态调试,则实际为dynamic_pr_debug
,否则与pr_devel
效果一致。
1/// include/linux/printk.h
2/**
3 * pr_devel - Print a debug-level message conditionally
4 * @fmt: format string
5 * @...: arguments for the format string
6 *
7 * This macro expands to a printk with KERN_DEBUG loglevel if DEBUG is
8 * defined. Otherwise it does nothing.
9 *
10 * It uses pr_fmt() to generate the format string.
11 */
12#ifdef DEBUG
13#define pr_devel(fmt, ...) \
14 printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
15#else
16#define pr_devel(fmt, ...) \
17 no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
18#endif
1/* If you are writing a driver, please use dev_dbg instead */
2#if defined(CONFIG_DYNAMIC_DEBUG) || \
3 (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
4#include <linux/dynamic_debug.h>
5
6/**
7 * pr_debug - Print a debug-level message conditionally
8 * @fmt: format string
9 * @...: arguments for the format string
10 *
11 * This macro expands to dynamic_pr_debug() if CONFIG_DYNAMIC_DEBUG is
12 * set. Otherwise, if DEBUG is defined, it's equivalent to a printk with
13 * KERN_DEBUG loglevel. If DEBUG is not defined it does nothing.
14 *
15 * It uses pr_fmt() to generate the format string (dynamic_pr_debug() uses
16 * pr_fmt() internally).
17 */
18#define pr_debug(fmt, ...) \
19 dynamic_pr_debug(fmt, ##__VA_ARGS__)
20#elif defined(DEBUG)
21#define pr_debug(fmt, ...) \
22 printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
23#else
24#define pr_debug(fmt, ...) \
25 no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
26#endif
3.2. 关于no_printk
no_printk
表示信息不会被输出,但是为了在不同的配置下,内核都可以正常工作,需要让编译器对传入pr_xxx
的参数进行检查。
4. 常用pr_fmt定义
4.1. 打印模块名、函数名和行号
KBUILD_MODNAME
是编译时通过编译选项指定的,无需自己定义。
1#define pr_fmt(fmt) \
2 KBUILD_MODNAME ": [%s:%d] " fmt, __func__, __LINE__
4.2. 打印CPU号
使用raw_smp_processor_id
需要包含linux/smp.h
。
1#define pr_fmt(fmt) \
2 KBUILD_MODNAME ": <C%u> " fmt, raw_smp_processor_id()
4.3. 打印线程pid和线程名
线程的task_struct
使用current
宏来获取,需要包含linux/sched.h
。
1#define pr_fmt(fmt) \
2 "{t%d-%s} " fmt, current->pid, current->comm
4.4. 打印进程pid和进程名
进程的task_struct
可以通过current->group_leader
来获取。
1#define pr_fmt(fmt) \
2 "{p%d-%s} " fmt, \
3 current->group_leader->pid, current->group_leader->comm
4.5. 打印进程pid和线程pid
进程pid current->tgid
与current->group_leader->pid
相同。
1#define pr_fmt(fmt) \
2 "{p%d:t%d} " fmt, current->tgid, current->pid
4.6. 大杂烩
1#define pr_fmt(fmt) \
2 KBUILD_MODNAME ": <C%u>{p%d-%s}{t%d-%s}[%s:%d] " fmt, raw_smp_processor_id(), \
3 current->group_leader->pid, current->group_leader->comm, \
4 current->pid, current->comm, __func__, __LINE__