Linux内核调试利器——printk
2015-09-29 14:32
681 查看
在Linux开发环境下,打印log一直是最有效的调试方式,内核开发也不例外。
先看一下下面这段代码:
将其编译成hello.ko模块,反复insmod/rmmod之后发现,我在insmod的时候,它打印出”Goodbye, linux kernel”;而在rmmod时,它打印出”hello, linux kernel”,奇了个怪!
后来,在Linux Device Driver 里面看到这么一句话:
Based on the loglevel, the kernel may print the message to the current console, be it a text-mode terminal, a serial port, or a parallel printer. If the priority is less than the integer variable console_loglevel, the message is delivered to the console one line at a time (nothing is sent unless a trailing newline is provided).
原来是printk里面未在末尾添加换行符,导致不能及时flush到终端。修复后即正常。
下面是内核日志系统的基本框架和使用方法。
![](https://img-blog.csdn.net/20150928105709511)
这是一个典型的生产者-消费者模型。
printk将消息写入一个循环buffer,大小在编译内核时(CONFIG_LOG_BUF_SHIFT)指定。当buffer满时,会覆盖掉开始处的(最老的)的消息。ring buffer的设计可以使读写操作无需同步:读操作总是发生在队列头,写操作总是发生在队列尾。因此,可以在任何上下文中调用printk:可以在进程上下文中调用,也可以在中断上下文中调用,甚至在持有锁的情况下调用。
消费者通过syslog()系统调用或者直接读”/proc/kmsg”文件,即可从ring buffer读取数据,若无数据可读,则会阻塞。klogd进程采用的就是第二种方法,将内核消息读出来,并发送到syslogd进程。
此外,printk会判断消息级别和系统当前console_loglevel的值,如果消息级别高于console loglevel,会将消息同时输出到控制终端。
注意,上面的syslog()指的是系统调用,而非glibc(用户空间)的syslog()。这两个的作用是不同的:内核里的syslog作为消费者,从ring buffer读取数据(定义在linux-source/kernel/printk.c中的);用户空间的syslog()则是一个工具,可以向syslogd(或rsyslogd)进程写入数据,syslogd再将数据dispatch到不同的文件(根据/etc/syslog.conf)。默认情况下,从klogd发送过来的内核消息,会被写入到/var/log/messages文件。
参考资料
[1] Linux kernel development, Robert Love
[2] Advanced Programming in UNIX Environment, 3rd
[3] Linux Device Driver, 3rd
先看一下下面这段代码:
#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Wang Shuxiao"); static int hello_init(void) { printk(KERN_INFO "hello, linux kernel"); return 0; } static void hello_exit(void) { printk(KERN_INFO "Goodbye, linux kernel"); } module_init(hello_init); module_exit(hello_exit);
将其编译成hello.ko模块,反复insmod/rmmod之后发现,我在insmod的时候,它打印出”Goodbye, linux kernel”;而在rmmod时,它打印出”hello, linux kernel”,奇了个怪!
bookxiao@ubuntu-kernel:~$ tail -f /var/log/messages Sep 28 10:12:47 ubuntu-kernel kernel: [ 742.327807] Goodbye, linux kernel Sep 28 10:14:05 ubuntu-kernel kernel: [ 838.865803] hello, linux kernel
后来,在Linux Device Driver 里面看到这么一句话:
Based on the loglevel, the kernel may print the message to the current console, be it a text-mode terminal, a serial port, or a parallel printer. If the priority is less than the integer variable console_loglevel, the message is delivered to the console one line at a time (nothing is sent unless a trailing newline is provided).
原来是printk里面未在末尾添加换行符,导致不能及时flush到终端。修复后即正常。
下面是内核日志系统的基本框架和使用方法。
这是一个典型的生产者-消费者模型。
printk将消息写入一个循环buffer,大小在编译内核时(CONFIG_LOG_BUF_SHIFT)指定。当buffer满时,会覆盖掉开始处的(最老的)的消息。ring buffer的设计可以使读写操作无需同步:读操作总是发生在队列头,写操作总是发生在队列尾。因此,可以在任何上下文中调用printk:可以在进程上下文中调用,也可以在中断上下文中调用,甚至在持有锁的情况下调用。
消费者通过syslog()系统调用或者直接读”/proc/kmsg”文件,即可从ring buffer读取数据,若无数据可读,则会阻塞。klogd进程采用的就是第二种方法,将内核消息读出来,并发送到syslogd进程。
此外,printk会判断消息级别和系统当前console_loglevel的值,如果消息级别高于console loglevel,会将消息同时输出到控制终端。
注意,上面的syslog()指的是系统调用,而非glibc(用户空间)的syslog()。这两个的作用是不同的:内核里的syslog作为消费者,从ring buffer读取数据(定义在linux-source/kernel/printk.c中的);用户空间的syslog()则是一个工具,可以向syslogd(或rsyslogd)进程写入数据,syslogd再将数据dispatch到不同的文件(根据/etc/syslog.conf)。默认情况下,从klogd发送过来的内核消息,会被写入到/var/log/messages文件。
/* kernel/printk.c */ SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) { return do_syslog(type, buf, len, SYSLOG_FROM_CALL); }
参考资料
[1] Linux kernel development, Robert Love
[2] Advanced Programming in UNIX Environment, 3rd
[3] Linux Device Driver, 3rd
相关文章推荐
- Linux 自检和 SystemTap
- 如何成为一名专家级的开发人员
- .NET微信公众号开发之公众号消息处理
- 使用nodejs开发cli项目实例
- nodejs开发微博实例
- Egret引擎开发指南之创建项目
- Linux内核链表实现过程
- Android开发自学笔记(二):工程文件剖析
- Web 开发常用工具 大家自己查找下载
- 三种Web开发主流技术的性价评价
- 在B/S开发中经常用到的JavaScript技术第1/3页
- 深入Android开发FAQ的详解
- Android生存指南之:开发中的注意事项
- asp.net 开发的一些常用技巧
- windows开发记事本程序纪实(二)逻辑篇1
- C#开发纽曼USB来电小秘书客户端总结
- node.js调用C++开发的模块实例
- 在EditPlus中配置Perl开发编译环境
- .NET微信公众号开发之创建自定义菜单
- JavaScript插件化开发教程 (一)