转载文章请标明作者和二维码及全文信息。
不会编程的程序员,不是好的构架师,编程和内核调试也是出众构架师的选修课。谈起编程人员的数目,基于Linux平台的软件工程师肯定是最多的,没有之一。那明天我们就以Linux为例,深入讲一下内核模块和内核的调试技术和调试工具KGDB。
1KGDB背景
KGDB是在内核2.6.26版本中即将支持的,对应发行版即SLES11及以上、RHEL6及以上,在此之前的内核版本由LinsyssoftTechnologies公司提供补丁以支持KGDB,但并不是所有内核版本都有补丁可用,同时打补丁操作也比较冗长且问题多多,因而可用性不高。
2调试环境搭建
注:以下称“被调试的主机”为目标机,运行gdb进行调试的主机为开发机
2.1目标机配置
2.1.1配置并口
化学机并口按照实际环境要求配置,虚拟机按如下方法配置,pipe名子可以更改,但要保证和开发机一致:
2.1.2更新内核以支持kgdb
注:本文以SLES11SPSP1作为目标机为例,内核源码直接安装RPM包就可以使用linux 安装gdb 设置环境变量,RHEL要稍为麻烦一些,须要下载源码包,进行编译后进行安装。
更新内核前打算
加入调试信息后内核及各个ko的容积会减小数倍,因而编译内核前一定要确认c盘有7G以上剩余空间(保险起见建议预留10G),执行make后源码目录空间占用超过5G。
执行makemodules_install后/lib/modules目录还要占用1.4G
SLES系列默认内核源码目录是/usr/src/linux-xxx/,但因为试验用的虚拟机创建时c盘选择默认大小只有8G,因而额外创建了一块20G的c盘挂载到/home目录作为内核编译目录,可直接将目录usr/src/linux-xxx/拷贝到/home/linux-xxx/不影响编译。
更新内核步骤
1、执行uname–r确认当前运行内核的类型,拷贝/boot/目录下对应内核类型的config文件到内核源码目录并重命名为.config;大多数情况下编译内核后启动失败都是由于内核配置不当,因而最好在系统原有配置文件基础上更改。
2、在内核源码目录执行makemenuconfig进行内核配置;
[*]Compilethekernelwithdebuginfo
[*]Compilethekernelwithframepointers
[*]KGDB:kerneldebuggingwithremotegdb
在SLES11SPSP1上除去Writeprotectkernelread-onlydatastructures后编译会出错,缘由是函数mark_rodata_ro在init/main.c和cacheflush.h中重复定义了
解决办法是注掉main.c中的定义:
3、执行makeall编译内核;(历时约1小时,可使用make–jxall推进编译速率,x表示线程数)
4、安装模块,编译完成后,新生成的模块ko还在源码目录红联linux论坛,并未更新到/lib/module/对应目录:
5、创建启动内核及initrd
6、为KGDB内核创建新的启动项
7、重启目标机,以KGDB选项启动
2.2开发机配置
开发机不须要和目标机硬件或内核相同,只要里面装的gdb版本满足kgdb的要求就可以。本文使用一个SLES10SPSP4的32位虚拟机作为开发机。
2.2.1配置并口
化学机并口按照实际环境要求配置,虚拟机按如下形式配置:
检测参数,确认并口配置正确:
2.2.2打算调试代码和目标二补码文件
调试代码
因为gdb调试须要源码文件,因而须要把内核源码拷贝到开发机。建议在目标机编译前把整个源码目录拷贝到开发机,否则编译后整个源码目录容积太大。
目标二补码文件
目标二补码文件就是要调试的文件,如vmlinux或xxx.ko,直接把目标机上编译好的文件拷贝到开发机,建议置于内核源码目录下。
3调试步骤
3.1调试内核vmlinux
以调试函数block层的函数get_request_wait为例
1、在目标机执行echog>/proc/sysrq-trigger,会触发目标机挂起以等待开发机输入;
2、在开发机启动gdb:
3、设置启动远程调试
在gdb界面输入以下两条命令linux 安装gdb 设置环境变量,成功的话会显示断在kgdb_breakpoint函数:
4、输入bget_request_wait为我们想调试的函数设置断点(b表示breakpoint),之后执行c(continue)让目标机继续运行直至断点;
5、查看调用栈(bt)和单步调试(n)都是比较有用的手段;
查看函数get_request_wait的调用栈:
单步调试:
6、调试完成后清理断点让目标机恢复正常运行;
目标机之前挂起后网路就中断了,此时恢复后又可重新登入:
3.2调试模块KO
以调试模块scsi_mod.ko为例:
1、先在目标机上查看模块在内核中的偏斜地址,之后挂起目标机:
2、在开发机启动gdb,并执行add-symbol-file[模块ko][内核地址]加载模块ko文件:
然后的步骤同调试内核vmlinux一样:启动远程调试、设置断点…
4总结
使用KGDB,一方面可以帮助阅读内核代码,实际观察代码执行的流程;另一方面可以帮助非自研模块相关流程的问题定位linux设置环境变量,不须要反复添加复印重编内核,提升问题定位效率。本文重点描述了KGDB环境搭建及启动调试的步骤,更多gdb调试方法请参考gdb指南。
环境搭建重点在于更新内核,这块也是整个过程中最历时和容易出错的,项目组可以组织分工进行各个版本、类型内核的KGDB更新(如SLES1132位/64位、RHEL等等)并保存,后续使用时可以直接拷贝。