在VMware环境下使用KGDB调试Linux内核及内核模块
来源:互联网 发布:明天教室网络课怎么样 编辑:程序博客网 时间:2024/05/01 20:44
1:前言:
最近几天学习Linux-2.6平台上的设备驱动,所以要建立内核及内核模块的调试平台.虽然网上有很多相关教程,但多是基于2.6.26以前的通过补丁安装的,过程非常复杂,而且问题比较多.linux从 2.6.26开始已经集成了kgdb,只需要重新编译2.6.26(或更高)内核即可.kgdb安装及模块调试过程也遇到不少问题,网上网下不断的搜索与探索,才算调通.现在记录下来,供朋友们参考.
首先说一下,开始本打算安装kdb进行内核调试,后来听说kdb只能进行汇编级别的调试,所以放弃,改用kgdb.
2: 系统环境:
虚拟环境: VMWare Workstation 5.5(英文版)
操作系统: CentOS-4.6-i386(原内核2.6.9,将会把内核升级至2.6.26)
注:CentOS 是RedHat的一个社区版本.
(由于我们采用的linux kernel 2.6.26已经集成kgdb,kgdb再不需要单独下载)
3:系统的安装:
在VMWare中新建一台计算机:
- 点击 Next
- 选中Custom 点击 Next
- 选中 New-Workstation 5,点击Next
- 选中Linux ,Version选中Other Linux 2.6.x kernel 点击Next
- Virtual machine name 输入Client(Development) 点击Next
- Processors 选中 One, 点击Next
- Memory 输入256,点击Next
- Network connection 选中Use network address translation(NAT) (选第一个貌似也可以) 点击Next
- I/O adapter types
- SCSI Adapters 选中默认的LSI Logic(这里如果你后面使用了SCSI格式的Disk,编译内核时需要添加相应的驱动,我选择的是IDE的硬盘,kernel默认就支持了)
- Disk 选中Create a new virtual disk 点击Next
- Virtual Disk Type 选中IDE,点击Next
- Disk capacity Disk size 输入80G (下面的Allocate all disk space now不要选中,表示在真正使用才分配磁盘空间, Split disk into 2 GB files项,可不选,如果你的系统分区为fat32格式,最好选中) 点击Next.
- Disk file ,输入Disk的名称,如:disk1.vmdk ,点击Finish.完成
安装完成后,关闭计算机,然后Clone一台同样的计算机.步骤如下:
- 点击VM->Clone
- 选中默认的From current state,点击Next
- 选中Create a full clone, 点击Next
- Virtual Machine name 输入Server(Targe),将克隆的机器命令为目标机.
- Client(Development):开发机,也称客户机,将在该计算机上进行程序的开发,GDB将在本计算机上运行.用于输入命令控制Server(target)的运行.
- Server(Target): 目标机,也称服务器,就是被调试的计算机,在Development机上开发好的内核模块程序将拷贝到Target上运行,其运行受到Development命令的控制.
- Client端选择"this end is the client", "the other end is a virtual machine"
- Server端选择"this end is the server", "the other end is a virtual machine"
- 备注: 两个pipe的名称要相同,并且选中下面的Connect at power on,及Advanced里面的Yield CPU on poll
- Server(Target) 输入: cat /dev/ttyS0
系统输出的信息: hello
- Client(Development) 输入: echo "hello" >/dev/ttuS0
- 串口添加完成后,使用如果命令测试:
- 在Server上cat /dev/ttyS0
- 然后到Client上 echo "hello" > /dev/ttyS0
- 这时回到Server上,如果能看到输入的hello,说明串口通讯正常.
4:升级内核2.6.26(添加关于KGDB的选项)
说明一下,这里是要升级Server的内核,因为kgdb是要Server上运行的,但是编译需要在Client完成(或者你也可以在Server上编译,之后再拷贝到Client上),因为调试时Client上的gdb会用到编译的内核及源代码.Client也需要升级,保证Client同Server上的内核一致,这样Client上编译的模块拿到Server上加载就不会有什么问题.
首先下载kernel 2.6.26
我习惯在windows上下载,然后共享,再到linux使用smbclient连接,拷贝到Linux上.你也可以直接在linux上下载.
smbclient用法 : smbclient //192.168.0.100/share -Uadministrator 回车后,会提示输入admin的密码.之后就可以通过get获取了 192.168.0.100是我在windows主机的IP,share为共享名,-U后面是用户名
编译Kernel2.6.26
- 进入Client(Development)系统,将linux-2.6.26.tar.bz2拷贝到/usr/src目录下:
- cd /usr/src
- tar jxvf linux-2.6.26.tar.bz2
- ln -s linux-2.6.26 linux
- cd linux
- make menuconfig
- File System --> 下面把ext3,ext2都编译进内核(就是把前面的M变成*)
- Kernel Hacking -->
选中Compile the kernel with frame pointers
选中KGDB:kernel debugging with remote gdb
并确认以下两项也是选中的(他们应该默认是选中的)
> kernel debugging
> Compile the kernel with debug info - 对于其它选项,请按实际情况,或你的要求定制.
- 在其它网友的说明里面,会有Serial port number for KGDB等选项,但是我使用的版本未找到这些选项,所以忽略过.
- 保存退出
- make -j10 bzImage
-j10表示使用10个线程进行编译. - make modules
编译内核模块 - make modules_install
安装内核模块 - make install
安装内核
将Client系统中的linux-2.6.26整个目录同步到Server上.
- 在Client系统上运行下列命令:
- cd /usr/src/linux
- scp -r linux-2.6.26 root@Server(Target)IP:/usr/src/
系统会提示输入root的密码,输入完了就会开始复制文件了,(这里要注意,如果原系统已经是2.6.26的内核,可以只拷贝arch/i386/boot/bzImage,及System.map文件到Server上,然后修改/boot/grub/grub.conf,但由于我是从2.6.9升级上来,所以需要将整个linux原代码目录拷贝到Server上进行升级)
升级Srever系统的内核
- 进入Server(Target)系统,usr/src目录:
- ln -s linux-2.6.26 linux
- cd linux
- make modules_install
安装内核模块 - make install
安装内核
1 # grub.conf generated by anaconda 2 # 3 # Note that you do not have to rerun grub after making changes to this file 4 # NOTICE: You have a /boot partition. This means that 5 # all kernel and initrd paths are relative to /boot/, eg. 6 # root (hd0,0) 7 # kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00 8 # initrd /initrd-version.img 9 #boot=/dev/hda10 default=011 timeout=512 splashimage=(hd0,0)/grub/splash.xpm.gz13 hiddenmenu14 title CentOS (2.6.26)15 root (hd0,0)16 kernel /vmlinuz-2.6.26 ro root=/dev/VolGroup00/LogVol0017 initrd /initrd-2.6.26.img18 title CentOS-4 i386 (2.6.9-67.ELsmp)19 root (hd0,0)20 kernel /vmlinuz-2.6.9-67.ELsmp ro root=/dev/VolGroup00/LogVol0021 initrd /initrd-2.6.9-67.ELsmp.img注意里面的NOTICE说明,我的系统/boot是一个独立的分区,所以下面配置的文件路径都是相对于/boot/目录的,像 /vmlinuz-2.6.26,实际到它的绝对位置应该是/boot/vmlinuz-2.6.26. 在你的系统上请根据实际情况处理.
修改一下grub.conf,修改成下面这样:
1 # grub.conf generated by anaconda 2 # 3 # Note that you do not have to rerun grub after making changes to this file 4 # NOTICE: You have a /boot partition. This means that 5 # all kernel and initrd paths are relative to /boot/, eg. 6 # root (hd0,0) 7 # kernel /vmlinuz-version ro root=/dev/VolGroup00/LogVol00 8 # initrd /initrd-version.img 9 #boot=/dev/hda10 default=011 timeout=512 splashimage=(hd0,0)/grub/splash.xpm.gz13 hiddenmenu14 title CentOS (2.6.26)15 root (hd0,0)16 kernel /vmlinuz-2.6.26 ro root=/dev/VolGroup00/LogVol00 kgdboc=ttyS0,11520017 initrd /initrd-2.6.26.img18 title CentOS (2.6.26) Wait...(kernel debug)19 root (hd0,0)20 kernel /vmlinuz-2.6.26 ro root=/dev/VolGroup00/LogVol00 kgdboc=ttyS0,115200 kgdbwait21 initrd /initrd-2.6.26.img22 title CentOS-4 i386 (2.6.9-67.ELsmp)23 root (hd0,0)24 kernel /vmlinuz-2.6.9-67.ELsmp ro root=/dev/VolGroup00/LogVol0025 initrd /initrd-2.6.9-67.ELsmp.img
说明:
- 第一个启动项在原来的基础上添加了kgdb的参数kgdboc=ttyS0,115200
kgdboc 的意思是 kgdb over console,这里将kgdb连接的console设置为ttyS0,波特率为115200,如果不在内核启动项中配置该参数,可以在进入系统后执行命令:
echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc - 第二个启动项,同第一个使用同一个内核,只是添加了kgdbwait参数
kgdbwait 使 kernel 在启动过程中等待 gdb 的连接。
我的启动菜单如下:
- CentOS(2.6.26)
- CentOS(2.6.26)Wait...(kernel debug)
- CentOS-4 i386(2.6.9-67.ELsmp)
5.内核调试
重启Server,通过启动菜单第二项CentOS(2.6.26)Wait...(kernel debug)进入系统. 只到系统出现:
kgdb: Registered I/O driver kgdboc kgdb: Waiting for connection from remote gdb
进入Client系统.
- cd /usr/src/linux
- gdb vmlinux
启动gdb开始准备调试:输出大致如下:GNU gdb Red Hat Linux (6.3.0.0-1.153.el4rh)Copyright 2004 Free Software Foundation, Inc.GDB is free software, covered by the GNU General Public License, and you arewelcome to change it and/or distribute copies of it under certain conditions.Type "show copying" to see the conditions.There is absolutely no warranty for GDB. Type "show warranty" for details.This GDB was configured as "i386-redhat-linux-gnu"...Using host libthread_db library "/lib/tls/libthread_db.so.1"
- (gdb) set remotebaud 115200
- (gdb) target remote /dev/ttyS0
注意:有的文章讲:因为vmware的named piped不能被gdb直接使用,需要使用 socat -d -d /tmp/com_1 /dev/ttyS0转换,然后使用转换后的设备. socat需要自己下载安装. 但在我的环境中,直接使用并没有出错.
执行该命令后输出如下:Remote debugging using /dev/ttyS0kgdb_breakpoint () at kernel/kgdb.c:16741674wmb(); /*Sync point after breakpoint */warning: shared library handler failed to enable breakpoint
看到上面的内容说明已经连接成功,但Server上依然是假死状态,这时你可以像使用本地gdb一样设置断点(break),单步执行(step),或其它命令. - (gdb) cont
继续执行,Server就继续下面的系统初始化了.
系统启动完成后的内核调试:
进入Server后,执行命令
- echo g > /proc/sysrq-trigger
系统同样会中断,进入假死状态,等待远程gdb的连接.KGDB可能会输出如下信息:SysRq: GDB
上面的命令(echo g > /proc/sysrq-trigger)可以有一个快捷键(ALT-SysRq-G)代替,当然前提是你编译内核时需要选中相关选项,并且需要修改配置文件:/etc/sysctl.conf , 我用了一下,不太好用.因为有的桌面系统中PrintScreen/SysRq键是用于截屏的.所以还是直接用命令来的好!
我在~/.bashrc中添加了一句(添加完保存后,要执行source ~/.bashrc应用该配置):
alias debug='echo g > /proc/sysrq-trigger'
之后就可以直接输入debug来使内核进入调试状态.
6. Linux内核模块(设备驱动)的调试
编写内核模块,及Makefile
我使用的例子是Linux Device Driver 3中的例子scull. 你可以从这里下载LDD3的所有例子程序.
- 进入Client系统,解压example.tar.gz,将其中的example/scull目录拷贝到/root/scull
- cd /root/scull
- make
编译应该会出错,因为Linux Device Driver 3的例子程序是基于2.6.10内核的,请参靠下面的说明修改这些错误:
编译scull驱动,完成后,scull目录应该多出了scull.ko及其它中间文件. - scp scull.ko root@targetIp:/root/
将scull.ko模块文件拷贝到Server上.系统应该会提示输入密码:root@targetIp's password:
输入正确密码后,应该能看到如下信息,表示复制成功了:scull.ko100% 258k 258.0kb/s 00:00
然后执行:
- 进入Server系统输入:
- cd /root/
- insmod scull.ko
加载scull模块. - cat /sys/module/globalmem/sections/.text
显示scull模块的.text段地址.运行该命令后,会返回一个16进制的地址,如:0xd099a000
- echo g > /proc/sysrq-trigger
- 再次进入Client系统:
- cd /usr/src/linux
- gdb vmlinux
- (gdb) set remotebaud 115200
- (gdb) target remote /dev/ttyS0
Remote debugging using /dev/ttyS0kgdb_breakpoint () at kernel/kgdb.c:16741674wmb(); /*Sync point after breakpoint */warning: shared library handler failed to enable breakpoint
出现上面的信息表示连接成功,但此时还不可以设置断点.我试了N次,现在设置端点后,无论Server上对scull做什么操作,Client上的gdb都不会停止.也有人说这是gdb的BUG,gdb无法正常解析内核模块的符号信息. 说是下载kgdb网站上的gdbmod可以解决该问题,但我试了之后发现根本没有用. 所以只能通过命令手动加载相关符号信息: - (gdb) add-symbol-file /root/scull/scull.ko 0xd099a000
注意: 0xd099a000地址是在上面获取的,命令输入完了,系统会有如下提示信息(第二行后面的y是自己输入的:add symbol table from file "/root/scull/scull.ko" at .text_addr = 0xd099a000(y or n)yReading symbols from /root/scull/scull.ko...done.
- (gdb)break scull_write
Breakpoint 1 at 0xd099a2d9: file /root/scull/main.c,line 338.
- (gdb)break scull_read
Breakpoint 2 at 0xd099a1a2: file /root/scull/main.c,line 294
- (gdb)cont
Continuing
- Server现在处于运行状态,在Server上运行下面的命令:
- cat /proc/devices | grep "scull"
查看scull模块分配的major.我的系统中返回如下:253 scull253 scullp253 sculla
- mknod /dev/scull c 253 0
253是刚才查询到的版本号. - echo "this is a test " > /dev/scull
测试输入函数:scull_write. 该命令输入完成后,进程应该会停下来, 请切换到Client系统. - cat /dev/scull
测试输出函数:scull_read. 该命令输入完成后,进程应该会停下来, 请切换到Client系统.
- 回到Client系统,应该能看到gdb的输出信息:
Breakpoint 1, scull_write (filp=0xce5870c0,buf=0xb7f44000 "this is a test/nias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'/n",count=15,f_pos=0xce5c5f9c) at /root/scull/main.c:338338 { (gdb)_
以同样的方法也可以调试其它函数.(初始化函数暂时没想到办法调试,因为使用这种方法需要先加载后,才可以进行调试)
你可以自由使用和转载本文档,转载时请注明出处. (jie123108@163.com)
如果可以,我想写一个脚本自动完成这个添加符号文件的过程,简化调试过程.
Linux Device Driver 3rd中的scull 例程在2.6.26上编译出错的问题
- 1。scripts/Makefile.build:46: *** CFLAGS was changed in "examples/scull/Makefile". Fix it to use EXTRA_CFLAGS。 停止。
解决方法:将 Makefile 中的 CFLAGS 改为 EXTRA_CFLAGS - 2. examples/scull/main.c:17:26: error: linux/config.h: 没有该文件或目录
解决方法: 将 main.c 中的这条 include 语句注释掉。 - 3. examples/scull/access.c: 在函数‘scull_u_open’中: examples/scull/access.c:107: 错误: 提领指向不完全类型的指针
解决方法:access.c 中添加:#include <linux/sched.h> - 4. examples/scull/access.c: 在函数‘scull_access_setup’中:
examples/scull/access.c:355: 警告: 格式字符串不是一个字面字符串而且没有待格式化的实参
解决方法:将 kobject_set_name(&dev->cdev.kobj, devinfo->name); 改为:
kobject_set_name(&dev->cdev.kobj, "%s", devinfo->name);
因为 kobject_set_name 有一个像 printf 一样的参数表。 - 补充 : 老外作的改动http://www.cs.fsu.edu/~baker/devices/lxr/source/2.6.25/ldd-examples/基本上已经可以编译了
<<Using 2.6.26 Linux Kernel Debugger (KGDB) with VM>>
<<VMware环境下用kgdb调试内核>>
<<Using 2.6.26 Linux Kernel Debugger (KGDB) with VM>>
- 在VMware环境下使用KGDB调试Linux内核及内核模块
- 在VMware环境下,使用KGDB调试内核及内核模块---基于kernel 2.6.26
- 在VMware环境下,使用KGDB调试内核及内核模块---基于kernel 2.6.36
- 在VMware环境下,使用KGDB调试内核及内核模块---基于kernel 2.6.36
- 在VMware环境下,使用KGDB调试内核及内核模块---基于kernel 2.6.26
- 在VMware环境下,使用KGDB调试内核及内核模块---基于kernel 2.6.36
- 在VMware环境下,使用KGDB调试内核及内核模块---基于kernel 2.6.36
- (转载)使用kgdb调试linux内核及内核模块
- (转载)使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- (转载)使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- 转 使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- 洛神赋
- MyEclipse快捷键大全
- python3-网络编程-TypeError: send() argument 1 must be bytes or buffer, not str异常
- 5.关于精灵runAction无效果的bug的解决方案。
- 谈谈Java虚拟机——Class文件结构
- 在VMware环境下使用KGDB调试Linux内核及内核模块
- 空间中直线之间距离介绍及原码
- 解决 CentOS 6.4 升级 Python2.7 后 Ibus 输入法无法使用问题
- contrastive divergence 算法
- widow下svn上传项目时的文件可执行权限问题
- Fragment和Activity
- 关于s3c2440+linux2.6.34.14KGDB的使用
- HDU-OJ-1698 Just a Hook
- 母猪的产后护理