Linux 内核调试之 printk

问题描述:最近这两天再调试 platform 驱动,程序老是有点小问题,得不到自己想要的结果,突然意识到内核调试重要性,重新整理一下 printk 基本用法。内核通过 printk() 输出相关信息,在调用 printk() 函数时必须要指定日志级别。

1、printk 日志等级

在 include/linux/kernel.h 中定义了如下几个日志级别

<span style="font-family:Microsoft YaHei;font-size:12px;">#define	KERN_EMERG	"<0>"	/* 系统崩溃 */
#define	KERN_ALERT	"<1>"	/* 必须紧急处理 */
#define	KERN_CRIT	"<2>"	/* 临界条件,严重的硬软件错误 */
#define	KERN_ERR	        "<3>"     /* 报告错误 */
#define	KERN_WARNING	"<4>"	/* 警告 */
#define	KERN_NOTICE	"<5>"	/* 普通但还是须注意 */
#define	KERN_INFO	"<6>"	/* 信息 */
#define	KERN_DEBUG	"<7>"	/* 调试信息 */</span>
这里也可以看出数值越小,其紧急和严重程度就越高。


接下来,我们来看 kernel/printk.c 文件:

/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
/* 因此,如果未在 printk() 中指定日志级别,系统将默认采用4级 */
/* We show everything that is MORE important than this.. */
#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */
DECLARE_WAIT_QUEUE_HEAD(log_wait);
int console_printk[4] = {
	DEFAULT_CONSOLE_LOGLEVEL,	/* console_loglevel */
	DEFAULT_MESSAGE_LOGLEVEL,	/* default_message_loglevel */
	MINIMUM_CONSOLE_LOGLEVEL,	/* minimum_console_loglevel */
	DEFAULT_CONSOLE_LOGLEVEL,	/* default_console_loglevel */
};
/* 这4组数字可以在/proc/sys/kernel/printk中更改 */

在 /proc/sys/kernel/printk 会显示4个数值(可由 echo 修改),分别表示
当前控制台日志级别;
未明确指定日志级别的默认消息日志级别;
最小(最高)允许设置的控制台日志级别;
引导时默认的日志级别;
当 printk()中指定的级别 (数值上)小于 当前控制台日志级别(前面说过,数值越小,严重性越高)时,printk 的信息(要有\n符)就会在控制台上显示。但无论当前控制台日志级别是何值,通过 dmesg 总能查看。

系统的日志记录工具有两种主要的:syslog 和 klog。
syslog 用于执行系统日志记录活动,系统进程显示为 syslogd。配置文件是/etc/syslog.conf。如果在配置文件中把kern.*这一行前的#号去掉,那么printk的信息也会输出到控制台。其守护进程是syslogd。syslogd 进程从一组日志源(如 /dev/log 和 /dev/klog )中读取数据,并按照 /etc/syslog.conf 中的说明处理这些日志消息。

2、printk 输出格式符

如果变量类型是 , 使用 prink 的格式说明符 : 
  int                                         %d 或者 %x( 注: %d 是十进制, %x 是十六进制 ) 
  unsigned int                          %u 或者 %x 
  long                                      %ld 或者 %lx 
  unsigned long                       %lu 或者 %lx 
  long long                              %lld 或者 %llx 
  unsigned long long               %llu 或者 %llx 
  size_t                                    %zu 或者 %zx 
  ssize_t                                   %zd 或者 %zx 
  原始指针值必须用 %p 输出。 
  u64,即(unsigned long log n),必须用 %llu 或者 %llx 输出,如: 
  printk("%llu", (unsigned long long)u64_var); 
  s64,即(long long),必须用 %lld 或者 %llx 输出,如 : 
  printk("%lld", (long long)s64_var); 


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。