您的位置:首页 > 运维架构 > Linux

linux设备驱动学习笔记--内核调试方法之printk

2017-05-10 16:51 441 查看

1,printk类似于用户态的printf函数,但是比printf函数多了一个日志级别,内核中最常见的日志输出都是通过调用printk来实现的,其打印级别有8种可能的记录字串, 在头文件 <Linux/kernel.h> 里定义:

[html] view plain copy







KERN_EMERG 0用于紧急消息, 常常是那些崩溃前的消息.

KERN_ALERT 1需要立刻动作的情形.

KERN_CRIT 2严重情况, 常常与严重的硬件或者软件失效有关.

KERN_ERR 3用来报告错误情况; 设备驱动常常使用KERN_ERR 来报告硬件故障.

KERN_WARNING 4有问题的情况的警告, 这些情况自己不会引起系统的严重问题.

KERN_NOTICE 5正常情况, 但是仍然值得注意. 在这个级别一些安全相关的情况会报告.

KERN_INFO 6信息型消息. 在这个级别, 很多驱动在启动时打印它们发现的硬件的信息.

KERN_DEBUG 7用作调试消息.

2,信息格式化与printf一致,可以有以下几种用法:

[html] view plain copy







If variable is of Type, useprintk format specifier:

int %d or %x

unsignedint %u or %x

long %ld or %lx

unsignedlong %lu or %lx

longlong %lld or %llx

unsignedlong long %llu or %llx

size_t %zu or %zx

ssize_t %zd or %zx

pointer %p

3,内核有的代码执行很快,如果直接用printk打印会导致系统慢或者卡死现象,内核提供了一个日志流控函数printk_ratelimit,定义及使用如下:

[html] view plain copy







int printk_ratelimit(void);

[html] view plain copy







if (printk_ratelimit())

printk(KERN_INFO“testprint rate limit.\n”);

4,内核中为了方便打印设备编号提供了以下两个函数:

[html] view plain copy







int print_dev_t(char *buffer, dev_t dev);

char *format_dev_t(char *buffer, dev_t dev);

定义见内核代码(include\linux\kdev_t.h):

[html] view plain copy







#define print_dev_t(buffer, dev) \

sprintf((buffer),"%u:%u\n", MAJOR(dev), MINOR(dev))

#define format_dev_t(buffer, dev) \

({ \

sprintf(buffer,"%u:%u", MAJOR(dev), MINOR(dev)); \

buffer; \

})

5,在linux系统中通过文件/proc/sys/kernel/printk文件可以查看、修改内核的日志级别,此文件有四个数值,分别表示:当前记录级别, 适用没有明确记录级别的消息的缺省级别,允许的最小记录级别, 以及启动时缺省记录级别。例如

[plain] view plain copy







[root@bogon ~]# cat/proc/sys/kernel/printk

4 4 1 7

[root@bogon ~]#

6,不仅可以控制内核的日志级别,还可以通过下面两个文件来控制控制内核通过printk打印的速度。/proc/sys/kernel/{printk_ratelimit ,printk_ratelimit_burst},对应内核代码:

内核对/proc/sys下面的文件会统一导出,其定义在struct ctl_table kern_table[]中:

[html] view plain copy







{

.procname = "printk_ratelimit",

.data =&printk_ratelimit_state.interval, //表示printk_ratelimit文件对应interval值

.maxlen = sizeof(int),

.mode = 0644,

.proc_handler = proc_dointvec_jiffies,

},

{

.procname = "printk_ratelimit_burst",

.data =&printk_ratelimit_state.burst, //<span style="font-family: Arial, Helvetica, sans-serif;">表示printk_ratelimit文件对应burst值</span>

.maxlen = sizeof(int),

.mode = 0644,

.proc_handler = proc_dointvec,

},</span>

流控函数printk_ratelimit()的定义在include\linux\printk.h中,

[html] view plain copy







#define printk_ratelimit() __printk_ratelimit(__func__)

__printk_ratelimit()函数定义在include\linux\printk.c中

[html] view plain copy







int __printk_ratelimit(const char *func)

{

return ___ratelimit(&printk_ratelimit_state, func);

}

EXPORT_SYMBOL(__printk_ratelimit);

最终调用到函数__ratelimit,此函数在lib\ratelimit.c中实现,从实现中可以看出interval控制时间长度,burst控制打印的条数,即调用printk_ratelimit的结果是:在/proc/sys/kernel/printk_ratelimit对应的时间段内(单位秒),打印不超过/proc/sys/kernel/printk_ratelimit_burst对应的条数。

[html] view plain copy







int ___ratelimit(struct ratelimit_state*rs, const char *func)

{

unsignedlong flags;

intret;

if(!rs->interval) //从上面可以这个就对应/proc下面的print_ratelimit文件的值

return1;

/*

* If we contend on this state's lock thenalmost

* by definition we are too busy to print amessage,

* in addition to the one that will be printedby

* the entity that is holding the lock already:

*/

if(!raw_spin_trylock_irqsave(&rs->lock, flags))

return0;

if(!rs->begin)

rs->begin= jiffies;

if(time_is_before_jiffies(rs->begin + rs->interval)) {

if(rs->missed)

printk(KERN_WARNING"%s: %d callbacks suppressed\n",

func,rs->missed);

rs->begin = 0;

rs->printed= 0;

rs->missed = 0;

}

if(rs->burst && rs->burst > rs->printed) { //对应前面的proc文件中print_ratelimit_burst文件的值

rs->printed++;

ret= 1;

}else {

rs->missed++;

ret= 0;

}

raw_spin_unlock_irqrestore(&rs->lock,flags);

return ret;

}
http://blog.csdn.net/itsenlin/article/details/43205983
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: