Debugging kernel with qemu and gdb

Assuming that you have your (or Linux/*BSD/Solaris/Windows or any other) kernel on a bootable device, you can debug the kernel and also the loadable modules as well as user mode applications with QEmu/Bochs and good old gdb.
  • Configuring QEmu
You need qemu compiled with gdb support. QEmu needs no configuration file as such, and can be launched with gdb support as:
qemu -hda hd.img -fda floppy.img -boot ac -m 512M -S -gdb tcp::5022
 After this, qemu will continue executing the VM, and wait for a gdbmi connection on tcp 5022.
  • Configuring bochs
bochs is one of the most popular emulators in the hobbyist x86 kernel developers' world. Again, you need bochs which was configured and compiled with gdb stub. Some distributions like Fedora have a separate package for bochs with gdb stub, in case you do not want to go through the trouble of compiling it yourself.

Bochs needs a configuration file for launching a VM. Assuming you know the basic syntax, go ahead and add the following :
gdbstub: enabled=1, port=5022, text_base=0, data_base=0, bss_base=0
adjust the segment bases according to the bases of your segments. If you are following a flat memory model, pin them to 0.
After starting with this config, bochs will wait for a gdb connection even before the first instruction in BIOS trampoline is executed. This way you can debug a bootloader, and also your custom bios!
  • GDB
Obviously you need to compile what you plan to debug (be it kernel, user libs, user apps) with good amount of debug support. -g3 with gcc is my default. Not to mention, do not strip the binaries.

Start up gdb.

This tells gdb to read debug info from kernel image 'krnl/kernel'.
file krnl/kernel

This tells gdb to connect with a gdbmi connection to tcp 5022, the port on which either qemu or bochs is already waiting.
target remote localhost:5022

In order to debug user mode apps,
add-symbol-file apps/testApp1.elf 0x04000000

There you go. Now you can pretty much debug the entire system so as to say. Almost all common gdb commands like breakpoint, watchpoint, assembly debugging etc. work without sweat. If your fingers hurt, put all these commands in a file named '.gdbinit' in your project directory. gdb will pick it up and load and connect automatically.

This can save gazillions of man hours of a hobby kernel developer. Believe me, printk debugging is no fun. Source level kernel debugging when you are writing IDT handling code is must. When writing interrupt handler and paging, I have wasted two weekends in pleasing company of triple faults, completely clueless.

For the sickle minded and the general wannabe h4x0r, you just got a (way more) powerful alternative to rootkits. Rev those dongles and drivers. Let your imagination run wild ;)

3 comments:

  1. he post kahich kalale nahi. aso! but this layout is rocking! aata kasa prashant cha blog watatoy :)

    ReplyDelete
  2. Hi Thanks for your post.

    This is what I am trying, could you tell me whats wrong ?

    1. I am starting qemu with the following command
    qemu-kvm -hda F12.raw -m 128 KUSP_F12.qcow2 -redir tcp:123456::22 -nographic -s -S

    2. The I start gdb
    bash>

    3. (gdb) symbol-file vmlinux.o
    (gdb) hbreak sys_ioctl
    Hardware assisted breakpoint 1 at 0x84c2c: file /home/kvmuser/Code/kernel/kusp-unstable/fs/ioctl.c, line 610.

    4. Then I type continue

    But the breakpoint is never hit. I have tried with regular breakpoint as well.

    ReplyDelete
  3. Some additional info: kvm has bug with real mode code handling. Doesn't put breakpoints. Try qemu -no-kvm. With kvm int3 works for breakpoint, but CC is replaced with 00 in memory.

    ReplyDelete