printk接口

-- TOC --

Kernel编程没有runtime lib(glibc),也就没有printf。因此printk接口就成了虽然很传统,但是非常重要的一个debug手段。

<linux/kern_levels.h>中,定义了printk接口可以使用的level:

#define KERN_EMERG  KERN_SOH "0"    /* system is unusable */
#define KERN_ALERT  KERN_SOH "1"    /* action must be taken immediately */
#define KERN_CRIT   KERN_SOH "2"    /* critical conditions */
#define KERN_ERR    KERN_SOH "3"    /* error conditions */
#define KERN_WARNING    KERN_SOH "4"    /* warning conditions */
#define KERN_NOTICE KERN_SOH "5"    /* normal but significant condition */
#define KERN_INFO   KERN_SOH "6"    /* informational */
#define KERN_DEBUG  KERN_SOH "7"    /* debug-level messages */

#define KERN_DEFAULT    ""      /* the default kernel loglevel */

0到7,一共8级!

pintk的输出,可以用dmesg命令查看,也可以通过设置直接输出到tty(pts不行),或者单独开一个terminal窗口,执行sudo cat /proc/kmsg

dmesg将printk使用的ringbuffer全部打印出来,读取/proc/kmsg只会将最新的信息打印出来,同时受到log level的限制,并且一直等待新消息。后来使用发现,读取/proc/kmsg貌似会丢失信息,可能与ratelimit有关,还没搞清楚原因....另一个更友好的选项是cat /dev/kmsg

/proc/kmsg provides a root-only, read-only, consuming view of the kernel log buffer. It’s equivalent to calling syslog(2) with the SYSLOG_ACTION_READ action. /dev/kmsg provides access to the same kernel log buffer, but in an easier-to-use fashion. Reads are tracked per open, so multiple processes can read in parallel, and entries aren’t removed from the buffer as they are read. /dev/kmsg also provides write access to the log buffer, so it can be used to add entries to the log buffer.

查看pirntk运行时参数:

$ sudo cat /proc/sys/kernel/printk
4   4   1   7

这4个数字的含义为,参考kernel.printk

代码kernel/printk/printk.c中有如下定义:

int console_printk[4] = {
        CONSOLE_LOGLEVEL_DEFAULT,       /* console_loglevel */
        MESSAGE_LOGLEVEL_DEFAULT,       /* default_message_loglevel */
        CONSOLE_LOGLEVEL_MIN,           /* minimum_console_loglevel */
        CONSOLE_LOGLEVEL_DEFAULT,       /* default_console_loglevel */
};
EXPORT_SYMBOL_GPL(console_printk);

调试内核模块的时候,可以修改第1个参数,让log信息能够在TTY上打印出来:

# echo 8 > /proc/sys/kernel/printk

我发现这条命令sudo不行,只能由root用户来执行!还是用sudo sysctl简单一点。

或者,使用sysctl命令来修改running kernel的参数:

$ sudo sysctl -a | grep kernel.printk  # query
$ sudo sysctl kernel.printk  # query another way
$ sudo sysctl -w kernel.printk='3 4 5 6'  # write
# echo 3 4 5 6 > /proc/sys/kernel/printk  # the same with above

或者修改/etc/sysctl.conf文件,然后执行sysctl -p

Based on the loglevel, the kernel may print the message to the current console, be it a text-mode terminal, a serial port, or a parallel printer. If the priority is less than the integer variable console_loglevel , the message is delivered to the console one line at a time (nothing is sent unless a trailing newline is provided). If both klogd and syslogd are running on the system, kernel messages are appended to /var/log/messages (or otherwise treated depending on your syslogd configuration), independent of console_loglevel . If klogd is not running, the message won’t reach user space unless you read /proc/kmsg (which is often most easily done with the dmesg command). When using klogd, you should remember that it doesn’t save consecutive identical lines; it only saves the first such line and, at a later time, the number of repetitions it received.

kernel似乎并不推荐直接使用printk接口,而是使用pr_xxx或者dev_xxx接口,他们都是printk的封装。

pr_xxx这一组macro定义在<linux/printk.h>内,使用它们可以简化输入,比较特别的是pr_debug(或者pr_devel)这个macro,要打开CONFIG_DYNAMIC_DEBUG才有效。

使用pr_*接口来代替printk的好处:

  1. 减少输入,macro的名称就说明了level;
  2. 可以自定义使用pr_fmt这个macro,实现所有log的统一风格,比如在所有log前面增加KBUILD_MODNAME和__func__。

参考:Documentation/core-api/printk-basics.rst

针对不同的打印对象,printk也有很多打印参数:

If variable is of Type, use printk format specifier:
char %d or %x
unsigned char %u or %x
short int %d or %x
unsigned short int %u or %x
int %d or %x
unsigned int %u or %x
long %ld or %lx
unsigned long %lu or %lx
long long %lld or %llx
unsigned long long %llu or %llx
size_t %zu or %zx
ssize_t %zd or %zx
s8 %d or %x
u8 %u or %x
s16 %d or %x
u16 %u or %x
s32 %d or %x
u32 %u or %x
s64 %lld or %llx
u64 %llu or %llx

更多打印参数,请参考:Documentation/core-api/printk-formats.rst

本文链接:https://cs.pynote.net/sf/linux/dd/202112131/

-- EOF --

-- MORE --