最容易出现的问题是找不到arm-uclinux-gcc命令的错误,主要原因是PATH变量中没有 包含arm-uclinux-gcc命令所在目录。在arm-linux-gcc的缺省安装情况下,它的安装目录是/root/bin/arm-linux-tool/,使用以下命令将路径加到PATH环境变量中。
|
IV、根文件系统的制作
Linux内核在启动的时的最后操作之一是加载根文件系统。根文件系统中存放了嵌入式 系统使用的所有应用程序、库文件及其他一些需要用到的服务。出于文章篇幅的考虑,这里不打算介绍根文件系统的制作方法,读者可以查阅一些其他的相关资料。值得注意的是,由配置文件skyeye.conf指定了装载到内核中的根文件系统。
编译完μcLinux内核后,就可以在SkyEye中调试该ELF执行文件格式的内核了。前面已经说过利用SkyEye调试内核与使用gdb调试运用程序的方法相同。
需 要提醒读者的是,SkyEye的配置文件-skyeye.conf记录了模拟的硬件配置和模拟执行行为。该配置文件是SkyEye系统中一个及其重要的文 件,很多错误和异常情况的发生都和该文件有关。在安装配置SkyEye出错时,请首先检查该配置文件然后再进行其他的工作。此时,所有的准备工作已经完 成,就可以进行内核的调试工作了。
在SkyEye 中可以进行对Linux系统内核的全程调试。由于SkyEye目前主要支持基于ARM内核的CPU,因此一般而言需要使用交叉编译工具编译待调试的 Linux系统内核。另外,制作SkyEye中使用的内核编译、配置过程比较复杂、繁琐。不过,当调试过程结束后无需重新制作所要发布的内核。
SkyEye只是对系统硬件进行了一定程度上的模拟,所以在SkyEye与真实硬件环境相比较而言还是有一定的差距,这对一些与硬件紧密相关的调试可能会有一定的影响,例如驱动程序的调试。不过对于大部分软件的调试,SkyEye已经提供了精度足够的模拟了。
SkyEye的下一个目标是和eclipse结合,有了图形界面,能为调试和查看源码提供一些方便。
User-mode Linux(UML)简单说来就是在Linux内运行的Linux。该项目是使Linux内核成为一个运行在 Linux 系统之上单独的、用户空间的进程。UML并不是运行在某种新的硬件体系结构之上,而是运行在基于 Linux 系统调用接口所实现的虚拟机。正是由于UML是一个将Linux作为用户空间进程运行的特性,可以使用UML来进行操作系统内核的调试。有关UML的介绍 请查阅参考资料[10]、[12]。
UML 的安装需要一台运行Linux 2.2.15以上,或者2.3.22以上的I386机器。对于2.6.8及其以前版本的UML,采用两种形式发布:一种是以RPM包的形式发布,一种是以 源代码的形式提供UML的安装。按照UML的说明,以RPM形式提供的安装包比较陈旧且会有许多问题。以二进制形式发布的UML包并不包含所需要的调试信 息,这些代码在发布时已经做了程度不同的优化。所以,要想利用UML调试Linux系统内核,需要使用最新的UML patch代码和对应版本的Linux内核编译、安装UML。完成UML的补丁之后,会在arch目录下产生一个um目录,主要的UML代码都放在该目录 下。
从2.6.9版本之后(包含2.6.9版本的Linux),User-Mode Linux已经随Linux内核源代码树一起发布,它存放于arch/um目录下。
编译好UML的内核之后,直接使用gdb运行已经编译好的内核即可进行调试。
目 前,用户模式 Linux 虚拟机也存在一定的局限性。由于UML虚拟机是基于Linux系统调用接口的方式实现的虚拟机,所以用户模式内核不能访问主机系统上的硬件设备。因此, UML并不适合于调试那些处理实际硬件的驱动程序。不过,如果所编写的内核程序不是硬件驱动,例如Linux文件系统、协议栈等情况,使用UML作为调试 工具还是一个不错的选择。
为了方便调试和测试代码,内核提供了许多与内核调试相关的配置选项。这些选项大部分都在内核配置编辑器的内核开发(kernel hacking)菜单项中。在内核配置目录树菜单的其他地方也还有一些可配置的调试选项,下面将对他们作一定的介绍。
Page alloc debugging :CONFIG_DEBUG_PAGEALLOC:
不使用该选项时,释放的内存页将从内核地址空间中移出。使用该选项后,内核推迟移 出内存页的过程,因此能够发现内存泄漏的错误。
Debug memory allocations :CONFIG_DEBUG_SLAB:
该打开该选项时,在内核执行内存分配之前将执行多种类型检查,通过这些类型检查可 以发现诸如内核过量分配或者未初始化等错误。内核将会在每次分配内存前后时设置一些警戒值,如果这些值发生了变化那么内核就会知道内存已经被操作过并给出明确的提示,从而使各种隐晦的错误变得容易被跟踪。
Spinlock debugging :CONFIG_DEBUG_SPINLOCK:
打开此选项时,内核将能够发现spinlock未初始化及各种其他的错误,能用于排除一些死锁引起的错误。
Sleep-inside-spinlock checking:CONFIG_DEBUG_SPINLOCK_SLEEP:
打开该选项时,当spinlock的持有者要睡眠时会执行相应的检查。实际上即使调用者目前没有睡眠,而只是存在睡眠的可能性时也会给出提示。
Compile the kernel with debug info :CONFIG_DEBUG_INFO:
打开该选项时,编译出的内核将会包含全部的调试信息,使用gdb时需要这些调试信息。
Stack utilization instrumentation :CONFIG_DEBUG_STACK_USAGE:
该选项用于跟踪内核栈的溢出错误,一个内核栈溢出错误的明显的现象是产生oops错 误却没有列出系统的调用栈信息。该选项将使内核进行栈溢出检查,并使内核进行栈使用的统计。
Driver Core verbose debug messages:CONFIG_DEBUG_DRIVER:
该选项位于"Device drivers-> Generic Driver Options"下,打开该选项使得内核驱动核心产生大量的调试信息,并将他们记录到系统日志中。
Verbose SCSI error reporting (kernel size +=12K) :CONFIG_SCSI_CONSTANTS:
该选项位于"Device drivers/SCSI device support"下。当SCSI设备出错时内核将给出详细的出错信息。
Event debugging:CONFIG_INPUT_EVBUG:
打开该选项时,会将输入子系统的错误及所有事件都输出到系统日志中。该选项在产生了详细的输入报告的同时,也会导致一定的安全问题。
以上内核编译选项需要读者根据自己所进行的内核编程的实际情况,灵活选取。在使用以上介绍的三种源代码级的内核调试工具时,一般需要选取CONFIG_DEBUG_INFO选项,以使编译的内核包含调试信息。
上面介绍了一些调试Linux内核的方法,特别是详细介绍了三种源代码级的内核调试工具,以及搭建这些内核调试环境的方法,读者可以根据自己的情况从中作出选择。
调试工具(例如gdb)的运行都需要操作系统的支持,而此时内核由于一些错误的代码而不能正确执行对系统的管理功能,所以对内核的调试必须采取一些特殊的方法进行。以上介绍的三种源代码级的调试方法,可以归纳为以下两种策略:
I、为内核增加调试Stub,利用调试Stub进行远程调试,这种调试策略需要target及development机器才能完成调试任务。
II、将虚拟机技术与调试工具相结合,使Linux内核在虚拟机中运行从而利用调试器对内核进行调试。这种策略需要制作适合在虚拟机中运行的系统内核。
由不同的调试策略决定了进行调试时不同的工作原理,同时也形成了各种调试方法不同的软硬件需求和各自的特点。
另外,需要说明的是内核调试能力的掌握很大程度上取决于经验和对整个操作系统的深入理解。对系统内核的全面深入的理解,将能在很大程度上加快对Linux系统内核的开发和调试。
对系统内核的调试技术和方法绝不止上面介绍所涉及的内容,这里只是介绍了一些经常看到和听到方法。在Linux内核向前发展的同时,内核的调试技术也在不断的进步。希望以上介绍的一些方法能对读者开发和学习Linux有所帮助。
[1] http://oss.sgi.com/projects/kdb/
[2] http://www-128.ibm.com/developerworks/cn/linux/sdk/l-debug/index.html
[3] http://www-128.ibm.com/developerworks/cn/linux/l-kdbug/
[4] http://www-128.ibm.com/developerworks/cn/linux/l-kprobes.html
[5] http://kgdb.linsyssoft.com/downloads.htm
[7] http://adam.kaist.ac.kr/~hschoe/dow...ols-20040427.sh
[8] http://www.uclinux.org/pub/uClinux/dist/
[9] http://adam.kaist.ac.kr/~hschoe/dow...5-hsc2.patch.gz
[11] http://user-mode-linux.sourceforge.net/
[12] http://www-128.ibm.com/developerworks/cn/linux/l-skyeye/part1/
[13] http://www-128.ibm.com/developerworks/cn/views/linux/tutorials.jsp?cv_doc_id=84978
[1]Robert Love Linux kernel development机械工业出版社
[2]陈渝 源代码开发的嵌入式系统软件分析与实践 北京航空航天大学出版社
[3]Alessandro Rubini Linux device driver 2se Edition O'Reilly
[4]Jonathan Corbet Linux device driver 3rd Edition O'Reilly
[5]李善平 Linux内核源代码分析大全 机械工业出版社
李树雷,清华大学计算机系硕士研究生,主要从事操作系统与中间件的研究。通过lisl03@mails.tsinghua.edu.cn 可以跟他联系 | |
陈渝, 清华大学,通过 yuchen@tsinghua.edu.cn 可以和他联系。 | |