本文希望能给想用ubuntu12.04做主机,vmware做虚拟机,搭建宿机内被gdb远程调试环境的人做参考。
环境搭建:
1. 宿机准备:
1.1.2 配置并编译内核,并安装,同时升级grub引导菜单。也就是说,新编译安装的内核也让grub进行引导。
http://blog.csdn.net/dndxhej/article/details/7171805
其中这个选项很重要,一定要选上,这个就是我们开机时,让内核等待远程连接进行调试或者是用魔术键停止内核,更或是用kdb停止时,远程gdb连接的基础,停止内核的魔术键也一定要看弄好。
KGDB:kerneldebugging with remote gdb
有关kgdb的选项都选上,可以参考上边的链接,完成配置。我也关注了下魔术键的开启,给我的感受,可能kgdb只要开启了kgdb调试的相关选项,魔术键的环境变量也很自然会跟随变化。
大家关注一下是否选中即可。
编译没什么可说的,make完等着就行了。
1.1.2 内核安装
安装参考linux内核api编程第一章中的预备知识部分,记得在安装之前虚拟机做快照,启动菜单做备份。
1.1.3 修改grub引导启动菜单
$ uname -r
2.6.30-kdb-kgdb-nat
这是我自己定制的内核版本号
修改/boot/grub/menu.lst菜单,在启动内核的一行,在ro locale=zh_CN 和 quiet splash 之间添加上 kgdb=ttyS1,115200 kgdboc=ttyS1,115200 kgdbwait
当然了,这个其中对应的串口id还有待确定。这个意思是让gdb远程调试内核,并用串口1,波特率115200作为链接,kgdbwait是让内核启动时等待远程链接。
如果不是启动时选择,也可以在启动后设置。
1)
$echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc
2) $echo "g"> /proc/sysrq-trigger,再次触发
title Ubuntu 9.04, kernel 2.6.30-kdb-kgdb-nat
uuid 2e725837-e491-4fbf-a91c-98d4fb46c8bd
kernel /boot/vmlinuz-2.6.30-kdb-kgdb-nat root=UUID=2e725837-e491-4fbf-a91c-98d4fb46c8bd ro locale=zh_CN kgdb=ttyS1,115200 kgdboc=ttyS1,115200 kgdbwait quiet splash
initrd /boot/initrd.img-2.6.30-kdb-kgdb-nat
quiet
虚拟机内宿机环境暂时搭建完毕,我们说的暂时,如果情况不对,可能还要继续调整,这是我最终的启动菜单样貌。
2.虚拟机设置:
2.1 添加串口:
虚拟机设置用到的最难的知识点就是用有名管道模拟串口,在我当前的vmware 9下,可以设置上有名管道,设置上之后看各方面的表象也设置成功了,但觉得不知道怎么入手测试是否成功。
首先关闭虚拟机的宿机系统,然后选虚拟机的设置=》添加,添加一个serial 串口-》复选框三个选项选择named pipe 有名管道-》键入一个有名管道的绝对路径文件名(可以是存在的,但会被重写,最好设置在普通用户就有都写权限的地方,我的是跟我宿机一个路径)-》再往下是选择from server(虚拟机内的内核启动,作为一个服务器,会等带gdb远程链接)to appication (到一个应用,到我们主机gdb连接去调试),接下来的选项是可选的,选上好,cpu工作于多路io状态。
还有device state 设备的状态,单选框选上,让串口在开机的时候链接。
这个过程选完就,每当虚拟机内的虚拟开启时,vmware都会以我们刚才命名的键入的名字作为套接字的本地文件,自动建立一个unix domain socket的套接字。所以刚开启启动时的选项一定要选中,而且首先建立起串口,后续借用串口远程调试内核以及内核在启动阶段等待链接,才能满足前提。
2.2 调试串口,这部分的工作,是我最头疼的部分。
其实在我搭建这个环境期间,都已经很多次的与真相擦肩而过了,就差一层窗户纸的问题。
2.2.1 主机准备:
主机上用到工具有几个,我们先说当中一个minicom
minicom是支持直接读取管道文件的,这是令我没想到的:
配置minicom默认配置:
$ sudo vim /etc/minicom/minirc.dfl
添加:pu port unix#/media/Office/ubuntu9.04/serial.socket
保存,退出
这个就是默认minicom的启动文件,这样设置,是用minicom直接打开了,我们虚拟机刚设置的有名管道文件,从unix#的部分,与我们在虚拟机当中键入的有名管道文件名字是要一致。不难看出来unix#就是minicom读取一个unix domain socket文件的语法。
运行minicom,进入等待状态
界面显示出了所要读取文件的绝对路径名。
这时候主机作为观察者等着就行了,剩下就是宿机的工作。
2.2.2 宿机准备:
在虚拟机配置的过程中,我们不难发现,当你配置完串口的时候,你并不知道,虚拟机虚拟有名管道虚拟到了宿机内的哪个串口文件。
没办法,我就得自己去确认,这就是为什么,上边我说的是暂时配置成启动菜单是ttyS1的选项。
以下是发现也是测试过程过程:
一般串口文件都是/dev/ttySN,其中最后一个字母大n是个数字,我们只对这样的文件做操作,向这种文件里写内容,看主机minicom的输出,如果提示没有权限,就切换到超级用户下。
$ echo 1 > /dev/ttyS1
结果在我的环境下,ttyS1写入时,minicom有输出了。
好了,这就证明,我们宿机的串口,可以和主机之间形成的管道文件直接通信了,注意,我们这里用直接读取的是管道文件,并不是串口,gdb调试是要串口之间的通信。不过没关系,现在,宿机和虚拟机的环境搭建都没有问题了,下面我们集中经历解决主机上怎么和这个串口通信,怎么用gdb调试。
还有一点顺便要说明,现在可以确定,写入虚拟机宿机启动菜单menu.lst的串口文件名到底是哪个了,写入便是,就是本文的1.1.3部分,回头查查,写进启动菜单,正确的串口名。
现在不要重启,还有工作要做。
3. 主机环境搭建:
3.1 主机gdb调试源文件准备
现在将虚拟机内,我们刚才编译好的linux内核文件根目录下,生成的两个文件vmlinux和System.map,这个两个文件拷贝到主机一样的源码目录下。意思就是说,这个两个文件,加上生成这个两个文件的源码,用作gdb调试只用,gdb调试时就是在调试vmlinux这个文件,System.map是符号表,将可执行文件与源码对应起来,而且vmlinux是未压缩过的,以我的2.6.30为例,开启kgdb调试选项之后51M,而原来没有开启这个选项的vmlinux文件则只有2M
,大了许多,不过这也是必不可少的。
3.2 宿机内核重启
如果个方面设置都成功的话,虚拟机中的宿机重启应该这样样子:
这时候他在等待客户端链接
3.3 利用socat工具,让有名管道文件,变为串口:
办法很简单,利用一个工具,socat 感兴趣可以man一下这个工具到底都能做哪些事,顾名思义,在我理解是socket cat,名字起的有点中国汉语顶针味道,没有这个工具当然apt-get一个就行了,而在我们这里,我们要用的命令是:
$ socat -d -d /media/Office/ubuntu9.04/serial.socket pty &
这时候有很多东西就都体现作用了,原来设置文件的路径,设置成当前用户就能都写的位置,这个时候就方便了,而这个命令的执行是做了这么一件事:
他将我们主机与宿机之间通信的有名管道/media/Office/ubuntu9.04/serial.socket文件,映射成为了一个串口,如何体现串口的那,在-d -d两个选项上,这个命令执行之后,这个管道文件的输出被绑定在了哪个串口上,就显示在屏幕上,提示给我们了。
让我多次与正确调试方法擦肩而过的,就是这里,我没理解这个程序要一直运行才一直生效,而是每次运行之后,ctrl+c杀掉,然后也不见gdb能链接上。
后来摸索到,有豁然开朗的赶脚,但也觉得,这就是层窗户纸。
2015/05/18 18:51:55 socat[8771] N PTY is /dev/pts/1
而整个命令后我加了一个&,这是让这个进程挂在后台,我们做是有原因的,而且是比较头疼的教训:
第一,这个程序事实上是以守护进程的方式,或是说一直运行的方式,才能保持将管道文件绑定到相应的串口上。
第二,我们还要利用这个端口继续做剩下的事情。那就是利用当前shell启动gdb调试,而socat只需要还在运行就行。
3.4 gdb链接调试
进入到我们刚才宿机系统中编译生成的vmlinux文件拷贝的主机内核文件源码路径。就是说,把虚拟机生成的两个文件复制到同版本的源码路径下之后,进入到源码路径的根目录下,只有这么做,运行起来gdb时,才能跟踪现实代码。
然后运行gdb
$ gdb vmlinux
很明显,gdb空格编译后未经压缩的内核可执行文件
以下是进入到gdb调试环境下的gdb对串口的设置
设置波特率
(gdb) set remotebaud 115200
设置远程文件
(gdb) target remote /dev/pts/1
Remote debugging using /dev/pts/1
kgdb_breakpoint () at kernel/kgdb.c:1721
1721 wmb(); /* Sync point after breakpoint */
qTStatus: trace API error 0x2.
回车之后,就会看见内核停止的位置,按c简写continue继续执行。
Continuing.
qTStatus: trace API error 0x2.
我这个是有些api的跟随的配置,在配置内核编译选项时并未开启导致的,不影响代码调试,需要的时候可开启
这时候在看虚拟机系统,如正常时的启动过程了,事实上,这个时候宿机内的内核运行执行的输入输出,都通过有名管道模拟的串口,主机进行了交互。
以下是我主机运行起socat和gdb以及全部调试信息时的样貌。
4. 再提供几个可能方法:
4.1 grub引导命令简单调试:
如果宿机内的系统运行不正常的话,比如开机时并未做为服务器,等待客户端链接,那么可进入到grub界面,对grub启动的引导行进行手动改写,以确认是否是设置错误,直到改写正确。或者你已经设置好启动是内核等待gdb远程连接,你不想做这个操作,想让内核正常启动,那你就也手动编辑grub引导菜单。
方法很简单,开机等待三秒的时候按ESC,进入grub
在对应要启动哪个内核我选项上按E (edit编辑),进入到该选项详细的启动命令,这时候看到的和menu.lst文件的每个启动选项是一直的
我们这里基本上就编辑kernel开头的的那一条,引导内核,当然了,还是按E,对其进行编辑,编辑完,按回车,确认编辑内容,并返回刚才的启动选项菜单,然后就剩下启动了,按b(boot 启动),ok了
4.2 启动之后内核停止的调试方法:
1)
$echo ttyS0 > /sys/module/kgdboc/parameters/kgdboc
2) $echo "g"> /proc/sysrq-trigger,再次触发
主机端跟内核启动时链接是一样的。
参考文章:
http://blog.csdn.net/dndxhej/article/details/7171805
minicom:
http://blog.163.com/wenwen10090215@126/blog/static/17332211420144983925757/
http://blog.chinaunix.net/uid-27717694-id-4051339.html