日期:2014-05-16  浏览次数:20427 次

使用KGDB构建Linux内核调试环境

使用KGDB构建Linux内核调试环境
2010年06月27日
  kgdb提供了一种使用 gdb调试 Linux 内核的机制。使用KGDB可以象调试普通的应用程序那样,在内核中进行设置断点、检查变量值、单步跟踪程序运行等操作。使用KGDB调试时需要两台机器,一台作为开发机(Development Machine),另一台作为目标机(Target Machine),两台机器之间通过串口或者以太网口相连。串口连接线是一根RS-232接口的电缆,在其内部两端的第2脚(TXD)与第3脚(RXD)交叉相连,第7脚(接地脚)直接相连。调试过程中,被调试的内核运行在目标机上,gdb调试器运行在开发机上。
  目前,kgdb发布支持i386、x86_64、32-bit PPC、SPARC等几种体系结构的调试器。有关kgdb补丁的下载地址见参考资料[4]。
  2.1 kgdb的调试原理
  安装kgdb调试环境需要为Linux内核应用kgdb补丁,补丁实现的gdb远程调试所需要的功能包括命令处理、陷阱处理及串口通讯3个主要的部分。kgdb补丁的主要作用是在Linux内核中添加了一个调试Stub。调试Stub是Linux内核中的一小段代码,提供了运行gdb的开发机和所调试内核之间的一个媒介。gdb和调试stub之间通过gdb串行协议进行通讯。gdb串行协议是一种基于消息的ASCII码协议,包含了各种调试命令。当设置断点时,kgdb负责在设置断点的指令前增加一条trap指令,当执行到断点时控制权就转移到调试stub中去。此时,调试stub的任务就是使用远程串行通信协议将当前环境传送给gdb,然后从gdb处接受命令。gdb命令告诉stub下一步该做什么,当stub收到继续执行的命令时,将恢复程序的运行环境,把对CPU的控制权重新交还给内核。
  2.2 Kgdb的安装与设置
  下面我们将以Linux 2.6.7内核为例详细介绍kgdb调试环境的建立过程。
  2.2.1软硬件准备
  以下软硬件配置取自笔者进行试验的系统配置情况:
  kgdb补丁的版本遵循如下命名模式:Linux-A-kgdb-B,其中A表示Linux的内核版本号,B为kgdb的版本号。以试验使用的 kgdb补丁为例,linux内核的版本为linux-2.6.7,补丁版本为kgdb-2.2。
  物理连接好串口线后,使用以下命令来测试两台机器之间串口连接情况,stty命令可以对串口参数进行设置:
  在development机上执行:
  stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
  在target机上执行:
  stty ispeed 115200 ospeed 115200 -F /dev/ttyS0
  在developement机上执行:
  echo hello > /dev/ttyS0
  在target机上执行:
  cat /dev/ttyS0
  如果串口连接没问题的话在将在target机的屏幕上显示"hello"。
  2.2.2 安装与配置
  下面我们需要应用kgdb补丁到Linux内核,设置内核选项并编译内核。这方面的资料相对较少,笔者这里给出详细的介绍。下面的工作在开发机(developement)上进行,以上面介绍的试验环境为例,某些具体步骤在实际的环境中可能要做适当的改动:
  I、内核的配置与编译
  [root@lisl tmp]# tar -jxvf linux-2.6.7.tar.bz2
  [root@lisl tmp]#tar -jxvf linux-2.6.7-kgdb-2.2.tar.tar
  [root@lisl tmp]#cd inux-2.6.7
  请参照目录补丁包中文件README给出的说明,执行对应体系结构的补丁程序。由于试验在i386体系结构上完成,所以只需要安装一下补丁:core-lite.patch、i386-lite.patch、8250.patch、eth.patch、core.patch、 i386.patch。应用补丁文件时,请遵循kgdb软件包内series文件所指定的顺序,否则可能会带来预想不到的问题。eth.patch文件是选择以太网口作为调试的连接端口时需要运用的补丁
  。
  应用补丁的命令如下所示:
  [root@lisl tmp]#patch -p1   
  
  • KGDB: Thread analysis                                                                            
  •   
  • KGDB: Console messages through gdb
  •   [root@lisl tmp]#make
      编译内核之前请注意Linux目录下Makefile中的优化选项,默认的Linux内核的编译都以-O2的优化级别进行。在这个优化级别之下,编译器要对内核中的某些代码的执行顺序进行改动,所以在调试时会出现程序运行与代码顺序不一致的情况。可以把Makefile中的-O2选项改为-O,但不可去掉-O,否则编译会出问题。为了使编译后的内核带有调试信息,注意在编译内核的时候需要加上-g选项。
      不过,当选择"Kernel debugging->Compile the kernel with debug info"选项后配置系统将自动打开调试选项。另外,选择"kernel debugging with remote gdb"后,配置系统将自动打开"Compile the kernel with debug info"选项。
      内核编译完成后,使用scp命令进行将相关文件拷贝到target机上(当然也可以使用其它的网络工具,如rcp)。
      [root@lisl tmp]#scp arch/i386/boot/bzImage root@192.168.6.13:/boot/vmlinuz-2.6.7-kgdb
      [root@lisl tmp]#scp System.map root@192.168.6.13:/boot/System.map-2.6.7-kgdb
      如果系统启动使所需要的某些设备驱动没有编译进内核的情况下,那么还需要执行如下操作:
      [root@lisl tmp]#mkinitrd /boot/initrd-2.6.7-kgdb 2.6.7
      [root@lisl tmp]#scp initrd-2.6.7-kgdb root@192.168.6.13:/boot/ initrd-2.6.7-kgdb
      II、kgdb的启动
      在将编译出的内核拷贝的到target机器之后,需要配置系统引导程序,加入内核的启动选项。以下是kgdb内核引导参数的说明:
      如表中所述,在kgdb 2.0版本之后内核的引导参数已经与以前的版本有所不同。使用grub引导程序时,直接将kgdb参数作为内核vmlinuz的引导参数。下面给出引导器的配置示例。
      title 2.6.7 kgdb
      root (hd0,0)
      kernel /boot/vmlinuz-2.6.7-kgdb ro root=/dev/hda1 kgdbwait kgdb8250=1,115200
      在使用lilo作为引导程序时,需要把kgdb参放在由append修饰的语句中。下面给出使用lilo作为引导器时的配置示例。
      image=/boot/vmlinuz-2.6.7-kgdb
      label=kgdb
      read-only
      root=/dev/hda3
      append="gdb gdbttyS=1 g