Skip to main content

Chapter 11: Deep into the Kernel: When the Debugger Becomes Part of the Kernel

There is a class of problems that ordinary debuggers simply cannot reach.

When your code runs at Ring 0, when the output buffer of printk cannot be flushed because of a system crash, or when you need to debug an Interrupt Handler—ordinary user-space debugging tools are not just powerless, they don't even exist.

Our mission in this chapter is to build a more low-level debugging capability. Instead of observing processes from the outside, we will make the debugger itself part of the kernel.

This is not as simple as "learning to use a tool." Understanding KGDB means you begin to grasp the OS's god-mode perspective—the ability to pause the entire world, inspect its state, and then let time resume.


11.1 Technical Preparation

Before diving into the kernel, we need to clear the ground first.

The base workspace and toolchain for this chapter still follow the conventions we established in Chapter 1—if you haven't set up that environment yet, now is a good time to go back and catch up. All code examples are already sitting in the book's GitHub repository, ready to be used whenever you need them.

But this time, we're playing with something a bit bigger. Besides our regular arsenal, we need to install heavier emulator components and a prepared rootfs image.

This step might be tedious, but don't cut corners. If the foundation isn't solid, once the kernel crashes later on, you won't even be able to tell which ring the problem occurred in.

1. Installing QEMU and Dependencies

We need the ARM and x86 versions of QEMU. This isn't just about running two virtual machines—in this chapter, we will rely heavily on QEMU's debugging features.

Open a terminal and run the following command. This string of packages will consume roughly 400 MB of disk space:

sudo apt install qemu-system-arm qemu-system-x86 lzop \
libncursesw5 libncursesw5-dev p7zip-full

Here's a breakdown of the key players:

  • qemu-system-arm and qemu-system-x86: These are our "sandbox." KGDB debugging typically requires two machines, or a VM acting as the target. QEMU perfectly plays the role of this unfortunate target machine, and its GDB support is excellent.
  • lzop: A compression tool. In the kernel world, you will sometimes encounter things in xz format.
  • libncursesw5: If you want to configure the kernel (make menuconfig), this library is required for the menu interface to appear.
  • p7zip-full: We'll need this to extract the rootfs later. Don't ask why we don't use tar—some things are just the way they are.

2. Getting the Rootfs Image

Next, we need a ready-made ARM Linux rootfs.

We will use this file later when debugging kernel modules. Navigate to the rootfs directory of the book's source code, and download this hefty file (about 178 MB—grab a coffee and wait):

cd <book_src>/ch11
wget https://github.com/PacktPublishing/Linux-Kernel-Debugging/raw/main/ch11/rootfs_deb.img.7z

warning Note — Watch out for this little pitfall

If you run the make command above directly, GitHub might throw a little tantrum. Since the repository already contains a placeholder rootfs.cpio.gz (a meta file), make will rename the actual file you just downloaded to rootfs.cpio.gz.tmp to avoid overwriting it.

This name is wrong, and subsequent scripts won't be able to find it. You need to manually fix this "typo":

rm rootfs_deb.img.7z mv rootfs_deb.img.7z.1 rootfs_deb.img.7z


The directory structure should now be clean and tidy (if you're curious, you can flip ahead to Figure 11.8 to see what it ultimately looks like, but for now, let's just leave the file here and extract it when we need it later).

### 3. Prerequisite Knowledge About GDB

One last thing: we will use GDB extensively in this chapter.

I'll assume you're no longer a GDB novice—for instance, you know what `break`, `continue`, `step`, and `next` do. If `printf` debugging is the only technique in your mental toolkit right now, I recommend searching for a "GDB cheat sheet" and giving it a quick glance.

But don't worry—kernel debugging and user-space debugging are still a bit different. We will walk you through those truly cool (and dangerous) operations step by step.

The ground is cleared. Next, we are going to officially implant this debugger cheat code into the kernel.