1.4 搭建工作台
上一节那些血淋淋的案例应该已经给你留下了足够的心理阴影。现在,带着这种「如履薄冰」的敬畏感,我们终于可以动手了。
我们要构建一个用来搞破坏——哦不,搞调试——的实验室。
但在敲下第一条命令之前,我们必须先做一个决定:你打算把这间实验室建在哪里?
裸机还是虚拟机?
如果你有条件,最理想的情况是在物理机上直接运行一个现代的 Linux 发行版(Ubuntu、Fedora 等)。在本书的大部分演示中,我会以 Ubuntu 20.04 LTS 作为基准系统。
这种方案的优点显而易见:性能直接、反馈真实。
但是,这里有个巨大的**⚠️ 踩坑预警**:
既然我们要深入到内核层面去调试,崩溃就是家常便饭。而且别以为只是简单地死机,数据丢失完全可能发生——虽然概率不大,但一旦发生,你连哭的地方都没有。
所以,如果你选择裸机,请确保这台机器里没有任何有价值的数据。把它当作一次性的实验台,而不是你的主力工作机。
如果裸机不现实(毕竟谁也不想随时搞崩主力机),那么最实用的替代方案就是虚拟机(VM)。
虚拟机虽然性能上肯定不如裸机(无论你配置多高,虚拟化层的开销都在那里),但在安全性上完胜。这一点在内核调试时尤为关键:当你把系统搞得彻底崩溃甚至 Panic 时,你只需要重置一下虚拟机软件(比如 Oracle VirtualBox),而不需要去重启物理硬件。
这带来的心理上的安全感是巨大的——你敢在虚拟机里尝试任何疯狂的操作,但这在物理机上你得犹豫半天。
备选路线:ARM 与树莓派
虽然本书默认架构是 x86_64,但如果你想让这段旅程更有趣——或者更接近真实的嵌入式开发——我强烈建议你在 ARM 架构上跑一下书里的示例代码。
现在的嵌入式 Linux 世界(无论是 32-bit ARM 还是 64-bit AArch64)几乎是 ARM 的天下。
在这个领域,树莓派 是完美的实验床:
- 它足够便宜;
- 社区支持极强;
- 你能亲手摸到真实的硬件(而不是虚拟出来的抽象层)。
我会在后续章节里穿插一些 ARM 相关的内容。如果你想跟着做,树莓派的官方文档已经把安装和配置讲得很透彻了:Raspberry Pi Documentation。
除了树莓派,TI 的 BeagleBone Black (BBB) 也是极好的选择,尤其是对那些想深挖底层硬件交互的人来说。入门指南在这里:BeagleBoard.org - Black。
虚拟机软件的选择
如果你决定走虚拟机路线,我首推 Oracle VirtualBox 6.x(或最新的稳定版)。
当然,VMware Workstation 或者 QEMU 也没问题,它们都是自由软件。但本书里的所有代码,我都实实在在地在 VirtualBox 6.1 上测过,能保证不坑你。VirtualBox 是开源软件(GPL v2 协议,跟 Linux 内核一样),你可以直接去官网下:VirtualBox Downloads。
宿主系统可以是 Windows 10/11、Linux(Ubuntu/Fedora)或者 macOS。
至于虚拟机里装的系统,我建议直接跟着我用 Ubuntu 20.04 LTS。统一环境能帮你省去很多「为什么我的报错跟书里不一样」的麻烦。
🔍 几个实用的小技巧
怎么查系统版本?
在 Debian/Ubuntu 系统上,用 lsb_release 一眼就能看穿:
$ lsb_release -a 2> /dev/null
Distributor ID: Ubuntu
Description: Ubuntu 20.04.2 LTS
Release: 20.04
Codename: focal
怎么判断当前系统是虚拟机还是裸机? 有时候你会忘。这时候可以用几个命令自检:
virt-what(我们稍后会装它)systemd-detect-virt(如果你的 init 系统是 systemd)- 或者简单粗暴地看
dmesg | grep -i hypervisor
图省事:OSBoxes 预装镜像
如果你不想从头装系统,有个网站叫 OSBoxes,简直是懒人福音。
他们提供现成的 VirtualBox(和 VMware)镜像,Ubuntu 20.04.3 自然也在列。最棒的是,这些镜像预装了 Guest Additions(我们马上就要讲到这玩意儿)。
下载地址:OSBoxes Ubuntu。
默认账号密码通常是 osboxes / osboxes.org。
如果你是老手,可能更喜欢用 QEMU 搞个定制的轻量级系统,那也完全没问题。对于那种玩法,你可以直接跳过下一节。
安装 VirtualBox 增强功能包
如果你的 Linux 是跑在 VirtualBox 里的,这一步千万别跳过。
客户机附加组件 实际上就是一组驱动和应用程序。它的作用有两个:
- 性能加速:装完后,你会明显感觉鼠标不飘了,画面流畅了。
- 体验增强:支持鼠标无缝切换、剪贴板共享、文件夹共享、拖拽文件。
没装它之前,用虚拟机简直是折磨;装完之后,它就像原生应用一样顺滑。
在安装之前,请确保你已经进系统并做了一次更新:
sudo apt update
sudo apt upgrade
第一步:准备编译环境 安装增强组件需要编译内核模块,所以得先把工具链备齐。打开终端,执行:
sudo apt install build-essential dkms linux-headers-$(uname -r) ssh -y
注意,linux-headers-$(uname -r) 会自动匹配你当前的内核版本,这一步至关重要,否则编译会报错。
第二步:安装增强包
这一步在图形界面里操作最方便。
在 VirtualBox 的菜单栏点击 设备 -> 安装增强功能。
通常这会在虚拟机里挂载一个虚拟光盘。你需要进到光盘目录里,用 root 权限跑 autorun.sh 脚本。
(如果不想手动点,可以参考这篇手把手教程:How to Install VirtualBox Guest Additions in Ubuntu)
第三步:搞定文件夹共享权限
装完之后,如果你想在宿主机和虚拟机之间传文件(比如共享文件夹),你得把当前用户加到 vboxsf 组里:
sudo usermod -G vboxsf -a ${USER}
执行完这步,你需要重新登录(有时候甚至得重启),权限才会生效。不然你看着共享文件夹就在那里,就是点不开,那是很让人抓狂的。
安装基础开发工具
好了,虚拟机调教完毕,系统也更新了。现在是时候武装我们的编译器了。
内核编译可不是随便找个文本编辑器就能干的活,它需要一大堆特定的库和工具。
假设你跟着我推荐用了 Ubuntu 20.04 LTS,我们需要分两步走。
第一步:内核构建 essentials
先更新一下索引(虽然前面更过,但这是个好习惯):
sudo apt update
然后,安装构建内核绝对需要的包(这是一整行命令,别敲断了):
sudo apt install bison flex libncurses5-dev ncurses-dev xz-utils libssl-dev libelf-dev util-linux tar -y
这里稍微解释一下都在装什么鬼:
bison/flex:内核代码里有相当一部分是用脚本生成的语法解析器,没这两个跑不起来。libncurses5-dev/ncurses-dev:为了make menuconfig这个图形配置界面,没这个你就得面对纯文本的配置文件抓瞎。libssl-dev/libelf-dev:内核镜像签名和模块处理需要用到。-y:这个参数告诉 apt 「别问我 Yes/No,全给我装上」。虽然有点粗暴,但在这种确定的环境下能省不少事。
第二步:调试与分析工具集
为了跑完本书所有的示例(包括后面要讲的 BPF、性能分析等),你还需要的工具更多。
同样是请复制粘贴这一大长串(注意换行符):
sudo apt install bc bpfcc-tools bsdmainutils clang cmake cppcheck cscope curl \
dwarves exuberant-ctags fakeroot flawfinder git gnome-system-monitor gnuplot \
hwloc indent kernelshark libnuma-dev libjson-c-dev linux-tools-$(uname -r) \
net-tools numactl openjdk-16-jre openssh-server perf-tools-unstable psmisc \
python3-distutils rt-tests smem sparse stress sysfsutils tldr-py trace-cmd \
tree tuna virt-what -y
⚠️ 注意:这里有些包你可能一辈子只用一次。比如 flawfinder 是用来静态扫描代码安全漏洞的,而 openjdk-16-jre 是为了跑某些特定的 Java 用户态测试程序。如果你硬盘空间捉襟见肘,可以挑着装,但对于现代硬盘来说,这一步也就占几百兆,建议还是全装了省心。
💡 救懒脚本
我知道你们看见那么长的 apt install 命令头会大。
我把上面所有步骤封装成了一个脚本 pkg_install4ubuntu_lkd.sh,放在了本书的 GitHub 仓库里。如果你下的是 OSBoxes 的 Ubuntu 20.04.3 镜像,直接跑这个脚本是最稳的。
如果你后续想排查下哪个包最占硬盘,可以装个 wajig 然后跑:
sudo wajig large
好了,现在软件包也都就位了,工具箱里沉甸甸的。
我们离编译内核只差最后一块拼图——你可能不知道的是,内核开发者的桌子上通常摆着两个内核。
下一节,我们就来讲讲这个「双核」奇观。