linxu 内核调试(3) - printk
- 了解printk
1.Description
Specify the initial console log level. Any log messages with levels less than this (that is, of higher priority) will be printed to the console, whereas any messages with levels equal to or greater than this will not be displayed.
The console log level can also be changed by the klogd program, or by writing the specified level to the /proc/sys/kernel/printk file.
The kernel log levels are:
-
0 (KERN_EMERG)
The system is unusable. -
1 (KERN_ALERT)
Actions that must be taken care of immediately. -
2 (KERN_CRIT)
Critical conditions. -
3 (KERN_ERR)
Non-critical error conditions. -
4 (KERN_WARNING)
Warning conditions that should be taken care of. -
5 (KERN_NOTICE)
Normal, but significant events. -
6 (KERN_INFO)
Informational messages that require no action. -
7 (KERN_DEBUG)
Kernel debugging messages, output by the kernel if the developer enabled debugging at compile time.
预定义的内核log等级:
// include/linux/kern_levels.h
#define KERN_SOH "\001" /* ASCII Start Of Header */
#define KERN_SOH_ASCII '\001'
#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 KERN_SOH "d" /* the default kernel loglevel */
The pr_* macros (with exception of pr_debug) are simple shorthand definitions in include/linux/printk.h for their respective printk call and should probably be used in newer drivers.
pr_devel and pr_debug are replaced with printk(KERN_DEBUG … if the kernel was compiled with DEBUG, otherwise replaced with an empty statement.
For drivers the pr_debug should not be used anymore (use dev_dbg instead).
If you don’t specify a log level in your message it defaults to MESSAGE_LOGLEVEL_DEFAULT (usually “4”=KERN_WARNING) which can be set via the CONFIG_MESSAGE_LOGLEVEL_DEFAULT kernel config option (make menuconfig-> Kernel Hacking -> Default message log level)
函数宏定义如下:
include/linux/printk.h:
297 #define pr_emerg(fmt, ...) \
298 printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
299 #define pr_alert(fmt, ...) \
300 printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
301 #define pr_crit(fmt, ...) \
302 printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
303 #define pr_err(fmt, ...) \
304 printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
305 #define pr_warning(fmt, ...) \
306 printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
307 #define pr_warn pr_warning
308 #define pr_notice(fmt, ...) \
309 printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
310 #define pr_info(fmt, ...) \
311 printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
2.log_buf_len Description
Set the size of the kernel’s internal log buffer. n must be a power of 2, if not, it will be rounded up to be a power of two. This value can also be changed by the CONFIG_LOG_BUF_SHIFT kernel configuration value.
Kernel log 默认大小是128KB,即17,修改该值,然后重新编译内核即可.
kernel/init/Kconfig
741 config LOG_BUF_SHIFT
742 int "Kernel log buffer size (16 => 64KB, 17 => 128KB)"
743 range 12 21
744 default 17
745 help
746 Select kernel log buffer size as a power of 2.
747 Examples:
748 17 => 128 KB
749 16 => 64 KB
750 15 => 32 KB
751 14 => 16 KB
752 13 => 8 KB
753 12 => 4 KB
- 编译后,查看android/out/target/product/msm8952_64/obj/KERNEL_OBJ/.config:
CONFIG_LOG_BUF_SHIFT=19
For example:
add log buf size from 128K to 2M
-CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_LOG_BUF_SHIFT=21
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=21
3.printk
3.1.printk的log等级控制
// linux/include/printk.h
/* printk's without a loglevel use this.. */
#define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT
/* We show everything that is MORE important than this.. */
#define CONSOLE_LOGLEVEL_DEFAULT 7
#define CONSOLE_LOGLEVEL_MIN 1
#define CONSOLE_LOGLEVEL_DEFAULT 7
-------------------------------------------------------------------------
// kernel/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 */
};
-------------------------------------------------------------------------
// linux/include/printk.h
extern int console_printk[];
#define console_loglevel (console_printk[0])
#define default_message_loglevel (console_printk[1])
#define minimum_console_loglevel (console_printk[2])
#define default_console_loglevel (console_printk[3])
-
console_loglevel
只有当printk打印消息的log优先级高于console_loglevel时,才能输出到终端上 -
default_message_loglevel
printk打印消息时默认的log等级 -
minimum_console_loglevel
console_loglevel可以被设置的最小值 -
default_console_loglevel
console_loglevel的缺省值
只有当printk打印信息时的loglevel小于console loglevel的值(即:优先级高于console loglevel),这些信息才会被打印到console上。
3.2.改变console loglevel方法
- 启动时Kernel boot option:loglevel=level
- 运行时Runtime: dmesg -n level
(注意:demsg -n level 改变的是console上的loglevel,dmesg命令仍然会打印出所有级别的系统信息。) - 运行时Runtime: echo $level > /proc/sys/kernel/printk
- 运行时Runtime:写程序使用syslog系统调用(可以man syslog)
3.3.通过procfs改变log等级 [案例参考]
1.查看当前printk的log等级
# cat /proc/sys/kernel/printk
# 7 4 1 7
“7 4 1 7” 分别对应console_loglevel、default_message_loglevel、minimum_c onsole_loglevel、default_console_loglevel,意味着只有优先级高于KERN_DEBUG(7)的打印消息才能输出到终端。
2.改变console_loglevel
# echo 8 4 1 7 > /proc/sys/kernel/printk
输入“8 4 1 7”改变console_loglevel值,使得所有的打印消息都能输出到终端
3.4.修改内核配置
lib/Kconfig.debug:
CONFIG_PRINTK_TIME=y
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=7
CONFIG_MESSAGE_LOGLEVEL_DEFAULT=4
38 config CONSOLE_LOGLEVEL_DEFAULT
39 int "Default console loglevel (1-15)"
40 range 1 15
41 default "7"
42 help
43 Default loglevel to determine what will be printed on the console.
44
45 Setting a default here is equivalent to passing in loglevel=<x> in
46 the kernel bootargs. loglevel=<x> continues to override whatever
47 value is specified here as well.
48
49 Note: This does not affect the log level of un-prefixed printk()
50 usage in the kernel. That is controlled by the MESSAGE_LOGLEVEL_DEFAULT
51 option.
-----------------------------------------------------------------------------------
64 config MESSAGE_LOGLEVEL_DEFAULT
65 int "Default message log level (1-7)"
66 range 1 7
67 default "4"
68 help
69 Default log level for printk statements with no specified priority.
70
71 This was hard-coded to KERN_WARNING since at least 2.6.10 but folks
72 that are auditing their logs closely may want to set it to a lower
73 priority.
74
75 Note: This does not affect what message level gets printed on the console
76 by default. To change that, use loglevel=<x> in the kernel bootargs,
77 or pick a different CONSOLE_LOGLEVEL_DEFAULT configuration value.
4.dmesg
dmesg是从kernel的ring buffer(环缓冲区)中读取信息的.
dmesg is used to examine or control the kernel ring buffer.The program helps users to print out their bootup messages. Instead of copying the messages by hand, the user need only: dmesg > dmesg.log
ring buffer:
在LINUX中,所有的系统信息(包括内核信息)都会传送到ring buffer中。而内核产生的信息由printk()打印出来。系统启动时所看到的信息都是由该函数打印到屏幕中。printk()打出的信息往往以 <0>…<2>… 这的数字表明消息的重要级别。高于一定的优先级别(当前的console loglevel)就会打印到console上,否则只会保留在系统的缓冲区中(ring buffer)。
4.1.Not all kernel messages are displayed by dmesg
The printk-times feature adds a number of bytes at the beginning of each printk message. The default kernel message buffer size may not be sufficient to hold all the messages with this additional overhead. You can increase the kernel message buffer size when compiling the kernel, by adjusting the “Kernel Log buffer size” (found on the “General Setup” menu). Note that you must also specify a larger buffer read size with “dmesg”, with the ‘-s’ option.
ex: dmesg -s 128000 >/tmp/bootup_printks
refer to
- kernel/printk/printk.c
- https://www.cnblogs.com/mylinux/p/4028787.html