搞过内核开发的人都知道,内核调试是个脑力活,也是个体力活,因为底层的内核开发和应用程序开发有着较大的差别。应用程序的开发在操作系统之上,有许多优 秀的IDE供我们选择,从而能够非常方便进行调试;而内核级的开发则不一样,操作系统的内核调试器除完成一般的调试功能外,还必须工作在内核中。在 Linux中,内核调试方法有多种,可以在内核中插入printk()函数来调试分析,可以使用/proc文件系统对内核进行分析,也可以使用kgdb进 行内核源代码级的调试。本文将介绍如何使用VirtualBox 3.0.12 + RHEL 5 + KGDB的方式调试Linux内核(在一台主机运行RHEL 5,用VirtualBox 3.0.12虚拟两个RHEL 5代替两台机器,并在两台虚拟机上配置KGDB来进行内核的调试)。
kgdb提供了一种使用gdb调试Linux内核的机制。使用kgdb调试内核需要准备两台机器,一台作为开发机(用来远程查看内核信息并调试内核),另一台作为目标机(跑有要调试的内核), 并通过串口将它们连接起来。在2.6.26以前的Linux内核中使用kgdb需要打上补丁,而在2.6.26及以后的内核里已经加入了对kgdb的支 持。当kgdb内核调试环境搭好后,目标机上运行的是打了kgdb补丁的Linux内核,而开发机上运行gdb,gdb通过串口与要调试的内核进行通信, 对目标机上的内核进行控制,从而实现远程对内核的调试。
首先从下 载for RHEL5的VirtualBox,测试的版本是VirtualBox 3.0.12。装上VirtualBox后,就可以虚拟出两个RHEL 5虚拟机来代替两台机器了。当然我们也可以使用VirtualBox的clone功能,如果第一台虚拟机的文件名为rhel1.vdi,可使用命令VBoxManage clonevdi rhel1.vdi rhel2.vdi命令迅速克隆出另一台虚拟机。我们将一台虚拟机用作目标机,另一台用作开发机。
我 们可以利用主机的命名管道来完成两台虚拟机间的通信。一台虚拟机在主机中创建命名管道并将其串口与管道相连,另外一台虚拟机也将自己的串口连接到主机的命 名管道上,这样就实现了两个虚拟机串口的连接。两台虚拟机都使用自己的COM1端口,主机的命名管道同为/tmp/vbox,在配置时由一台虚拟机创建, 另一台则不创建。我们可使用以下的方式来测试两虚拟机的串口是否连接成功:
(1)首先启动创建管道的虚拟机,再启动另一台虚拟机,然后使用命令stty ispeed 115200 ospeed 115200 -F /dev/ttyS0将各自COM1端口的输入输出波特率都设为115200。
(2)在其中一台虚拟机v1终端上执行cat /dev/ttyS0, 在另一台虚拟机v2上执行 echo ok > /dev/ttyS0, 这时如果虚拟机v1的终端接受到v2发来的ok消息,则说明两虚拟机的串口通信正常,连接成功。
由于作为目标机的虚拟机上跑的RHEL 5内核版本是2.6.18,可以使用kgdb for 2.6.18的patch对内核打补丁并重新编译来使用kgdb,点击此处下载2.6.18的kgdb补丁。 由于在2.6.26及以后的内核里已经加入了对kgdb的支持,我选择了2.6.31的内核进行重新编译。如果我们在主机RHEL 5下载了2.6.31的源代码,并希望共享给虚拟机中的RHEL 5(共享给目标机),这就涉及到VirtualBox硬盘资源共享,具体过程如下:
(1)设备->安装增强功能,然后再使用以下命令将增强功能的iso文件挂接:
mkdir /mnt/vboxadd
mount /dev/hdc /mnt/vboxadd
(2)根据自己的机器和OS类型选择相应的安装程序,x86的RHEL 5上的安装如下:
cd /mnt/vboxadd
./VBoxLinuxAdditions-x86.run (需要保证kernel-devel、gcc已经存在并更新,可使用yum install kernel-devel和yum install gcc安装并更新)
(3)安装后使用命令modprobe vboxvfs导入模块
设备->分配数据空间,选择要共享的文件夹,使用命令mount -t vboxsf home /mnt/home即可将名为home的数据空间挂载到/mnt/home下了。
资源共享成功后,接下来就可以重新编译内核2.6.31了:
(1)从下载2.6.31稳定版内核,使用命令tar xjvf linux-2.6.31.6.tar.bz2 -C /usr/src将内核代码解压到/usr/src目录下。
(2)make menuconfig进行配置:进入kernel hacking ,在保证Compile the kernel with debug info被勾上的同时,选中KGDB: kernel debugging with remote gdb,save配置信息。
(3)make bzImage
make modules
make modules_install
make install
由于要使用串口来调试内核,所以在grub的内核启动参数上要加上kgdbwait,它的作用是在系统内核启动时停下来等待调试。我们可使用 kgdb8250驱动来改变串口的参数,当内核启动参数为kgdb8250=0,115200时,0代表使用串口0(/dev /ttyS0),115200代表波特率是115200。
配置好grub后,重新启动虚拟机,进入grub界面后选择2.6.31,会发现kernel停住不动等待调试。这时切换到作为开发机的虚拟机上并进入到源码目录下,运行gdb ./vmlinux。gdb启动后,使用以下命令设置波特率和调试终端:
(gdb)set remotebaud 115200
(gdb)target remote /dev/ttyS0