原文地址:Linux设备驱动程序学习(2)-调试技术 作者:tekkamanninja
为了实现内核调试,我在内核配置上增加了几项:
Kernel hacking --->
[*] Magic SysRq key
[*] Kernel debugging
[*] Debug slab memory allocations
[*] Spinlock and rw-lock debugging: basic checks
[*] Spinlock debugging: sleep-inside-spinlock checking
[*] Compile the kernel with debug info
[*] Magic SysRq key
Device Drivers --->
Generic Driver Options --->
[*] Driver Core verbose debug messages
General setup --->
[*] Configure standard kernel features (for small systems) --->
[*] Load all symbols for debugging/ksymoops
书上介绍的还有其他配置,有的我不需要,或是s3c2440不支持,菜单里看不见。
(1)printk
首先,printk有8个loglevel,定义在<linux/kernel.h>中:
#define KERN_EMERG "<0>" /* system is unusable */ |
未指定优先级的默认级别定义在/kernel/printk.c中:
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ |
当优先级的值小于console_loglevel这个整数变量的值,信息才能显示出来。而console_loglevel的初始值DEFAULT_CONSOLE_LOGLEVEL也定义在/kernel/printk.c中:
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ |
而在运行是改变console_loglevel的程序(《Linux设备驱动程序(第3版)》提供,仅支持glibc2.0之前的版本)如下:
#include <stdio.h> |
最关键的 “syslog(8,NULL,level)” 是控制内核printk的ring buffer的系统调用syslog的glibc函数接口。通过在ARM9板上的实验表明:程序是ok的!我用Hello world模块做了实验,现象和书上的一致。
[Tekkaman2440@SBC2440V4]#cd /tmp/ |
由于 glibc 2.0 中,由于词汇 syslog 使用过于广泛,这个函数的名称被修改成 klogctl,新代码请参阅我的另一篇博文:《内核日志及printk结构浅析》
[Tekkaman2440@SBC2440V4]#echo 1 > /proc/sys/kernel/printk [Tekkaman2440@SBC2440V4]#cat /proc/sys/kernel/printk [Tekkaman2440@SBC2440V4]#insmod hello.ko [Tekkaman2440@SBC2440V4]#insmod hello.ko |
四个数字的含义:当前的loglevel、默认loglevel、最小允许的loglevel、引导时的默认loglevel。
/* Macros to help debugging */ |
Makefile中要添加的语句:
# Comment/uncomment the following line to disable/enable debugging |
为了避免printk重复输出过快而阻塞系统,内核使用以下函数跳过部分输出:
int printk_ratelimit(void); |
典型的应用如下:
if (printk_ratelimit( )) |
可以通过修改/proc/sys/kernel/printk_ratelimit(重开信息前应等待的秒数)和/proc/sys/kernel/printk_ratelimit_burst(在速度限制前可接受的信息数)来定制printk_ratelimit的行为。
Linux还提供了打印设备编号的宏(在<linux/kdev_t.h>中定义):
int print_dev_t(char *buffer, dev_t dev); |
两个函数的唯一区别是:print_dev_t返回打印字符数,format_dev_t返回缓冲区指针。注意缓冲区char *buffer的大小应至少有20B。
三、通过查询调试
多数情况中,获取相关信息的最好方法是在需要的时候才去查询系统信息,而不是持续不断地产生数据。
使用/proc文件系统
/proc文件系统是一种特殊的、由软件创建的文件系统,内核使用他向外界导出信息。/proc下面的每个文件都绑定于一个内核函数,用户读取其中的文件时,该函数动态的生成文件的内容。如以前用过的:
[Tekkaman2440@SBC2440V4]#cat /proc/devices |
使用/proc的模块必须包含<linux/proc_fs.h>,而使用seq_file接口要包含<linux/seq_file.h>。
具体的应用方法看源程序、做实验更有效果。
至于其他的调试方法,如gdb、LTT、SysRq等方法,在其他的书籍,如:《嵌入式Linux系统开发技术详解-基于ARM》、《构建嵌入式Linux系统》等,上讲解的更为详细,以后专门花时间研究。
四、源码实验
模块程序链接: 模块程序
模块测试程序 链接 : 模块测试程序
实验现象:
[Tekkaman2440@SBC2440V4]#cd /lib/modules/ |