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 的界面如下:

Eclipse CDT plugin install screenshot

除了上面与C/C++相关的工具,还需要安装与Linux相关的GDB,将“Linux Tools”里的“GDB Tracepoint Analysis”和“Mobile and Device Development”里的“C/C++ GDB Hardware Debugging”选中安装上,如下截图:

Eclipse GDB plugin install screenshot

注:上面装的工具有些过多,可自行删减,这里是满足更多需求,将相关的全安装上了。
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-g0.前言eneric
这里我们模拟的是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 >”按钮,出现的对话框配置如下:

Eclipse Create Project Screenshot

其中,“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”,配置如下截图:

Eclipse Debug Configurations screenshot

将“C/C++ Application:”栏设置为Linux Kernel源码编译出来的vmlinux文件所在路径(包含文件名),然后将“Disable auto build”选上,切换到“Debugger”页,修改配置如下截图:

Eclipse Debug Configurations Debugger  Settings Screenshot

将“Stop on startup at”设置为start_kernel(Linux Kernel的入口函数),将“Port number:”设置为之前QEMU运行时的默认端口号1234,“Apply”后再点击上图中的“Debug”按钮开始调试,此时会切换到如下界面:

Eclipse Debug Screenshot

至此,调试环境也配置好了,接下来是试验下能不能调试了。
d.此时,满心欢喜的等看结果,发现QEMU的状态是Paused,如下截图:

QEMU running Screenshot

想想肯定是GDB(我的系统GDB版本为7.6.1)搞鬼,又回到Eclipse下查看了, 双击上面Eclipse调试界面的“Console”标题,让该页最大显示,再点击其右边的“Display Selected Console”按钮(小显示器图标),有如下截图:

Eclipse GDB Console screenshot

原来是有“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更新好后,上面配置安装到/home/xinu/dev_tools/mygdb目录下。接下来重新配置下Eclipse,点击菜单“Run”->“Debug Configurations…”,在弹出的对话框中,切换到“Debugger”下的“Main”页,修改“GDB debugger:”为刚编译出来的GDB,而不是默认的gdb,相应的.gdbinit也可在该页设置,如下截图:

Eclipse Debug Configurations Debugger GDB path setting screenshot

配置好“Apply”后,再点击“Debug”,此时QEMU仍是停在上面的截图位置,但Eclipse已停在上图的“start_kernel”处,接下来就可以任我虐了(Step Into、Step Over等Step调试),有如下截图:

Eclipse Debug Breakpoint screenshot

从上图可以看到断点位置相关的源码和汇编代码,这样就可以方便我们跟踪阅读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换颗“心”》
http://x-slam.com/wei_ubuntu_huan_ke_xin
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