-- 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的好处:
参考: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 --