Setup QEMU for Kernel GDB Debugging (no display)
You need these to run a compiled kernel and debug it using GDB:
- The kernel bzImage
- ramdisk image
Tips:
- To debug it with gdb, run QEMU with option
-s(shorthand forgdb -tcp::1234) and-Sfor starting the CPU in the stopped stated. - Load the GDB scripts by adding the
add-auto-load-safe-pathscript to gdbinit. The position of gdbinit can be~/.gdbinitor~/.config/gdb/gdbinit.
echo "add-auto-load-safe-path /path/to/linux/scripts/gdb/vmlinux-gdb.py" >> ~/.gdbinit
Steps
- Run the default config :
make defconfig - Add or set these symbols in
.configfile of the kernel :
CONFIG_GDB_SCRIPTS=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_KALLSYMS=y
CONFIG_RANDOMIZE_BASE=n
- You can also run these :
$ ./scripts/config -e DEBUG_INFO -e DEBUG_KERNEL -e DEBUG_INFO_DWARF4
$ ./scripts/config -e DEBUG_SECTION_MISMATCH -e DEBUG_OBJECTS -e DEBUG_OBJECTS_WORK -e DEBUG_VM
$ ./scripts/config -e GDB_SCRIPTS -e HEADERS_INSTALL
- Run
make -j$(nproc)to build the kernel - Build gdb scripts:
make scripts_gdb - Run modules_install:
make modules_install - Build the ramdisk image
sudo dracut --kernel-image arch/x86/boot/bzImage --confdir /etc/dracut.conf.d/ -v ramdisk.img <version>
- Run QEMU :
qemu-system-x86_64 \
-kernel $kernel_path/vmlinux \
-initrd $ramdisk_path/ramdisk.img \
-append "console=ttyS0 nokaslr" \
-nographic -enable-kvm -cpu host -m 512 \
-s -S
- Run
gdb $KERNEL_SRC/vmlinuxin another terminal - Enter
target remote localhost:1234to get started with remote debugging the kernel
Note: Try to use
hbreakinstead ofbin gdb to attach breakpoints early in the kernel
If you are getting memory cannot be accessed during adding a breakpoint, then you must have missed disabling
KASLR or Kernel Address Space Layour Randomisation. See CONFIG_RANDOMIZE_BASE config flag.
Setup QEMU for running QEMU with a custom kernel and display
This will help you setup a shared folder between a QEMU guest and the host. This also disables KASLR or Kernel Address Space Layout Randomisation (which is a security feature, but can be disabled for easier debugging - Wikipedia).
Make sure to adjust the parameters to your RAM (-m), file with your_os.qcow2 location and shared_folder parameters with your own shared folder values.
Host
# boot arch-linux image with installed kernel
# to get the tty or the terminal, run,
# $ telnet localhost 4321
$ sudo qemu-system-x86_64 \
--enable-kvm \
-cpu host -smp $(nproc) \
-m 8192 \
-nographic \
-device virtio-net,netdev=vmnic -netdev user,id=vmnic \
-drive file=archlinux.qcow2,media=disk,if=virtio \
-virtfs local,path=/path/to/shared/folder,mount_tag=shared_folder,security_model=passthrough,id=shared_folder \
-serial telnet:localhost:4321,server,nowait
# boot custom kernel using bzImage.
# this will open the display in a window, else you can add `-serial` at the
# end same as previous command and then runn using telnet
$ sudo qemu-system-x86_64 \
--enable-kvm \
-cpu host -smp $(nproc) \
-m 8192 \
-kernel linux-next/arch/x86_64/boot/bzImage \
-append "rw nokaslr root=/dev/vda1" \
-device virtio-net,netdev=vmnic -netdev user,id=vmnic \
-device VGA,vgamem_mb=256 \
-drive file=debian.qcow2,media=disk,if=virtio \
-virtfs local,path=/path/to/shared/folder,mount_tag=shared_folder,security_model=passthrough,id=shared_folder
Guest
$ sudo apt install -y qemu-guest-agent
$ sudo mkdir /mnt/shared_folder
$ sudo mount -t 9p -o trans=virtio,version=9p2000.L shared_folder /mnt/shared_folder
# tty settings in case of telnet tty
$ stty rows 30 && stty columns 136
Reference: https://wiki.gentoo.org/wiki/QEMU/Options