ubuntu: qemu+gdb 调试linux kernel 学习笔记

 

声明:

  本笔记内容并非本人原创,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 调试

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。