This tutorial focuses on the practical aspects of preparing a QEMU system to debug the kernel with GDB.
The main goal of this tutorial is to quickly prepare a system for debugging:
- In order to debug the kernel is necessary to keep the build root locally. Because of that, this tutoral focus on how to build a minimal kernel image that can be compiled in a few minutes.
- Since the focus is the kernel, this tutorial makes use of pre-generated rootfs images to simplify the process.
Compiling a small kernel
Using the default config as base:
make alldefconfig
Enable serial console and init ram disk:
make menuconfig
Search for the following configs and enable them:
CONFIG_GDB_SCRIPTS
CONFIG_SERIAL_8250
CONFIG_SERIAL_8250_CONSOLE
CONFIG_BLK_DEV_INITRD
Use
/
to search for the config and type the corresponding number to go to the desired entry.
Enable better KVM support:
make kvmconfig
Compile the kernel:
time make -j"$(getconf _NPROCESSORS_ONLN)"
For x86, the kernel image will located at arch/x86/boot/bzImage
.
Obtaining the pre-generated rootfs image
Download the correspondent system image for your architecture from this
link and decompress it. The rootfs image
is located at system-image-x86_64/rootfs.cpio.gz
.
Starting a virtual machine
The more basic command to start a VM is:
qemu-system-x86_64 -enable-kvm -s \
-kernel ./arch/x86_64/boot/bzImage \
-initrd ./rootfs.cpio.gz -nographic \
-append 'console=ttyS0'
-s
tells QEMU to start a GDB server on port 1234. -S
can be appended to
pause the VM before starting to run.
The virtual machine should start with console output.
Use Ctrl-a c
to access the QEMU monitor console. Type quit
from the monitor
console to finish the VM or Ctrl-a c
to return to the VM console.
In order to share a directory from host with the VM (which might be useful for testing out-of-tree modules), append the following arguments:
-fsdev local,security_model=passthrough,id=fsdev-root,path="$DIR",readonly \
-device virtio-9p-pci,id=fs-root,fsdev=fsdev-root,mount_tag=share
Replacing $DIR
with the path to the directory to be shared.
Mount the tag share
inside the guest:
mount -t 9p share /mnt -o trans=virtio,version=9p2000.u
Debugging the kernel
Enable auto-loading of GDB scripts:
echo "add-auto-load-safe-path $HOME" >> ~/.gdbinit
Start gdb:
gdb ./vmlinux
Attach to the VM:
target remote :1234
Load main kernel symbols:
lx-symbols
Set a breakpoint:
b <some point>
And continue:
c
Use
Ctrl-x Ctrl-a
to switch totui
and follow the source code.
Links
- Kernel documentation - Debugging kernel and modules via gdb. This page provides details about the main aspects of debugging the kernel with GDB.
- Pool of machine images and toolchains. That’s a good place to obtain pre-generated rootfs images for several architectures.
- How to Build A Custom Linux Kernel For Qemu. A good tutorial to build a small kernel to use with QEMU/KVM.
- Network lab with QEMU. Tutorial that covers kernel debugging using qemu.
To do
- How to generate your own rootfs image.