网易视频云技术分享:UML调试Linux内核
概述
UML这里不是统一建模语言,而是UserMode Linux的偕媸蝾纱缩写,从字面上看,是在用户态运行linux内核,即将内核当作一个应用程序在跑,这样我们就可以用调试应用层程序的方法调试内核了,应用层的强大调试工具gdb就派上用场了。很多时候我们写内核代码,当遇到算法比较复杂但又不涉及底层结构的时候总是喜欢现在应用层实现并调试,然后在写到内核层。为什么,就是因为用户层调试比内核调试方便。但是UML的最大局限性就是不能调试硬件关联性强的代码,但是还是有很多方面可以应用的,比如调度算法、VFS等。用gdb像跟踪用户程序一样跟踪这样的代码,相信你一定非常感兴趣,那么让我们马上开始第一步:搭建一个UML测试环境。
安装下载编译内核代码
1.首先从网上下载你感兴趣的内核代码版本,比如我下载的版本是2.6.36.4。
2.编译内核:在真正进入编译之前(make linux ARCH=um之前),需要先进行内核配置,具体配置可参考下图所示:
注意ARCH=um是必不可少的,否则就不是编译UML平台的内核了。如果编译过正常平台下(如amd64, i386,ppc等)的内核的人会发现,这个配置列表和以往的有一些不同,这就是ARCH=um的作用,我们现在要配置的是一个要跑在应用层的内核。除了选上你需要的功能对应选项以外,还有一些选项是必要为UML选的:
构建运行环境
让uml的内核跑在一个独立出来的运行环境中,我们需要一块磁盘,并在这块磁盘上作一个文件系统,即根文件系统,再在上面作一个可运行的最小系统(因为要让系统可运行,需要的不仅仅是一个内核,还有一些相关的运行环境的支持)。这里可以自己制作带最小系统的根文件系统,也可以从网上直接下载一个现成的,刚开始的时候我采用了自己制作的方法,但是系统运行没有成功,我便从网上down了一个现成的,最终算是大功告成。我在这里分别给出两种办法,任各位自己挑选。
手动制作方法:
1. 首先创建一个设备用来作为文件系统的载体并格式化成想要的文件系统:mkdir disk dd if=/dev/zero of=disk/um-rootbs=1024K count=1000 mkfs.ext3disk/um-root
2. 挂载设备:创建目录挂载点目录并将上面已格式化的设备挂载mkdir -p mnt/ mount -o loop disk/um-rootmnt/
3. 构建最小化系统debootstrap squeeze mnt/ http://ftp.debian.org/debian(ubuntu上)
4. 等到一切就绪以后,系统运行所需的一切条件就已经具备了。
网上下载办法:(推荐)
上面我们介绍了自己手动制作根文件系统的办法,这种办法可能会让你对系统有更深入的理解,但是出错的可能性也更大,我在第一次尝试的时候就出错了,而且找不到出错的原因,让我很是郁闷,于是选择了这种方法。这种办法非常简单,只需要从网上下载适合你的root_fs即可。下载地址为:http://fs.devloop.org.uk/,比如我下载的就是DebianSqueeze。
运行UML
上面一切准备工作就绪以后,就可以让UML跑起来了。再次申明,让UML跑起来需要的两个条件:
1.编译好的内核;
2.制作好的根文件系统,在我自己的系统中,我将他们存储在不同的目录下,编译好的内核位于目录kernel/linux-2.6.36.4下,而制作好的根文件系统位于disk下,名为root_fs。
运行UML很简单,直接输入下面的命令即可:./kernel/linux-2.6.36.4/linux ubda=disk/root_fs mem=256m UML执行的结果是会弹出一个登陆对话框,提示你输入用户名和密码,网上下载的根文件系统,默认用户名是root,密码为空,如下图所示:
等你正确输入用户名和密码以后,展现在你面前的就是一个用户态的linux系统了,你可以完成和普通操作系统的所有功能。
使用UML调试内核
搞清楚了如何使用UML以后,利用UML调试内核也就变得易如反掌了,我们使用的工具还是强大的GDB。使用GDB加载编译好的内核,然后设置断点,用法与gdb调试普通应用程序无异。这里不妨给出我的gdb调试截图:
Q&A
在编译使用和调试UML的过程中,可能会遇到很多意想不到的麻烦,这部分我将自己遇到过的意外贴在这里,希望对初学者有所帮助,如果你有任何的补充,希望你能给出问题以及行得通的解决方案并留言,我会不断补充。
问题1:
解决办法:tell gdb toignore SIGSEGV:告诉gdb忽略SIGSEGV。在gdb命令框中输入:handle SIGSEGVnoprint nostop pass
问题2:Programreceived signal SIGTRAP, Trace/breakpoint trap. 0x08066a4c in get_signals () atarch/um/os-Linux/signal.c:284
解决办法:在gdb命令框中输入:handle SIGTRAPnostop noprint