最近做的research涉及到在调试一个loadable linux kernelmodule, 查了下相关资料,发现在kernel下debug 需要的工具是KGDB(其实KGDB主要是做一个连接桥梁的作用,真正的debug工作还是要交给GDB去做)。
本文就是讲下如何去进行KGDB环境的搭建,以及如何进行简单的内核调试。
本人才疏学浅,可能有的地方讲的也不是很清楚,读者可以自行google
文章布局我打算沿用上篇文章的思路,先把自己各种纠结过程讲下(遇到的各种问题)。在文章最后,提供一个完整的KGDB环境搭建和简单的内核模块调试的例子。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
澄清一个概念先:
The machine thatruns the kernel to be debugged is called the Test
machine while the machinethat runs gdb is called the Development machine.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
起先查了一些KGDB的相关文档,一个比较有名的网站是:
http://kgdb.linsyssoft.com/index.html
这个网站主要是提供了一个比较老的内核的KGDB patch,比如kernel 2.6.13,
kernel 2.4.6 至Kernel 2.4.23 之间的一些版本。(具体链接:http://kgdb.linsyssoft.com/downloads.htm)
而且这个网站(http://kgdb.linsyssoft.com/index.html)提供了一些比较实用的KGDB文档(http://kgdb.linsyssoft.com/docu.htm),虽然这些文档对于怎么样搭建KGDB环境已经描述的很详细了,但是也有不少缺陷,文档省略了几个关键的问题,而这几个问题,是导致我之后做内核调试遇到的比较棘手的几个问题。
对于其他的linux内核版本,从kernel 2.6.26,内核就自带了KGDB功能,不用再打patch了。而针对kernel versions between 2.6.16 and2.6.26,这些属于KGDB开发过程中的过渡版本kernel,所以根本没有对应的官方KGDB补丁(至于一些linux kgdb的历史原因,这个网站给了比较详细的描述:http://www.linuxsmiths.com/blog/?p=386)
但是,我research 用的click router,比较悲摧的在 kernel 2.6.x level,只提供了2.6.16, 2.6.19, 2.6.24这三个版本的kernel补丁。。。
如果我转战去编译click 支持的2.4.x,估计也会遇到不少问题,因为2.4.x的内核太老了,而我现在使用的编译内核的平台是ubuntu 8.04LTS, 所以我觉得很可能出现各种兼容性问题,比如GCC版本过高什么的。
但是,幸运的是,上文提到的一个网站(http://www.linuxsmiths.com/blog/?p=386)中,有个大神正好需要进行linux kernel 2.6.24KGDB debug,大神自己写了一个针对kernel2.6.24的 KGDB patch. 后来我可以成功把这个patch打补丁到kernel里进行编译,使用。
下面简单谈下在KGDB内核调试过程中,我遇到几个比较棘手的问题:
1
当我把基本的调试环境搭建好了之后,我按照(http://kgdb.linsyssoft.com/docu.htm)的KGDBdocumentation for version 2.3 and 2.4 的说明,尝试在Development machine上,用GDB 调试。出现的问题就是我使用Ctrl+C 命令去 stopping kernel execution。之后系统提示:
Interrupted while waiting for the program.
Give up (and stop debugging it)? (y or n)
当我选择了n之后,这个调试器就彻底退出了kernel debug,我是无法使用
(gdb) continue
命令,再次恢复kernel调试的
所以,我觉得可能documentation for version 2.3 and 2.4,page 10, controlling the execution of a kernel下面的stoppingkernel execution 和continuing kernel execution 两部分写的有错误。
而且,不光是我用本机ubuntu自带的GDB调试出现这个问题,就算我使用这个链接(http://kgdb.linsyssoft.com/downloads.htm)提供的,号称改进过的(为内核调试特定的)GDB,“gdbmod-2.4”调试,也会出现同样的问题。
这个问题的解决方法就是不用Ctrl+C命令去中断GDB,而是在Test machine上面,在terminal 里,输入 echo g >/proc/sysrq-trigger 命令,来使Test machine进入一个假死状态,然后在development machine那边,可以在terminal看到GDB又可以输入命令行了。
2
我遇到的另外一个问题就是,在developmentmachine上面,设定函数断点后,之后用continue命令去恢复test machine端的运行,但是会遇到error:
比如:
Cannot insert breakpoint 4.
Error accessing memory address 0xd0ce8000: 未知的错误 4294967295
问题的解决方法:(ZZ:http://blog.youkuaiyun.com/unbutun/article/details/6526670)(http://blog.youkuaiyun.com/chaolumon/article/details/4736546)
原因:
内核编译选项CONFIG_DEBUG_RODATA,会对kernel text做write protect。那么kgdb就不能设置断点了。
解决方法是:
编辑kernel source目录下生成的.config文件,禁用CONFIG_DEBUG_RODATA=n(read only data)即可。
好吧,知道了问题出在哪里,又去重新编译了一遍内核。这次在linux-2.6.24目录下,找到config, 设定好CONFIG_DEBUG_RODATA里面的参数。
但是编译后进行调试,如果使用gdbmod-2.4,问题依旧存在。之后,改用了本机自带的GDB调试,问题就解决了。
下面,列下我主要参考的一些网站:
1 http://kgdb.linsyssoft.com/intro.htm
比较官方的讲了kgdb的搭建和用法(document),还提供 kgdb kernel patch以及gdbmod下载
2 http://www.linuxsmiths.com/blog/?p=386
讲述了kgdb的一些发展历史,以及提供 kgdb patch for kernel 2.6.24 (the same kernel as ubuntu 8.04 LTS)
3 http://www.kgdb.info/category/kgdb/use_kgdb/
这个站点的内容还挺多的,不过我没有特别具体的看。里面有讲使用QEMU搭建内核调试平台的东西
4 https://kgdb.wiki.kernel.org/(一个关于KGDB的简单介绍的wiki)
5 http://blog.youkuaiyun.com/jie12310/article/details/4564853
这篇文章写的不错,csdn上的大牛果然多。不过一开始内核的编译环境使用的centos
6 http://linux-hacks.blogspot.com/2008/05/setting-up-kgdb-using-kvmqemu.html
又是一篇讲用QEMU搭建内核调试环境的
7 http://www.arm9home.net/read.php?tid-16429.html
文章还不错,而且我记得自己当时是通过这篇文章,注意到了编译完内核,要针对KGDB调试,对GRUB里面的启动项做配置
8 http://jianel.net/article/showArticlex20253.html
讲的挺好,而且给出了正确的grub配置,只不过虚拟环境没有像我用vmware
9 http://blog.youkuaiyun.com/mikefeng/article/details/1508383
10 http://www.360doc.com/content/10/1227/11/1429472_81681009.shtml
我是通过这篇文章,学到的如何在虚拟机(vmware)上,搭建串口通信,然后测试搭建好的两个OS的串口,是否能够很好发送信息。
11 http://blog.chinaunix.net/space.php?uid=21525518&do=blog&id=1824629(用IE浏览器打开)
12 http://blog.youkuaiyun.com/ruixj/article/details/5698263
13 http://blog.youkuaiyun.com/ruixj/article/details/5698252
14 http://www.360doc.com/content/10/0608/07/865714_31873686.shtml
15 http://blog.youkuaiyun.com/defeattroy/article/details/5262933
16 http://www.xfocus.net/articles/200509/820.html
其他
1 http://kerneltrap.org/debugger
3 http://www.diybl.com/course/6_system/linux/Linuxjs/200888/135056.html
4 http://www.360doc.com/relevant/32016606_more.shtml
5 http://www.vanemery.com/Linux/Serial/serial-console.html
http://www.cyberciti.biz/faq/find-out-linux-serial-ports-with-setserial/
http://www.cyberciti.biz/faq/find-out-linux-serial-ports-with-setserial/
讲如何建立linux 串口通信
7 http://www.linuxjournal.com/article/9252
还有一些链接,是我后来整理的:
2 http://topic.youkuaiyun.com/u/20081005/23/68537F7A-3844-4546-8FE5-FF9196DA12B9.html
3 http://kernel.org/pub/linux/kernel/people/jwessel/kdb/index.html
4 http://www.youtube.com/watch?v=PvzKny_TSNM
5 http://www.linuxjournal.com/article/4525?page=0,0
6 http://blog.markloiseau.com/2012/04/hello-world-loadable-kernel-module-tutorial/
这个网站,教你写一个loadable kernel module的helloworld程序
(一本书:Linux Device Drivers, Third Edition)
8 http://kernel.org/doc/htmldocs/kgdb.html
(Using kgdb, kdb and the kernel debugger internals)
还成,不过讲的有点偏理论
9 http://www.stlinux.com/devel/debug/kgdb/modules
10 http://lagignition.blog.163.com/blog/static/128730023201028114147466/
讲的不错
11 http://lwn.net/Articles/332611/
12 http://www.embexperts.com/viewthread.php?tid=133
13 http://blog.youkuaiyun.com/chaolumon/article/details/4736546
最后,从内核的编译,到KGDB环境的搭建,完整的讲下。
说下自己使用的配置环境啥的:
VMware : 7.0.1 build-227600
Test machine original OS: [乌班图].ubuntu-8.04.3-desktop-i386.iso
Development machine OS: [乌班图].ubuntu-8.04.3-desktop-i386.iso
Kernel being compiled on test machine: kernel2.6.24 (but I also tried 2.6.26)
KGDB kernel patch source: http://www.linuxsmiths.com/blog/?p=386
澄清一个概念:
The machine thatruns the kernel to be debugged is called the Test
machine while the machinethat runs gdb is called the Development machine.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
关于内核的编译:
1 通过kernel.org 下载内核
2.6.24 版本
2 配置一个合适的编译环境:[乌班图].ubuntu-8.04.3-desktop-i386.iso
3 下载编译内核需要的工具:
apt-get install build-essential kernel-package libncurses5-dev
4 在 /usr/src/linux-2.6.24 路径下,给linux 打KGDB patch
patch –p1 –b < /home/wp/kgdb-patch-linux-2.6.24
patch 的来源:http://www.linuxsmiths.com/blog/?p=386
(给我要用的clickmodular router 打patch)
patch –p1 –b </home/wp/linux-2.6.24.7-patch
5 在 /usr/src/linux-2.6.24 路径下
makemenuconfig 进行内核配置
主要去配置kernel hacking栏下的 KGDB那些选项
6 在make menuconfig之后编辑kernel source目录下生成的.config文件
参考文章(http://blog.youkuaiyun.com/unbutun/article/details/6526670)(http://blog.youkuaiyun.com/chaolumon/article/details/4736546)
whereis .config
找到.config文件
用vim到 config去修改文件里面设定的参数
http://blog.youkuaiyun.com/chaolumon/article/details/4736546文章中提到:
编译内核
Make menuconfig,按照KGDB官方网站上的说明文档配置必要的KGDB选项。注意将默认的串口1改为0。这个在make menuconfig的过程中不能更改,可以通过make oldconfig进行交互式配置更改,也可以在make menuconfig之后编辑kernel source目录下生成的.config文件
,确保关于kgdb的配置如下(特别是最后一句)
# by linux 2.6.15 - 2.6.25
CONFIG_KGDB_8250_NOMODULE=y
CONFIG_KGDB_8250=y
CONFIG_KGDB_SIMPLE_SERIAL=y
CONFIG_KGDB_BAUDRATE=115200
CONFIG_KGDB_PORT_NUM=0
# by linux 2.6.26+
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_INFO=y
禁用CONFIG_DEBUG_RODATA=n (read onlydata)
但是,其实我自己编译 kernel 2.6.24的时候,也就是用的#by linux 2.6.26+标明的那几条方法
我觉得最重要的,就是修改“禁用CONFIG_DEBUG_RODATA=n (read only data)”这项
7以下一系列命令,都在/usr/src/linux-2.6.24路径下完成
(zz)
配置完以后保存(系统中保存的一份内核配置文件是在/usr/src/linux-2.6.24下名为.config,你也可以自己在别的地方另存一份)也可以cp原来在/boot目录下的config-2.6.xx 到当前目录下,在make menuconfig是使用这个配置文件。
make dep //也许系统会提示现在不必要进行make dep,那就下一步 2.6.24的我编译就没有使用过。
make clean //清除旧数据 ,新解压的内核源码就不需要这一步了
make –j2 可以分两个线程来进行编译工作,不过我用make –j4 却发现系统有9个make进程在工作。所以这个参数未必起作用。
make bzImage //编译内核,将保存到/usr/src/linux-2.6.24/arch/i386/boot/下
make modules //编译模块
make modules_install //安装模块
8
在/usr/src/linux-2.6.24路径下
添加引导信息
mkinitramfs –o /boot/initrd.img-2.6.24 /lib/modules/2.6.24
9修改grub (蓝字那段,是我自己添加的,红字是针对KGDB调试所做的更改)
title Ubuntu 8.04 , kernel 2.6.26 test with KGDB
root (hd0,0)
kernel /boot/vmlinuz-2.6.26root=UUID=d433f98a-2c1b-43c0-906f-f083992861d2 ro kgdboc=ttyS0,115200 kgdbwait
initrd /boot/initrd.img-2.6.26
title Ubuntu8.04.3 LTS, kernel 2.6.24-24-generic
root (hd0,0)
kernel /boot/vmlinuz-2.6.24-24-genericroot=UUID=d433f98a-2c1b-43c0-906f-f083992861d2 ro quiet splashfind_preseed=/preseed.cfg auto automatic-ubiquity noprompt priority=criticallocale=en_US
initrd /boot/initrd.img-2.6.24-24-generic
quiet
title Ubuntu8.04.3 LTS, kernel 2.6.24-24-generic (recovery mode)
root (hd0,0)
kernel /boot/vmlinuz-2.6.24-24-genericroot=UUID=d433f98a-2c1b-43c0-906f-f083992861d2 ro single
initrd /boot/initrd.img-2.6.24-24-generic
title Ubuntu8.04.3 LTS, memtest86+
root (hd0,0)
kernel /boot/memtest86+.bin
quiet
10
这样就大概把 testmachine 上的系统编译配置好了
重启,然后引导系统进入Ubuntu 8.04 ,kernel 2.6.26 test with KGDB
应该出现的命令行是

注意最后:
Kgdb: waiting forconnection from remote gdb
出现这个提示,就说明在testmachine上,KGDB配置成功了
至此,内核编译的工作完成
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
下面谈下配置VMware上面的两台OS进行串口通信
(讲点相关的事:GDBwith KGDB debug支持串口通信和ethernet通信(recent versions of kgdb work overEthernet also) )
如果是用两台实际的主机,进行KGDBdebug,那么就需要一条串口线,连接好两台主机的串口,进行通信。
但是,我是基于VMware做的试验,可以就在VMware上面设定虚拟串口连接,进行通信。
我主要是参考的这篇文章,进行的设定和检测串口连接是否设定成功:
(http://www.360doc.com/content/10/1227/11/1429472_81681009.shtml)




至此,串口通信就设定好了
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
下面就是讲下如何操作两个OS(test/development),进行远程调试
先提一个有意思的东西,就是如何写一个loadable linux kernel 的helloworld程序
具体网址(http://blog.markloiseau.com/2012/04/hello-world-loadable-kernel-module-tutorial/)
我参考的两篇文章:
http://blog.youkuaiyun.com/mikefeng/article/details/1508383
http://blog.chinaunix.net/space.php?uid=21525518&do=blog&id=1824629
去进行联机调试
好了,言归正传:
1 首先,需要把test machine 中的 vmlinux文件copy到developmentmachine中。
(vmlinux存放在test machine 的 /usr/src/linux-2.6.24 路径下)
2 启动development machine
键入命令行:stty ispeed 115200ospped 115200 < /dev/ttyS0
(设定通信速率是115200)
这篇文章中(http://blog.youkuaiyun.com/mikefeng/article/details/1508383)提到:
确保调试机和被调试机的源码和System.map一致
我也没有特别注意,不知道是不是必须要一致。
然后切换到development machine, 存放了vmlinux的目录。
键入命令行:gdb vmlinux
(用gdb打开test OS对应的系统文件)
启动后, 键入命令行:
target remote /dev/ttyS0
等待断点:

可以看到,断点在kgdb.c的1674行
Backtrace下,可以观查下系统的call stack
2 在development machine上,设定一个path,至于为啥要设定,参考这段话:

但是,其实,这里面使用GDB是gdbmod。而我在做试验的时候,使用的是系统自带的gdb。我没有验证敲入那段set…命令,到底是否起作用。因为我之后用的调试方法,和这个document上提到的,不完全一样。。。
Anyway,还是输入下吧:
set solib-search-path/home/wp/hello
(这是前面提到的那个loadable kernel module helloworld程序在test machine上面的路径)
2 然后在development machine上,键入continue命令,这时,testmachine就会正常启动了(如果没有遇到任何断点的话)
3 在test machine 下,进入路径 /home/wp/hello
在terminal下输入命令:
echo g > /proc/sysrq-trigge
来使Testmachine进入一个假死状态,然后在development machine那边,可以在terminal看到GDB又可以输入命令行了。
4 在 development machine 上,
键入命令:(针对2.6.24版本的内核)
(gdb) break kernel/module.c: 2108
(对应的line of code: mod= load_module(umod,len,uargs))
(gdb) break kernel/module.c: 2125
(对应的line of code: if(mod->init!=NULL))
(注意:不同版本的内核,对应的断点也不同)
7在test machine 下,路径 /home/wp/hello下
键入命令:insmodhello.ko
这时,testmachine系统会遇到我之前设定的第一个断点,然后假死
在developmentmachine 上,gdb恢复控制权:

这时,应该就算可以正式debug这个 loadable kernelmodule helloworld 程序了
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
**********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
对于内核的编译。这个网址讲的是比较详细,比较好的了。
http://www.kerneltravel.net/?p=72
(ZZ)
第一步 安装必要的工具
首先要安装必要的包。
包有:libncurses5-dev(menuconfig需要的)和essential
sudo apt-get install build-essential kernel-package
sudo apt-get install make
sudo apt-get install gcc
另外,查看系统是否有这样的两个命令
mkinitramfs mkisofs
这两个工具在编译内核时用来生成 *.img文件的。如果没有就需安装。
第二步 下载内核
到www.kernel.org下载新内核到/usr/src
我下载的是linux-2.6.24.tar.gz(原来的内核是2.6.20-15-generic)
第三步 编译前的准备
察看当前内核的版本
helight@helight-desktop:/$ uname -a
Linuxhelight-desktop 2.6.20-15-generic #1 SMP Mon Aug 25 17:32:09 UTC 2008 i686GNU/Linux
helight@helight-desktop:/$
建议最好下载比当前已安装版本高的内核
解压linux-2.6.24.tar.gz到linux-2.6.24
cd /usr/src
sudo tar zxvf linux-2.6.24.tar
cd linux-2.6.24/
第四步 开始编译
cd /usr/src/linux-2.6.24 //以下所有的工作都在/usr/src/linux-2.6.24下完成
sudo make menuconfig //用menuconfig的话还需要Ncurses,或者用
sudo make xconfig
sudo make menuconfig //一般是用menuconfig
配置完以后保存(系统中保存的一份内核配置文件是在/usr/src/linux-2.6.24下名为.config,你也可以自己在别的地方另存一份)
也可以cp原来在/boot目录下的config-2.6.xx 到当前目录下,在make menuconfig是使用这个配置文件。
sudo make dep //也许系统会提示现在不必要进行make dep,那就下一步 2.6.24的我编译就没有使用过。
sudo make clean //清除旧数据 ,新解压的内核源码就不需要这一步了
sudo make –j2 可以分两个线程来进行编译工作,不过我用make –j4 却发现系统有9个make进程在工作。所以这个参数未必起作用。
sudo make bzImage //编译内核,将保存到/usr/src/linux-2.6.24/arch/i386/boot/下
sudo make modules //编译模块
sudo make modules_install //安装模块
sudo mkinitramfs -o /boot/initrd-2.6.24.img 2.6.24
此时可能提示找不到这样的一个文件夹“/lib/firmware/2.6.24”,你需要手工创建一个这样的文件夹。
sudo mkdir /lib/firmware/2.6.24
sudo make install //安装内核
安装完后/boot下将增加以下几个文件(用ls -l *24*查看)
helight@helight-desktop:/boot$ ls -l *24*
-rw-r–r– 1 root root 852032008-03-14 22:24 config-2.6.24
-rw-r–r– 1 root root 852032008-03-14 20:23 config-2.6.24.old
-rw-r–r– 1 root root 37968871 2008-03-1508:31 initrd-2.6.24.img
-rw-r–r– 1 root root 4014080 2008-03-1422:24 initrd.img-2.6.24
-rw-r–r– 1 root root 9323152008-03-14 22:24 System.map-2.6.24
-rw-r–r– 1 root root 9323152008-03-14 20:23 System.map-2.6.24.old
-rw-r–r– 1 root root 1858864 2008-03-1422:24 vmlinuz-2.6.24
-rw-r–r– 1 root root 1858864 2008-03-1420:23 vmlinuz-2.6.24.old
helight@helight-desktop:/boot$
给/boot/grub/menu.lst中添加一个新的启动项,如我的menu.lst增加了如下一段文字
title Ubuntu, kernel 2.6.24
root (hd0,0)
kernel /boot/vmlinuz-2.6.24root=UUID=d7e2cf74-ebf5-4c78-ac2c-9f85a9809eae ro
initrd /boot/initrd-2.6.24.img
从新启动即可。
**********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
PS:我什么时候,能达到我崇拜的大神的一半牛逼呢。。。

6329

被折叠的 条评论
为什么被折叠?



