Linux 系统内核的调试_02

来源:互联网 发布:php 处理图片缩略图 编辑:程序博客网 时间:2024/06/14 19:42

2.4 kgdb的一些特点和不足

使 用kgdb作为内核调试环境最大的不足在于对kgdb硬件环境的要求较高,必须使用两台计算机分别作为target和development机。尽管使用 虚拟机的方法可以只用一台PC即能搭建调试环境,但是对系统其他方面的性能也提出了一定的要求,同时也增加了搭建调试环境时复杂程度。另外,kgdb内核 的编译、配置也比较复杂,需要一定的技巧,笔者当时做的时候也是费了很多周折。当调试过程结束后时,还需要重新制作所要发布的内核。使用kgdb并不能进 行全程调试,也就是说kgdb并不能用于调试系统一开始的初始化引导过程。

不过,kgdb是一个不错的内核调试工具,使用它可以进行对内核的全面调试,甚至可以调试内核的中断处理程序。如果在一些图形化的开发工具的帮助下,对内核的调试将更方便。




 回页首 

3. 使用SkyEye构建Linux内核调试环境

SkyEye 是一个开源软件项目(OPenSource Software),SkyEye项目的目标是在通用的Linux和Windows平台上模拟常见的嵌入式计算机系统。SkyEye实现了一个指令级的硬 件模拟平台,可以模拟多种嵌入式开发板,支持多种CPU指令集。SkyEye 的核心是 GNU 的 gdb 项目,它把gdb和 ARM Simulator很好地结合在了一起。加入ARMulator 的功能之后,它就可以来仿真嵌入式开发板,在它上面不仅可以调试硬件驱动,还可以调试操作系统。Skyeye项目目前已经在嵌入式系统开发领域得到了很大 的推广。

3.1 SkyEye的安装和μcLinux内核编译

3.1.1 SkyEye的安装

SkyEye 的安装不是本文要介绍的重点,目前已经有大量的资料对此进行了介绍。有关SkyEye的安装与使用的内容请查阅参考资料[11]。由于skyeye面目主 要用于嵌入式系统领域,所以在skyeye上经常使用的是μcLinux系统,当然使用Linux作为skyeye上运行的系统也是可以的。由于介绍 μcLinux 2.6在skyeye上编译的相关资料并不多,所以下面进行详细介绍。

3.1.2 μcLinux 2.6.x的编译

要 在SkyEye中调试操作系统内核,首先必须使被调试内核能在SkyEye所模拟的开发板上正确运行。因此,正确编译待调试操作系统内核并配置 SkyEye是进行内核调试的第一步。下面我们以SkyEye模拟基于Atmel AT91X40的开发板,并运行μcLinux 2.6为例介绍SkyEye的具体调试方法。

I、安装交叉编译环境

先 安装交叉编译器。尽管在一些资料中说明使用工具链arm-elf-tools-20040427.sh ,但是由于arm-elf-xxx与arm-linux-xxx对宏及链接处理的不同,经验证明使用arm-elf-xxx工具链在链接vmlinux的 最后阶段将会出错。所以这里我们使用的交叉编译工具链是:arm-uclinux-tools-base-gcc3.4.0-20040713.sh,关 于该交叉编译工具链的下载地址请参见[6]。注意以下步骤最好用root用户来执行。


[root@lisl tmp]#chmod +x arm-uclinux-tools-base-gcc3.4.0-20040713.sh
[root@lisl tmp]#./arm-uclinux-tools-base-gcc3.4.0-20040713.sh 

安装交叉编译工具链之后,请确保工具链安装路径存在于系统PATH变量中。

II、制作μcLinux内核

得 到μcLinux发布包的一个最容易的方法是直接访问uClinux.org站点[7]。该站点发布的内核版本可能不是最新的,但你能找到一个最新的 μcLinux补丁以及找一个对应的Linux内核版本来制作一个最新的μcLinux内核。这里,将使用这种方法来制作最新的μcLinux内核。目前 (笔者记录编写此文章时),所能得到的发布包的最新版本是uClinux-dist.20041215.tar.gz。

下载uClinux-dist.20041215.tar.gz,文件的下载地址请参见[7]。

下载linux-2.6.9-hsc0.patch.gz,文件的下载地址请参见[8]。

下载linux-2.6.9.tar.bz2,文件的下载地址请参见[9]。

现在我们得到了整个的linux-2.6.9源代码,以及所需的内核补丁。请准备一个有2GB空间的目录里来完成以下制作μcLinux内核的过程。


[root@lisl tmp]# tar -jxvf uClinux-dist-20041215.tar.bz2
[root@lisl uClinux-dist]# tar -jxvf linux-2.6.9.tar.bz2
[root@lisl uClinux-dist]# gzip -dc linux-2.6.9-hsc0.patch.gz | patch -p0 

或者使用:


[root@lisl uClinux-dist]# gunzip linux-2.6.9-hsc0.patch.gz 
[root@lisl uClinux-dist]patch -p0 < linux-2.6.9-hsc0.patch 

执行以上过程后,将在linux-2.6.9/arch目录下生成一个补丁目录-armnommu。删除原来μcLinux目录里的linux-2.6.x(即那个linux-2.6.9-uc0),并将我们打好补丁的Linux内核目录更名为linux-2.6.x。


[root@lisl uClinux-dist]# rm -rf linux-2.6.x/
[root@lisl uClinux-dist]# mv linux-2.6.9 linux-2.6.x 

III、配置和编译μcLinux内核

因为只是出于调试μcLinux内核的目的,这里没有生成uClibc库文件及romfs.img文件。在发布μcLinux时,已经预置了某些常用嵌入式开发板的配置文件,因此这里直接使用这些配置文件,过程如下:


[root@lisl uClinux-dist]# cd linux-2.6.x
[root@lisl linux-2.6.x]#make ARCH=armnommu CROSS_COMPILE=arm-uclinux- atmel_
deconfig 

atmel_deconfig文件是μcLinux发布时提供的一个配置文件,存放于目录linux-2.6.x /arch/armnommu/configs/中。


[root@lisl linux-2.6.x]#make ARCH=armnommu CROSS_COMPILE=arm-uclinux-
oldconfig 

下面编译配置好的内核:


[root@lisl linux-2.6.x]# make ARCH=armnommu CROSS_COMPILE=arm-uclinux- v=1 

一般情况下,编译将顺利结束并在Linux-2.6.x/目录下生成未经压缩的μcLinux内核文件vmlinux。需要注意的是为了调试μcLinux内核,需要打开内核编译的调试选项-g,使编译后的内核带有调试信息。打开编译选项的方法可以选择:

"Kernel debugging->Compile the kernel with debug info"后将自动打开调试选项。也可以直接修改linux-2.6.x目录下的Makefile文件,为其打开调试开关。方法如下:。


CFLAGS += -g 

最 容易出现的问题是找不到arm-uclinux-gcc命令的错误,主要原因是PATH变量中没有包含arm-uclinux-gcc命令所在目录。在 arm-linux-gcc的缺省安装情况下,它的安装目录是/root/bin/arm-linux-tool/,使用以下命令将路径加到PATH环境 变量中。


Export PATH=$PATH:/root/bin/arm-linux-tool/bin 

IV、根文件系统的制作

Linux 内核在启动的时的最后操作之一是加载根文件系统。根文件系统中存放了嵌入式系统使用的所有应用程序、库文件及其他一些需要用到的服务。出于文章篇幅的考 虑,这里不打算介绍根文件系统的制作方法,读者可以查阅一些其他的相关资料。值得注意的是,由配置文件skyeye.conf指定了装载到内核中的根文件 系统。

3.2 使用SkyEye调试

编译完μcLinux内核后,就可以在SkyEye中调试该ELF执行文件格式的内核了。前面已经说过利用SkyEye调试内核与使用gdb调试运用程序的方法相同。

需 要提醒读者的是,SkyEye的配置文件-skyeye.conf记录了模拟的硬件配置和模拟执行行为。该配置文件是SkyEye系统中一个及其重要的文 件,很多错误和异常情况的发生都和该文件有关。在安装配置SkyEye出错时,请首先检查该配置文件然后再进行其他的工作。此时,所有的准备工作已经完 成,就可以进行内核的调试工作了。

3.3使用SkyEye调试内核的特点和不足

在 SkyEye中可以进行对Linux系统内核的全程调试。由于SkyEye目前主要支持基于ARM内核的CPU,因此一般而言需要使用交叉编译工具编译待 调试的Linux系统内核。另外,制作SkyEye中使用的内核编译、配置过程比较复杂、繁琐。不过,当调试过程结束后无需重新制作所要发布的内核。

SkyEye只是对系统硬件进行了一定程度上的模拟,所以在SkyEye与真实硬件环境相比较而言还是有一定的差距,这对一些与硬件紧密相关的调试可能会有一定的影响,例如驱动程序的调试。不过对于大部分软件的调试,SkyEye已经提供了精度足够的模拟了。

SkyEye的下一个目标是和eclipse结合,有了图形界面,能为调试和查看源码提供一些方便。




 回页首 

4. 使用UML调试Linux内核

User-mode Linux(UML)简单说来就是在Linux内运行的Linux。该项目是使Linux内核成为一个运行在 Linux 系统之上单独的、用户空间的进程。UML并不是运行在某种新的硬件体系结构之上,而是运行在基于 Linux 系统调用接口所实现的虚拟机。正是由于UML是一个将Linux作为用户空间进程运行的特性,可以使用UML来进行操作系统内核的调试。有关UML的介绍 请查阅参考资料[10]、[12]。

4.1 UML的安装与调试

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运行已经编译好的内核即可进行调试。

4.2使用UML调试系统内核的特点和不足

目 前,用户模式 Linux 虚拟机也存在一定的局限性。由于UML虚拟机是基于Linux系统调用接口的方式实现的虚拟机,所以用户模式内核不能访问主机系统上的硬件设备。因 此,UML并不适合于调试那些处理实际硬件的驱动程序。不过,如果所编写的内核程序不是硬件驱动,例如Linux文件系统、协议栈等情况,使用UML作为 调试工具还是一个不错的选择。




 回页首 

5. 内核调试配置选项

为了方便调试和测试代码,内核提供了许多与内核调试相关的配置选项。这些选项大部分都在内核配置编辑器的内核开发(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选项,以使编译的内核包含调试信息。




 回页首 

6. 总结

上面介绍了一些调试Linux内核的方法,特别是详细介绍了三种源代码级的内核调试工具,以及搭建这些内核调试环境的方法,读者可以根据自己的情况从中作出选择。

调试工具(例如gdb)的运行都需要操作系统的支持,而此时内核由于一些错误的代码而不能正确执行对系统的管理功能,所以对内核的调试必须采取一些特殊的方法进行。以上介绍的三种源代码级的调试方法,可以归纳为以下两种策略:

I、为内核增加调试Stub,利用调试Stub进行远程调试,这种调试策略需要target及development机器才能完成调试任务。

II、将虚拟机技术与调试工具相结合,使Linux内核在虚拟机中运行从而利用调试器对内核进行调试。这种策略需要制作适合在虚拟机中运行的系统内核。

由不同的调试策略决定了进行调试时不同的工作原理,同时也形成了各种调试方法不同的软硬件需求和各自的特点。

另外,需要说明的是内核调试能力的掌握很大程度上取决于经验和对整个操作系统的深入理解。对系统内核的全面深入的理解,将能在很大程度上加快对Linux系统内核的开发和调试。

对系统内核的调试技术和方法绝不止上面介绍所涉及的内容,这里只是介绍了一些经常看到和听到方法。在Linux内核向前发展的同时,内核的调试技术也在不断的进步。希望以上介绍的一些方法能对读者开发和学习Linux有所帮助。

0 0
原创粉丝点击