Linux设备驱动程式学习(2)-调试技术

 今天进入《Linux设备驱动程式(第3版)》第四章调试技术的学习。
一、内核中的调试支持
在前面已建议过:学习编写驱动程式要构建安装自己的内核(标准主线内核)。最重要的原因之一是:内核研发者已建立了多项用于调试的功能。但是由于这些功能会造成额外的输出,并导致能下降,因此发行版厂商通常会禁止发行版内核中的调试功能。
为了实现内核调试,我在内核配置上增加了几项:
  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,定义在 中:
#define    KERN_EMERG    ""    /* system is unusable           */
#define    KERN_ALERT    ""   /* action must be taken immediately*/
#define    KERN_CRIT    ""    /* critical conditions    */
#define    KERN_ERR    ""    /* error conditions            */
#define    KERN_WARNING    ""    /* warning conditions   */
#define    KERN_NOTICE    ""    /* normal but significant condition */
#define    KERN_INFO    ""    /* informational            */
#define    KERN_DEBUG    ""    /* debug-level messages   */
未指定优先级的默认级别定义在/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版)》提供)如下:
#include stdio.h>
#include stdlib.h>
#include string.h>
#include errno.h>
#define __LIBRARY__ /* _syscall3 and friends are only available through this */
#include linux/unistd.h>
/* define the system call, to override the library function */
_syscall3(int, syslog, int, type, char *, bufp, int, len);
int main(int argc, char **argv)
{
    int level;
    if (argc==2) {
    level = atoi(argv[1]); /* the chosen console */
    } else {
        fprintf(stderr, "%s: need a single arg/n",argv[0]); exit(1);
    }
    if (syslog(8,NULL,level)  0) {
        fprintf(stderr,"%s: syslog(setlevel): %s/n",
                argv[0],strerror(errno));
        exit(1);
    }
    exit(0);
}
最关键的“syslog(8,NULL,level)”语句我不理解,没有找到相关资料。但是通过在ARM9板上的实验表明:程式是ok的!我用Hello world模块做了实验,现象和书上的一致。
[Tekkaman2440@SBC2440V4]#cd /tmp/
[Tekkaman2440@SBC2440V4]#./setlevel 1
[Tekkaman2440@SBC2440V4]#cd /lib/modules/
[Tekkaman2440@SBC2440V4]#insmod hello.ko
[Tekkaman2440@SBC2440V4]#rmmod hello
[Tekkaman2440@SBC2440V4]#cd /tmp/
[Tekkaman2440@SBC2440V4]#./setlevel 7
[Tekkaman2440@SBC2440V4]#cd /lib/modules/
[Tekkaman2440@SBC2440V4]#insmod hello.ko
Hello, Tekkaman Ninja !
[Tekkaman2440@SBC2440V4]#rmmod hello
Goodbye, Tekkaman Ninja !
Love Linux !Love ARM ! Love KeKe !
[Tekkaman2440@SBC2440V4]#
更有通过对/proc/sys/kernel/printk的访问来改变console_loglevel的值:
[Tekkaman2440@SBC2440V4]#echo 1 > /proc/sys/kernel/printk
[Tekkaman2440@SBC2440V4]#cat /proc/sys/kernel/printk
1       4       1       7
[Tekkaman2440@SBC2440V4]#insmod hello.ko
[Tekkaman2440@SBC2440V4]#rmmod hello
[Tekkaman2440@SBC2440V4]#echo 7 > /proc/sys/kernel/printk
[Tekkaman2440@SBC2440V4]#cat /proc/sys/kernel/printk7       4       1       7
[Tekkaman2440@SBC2440V4]#insmod hello.ko
Hello, Tekkaman Ninja !
[Tekkaman2440@SBC2440V4]#rmmod hello
Goodbye, Tekkaman Ninja !
Love Linux !Love ARM ! Love KeKe !
四个数字的含义:当前的loglevel、默认loglevel、最小允许的loglevel、引导时的默认loglevel。
为了方便的打开和关闭调试信息,《Linux设备驱动程式(第3版)》 提供以下源码:
/* Macros to help debugging */
#undef PDEBUG /* undef it, just in case */
#ifdef SCULL_DEBUG
# ifdef __KERNEL__
     /* This one if debugging is on, and kernel space */
# define PDEBUG(fmt, args...) printk( KERN_DEBUG "scull: " fmt, ## args)
# else     /* This one for user space */
# define PDEBUG(fmt, args...) fprintf(stderr, fmt, ## args)
# endif
#else
# define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif
#undef PDEBUGG
#define PDEBUGG(fmt, args...) /* nothing: it's a placeholder */
Makefile中要添加的语句:
# Comment/uncomment the following line to disable/enable debugging
DEBUG = y
# Add your debugging flag (or not) to CFLAGS
ifeq ($(DEBUG),y)
  DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines
else
  DEBFLAGS = -O2
endif
CFLAGS += $(DEBFLAGS)
为了避免printk重复输出过快而阻塞系统,内核使用以下函数跳过部分输出:
int printk_ratelimit(void);
典型的应用如下:
if (printk_ratelimit( ))
    printk(KERN_NOTICE "The printer is still on fire/n");
能够通过修改 /proc/sys/kernel/printk_ratelimit(重开信息前应等待的秒数)和 /proc/sys/kernel/printk_ratelimit_burst(在速度限制前可接受的信息数)来定制printk_ratelimit的行为。
Linux还提供了打印设备编号的宏(在 中定义):
int print_dev_t(char *buffer, dev_t dev);
char *format_dev_t(char *buffer, dev_t dev);
两个函数的唯一区别是:print_dev_t返回打印字符数,format_dev_t返回缓冲区指针。 注意缓冲区char *buffer的大小应至少有20B。
三、通过查询调试
多数情况中,获取相关信息的最好方法是在需要的时候才去查询系统信息,而不是持续不断地产生数据。
使用/proc文档系统
/proc文档系统是一种特别的、由软件创建的文档系统,内核使用他向外界导出信息。/proc下面的每个文档都绑定于一个内核函数,用户读取其中的文档时,该函数动态的生成文档的内容。如以前用过的:
[Tekkaman2440@SBC2440V4]#cat /proc/devices
Character devices:
  1 mem
  2 pty
  3 ttyp
  4 /dev/vc/0
  4 tty
  4 ttyS
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
10 misc
13 input
14 sound
81 video4linux
89 i2c
90 mtd
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
204 s3c2410_serial
252 scull
253 usb_endpoint
254 rtc
Block devices:
  1 ramdisk
256 rfd
  7 loop
31 mtdblock
93 nftl
96 inftl
179 mmc
使用/proc的模块必须包含,而使用seq_file接口要包含。
具体的应用方法看源程式、做实验更有效果。
至于其他的调试方法,如gdb、LTT、SysRq等方法,在其他的书籍,如:《嵌入式Linux系统研发技术详解-基于ARM》、《构建嵌入式Linux系统》等,上讲解的更为周详,以后专门花时间研究。
四、源码实验
模块程式链接:
模块程式
模块测试程式 链接
模块测试程式
实验现象:
[Tekkaman2440@SBC2440V4]#cd /lib/modules/
[Tekkaman2440@SBC2440V4]#insmod scull_debug.ko scull_nr_devs=1 scull_quantum=6 scull_qset=2
[Tekkaman2440@SBC2440V4]#cd /tmp/
[Tekkaman2440@SBC2440V4]#./scull_test
write code=6write code=6write code=6write code=2read code=6read code=6read code=6read code=2
[0]=0 [1]=1 [2]=2 [3]=3 [4]=4
[5]=5 [6]=6 [7]=7 [8]=8 [9]=9
[10]=10 [11]=11 [12]=12 [13]=13 [14]=14
[15]=15 [16]=16 [17]=17 [18]=18 [19]=19
[Tekkaman2440@SBC2440V4]#cd /proc/
[Tekkaman2440@SBC2440V4]#ls
1              751            cmdline        kallsyms       stat
2              769            cpu            kmsg           swaps
3              77             cpuinfo        loadavg        sys
4              778            crypto         locks          sysrq-trigger
5              779            devices        meminfo        sysvipc
59             78             diskstats      misc           timer_list
6              781            driver         modules        tty
60             783            execdomains    mounts         uptime
63             785            filesystems    mtd            version
65             79             fs             net            vmstat
707            80             ide            partitions     yaffs
708            819            interrupts     scullmem       zoneinfo
709            asound         iomem          scullseq
710            buddyinfo      ioports        self
742            bus            irq            slabinfo
[Tekkaman2440@SBC2440V4]#cat scullmem
Device 0: qset 2, q 6, sz 20
  item at c071ebd4, qset at c071ef7c
  item at c071ef14, qset at c071eee0
       0: c071eeac
       1: c071ee78
[Tekkaman2440@SBC2440V4]#cat scullseq
Device 0: qset 2, q 6, sz 20
  item at c071ebd4, qset at c071ef7c
  item at c071ef14, qset at c071eee0
       0: c071eeac
       1: c071ee78
[Tekkaman2440@SBC2440V4]#rmmod scull_debug
[Tekkaman2440@SBC2440V4]#ls
1              742            buddyinfo      iomem          self
2              751            bus            ioports        slabinfo
3              769            cmdline        irq            stat
4              77             cpu            kallsyms       swaps
5              778            cpuinfo        kmsg           sys
59             779            crypto         loadavg        sysrq-trigger
6              78             devices        locks          sysvipc
60             781            diskstats      meminfo        timer_list
63             783            driver         misc           tty
65             785            execdomains    modules        uptime
707            79             filesystems    mounts         version
708            80             fs             mtd            vmstat
709            824            ide            net            yaffs
710            asound         interrupts     partitions     zoneinfo


本文来自ChinaUnix博客,假如查看原文请点:http://blog.chinaunix.net/u1/59291/showart_461589.html

你可能感兴趣的:(Linux相关)