Fundamentals 12 min read

Step-by-Step Guide: Compile Linux Kernel and Debug with QEMU + GDB

Learn how to compile the Linux 4.19.172 kernel on CentOS, create a rootfs with BusyBox, and set up QEMU‑based debugging using GDB, including required kernel boot parameters, troubleshooting static linking errors, and optional Eclipse visual debugging.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Step-by-Step Guide: Compile Linux Kernel and Debug with QEMU + GDB

1. Overview

When analyzing kernel execution flows, GDB step‑by‑step debugging is often more direct than BPF tracing. This guide details compiling a Linux kernel on a 16‑core CentOS 7.7 machine, building a BusyBox root filesystem, and debugging the kernel in an Ubuntu 20.04 VM using QEMU and GDB. Adding the nokaslr boot parameter is essential for breakpoints to be hit.

2. Linux Kernel Compilation

The source is downloaded from the Tsinghua mirror (e.g., linux-4.19.172.tar.gz) and compiled on CentOS 7.7.

sudo yum group install "Development Tools"
yum install ncurses-devel bison flex elfutils-libelf-devel openssl-devel
wget http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/v4.x/linux-4.19.172.tar.gz
tar xzvf linux-4.19.172.tar.gz
cd linux-4.19.172/
make menuconfig

Enable Compile the kernel with debug info (already selected in 4.19.172) under Kernel hacking → Compile-time checks and compiler options . Verify the option:

# grep CONFIG_DEBUG_INFO .config
CONFIG_DEBUG_INFO=y

Compile the kernel using all available cores:

# nproc   # show CPU count
make -j 12   # or make bzImage -j N

Resulting files: vmlinux – uncompressed kernel with symbols (≈ 449 MiB) arch/x86_64/boot/bzImage – compressed boot image (≈ 7.6 MiB)

3. Building the Initramfs with BusyBox

# Install static dependencies
yum install -y glibc-static.x86_64 -y

wget https://busybox.net/downloads/busybox-1.32.1.tar.bz2
tar -xvf busybox-1.32.1.tar.bz2
cd busybox-1.32.1/
make menuconfig
make && make install

cd _install
mkdir proc sys
touch init
chmod +x init
find . | cpio -o --format=newc > ./rootfs.img
ls -lh rootfs.img

The init script prints timing information during boot:

#!/bin/sh
echo "{==DBG==} INIT SCRIPT"
mkdir /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug
mount -t tmpfs none /tmp
mdev -s
echo -e "{==DBG==} Boot took $(cut -d' ' -f1 /proc/uptime) seconds"
setsid /bin/cttyhack setuidgid 1000 /bin/sh

4. Error Troubleshooting

Static linking may fail with messages such as:

/bin/ld: cannot find -lcrypt
/bin/ld: cannot find -lm
... (other missing libraries)

Install the missing static libraries (e.g., glibc-static) or use yum provides */libm.a to locate the appropriate packages, then rebuild.

5. Launching the Kernel with QEMU

On the Ubuntu 20.04 host (installed inside VirtualBox), install QEMU tools:

apt install qemu qemu-utils qemu-kvm virt-manager libvirt-daemon-system libvirt-clients bridge-utils

Copy vmlinux, bzImage, rootfs.img, and the kernel source directory to the Ubuntu machine.

Start QEMU with GDB support:

qemu-system-x86_64 -kernel ./bzImage -initrd ./rootfs.img -append "nokaslr console=ttyS0" -s -S -nographic

Explanation of key parameters: -kernel ./bzImage: specifies the kernel image. -initrd ./rootfs.img: supplies the initramfs. -append "nokaslr console=ttyS0": disables KASLR and redirects console output to the serial port; nokaslr is required for GDB breakpoints. -s: opens a GDB stub on port 1234. -S: pauses the VM at startup, waiting for GDB. -nographic: runs without a graphical display, sending output to the terminal.

6. GDB Debugging

On a second terminal, launch GDB against the uncompressed kernel:

(gdb) file vmlinux
(gdb) target remote :1234
(gdb) break start_kernel
(gdb) continue

The kernel stops at start_kernel, allowing step‑by‑step inspection.

7. Eclipse Visual Debugging (Optional)

Import the kernel source as a “Makefile Project with Existing Code” in Eclipse CDT. Create a “C/C++ Attach to Application” debug configuration:

Project: the imported kernel project.

C/C++ Application: vmlinux (with symbols).

Build before launching: disable auto‑build.

Debugger: gdbserver with TCP port 1234.

Start the debug session to obtain a graphical view similar to the GDB console.

8. References

How to compile and install Linux Kernel 5.6.9 from source code

Using QEMU + GDB to debug Linux kernel

QEMU + BusyBox environment setup

Full QEMU + GDB kernel debugging workflow

Linux kernel compilation and debugging methods

How to Build A Custom Linux Kernel For Qemu (2015 Edition)

Differences between QEMU and QEMU‑KVM

Debugging Linux kernel in QEMU environment

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

CompilationLinux kernelQEMUKernel Debuggingbusybox
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.