Skip to main content

Chapter 1: On the Edge of Low-Level Disorder

1.1 Technical Preparation: Setting Up Your Operating Table

There is a class of problems that are called "exceptions" in user space, but "panics" in the kernel.

When writing code in user space, the worst-case scenario is usually just a program crash. You see a Segmentation Fault, the process terminates, and the system keeps running. But in the kernel, the rules change. Nothing is there to protect you. Once pointers go wild, you might be facing a deadlocked machine, silently vanishing data, or that famous black boot screen (Kernel Panic).

The mission of this chapter is to equip you like a surgeon ready to operate on the kernel.

But this requires tools. You can't rely on printf to make it out of the kernel alive—actually, even if you could use printk in early kernel code, when you truly hit a concurrency race or memory corruption, plain logging often only tells you "it hung," not "why it hung."

What we need is a microscope, an X-ray machine—an environment that lets us pause and observe every microscopic action of the system.

This is the foundational capability we will build in this chapter.

Don't let the phrase "kernel debugging" intimidate you. Many people think it's forbidden territory reserved for kernel hackers. In reality, as long as you set up the environment correctly, debugging kernel code isn't worlds apart from debugging a regular C program in terms of operation—the only difference is that you need to tread more carefully on the tightrope.

Prepare your operating table. Let's begin.


Starting from Scratch: Hardware and System Preparation

First, you need a computer that isn't too old. Whether it's a desktop or a laptop, as long as the performance isn't completely ancient, it will do. To make experimentation easier and to avoid blowing up your primary work environment, we strongly recommend using a virtual machine as a "sandbox."

Why use a virtual machine?

Because kernel debugging is a high-risk activity. You will inevitably write code that hangs the system halfway through. If you run it directly on physical hardware, a single crash might mean a forced reboot or even data loss. In a virtual machine, even if the kernel completely crashes, your physical host remains rock solid. At worst, you just roll back the virtual machine to a snapshot, dust yourself off, and try again.

This is a core principle we will repeatedly apply throughout this chapter: build a safe, freely destructible environment.

For this book, we will use Ubuntu 20.04 LTS running on x86_64 architecture inside an Oracle VirtualBox virtual machine as our standard operating platform. Ubuntu officially provides recommended minimum system requirements (such as memory and CPU core count). Before installing, we suggest checking the official documentation (https://help.ubuntu.com/community/Installation/SystemRequirements) to verify these.

Even when allocating resources to a virtual machine, make sure these "soft metrics" are met. After all, kernel compilation and debugging toolchains are monsters that devour memory and CPU. Allocate too little, and the process will feel agonizingly sluggish; allocate enough, and the experience will be much smoother.

We will cover the specific details of installing Linux as a "guest" in VirtualBox in a later section, "Running Linux in a Virtual Machine." For now, just grasp the concept: we are simulating a complete x86_64 computer inside a virtual box.


Let's Go: Getting the Book's Source Code

With the environment ready, let's move on to the code.

All example code, experiment scripts, and configuration files for this book are hosted on GitHub. This means you don't need to type every character from scratch—although as a learner, typing it out by hand has its value, in a debugging scenario that requires constant trial and error, a ready-to-run baseline codebase will save you a tremendous amount of time.

Open a terminal and enter the following command:

git clone https://github.com/PacktPublishing/Linux-Kernel-Debugging

This command clones the entire repository to your local machine.

You can browse through the directory structure: the source code is organized chapter by chapter. Each chapter has its own independent folder.

For example, you will see a ch1/ directory in the repository, which contains all the materials and source code used in this chapter. This structural design is intentional—it lets you cleanly isolate your learning progress across different stages, rather than letting the code pile up like a tangled mess.

⚠️ Warning Never leave the code lying around in a directory without write permissions or one that might get cleaned up automatically (like a system temporary directory). Find a spot in your home directory and create a dedicated workspace folder. This is a good engineering habit that will save you from tearing your hair out looking for files later.

At this point, the basic ingredients—the operating system environment and the code repository—are in place. Next, we will truly begin building this "kernel debugging lab." This isn't just about installing a few pieces of software; it's about understanding: why do we need a custom kernel? Why isn't a standard production kernel sufficient for debugging?

The secret behind this will be revealed in the next section.