第 1 章 在底层失序的边缘
1.1 技术准备:搭建你的手术台
有一类问题,在应用层叫“异常”,到了内核里就叫“恐慌”。
在用户态写代码时,最坏的情况大不了程序崩溃,你会看到一条 Segmentation Fault,然后进程结束,系统依然运行。但在内核里,规则变了。没有谁来保护你,一旦指针乱飞,你面对的可能是整台机器的死锁、数据 silently 消失,或者那个著名的黑色开机画面(Kernel Panic)。
本章的任务,就是把你武装成一个能给内核做手术的医生。
但这需要工具。你不可能靠 printf 在内核里活着走出来——实际上,即便你能在早期的内核代码里用 printk,等你真正遇到并发竞态或者内存破坏时,单纯的日志往往只能告诉你“它挂了”,而不是“为什么挂”。
我们需要的是显微镜、是透视仪、是一个能让我们停下来观察系统每一个微小动作的环境。
这就是本章要建立的底层能力。
别被“内核调试”这几个字吓到了。很多人觉得这是内核黑客的禁地,实际上,只要环境搭对了,调试内核代码和调试普通 C 程序在操作上并没有天壤之别——区别只在于你需要更小心地踩在钢丝上。
准备好你的手术台。我们开始。
从零开始:硬件与系统准备
首先,你需要一台不算太旧的电脑。不管是桌面机还是笔记本,只要性能不要太古董就行。为了方便折腾,也为了不把自己的主力工作环境搞炸,我们强烈建议使用虚拟机作为“沙盒”。
为什么要用虚拟机?
因为内核调试是一个高风险活动。你肯定会写出把系统挂在半路上的代码。如果你在物理机上直接跑,一次死机可能意味着强制重启,甚至数据丢失。而在虚拟机里,哪怕内核彻底崩溃了,你的物理主机依然稳如泰山,大不了把这个虚拟机 snapshots 回滚一下,拍拍灰尘继续来。
这就是我们在本章即将反复用到的一个核心原则:构建一个安全的、可随意破坏的环境。
对于本书,我们将以 Ubuntu 20.04 LTS 运行在 x86_64 架构 的 Oracle VirtualBox 虚拟机作为标准操作平台。Ubuntu 官方给出了推荐的最低系统配置(比如内存、CPU 核心数等),在安装之前,建议你去官方文档(https://help.ubuntu.com/community/Installation/SystemRequirements)核对一下。
哪怕你是给虚拟机分配资源,也得确保这些“软指标”是达标的。毕竟,内核编译和调试工具链都是吃内存和 CPU 的怪兽。给少了,你会在这个过程里感到卡顿得令人绝望;给够了,体验会顺畅很多。
关于如何把 Linux 作为“客户机”安装在 VirtualBox 里的具体细节,我们会在后续的 “在虚拟机中运行 Linux” 一节里详细展开,现在先有个概念:我们要在一个虚拟的盒子里,模拟一台完整的 x86_64 电脑。
上号!获取本书源码
环境有了,接下来是代码。
本书的所有示例代码、实验脚本和配置文件,都已经托管在 GitHub 上了。这意味着你不需要从头敲每一个字符——虽然作为学习者,手敲一遍有它的价值,但在调试这种需要反复试错的场景里,一个能直接运行的基础代码库能帮你节省大把时间。
打开终端,输入下面的命令:
git clone https://github.com/PacktPublishing/Linux-Kernel-Debugging
这行命令会把整个代码仓库克隆到你的本地。
你可以顺着目录结构看进去:源码是按章节(chapter-wise)组织的。每一章都有自己独立的文件夹。
比如,你在仓库里会看到一个 ch1/ 目录,里面装的就是本章要用到的所有素材和源代码。这种结构设计是有意为之的——它让你能清晰地隔离不同阶段的学习进度,也不会让代码像一团乱麻一样堆在一起。
⚠️ 注意
千万别把代码随手放在一个没有写权限或者容易被清理的地方(比如系统临时目录)。找一个你自己的 home 目录,建一个专门的 workspace 文件夹。这是做工程的好习惯,免得到最后找文件找得头皮发麻。
到这里,基础原料——操作系统环境和代码仓库——就位了。接下来,我们要真正开始打造这个“内核调试实验室”。这不仅仅是安装几个软件,更是在理解:为什么我们需要一个特制的内核? 为什么标准的生产环境内核对调试来说是不够用的?
这其中的奥妙,我们在下一节揭晓。