使用KGDB 进行内核调试(平台搭建和调试)

最近做的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

 

 

问题的解决方法:(ZZhttp://blog.youkuaiyun.com/unbutun/article/details/6526670)(http://blog.youkuaiyun.com/chaolumon/article/details/4736546

原因:

内核编译选项CONFIG_DEBUG_RODATA,会对kernel textwrite protect那么kgdb就不能设置断点了。

解决方法是:

编辑kernel source目录下生成的.config文件,禁用CONFIG_DEBUG_RODATA=n(read only data)即可。

 

好吧,知道了问题出在哪里,又去重新编译了一遍内核。这次在linux-2.6.24目录下,找到config, 设定好CONFIG_DEBUG_RODATA里面的参数。

但是编译后进行调试,如果使用gdbmod-2.4问题依旧存在。之后,改用了本机自带的GDB调试,问题就解决了。

 

 

 

 

 

 

下面,列下我主要参考的一些网站:

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搭建内核调试环境的

 

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

 

2 http://kerneltrap.org/kgdb

 

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

 

 

 

还有一些链接,是我后来整理的:

 

http://www.kgdb.info/kgdb/

 

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

 

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 modulehelloworld程序

 

7        http://lwn.net/Kernel/LDD3/

(一本书: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,至于为啥要设定,参考这段话:


 

 


但是,其实,这里面使用GDBgdbmod。而我在做试验的时候,使用的是系统自带的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:我什么时候,能达到我崇拜的大神的一半牛逼呢。。。


 

 

 

 

 

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值