0.前言
本文讲述搭建环境的关键环节,相应的工具及版本如下:
JDK:1.6.0_45
Eclipse:eclipse-cpp-kepler-SR2-linux-gtk-x86_64.tar.gz
Qemu:QEMU emulator version 1.5.0 (Debian 1.5.0+dfsg-3ubuntu5.3)
OS:Ubuntu13.10,64bit
其中,JDK 和 Eclipse 工具下载和配置可查阅“参考资料 a”,而在我的 OS 环境里 Eclipse 会有菜单显示问题,可查阅“参考资料 c”。
1.安装 Eclipse 插件 CDT
运行 Eclipse,点击菜单“Help”->“Install New Software...”,在弹出的对话框里点击“Work with:”后面的下拉按钮,选择“Kepler – http://download.eclipse.org/releases/kepler”(不同的 Eclipse 版本选择不一样,与自己下载的版本一致一即可),然后在下面的选择框中将“Programming Languages”的“C/C++ Autotools support”和“C/C++ Visual C++ Support”这两项(对应http://download.eclipse.org/releases/juno 包里的 CDT)以及“C/C++ Development Tools”和“C/C++ Development Tools SDK”选中,接下来点击“Next >”按钮两次和“Finish”一次(共显示 3 个页面),注意其间要选中接收条款,剩下就是自动连网下载安装选中的软件包,安装好后自动重启Eclipse 即可。其中配置 CDT 的界面如下:
除了上面与 C/C++相关的工具,还需要安装与 Linux 相关的 GDB,将“Linux Tools”里的“GDB Tracepoint Analysis”和“Mobile and Device Development”里的“C/C++ GDB Hardware Debugging”选中安装上,如下截图:
注:上面装的工具有些过多,可自行删减,这里是满足更多需求,将相关的全安装上了。
2.安装 QEMU
执行如下命令即可安装下 QEMU 各平台的模拟工具:
sudo apt-get install qemu
3.配置联调环境
在上面的工具安装好后,接下来就是要配置联调环境了,首先先把 QEMU 运行起来,执行如
下命令:
qemu-system-x86_64 -s -S -kernel ~/linux-3.13.6/arch/x86_64/boot/bzImage -initrd /boot/initrd.img-3.11.0-12-generic
这里我们模拟的是 64 位的 X86,用到的 Kernel 为“参考资料 b”编译好的,而用到的 Ram Disk则是 Ubuntu13.10 里自带的,这里的-s 和-S 在帮助里分别说明如下:
-s shorthand for -gdb tcp::1234
-S freeze CPU at startup (use 'c' to start execution)
即-s 为开启 GDB 的调试端口 1234,而-S 则表示运行 QEMU 时冻结住,等待 GDB 执行(c)ontinue 操作。
就这样先执行着,不进行跟QEMU 相关的其他操作,QEMU 一直处于黑屏状态(Pause 状态),等待远程 GDB 的一个 c,接下来配置 Eclipse 环境:a.点击菜单“Window”->“Preferences”,在弹出的对话框中,点击左边的“General”->“Workspace”,将右边的“Build automatically”复选框不选中。再点击对话框左边的“C/C++”->“Indexer”,将右边的“Enable indexer”和“Automatically update the index”两复选框不选中。
b.接下来创建一个工程,点击菜单“File”->“New”->“Project...”,在弹出的对话框中选择“C/C++”->“C Project”,再点击“Next >”按钮,出现的对话框配置如下:
其中,“Project name:”为工程名,可自定义;而“Location:”则为工程文件所在路径,此处设置为 Linux Kernel 源码目录,而“Project type:”则设置为“Makefile project”/“Empty Project”,“Toolchains:”则设置为“Linux GCC”,最后点击“Finish”即可。
c.接下来进行 DEBUG 配置,在“Project Explorer”里右击刚创建的“Linux_Kernel_3.13.6”项目,在右键菜单中点击“Debug As”->“Debug Configurations...”,在弹出的对话框中双击“C/C++ Remote Application”,配置如下截图:
将“C/C++ Application:”栏设置为 Linux Kernel 源码编译出来的 vmlinux 文件所在路径(包含文件名),然后将“Disable auto build”选上,切换到“Debugger”页,修改配置如下截图:
将“Stop on startup at”设置为 start_kernel(Linux Kernel 的入口函数),将“Port number:”设置为之前 QEMU 运行时的默认端口号 1234,“Apply”后再点击上图中的“Debug”按钮开始调试,此时会切换到如下界面:
至此,调试环境也配置好了,接下来是试验下能不能调试了。
d.此时,满心欢喜的等看结果,发现 QEMU 的状态是 Paused,如下截图:
想想肯定是 GDB(我的系统 GDB 版本为 7.6.1)搞鬼,又回到 Eclipse 下查看了, 双击上面Eclipse 调试界面的“Console”标题,让该页最大显示,再点击其右边的“Display Selected Console”按钮(小显示器图标),有如下截图:
原来是有“Remote ‘g’ packet reply is too long:”卡住了,在接下来的“后记”里有说到, 往上跟踪执行的提示,发现有如下内容:
637,056 12source .gdbinit
637,056 &"source .gdbinit\n"
637,057 &".gdbinit: No such file or directory.\n"
637,057 12^error,msg=".gdbinit: No such file or directory."
于是想在当前工程根目录下创建一个.gdbinit 文件,然后把“后记”里的那句设置架构的语句放上,但是没效,继续跟踪上面的提示,有如下内容:
644,425 17-target-select remote localhost:1234
644,446 =thread-group-started,id="i1",pid="42000"
644,446 =thread-created,id="1",group-id="i1"
发现.gdbinit 是在 remote 连接前先执行,而设置架构是在连接后再设置的,故而也不是办法,只好另找出路了。
从网上找到需要修改 GDB 源码重新编译,故而我们也试试吧。首先,下载 GDB 源码:
cd ~/dev_tools
wget http://ftp.gnu.org/gnu/gdb/gdb-7.7.tar.gz
下载完成后进行解压和修改代码:
tar xvf gdb-7.7.tar.gz
cd gdb-7.7/
修改 gdb/remote.c 文件,在 process_g_packet 函数里,将如下代码:
if (buf_len > 2 * rsa->sizeof_g_packet)
error (_("Remote 'g' packet reply is too long: %s"), rs->buf);
更改为:
if (buf_len > 2 * rsa->sizeof_g_packet) {
rsa->sizeof_g_packet = buf_len ;
for (i = 0; i < gdbarch_num_regs (gdbarch); i++) {
if (rsa->regs[i].pnum == -1)
continue;
if (rsa->regs[i].offset >= rsa->sizeof_g_packet)
rsa->regs[i].in_g_packet = 0;
else
rsa->regs[i].in_g_packet = 1;
}
}
更新代码完成后接着配置、编译和安装:
./configure –prefix=/home/xinu/dev_tools/mygdb
make
make install
GDB更新好后,接下来重新配置下 Eclipse,点击菜单“Run”->“Debug Configurations...”,在弹出的对话框中,切换到“Debugger”下的“Main”页,修改“GDB debugger:”为刚编译出来的 GDB,而不是默认的 gdb,相应的.gdbinit 也可在该页设置,如下截图:
配置好“Apply”后,再点击“Debug”,此时 QEMU 仍是停在上面的截图位置,但 Eclipse 已停在上图的“start_kernel”处,接下来就可以任我虐了(Step Into、Step Over 等 Step 调试),有如下截图:
从上图可以看到断点位置相关的源码和汇编代码,这样就可以方便我们跟踪阅读 Kernel 的执行流程,学习 Kernel 的精辟设计思想。
4.后记
在使用 gdb 调试时会有如下错误提示:
Remote 'g' packet reply is too long: d85f8780ffffffff88......
省略号(......)表示后面还有一长串 16 进制数,解决的方法是在进行 gdb 操作前先在(gdb)后面执行如下语句:
set architecture i386:x86-64:intel
请根据实际情况配置,这个问题是 GDB 调试 64 位 Kernel 时才有的。我机器上有如下可选参数:
(gdb) set architecture
Requires an argument. Valid arguments are i386, i386:x86-64, i386:x64-32, i8086, i386:intel,i386:x86-64:intel, i386:x64-32:intel, auto.
5.参考资料
a.《Eclispe+qemu+gdb 调试 linux Kernel 全过程 》
http://yyqing.me/blog/2013/03/06/eclisep-plus-qemu-plus-gdbdiao-shi-linux-kernelquan-guo-cheng/
b.《为 Ubuntu 换颗“心”》
c.《Ubuntu13.10 下 eclipse 主菜单下拉菜单无显示》
http://blog.sina.com.cn/s/blog_3e4774e30101r24i.html
d.《【记录】给 Eclipse 安装 CDT 插件》
http://www.crifan.com/install_eclipse_cdt_plugin/
e.《利用 KVM 调试内核》
http://lenky.info/archives/2012/05/12/1624
f.《linux 内核调试:qemu+eclipse 组合》
http://blog.csdn.net/ustc_dylan/article/details/5991490
g.gdb-remote-7.x.patch
https://github.com/xinhaoyuan/ucore-mp64/blob/master/misc/gdb-remote-7.x.patch