本文讲述如何在VMware环境下搭建linux内核kgdb调试环境。
首先,linux内核的调试需要两台机器,被调试的系统称之为server,调试的系统称之为client(server和client通过串口相连)。
由于进行linux内核的源码级别的调试,需要内核的支持,因此需要在编译内核时加入对kgdb选项的支持,否则无法进行kgdb的调试,关于编译这一步我还会在后面详细讲述的。
而且,我们还需要明确一点,支持kgdb功能的内核需要在server上运行,而且client也需要有一份相同的内核。因此,我们只需要在其中一台机器上编译支持kgdb功能的内核,然后将相同的内核拷贝一份到另外一台机器上,两台机器上的内核必须一致。由于是在client上进行源码级别的调试,因此client上需要保留一份内核源码,而且编译好的内核符号链接中的路径信息应该与内核源码的路径一致。因此,我建议大家在client上编译内核,然后再将编译好的内核复制到server相应的路径下即可。而且,如果系统内核是2.6.26及以上版本的,可以只将/usr/src/linux/arch/x86/boot/bzImage和System.map文件拷贝到server相同的路径下即可。将bzImage和System.map拷贝到server的相同位置后,别忘了在server上执行相应的make install和make modules_install命令,以正确安装内核及其模块。
下面就如何编译带kgdb选项的linux内核做一个介绍。这一步是在执行make menuconfig命令的时候设置的。在make menuconfig的时候,在Files System选项中把ext3和ext2都编译进内核,也就是把前面的M变成*号。然后,在kernel Hacking中,选中如下选项:
选中Compile the kernel with frame pointers
选中KGDB: kernel debugging with remote gdb
并确认以下两项也是选中的(他们应该默认是选中的)
选中 kernel debugging
选中 Compile the kernel with debug info
对于其他选项,根据实际情况选择。
保存并退出。
然后,就接着执行:
make
make install
make modules
make modules_install
执行结束后,会在/boot目录下新添加vmlinuz-2.6.28.10和initrd.img-2.6.28.10这两个文件。
完成了上述步骤后,我们还只是得到了一个支持kgdb功能的内核,要让这个内核真正运行起来,还需要在/boot/grub/menu.lst文件中做一些修改和补充才行。
打开menu.lst文件,我们可以看到这样一个加载选项:
title Ubuntu 9.04, kernel 2.6.28-11-generic
uuid b836e381-ad06-402d-9066-62da2f588a27
kernel /boot/vmlinuz-2.6.28-11-generic root=UUID=b836e381-ad06-402d-9066-62da2f588a27 ro quiet splash
initrd /boot/initrd.img-2.6.28-11-generic
quiet
这就是系统原来的加载选项,为了能够在启动中选择加载支持kgdb模式的内核,我们可以在上面这个加载选项内容上做一些添加和修改即可,修改后的选项如下所示:
title Ubuntu 9.04, kernel 2.6.28.10(kgdb kernel)
uuid b836e381-ad06-402d-9066-62da2f588a27
kernel /boot/vmlinuz-2.6.28.10
root=UUID=b836e381-ad06-402d-9066-62da2f588a27 ro quiet splash text kgdboc=ttyS1,115200 kgdbwait
initrd /boot/initrd.img-2.6.28.10
quiet
首先,kernel部分的/boot/vmlinuz-2.6.28-11-generic替换成了/boot/vmlinuz-2.6.28.10,而这个vmlinuz-2.6.28.10恰恰是我们刚才新编译好的支持kgdb功能的新内核;initrd部分的
/boot/initrd.img-2.6.28-11-generic也换成了新生成的/boot/initrd.img-2.6.28.10。
其次,kgdboc=ttyS1,115200和 kgdbwait内容是新添加的。
kgdboc表示:kgdb over console,ttys1是串口设备名称,115200是串口通信的波特率。
如果不加kgdbwait则这样就可以调试内核模块,即可以动态加载内核模块然后进行调试,如果加了kgdbwait则可以直接调试linux系统的内核启动过程。这样设置表明server的内核在启动过程中会等待client的连接,连接完成后就直接进入调试状态。
下面我分别就两种方式展开讲述,第一种就是直接调试linux的内核,第二种是对可加载的内核模块进行调试。
第一种方式也就是加了kgdbwait的方式。我们在启动的菜单中选择了kgdb kernel后,server会出现如下信息:
Kgdb:Waiting for connection from remote gdb
这表明server正在等待client的连接。
此时,我们进入client系统,并在console中启动gdb:
cd /usr/src/linux (进入/usr/src/linux目录)
gdb vmlinux
(gdb) set remoteband 115200
(gdb) target remote /dev/ttyS1
这些步骤获得成功后,就进入了内核调试状态了,之后的操作就跟用gdb调试应用程序一样简单了。
在第二种方式中,server启动时并不会进入wait状态,而是直接启动完成。当server启动完成后,我们可以在server 的console终端中输入echo g > /proc/sysrq-trigger来使server进入内核调试状态。这样,server就会中断,进入调试状态,等待远端client 的gdb连接。
Server进入调试状态后,再转到client调用gdb,就可以调试了。如果要对server上的内核模块进行调试,需要在编译模块时加入调试信息,并且client和server的内核模块要处在同一个路径下面,而且client上需要有内核模块的源代码,同时client还要设置相应的符号文件的搜索路径等,完成这些步骤后,就可以通过gdb命令来调试了。
这样,我们就可以利用VMware的环境来对linux的内核和动态加载模块进行源码级别的调试了。