Linux設(shè)備驅(qū)動程序?qū)W習(2)-調(diào)試技術(shù) 今天進入《Linux設(shè)備驅(qū)動程序(第3版)》第四章調(diào)試技術(shù)的學習。 一、內(nèi)核中的調(diào)試支持 在前面已經(jīng)建議過:學習編寫驅(qū)動程序要構(gòu)建安裝自己的內(nèi)核(標準主線內(nèi)核)。最重要的原因之一是:內(nèi)核開發(fā)者已經(jīng)建立了多項用于調(diào)試的功能。但是由于這些功能會造成額外的輸出,并導(dǎo)致能下降,因此發(fā)行版廠商通常會禁止發(fā)行版內(nèi)核中的調(diào)試功能。 為了實現(xiàn)內(nèi)核調(diào)試,我在內(nèi)核配置上增加了幾項: Kernel hacking ---> Device Drivers ---> Generic Driver Options ---> General setup ---> 書上介紹的還有其他配置,有的我不需要,或是s3c2440不支持,菜單里看不見。 二、通過打印調(diào)試 (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 */ 未指定優(yōu)先級的默認級別定義在/kernel/printk.c中: #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ 當優(yōu)先級的值小于console_loglevel這個整數(shù)變量的值,信息才能顯示出來。而console_loglevel的初始值DEFAULT_CONSOLE_LOGLEVEL也定義在/kernel/printk.c中: #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ 而在運行是改變console_loglevel的程序(《Linux設(shè)備驅(qū)動程序(第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); } 最關(guān)鍵的“syslog(8,NULL,level)”語句我不理解,沒有找到相關(guān)資料。但是通過在ARMArray板上的實驗表明:程序是ok的!我用Hello world模塊做了實驗,現(xiàn)象和書上的一致。 [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 ! 四個數(shù)字的含義:當前的loglevel、默認loglevel、最小允許的loglevel、引導(dǎo)時的默認loglevel。 為了方便的打開和關(guān)閉調(diào)試信息,《Linux設(shè)備驅(qū)動程序(第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重復(fù)輸出過快而阻塞系統(tǒng),內(nèi)核使用以下函數(shù)跳過部分輸出: int printk_ratelimit(void); 典型的應(yīng)用如下: if (printk_ratelimit( )) printk(KERN_NOTICE "The printer is still on fire\n"); 可以通過修改/proc/sys/kernel/printk_ratelimit(重開信息前應(yīng)等待的秒數(shù))和/proc/sys/kernel/printk_ratelimit_burst(在速度限制前可接受的信息數(shù))來定制printk_ratelimit的行為。 Linux還提供了打印設(shè)備編號的宏(在中定義): int print_dev_t(char *buffer, dev_t dev); char *format_dev_t(char *buffer, dev_t dev); 兩個函數(shù)的唯一區(qū)別是:print_dev_t返回打印字符數(shù),format_dev_t返回緩沖區(qū)指針。注意緩沖區(qū)char *buffer的大小應(yīng)至少有20B。 三、通過查詢調(diào)試 多數(shù)情況中,獲取相關(guān)信息的最好方法是在需要的時候才去查詢系統(tǒng)信息,而不是持續(xù)不斷地產(chǎn)生數(shù)據(jù)。 使用/proc文件系統(tǒng) /proc文件系統(tǒng)是一種特殊的、由軟件創(chuàng)建的文件系統(tǒng),內(nèi)核使用他向外界導(dǎo)出信息。/proc下面的每個文件都綁定于一個內(nèi)核函數(shù),用戶讀取其中的文件時,該函數(shù)動態(tài)的生成文件的內(nèi)容。如以前用過的: [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 8Array i2c Array0 mtd 116 alsa 128 ptm 136 pts 180 usb 18Array usb_device 204 s3c2410_serial 252 scull 253 usb_endpoint 254 rtc Block devices: 1 ramdisk 256 rfd 7 loop 31 mtdblock Array3 nftl Array6 inftl 17Array mmc 使用/proc的模塊必須包含,而使用seq_file接口要包含。 具體的應(yīng)用方法看源程序、做實驗更有效果。 至于其他的調(diào)試方法,如gdb、LTT、SysRq等方法,在其他的書籍,如:《嵌入式Linux系統(tǒng)開發(fā)技術(shù)詳解-基于ARM》、《構(gòu)建嵌入式Linux系統(tǒng)》等,上講解的更為詳細,以后專門花時間研究。 四、源碼實驗 模塊程序鏈接: 模塊程序 模塊測試程序鏈接: 模塊測試程序 實驗現(xiàn)象: [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 [Array]=Array [10]=10 [11]=11 [12]=12 [13]=13 [14]=14 [15]=15 [16]=16 [17]=17 [18]=18 [1Array]=1Array [Tekkaman2440@SBC2440V4]#cd /proc/ [Tekkaman2440@SBC2440V4]#ls 1 751 cmdline kallsyms stat 2 76Array cpu kmsg swaps 3 77 cpuinfo loadavg sys 4 778 crypto locks sysrq-trigger 5 77Array devices meminfo sysvipc 5Array 78 diskstats misc timer_list 6 781 driver modules tty 60 783 execdomains mounts uptime 63 785 filesystems mtd version 65 7Array fs net vmstat 707 80 ide partitions yaffs 708 81Array interrupts scullmem zoneinfo 70Array 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 76Array cmdline irq stat 4 77 cpu kallsyms swaps 5 778 cpuinfo kmsg sys 5Array 77Array 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 7Array filesystems mounts version 708 80 fs mtd vmstat 70Array 824 ide net yaffs 710 asound interrupts partitions zoneinfo |
|