本文将首先介绍 Linux 内核上的一些内核代码监视和错误跟踪技术,这些调试和跟踪方法因所要求的使用环境和使用方法而各有不同,然后重点介绍三种 Linux 内核的源代码级的调试方法。调试是软件开发过程中一个必不可少的环节,在 Linux 内核开发的过程中也不可避免地会面对如何调试内核的问题。但是,Linux 系统的开发者出于保证内核代码正确性的考虑,不愿意在 Linux 内核源代码树中加入一个调试器。他们认为内核中的调试器会误导开发者,从而引入不良的修正[1]。所以对 Linux 内核进行调试一直是个令内核程序员感到棘手的问题,调试工作的艰苦性是内核级的开发区别于用户级开发的一个显著特点。 尽管缺乏一种内置的调试内核的有效方法,但是 Linux 系统在内核发展的过程中也逐渐形成了一些监视内核代码和错误跟踪的技术。同时,许多的补丁程序应运而生,它们为标准内核附加了内核调试的支持。尽管这些补丁有些并不被 Linux 官方组织认可,但他们确实功能完善,十分强大。调试内核问题时,利用这些工具与方法跟踪内核执行情况,并查看其内存和数据结构将是非常有用的。 本文将首先介绍 Linux 内核上的一些内核代码监视和错误跟踪技术,这些调试和跟踪方法因所要求的使用环境和使用方法而各有不同,然后重点介绍三种 Linux 内核的源代码级的调试方法。 1. Linux 系统内核级软件的调试技术 PRintk() 是调试内核代码时最常用的一种技术。在内核代码中的特定位置加入printk() 调试调用,可以直接把所关心的信息打打印到屏幕上,从而可以观察程序的执行路径和所关心的变量、指针等信息。 Linux 内核调试器(Linux kernel debugger,kdb)是 Linux 内核的补丁,它提供了一种在系统能运行时对内核内存和数据结构进行检查的办法。Oops、KDB在文章把握 Linux 调试技术有具体介绍,大家可以参考。 Kprobes 提供了一个强行进入任何内核例程,并从中断处理器无干扰地收集信息的接口。使用 Kprobes 可以轻松地收集处理器寄存器和全局数据结构等调试信息,而无需对Linux内核频繁编译和启动,具体使用方法,请参考使用 Kprobes 调试内核。 以上介绍了进行Linux内核调试和跟踪时的常用技术和方法。当然,内核调试与跟踪的方法还不止以上提到的这些。这些调试技术的一个共同的特点在于,他们都不能提供源代码级的有效的内核调试手段,有些只能称之为错误跟踪技术,因此这些方法都只能提供有限的调试能力。下面将介绍三种实用的源代码级的内核调试方法。
stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
echo hello > /dev/ttyS0
cat /dev/ttyS0
[root@lisl tmp]# tar -jxvf linux-2.6.7.tar.bz2[root@lisl tmp]#tar -jxvf linux-2.6.7-kgdb-2.2.tar.tar[root@lisl tmp]#cd inux-2.6.7
[root@lisl tmp]#patch -p1 <../linux-2.6.7-kgdb-2.2/core-lite.patch
[root@lisl tmp]#make menUConfig
[*] KGDB: kernel debugging with remote gdb Method for KGDB communication (KGDB: On generic serial port (8250)) ---> [*] KGDB: Thread analysis [*] KGDB: Console messages through gdb[root@lisl tmp]#make
[root@lisl tmp]#scp arch/i386/boot/bzImage root@192.168.6.13:/boot/vmlinuz-2.6.7-kgdb[root@lisl tmp]#scp System.map root@192.168.6.13:/boot/System.map-2.6.7-kgdb
[root@lisl tmp]#mkinitrd /boot/initrd-2.6.7-kgdb 2.6.7[root@lisl tmp]#scp initrd-2.6.7-kgdb root@192.168.6.13:/boot/ initrd-2.6.7-kgdb
title 2.6.7 kgdbroot (hd0,0)kernel /boot/vmlinuz-2.6.7-kgdb ro root=/dev/hda1 kgdbwait kgdb8250=1,115200
image=/boot/vmlinuz-2.6.7-kgdblabel=kgdb read-only root=/dev/hda3append="gdb gdBTtyS=1 gdbbaud=115200"
gdbfile vmlinuxset remotebaud 115200target remote /dev/ttyS0
[root@lisl boot]#gdbstart -s 115200 -t /dev/ttyS0
[*]KGDB: kernel debugging with remote gdbMethod for KGDB communication (KGDB: On ethernet) ---> ( ) KGDB: On generic serial port (8250)(X) KGDB: On ethernet
title 2.6.7 kgdbroot (hd0,0)kernel /boot/vmlinuz-2.6.7-kgdb ro root=/dev/hda1 kgdbwait kgdboe=@192.168.5.13/,@192.168. 6.13/
[root@lisl tmp]# insmod -m hello.ko >modaddr
.this 00000060 c88d8000 2**2.text 00000035 c88d8060 2**2.rodata 00000069 c88d80a0 2**5…….data 00000000 c88d833c 2**2.bss 00000000 c88d833c 2**2……
(gdb) Add-symbol-file hello.o 0xc88d8060 -s .data 0xc88d80a0 -s .rodata 0xc88d80a0 -s .bss 0x c88d833c
…… …… if (mod->init != NULL) ret = mod->init();…… ……
……int bss_var;static int hello_init(void){printk(KERN_ALERT "Text location .text(Code Segment):%p/n",hello_init);static int data_var=0;printk(KERN_ALERT "Data Location .data(Data Segment):%p/n",&data_var);printk(KERN_ALERT "BSS Location: .bss(BSS Segment):%p/n",&bss_var);……}Module_init(hello_init);
[root@lisl tmp]#chmod +x arm-uclinux-tools-base-gcc3.4.0-20040713.sh[root@lisl tmp]#./arm-uclinux-tools-base-gcc3.4.0-20040713.sh
[root@lisl tmp]# tar -jxvf uClinux-dist-20041215.tar.bz2[root@lisl uClinux-dist]# tar -jxvf linux-2.6.9.tar.bz2[root@lisl uClinux-dist]# gzip -dc linux-2.6.9-hsc0.patch.gz patch -p0
[root@lisl uClinux-dist]# gunzip linux-2.6.9-hsc0.patch.gz [root@lisl uClinux-dist]patch -p0 < linux-2.6.9-hsc0.patch
[root@lisl uClinux-dist]# rm -rf linux-2.6.x/[root@lisl uClinux-dist]# mv linux-2.6.9 linux-2.6.x
[root@lisl uClinux-dist]# cd linux-2.6.x[root@lisl linux-2.6.x]#make ARCH=armnommu CROSS_COMPILE=arm-uclinux- atmel_deconfig
[root@lisl linux-2.6.x]#make ARCH=armnommu CROSS_COMPILE=arm-uclinux-oldconfig
[root@lisl linux-2.6.x]# make ARCH=armnommu CROSS_COMPILE=arm-uclinux- v=1
CFLAGS += -g
EXPort PATH=$PATH:/root/bin/arm-linux-tool/bin
新闻热点
疑难解答