Mctrain's Blog

What I learned in IT, as well as thought about life

Debugging Linux Kernel Using GDB and QEMU

| Comments

I should say it is really a shame that after more than 5 years of Linux development I still don’t know how to debug linux kernel using GDB.

Yesterday I’ve seen how GodLiang do this, and learned it from him, and finally, 新技能Get:

Debugging Linux Kernel using GDB and QEMU - learn from Liangpig

Here I’ll just skip about how to setup KVM and QEMU, I suppose you’ve already known that.

Prepare virtual machine and its vmlinux

At first, prepare a virtual machine, and more importantly, you should have the vmlinux of the VM’s kernel.

But how?

The simplest way is downloading a new kernel from here, compile to get the vmlinux and install the kernel using make install.

But what if you want to keep the current kernel?

Please use following instructions (for example my kernel is linux-3.2) :

$ sudo aptitude install linux-headers-`uname -r`
$ sudo aptitude install linux-source-3.2
$ cd /usr/src
$ tar zxvf linux-source-3.2.tar.gz
$ cd linux-source-3.2
$ make localmodconfig
$ make menuconfig
$ make -j4; make modules_install; make install
$ mkinitramfs 3.2.57 -o /boot/initrd.img-3.2.57

After above 2 approaches, you can have vmlinux in the 1st level folder, copy that, as well as the whole source code to the host.

Note: Above operations are all done inside virtual machine, while the following should be done in the host

Prepare GDB environment

You may say it is quite simple since we only need to use apt-get install gdb.

That’s almost right, but the GDB has a bug when it is remotely attached to QEMU on x86-64 arch, as shown in here.

Thus we need to do the patching staff illustrated in the above link.

My current GDB version is 7.6.2, so I download the same version, patch and compile it, and finally install it:

$ wget http://ftp.gnu.org/gnu/gdb/gdb-7.6.2.tar.gz
$ tar zxvf gdb-7.6.2.tar.gz
$ cd gdb-7.6.2
// patch it as what is shown in http://www.cygwin.com/ml/gdb-patches/2012-03/msg00116.html
$ ./configure; make -j4; sudo make install

Now to the point

Now everything is ready, suppose the things we need are in following locations:

  • Main directory: /source/to/
  • VM image: /source/to/vm.img
  • vmlinux: /source/to/vmlinux
  • linux-source: /source/to/linux-source/
  • GDB directory: /source/to/gdb/
Prepare the bash script for qemu setup
$ cat /source/to/boot_gdb_kernel.sh
/source/to/boot_gdb_kernel.sh
1
2
3
4
5
6
#!/bin/bash

qemu=qemu-system-x86_64
img=/source/to/vm.img

${qemu} --enable-kvm -smp 1 -m 1024 -drive file=${img} -netdev "user,id=user.0,hostfwd=tcp:0.0.0.0:2222-:22" -device e1000,netdev=user.0 -gdb tcp::1234 -S $@

As shown in the script, it uses -gdb tcp::1234 -S to open GDB support in QEMU.

After we execute the script, it will open the virtual machine, but stuck in the black screen, that is because we use the -S option, which instruct QEMU to stop until we do something.

Prepare GDB configuration file

What we need to do next is executing the GDB in the gdb directory, which contains the following configuration file:

$ cat /source/to/gdb/.gdbinit
/source/to/gdb/.gdbinit
1
2
3
4
file /source/to/vmlinux
directory /source/to/linux-source
target remote :1234
hbreak start_kernel

and we also need to add following line to ~/.gdbinit file:

~/.gdbinit
1
add-auto-load-safe-path /source/to/gdb/.gdbinit
Begin to debug

when we execute gdb command in this exact directory, it will read the content in .gdbinit file, and attach to the remote 1234 port, and attach to the qemu process:

$ pwd
/source/to/gdb
$ gdb
GNU gdb (GDB) 7.6.2
Copyright (C) 2013 Free Software Foundation, Inc.
.....
0x0000000000000000 in irq_stack_union ()
Hardware assisted breakpoint 1 at 0xffffffff816aa787: file init/main.c, line 469.
(gdb)

Here we need to enter c to continue the execution, after that, it will stop at the start_kernel function which we hbreak in the /source/to/gdb/.gdbinit file:

......
(gdb) c
Continuing.
Breakpoint 1, start_kernel () at init/main.c:469
469 {
(gdb)

Again we enter c to continue, finally the linux kernel setup. Then we can use gdb to breakpoint any function or address we want to stop, to debug the linux kernel.


Thanks to Liangpig and hope to learn more from him.

Comments