声明:
本笔记内容并非本人原创,90%来自网络资料的整合。同时,由于自己是刚刚接触qemu & gdbserver remote debug,本文也就算不得教程,仅供有缘人参考而已。
------------------------------------------------------------------------------------------------分割线---------------------------------------------------------------------------
step 1: kernel 编译环境安装
apt-cache search build-essential sudo apt-get install build-essential -y apt-cache search libncurses-dev sudo apt-get install libncurses-dev -y
当然,可能还需要其他一些工具,如果gcc g++ make 之类的工具,毕竟build-essential是一个工具箱子,若有洁癖,可能就有点冲突。而ncurses-dev,这个是必须要有的,我记得在fedora上是直接yum install ncurses-dev即可,.deb系列的似乎是加了个前缀。
step 2: gdb的安装
需要告诉的是,build-essential 里应该是包含了一个gdb & gdbsever工具了,但是很抱歉的是无法使用,会出现这个错误:
Remote 'g' packet reply is too long: 000000000000000020000000000000004000000000000000001006000000000000f009000000000028aece81ffffffff981fc081ffffffff901fc081ffffffff0030c1010000000000000000000000000000000000000000f0b926020000000020f1d281ffffffffb01fc081ffffffff00e0e681ffffffff0010e781ffffffff02fbd281ffffffff9600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
于是,我们需要去下载一个比较新的gdb source下来(我使用的是7.8),网址是: http://ftp.gnu.org/gnu/gdb/
http://ftp.gnu.org/gnu/gdb/
然后按照网络前人们共享出来的资料,修改gdb的源码: 在 gdb-7.8/gdb/remote.c 文件的 static void process_g_packet (struct regcache *regcache)函数里面修改部分内容,如下:
1 static void 2 process_g_packet (struct regcache *regcache) 3 { 4 struct gdbarch *gdbarch = get_regcache_arch (regcache); 5 struct remote_state *rs = get_remote_state (); 6 struct remote_arch_state *rsa = get_remote_arch_state (); 7 int i, buf_len; 8 char *p; 9 char *regs; 10 11 buf_len = strlen (rs->buf); 12 13 /* Further sanity checks, with knowledge of the architecture. */ 14 /* if (buf_len > 2 * rsa->sizeof_g_packet) 15 error (_("Remote 'g' packet reply is too long: %s"), rs->buf); 16 */ 17 /*modify by xx*/ 18 if (buf_len > 2 * rsa->sizeof_g_packet) { 19 rsa->sizeof_g_packet = buf_len; 20 for (i = 0; i < gdbarch_num_regs(gdbarch); i++) { 21 if (rsa->regs[i].pnum == -1) 22 continue; 23 if (rsa->regs[i].offset >= rsa->sizeof_g_packet) 24 rsa->regs[i].in_g_packet = 0; 25 else 26 rsa->regs[i].in_g_packet = 1; 27 } 28 } 29 //....... 30 } 31 } 32 }
上面的14-15行是原来文件的,而18-27行是重新添加上的 <为了节约版面,我没有贴后面的,所以,注意 " { } " 可能导致的语法错误>,这样修改的具体原理,本人并不清楚,但确实解决了问题。
修改完整后,就开始编译gdb吧。在 gdb-7.8/ 下执行下面的命令:
1 ./configure --prefix=../../tools/ 2 make 3 make install
需要注意的是在gdb-7.8/ 目录下并没有Makefile文件,需要使用 ./configure来生产。在配置的时候,如果要指定gdb安装的路径(目录),那么就需要跟上 --prefix=$PATH的相关参数,一般这种情况可能会针对系统已经有一个gdb了但无法使用,同时也未删除,那么新编译的gdb可能需要安装在另外的目录了。当然我自己的是安装在 ../../tools/ 目录下。
step 3: 编译linux kernel
去 www.kernel.org下载自己需要的版本,待完毕后,对kernel编译生成bzImage & vmlinux 文件。如果是和我一样刚入门的,可以参考以下命令&步骤:
cd linux-3.12.35/ cp /boot/config-3.13.0-43-generic .config make menuconfig <save> make bzImage
需要说明的是,具体要看哪些调试信息,应该在make menuconfig的时候去配置,去选择,然后保存好后,就编译。编译后,bzImage这个是被压缩了的,供qemu虚拟机使用,vmlinux里面带了某些信息,没有压缩,供gdb使用。
当编译结束后,可以将vmlinux bzImage文件copy到一个干净的目录下吧---这个随自己的习惯了,不copy也无所谓了。
上面忘记了准备最重要的东西了: qemu
step 4: qemu的使用
简单说下: qemu 是一款虚拟机,可以模拟x86 & arm 等等硬件平台<似乎可模拟的硬件平台很多...>,而qemu 也内嵌了一个 gdbserver。这个gdbserver于是就可以和gdb构成一个远程合作伙伴,通过ip:port 网络方式或者是通过串口/dev/ttyS*来进行工作,一个在这头,一个在那头。
至于安装qemu虚拟机,可以通过源码编译,make & make install ,在这里可以下载:http://wiki.qemu.org/Download。也可以直接在ubuntu 软件包里apt-get install qemu-kvm即可。这里不详细记载了。当安装后,可能的文件是这些:
1 qemu-system-i386 2 3 qemu-system-x86_64 4 5 qemu-img 6 7 qemu-io 8 ....
这个是什么意思呢? 第一行的表示是 i386机器上使用的qemu虚拟机,第二行表示是 x86_64上使用的虚拟机。另外的就没使用过了。具体的请参考官网文档:http://wiki.qemu.org/Main_Page。当然,我自己的系统是 x86_64的,使用的是第二个。
step 4: 让kernel为你稍带片刻~
1 qemu-system-x86_64 -kernel ./bzImage -initrd ./initrd.img -smp 2 -gdb tcp::1234 -S
先使用命令启动qemu。
qemu-system-x86_64的参数比较多,这里简单说下:
-kernel 是指定一个大内核文件,当仁不让的是bzImage。
-initrd 是指定一个 initrd.img文件,这个文件可以从 /boot/initrd.img-3.13.0-43-generic 拷贝而来,关于它是什么东西呢? 可以参考这个: http://www.linuxfly.org/post/94/ ,或者是这个 http://blog.csdn.net/chrisniu1984/article/details/3907874 。
-smp 可以从名字猜想,它是给qemu指定几个处理器,或者是几个线程<嗯,大概意思就thread吧>。
-gdb则是启动qemu的内嵌gdbserver,监听的是本地tcp端口1234---如果这样写: -gdb tcp:192.168.1.100:1234 ,似乎也是没问题的。
-S 就是挂起gdbserver,让gdb remote connect it。还有一个-s,那是另外一种情况要使用了。
如果自己嫌敲命令麻烦<虽然那很酷>,可以使用以下的方式,将该命令保存到某个文件中,比如 qemu.start:
1 #!/bin/bash 2 qemu-system-x86_64 -kernel ./bzImage -initrd ./initrd.img -smp 2 -gdb tcp::1234 -S 3 <save> 4 chmod +x qemu.start 5 6 ./qemu.start
这样就可以启动qemu了 <注意自己的 bzImage & initrd.img 文件的路径>
提示: man qemu-system-x86_64,你会获得一些帮助。
step 5: 使用gdb去连接已将启动了的qemu:
1 ../tools/gdb/bin/gdb vmlinux 2 3 ----- 4 GNU gdb (GDB) 7.8 5 Copyright (C) 2014 Free Software Foundation, Inc. 6 License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 7 This is free software: you are free to change and redistribute it. 8 There is NO WARRANTY, to the extent permitted by law. Type "show copying" 9 and "show warranty" for details. 10 This GDB was configured as "x86_64-unknown-linux-gnu". 11 Type "show configuration" for configuration details. 12 For bug reporting instructions, please see: 13 <http://www.gnu.org/software/gdb/bugs/>. 14 Find the GDB manual and other documentation resources online at: 15 <http://www.gnu.org/software/gdb/documentation/>. 16 For help, type "help". 17 Type "apropos word" to search for commands related to "word"... 18 Reading symbols from vmlinux...done. 19 ----- 20 21 (gdb) target remote : 1234 22 Remote debugging using : 1234 23 0x0000000000000000 in irq_stack_union () 24 25 (gdb) b start_kernel 26 Breakpoint 1 at 0xffffffff81d2fb02: file init/main.c, line 476. 27 28 (gdb) c 29 Continuing. 30 31 Breakpoint 1, start_kernel () at init/main.c:476 32 476 { 33 34 35 (gdb) n 36 485 smp_setup_processor_id(); 37 (gdb) n 38 491 boot_init_stack_canary(); 39 (gdb) n 40 493 cgroup_init_early();
第一行表明启动我自己编译的gdb,这有两个方式 : gdb fileName 启动,或者 gdb启动后,再使用 file fileName 启动
第21行表明连接远程gdbserver,由于这是在同一台笔记本上,就没有指定ip地址,仅仅指定了port号码。----当然,如果是连接uart口,也行。
第25行,是break一个断点,在某个函数的入口处 。
第28行,应该是发一个命令,让qemu那边继续运行的意思,这个时候,qemu那边的屏幕上会闪现出:"Booting from ROM..."
后面啊,就是下一步下一步的意思咯: next ... next ... 当然,也可以选择step step s.... 直到哪里才会在qemu那边打印消息呢? 要在 console_init();这行代码后才会的。
做一个稍微重要的说明: 我这里并没有启用文件系统,如果有需要,可以试着用busybox做一个,然后参考qemu kernel调试手册,或者网络资源进行加入调试即可。
--------------------------------------------------------------------------------------扯淡分割线--------------------------------------------------------------------------------------------
后记:
至于gdb 的命令,还有很多很多,如果是new to kernel的话,请点击这里: http://www.sourceware.org/gdb/ 最好的是慢慢啃官网文档,然后再看看别人的理解,应该就差不多了。或者看看这个: http://www.yolinux.com/TUTORIALS/GDB-Commands.html
这几天也一直在搜索kernel debug的方法,qemu+gdb 是一种,当然也还有其他的方法。不过总结下来,代价以qemu+gdb最小。如果你是大屏幕pc,可以试试将qemu+gdb+eclipse这样,纳入IDE环境。而自己是笔记本,就不凑合IDE了,在vim shell 下足以。
稍微夹杂一点想法: 前面也是看了一些操作系统的书+linux kernel的入门读物,但是一直没机会去试着单步运行以下kernel,看看它是怎么走的<书中搭建方式花销比较大:要么就是两台电脑,要么就是搞一半就会放弃的那种>。久而久之,也就懈怠了,更别说再去详细的看代码了。linux kernel是真的很伟大,但没必要神话它。如果对操作系统原理和程序设计的理解达到一定水平,自己也可以整一个OS---尽管那可能会很粗糙。于是,知行合一也就有必要了。
最后就是,如果真对kernel有兴趣,那起码得把英语搞一搞,然后尽早关注kernel MailList----虽然是万变不离其宗,但世界也是发展变化的。书上多少是有时限的。
关键字: qemu kernel gdb gdbserver 调试