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

时间:2022-03-14 00:23:02

声明:

  本笔记内容并非本人原创,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)函数里面修改部分内容,如下:

 static void
process_g_packet (struct regcache *regcache)
{
struct gdbarch *gdbarch = get_regcache_arch (regcache);
struct remote_state *rs = get_remote_state ();
struct remote_arch_state *rsa = get_remote_arch_state ();
int i, buf_len;
char *p;
char *regs; buf_len = strlen (rs->buf); /* Further sanity checks, with knowledge of the architecture. */
/* if (buf_len > 2 * rsa->sizeof_g_packet)
error (_("Remote 'g' packet reply is too long: %s"), rs->buf);
*/
/*modify by xx*/
if (buf_len > * rsa->sizeof_g_packet) {
rsa->sizeof_g_packet = buf_len;
for (i = ; i < gdbarch_num_regs(gdbarch); i++) {
if (rsa->regs[i].pnum == -)
continue;
if (rsa->regs[i].offset >= rsa->sizeof_g_packet)
rsa->regs[i].in_g_packet = ;
else
rsa->regs[i].in_g_packet = ;
}
}
//.......
}
}
}

  上面的14-15行是原来文件的,而18-27行是重新添加上的 <为了节约版面,我没有贴后面的,所以,注意 " { } "  可能导致的语法错误>,这样修改的具体原理,本人并不清楚,但确实解决了问题。

  修改完整后,就开始编译gdb吧。在 gdb-7.8/  下执行下面的命令:

 ./configure --prefix=../../tools/
make
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./
cp /boot/config-3.13.--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即可。这里不详细记载了。当安装后,可能的文件是这些:

 qemu-system-i386

 qemu-system-x86_64

 qemu-img

 qemu-io
....

  这个是什么意思呢? 第一行的表示是 i386机器上使用的qemu虚拟机,第二行表示是 x86_64上使用的虚拟机。另外的就没使用过了。具体的请参考官网文档:http://wiki.qemu.org/Main_Page。当然,我自己的系统是 x86_64的,使用的是第二个。

step 4: 让kernel为你稍带片刻~

  

 qemu-system-x86_64 -kernel ./bzImage -initrd ./initrd.img -smp  -gdb tcp::  -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:

  

 #!/bin/bash
qemu-system-x86_64 -kernel ./bzImage -initrd ./initrd.img -smp -gdb tcp:: -S
<save>
chmod +x qemu.start ./qemu.start

  这样就可以启动qemu了 <注意自己的 bzImage & initrd.img 文件的路径>

  提示:  man qemu-system-x86_64,你会获得一些帮助。

step 5: 使用gdb去连接已将启动了的qemu:

  

 ../tools/gdb/bin/gdb vmlinux 

 -----
GNU gdb (GDB) 7.8
Copyright (C) Free Software Foundation, Inc.
License GPLv3+: GNU GPL version or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from vmlinux...done.
----- (gdb) target remote :
Remote debugging using :
0x0000000000000000 in irq_stack_union () (gdb) b start_kernel
Breakpoint at 0xffffffff81d2fb02: file init/main.c, line . (gdb) c
Continuing. Breakpoint , start_kernel () at init/main.c:
{ (gdb) n
smp_setup_processor_id();
(gdb) n
boot_init_stack_canary();
(gdb) n
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 调试