欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

linxu 内核调试(3) - printk

程序员文章站 2024-01-31 10:27:10
...
  • 了解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 */

linxu 内核调试(3) - printk
  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