其实调试内核我最喜欢的还是print,因为它很灵活,这基本上是一个万能的东西,但是print总是需要自己去找对位置然后写上合适的print语句,有时还要为print一个东西而作很多准备工作。如果很复杂的时候可能要在很多点放置print,然后重新编译一遍,再跑一遍再看,如果不行还要再重新写,这就是print的局限性(但我还是乐此不疲)。由于print的缺点我们会去寻求其它的调试内核的手段,下面要说的就是其中一种调试手段——UML。
注意,UML这里不是统一建模语言,而是User Mode Linux的缩写,从字面上也可以理解出来,是在用户态运行linux内核,把内核当作一个应用程序在跑,这样我们就可以用调试应用层程序的方法调试内核了,应用层的强大调试工具gdb就派上用场了。很多时候我们写内核代码,当遇到算法比较复杂但又不涉及底层结构的时候总是喜欢现在应用层实现并调试,然后在写到内核层。为什么,就是因为用户层调试比内核调试方便。但是局限性也说了,就是不能涉及底层,所以UML的最大局限性就是不能调试硬件关联性强的代码,但是还有有很多方面可以应用的,比如调度算法、VFS等。用gdb像跟踪用户程序一样跟踪这样的代码,相信你一定非常感兴趣,那么让我们马上开始第一步——搭建一个UML测试环境。
我是在debian6.0系统上操作的,内核是2.6.32版本。我现在所在的目录是我的家目录下的VM目录下( ~/VM/ ),在这个目录下我创建如下几个目录:
mkdir -p UML/kernel/
mkdir -p UML/mnt/debian/
mkdir -p UML/disks/
我在kernel里放着我要编译成UML内核的linux内核源码。disks目录用于存放一个从/dev/zero中dd出来的制作的设备文件。mnt/debian/目录用于挂载上面的设备文件,这个目录除了挂载时使用以外基本没用。
-
第一步你需要安装编译内核的软件,什么gcc啊、make啊、tar啊该装的都给它装上,有时你可能还需要libstdc++,哦对了,还有容易遗忘但是编译前第一步就需要的libncurses-dev包(名字可能不完全一样)。
-
第二步你需要一个linux内核源码,找一个你想要调试的版本,下载下来解压。进入源码目录就行了。如果你不知道到哪里去下载linux代码,参考www.kernel.org。我把它下载下来放到了kernel目录下。
-
第三步,编译前配置内核(确定你已经进入linux内核的第一层目录)。执行
" make ARCH=um menuconfig "
命令你将会看到类似如下的画面:
注意ARCH=um是必不可少的,