Linux内核pr_debug的应用及log级别控制原理简析

本文介绍了在Linux内核中使用pr_debug进行调试以及如何控制log级别。通过修改`/proc/sys/kernel/printk`的值,可以启用pr_debug宏的打印。在分析了一个gpio倒出失败的问题后,揭示了console_loglevel和printk级别控制的原理,包括log级别读写、pr_debug宏的条件判断以及vprintk函数的实现。
摘要由CSDN通过智能技术生成

调试环境------

CPUfreescale i.mx6

操作系统:Linux

内核版本号:3.0.35

 

最近在调试一个spi nor flash芯片的时候用到了gpio倒出的功能,就是可以在linux起来以后,通过串口倒出,并可以控制输入输出方向和高低电平的一种功能。配置好对应的pin后发现怎么都不能在/sys/class/gpio的目录下生成相应的接口目录,我要倒出的GPIO是gpio bank6的第11教,根据imx6平台gpio编号的计算方法IMX_GPIO_NR(6, 11),得到这个GPIO的编号是174(有兴趣的同学可以再imx6的平台代码上查看IMX_GPIO_NR这个宏的实现方法),通过如下命令实现倒出:

echo 174 > /sys/class/gpio/export

如果顺利倒出的话,会在gpio目录下生成gpio174这样的目录(/sys/class/gpio/gpio174),这个目录底下的接口可以对相应的gpio进行控制

 

执行了上述命令以后,没有生成gpio174这个目录,只好查看gpio_export函数实现,大概看了一下,整个倒出过程在关键步骤加了pr_debug调用,要用这个宏打印log可以通过DEBUG宏打开,具体打开方法如下:

1. 在内核根目录执行makemenuconfig

2. 进入内核配置图形界面以后查找

    

                并选中

3. 退回到根菜单进入

     

                              

                               选中

4. 重新编译uImage,烧录

5. 现在还不能实现pr_debug的打印,还要降低prink的打印级别:

   echo 8 > /proc/sys/kernel/printk

再执行gpio倒出,于是打印了下面的log:


在代码/drivers/gpio/gpiolib.c中找到了这个错误打印的位置

         if(status)

                   pr_debug("gpio_request:gpio-%d (%s) status %d\n",

                            gpio,label ? : "?", status);

在status不为0的情况下打印出来的,status是-16,经过查询-16是EBUSY的errorcode,EBUSY解释是:

#define     EBUSY                16     /* Device or resource busy */

这个gpio可能是被哪个设备占用了,所以导致倒出失败,查bsp代码还真是,注释调以后让我来用,再编译运行果然成功了,看来这个pr_debug还是挺有用的。

 

但是printk的级别控制引起了我的好奇心,为什么echo比7大的数值才能使用pr_debug呢?带着这个疑问开始看printk相关的内核代码:

先从printk的读写控制入手,看看proc文件系统中是怎么实现对printk节点进行读写的:

/fs/proc/proc_sysctl.c中proc_sys_init函数建立/proc/sys/目录,kernel目录是在/kernel/sysctl.c中structctl_table root_table中定义的,具体定义如下:

  static struct ctl_table root_table[] = {

         {

                   .procname        = "kernel",

                   .mode                = 0555,

                   .child                  = kern_table,

         },

kern_table包含了一对kernel目录下的子节点的定义,当然也包含了printk节点的定义:

     {

/* 节点名称 */

                   .procname        = "printk",

/* 控制台log等级 */

                   .data                  = &console_loglevel,

                   .maxlen             = 4*sizeof(int),

       /* 节点权限 */

                   .mode                = 0644,

       /* 操作节点的回调函数 */

                   .proc_handler  = proc_dointvec,

         },

其中有两个变量是比较重要的console_loglevel保存log级别,其中/kernel/printk.c源码中有如下定义:

#defineMINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */

#defineDEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */

 

intconsole_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 */

};

头文件/inclue/linux/printk.h对console_loglevel做了定义:

#defineconsole_loglevel (console_printk[0])

#definedefault_message_loglevel (console_printk[1])

#defineminimum_console_loglevel (console_printk[2])

#definedefault_console_loglevel (console_printk[3])

可以看到console_loglevel的值默认为7

 

proc_handler变量保存的函数指针proc_dointvec做了操作节点的工作,调用过程是 proc_dointvec->do_proc_dointvec->__do_proc_dointvec, 这个调用过程是多个kernel目录下的节点共用的,我以printk为例说明一下log级别是如何别改写的ÿ

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值