俗话说,工欲善其事必先利其器,有一个好用的开发与调试环境对内核学习来说事半功倍,因此在这里记录一下内核开发环境的搭建。
开发环境安装
开发环境我选择使用基于docker的ubuntu环境,ubuntu对开发友好,开发过程中常用的库也都能使用包管理工具apt下载到,而且该docker环境支持的架构也比较多,很适合跨平台开发,支持的架构如下:
安装docker
docker的安装方法不用赘述,网上教程很多,以Ubuntu为例,这里选择docker.io安装,其他系统也有可能是Docker Desktop,安装步骤如下:
# 1.安装docker.io
sudo apt-get update # 更新源,防止源中的下载连链接失效
sudo apt-get install docker.io
# 2.使普通用户可以使用docker,避免输入sudo
sudo groupadd docker
sudo usermode -aG docker $USER
# 2.给docker换国内源,加速docker pull
sudo mkdir -p /etc/docker
echo '{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"http://hub-mirror.c.163.com",
"https://registry.docker-cn.com"
]
}' > daemon.json
sudo mv daemon.json /etc/docker/
# 3.重启docker daemon
sudo systemctl restart docker
# 4.拉取Ubuntu22.04的镜像
docker pull ubuntu:22.04
# 5.查看是否安装成功
docker images | grep ubuntu | grep 22.04
编译内核
apt-get install wget xz-utils -y # 安装wget下载工具和xz压缩工具
cd /root && wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.108.tar.xz
tar -xf linux-5.15.108.tar.xz # 解压源码
#安装编译环境和依赖库
apt-get install libncurses-dev flex bison bc openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf gcc make gnu-standards libtool gettext
cd linux-5.15.108 # 进入源码目录
# 生成基于文本界面的内核配置菜单,该操作依赖ncurses库
# 当出现’Your display is too small to run Menuconfig!‘提示时,将终端放大重新执行这条命令即可
make menuconf
## 配置开启KGDB参数,然后光标选择save,将选项保存到.config文件中
## Kernel hacking --->
## Compile-time checks and compiler options --->
## [*] Compile the kernel with debug info
## [*] Provide GDB scripts for kernel debugging
## Generic Kernel Debugging Instruments --->
## [*] KGDB: kernel debugger
make -j $(nproc) # 进行编译,此处nproc变量为cpu核心的个数
制作根文件系统
# 安装依赖
apt-get install cpio unzip rsync
# 下载buildroot
wget https://github.com/buildroot/buildroot/archive/refs/tags/2022.02.11.tar.gz
tar -xf buildroot-2022.02.11.tar.gz
cd buildroot-2022.02.11
# 配置buildroot
make menuconfig
## Target options --->
## Target Architecture --->
## (X) x86_64
## Toolchain --->
## Toolchain type --->
## (X) Buildroot toolchain
## C library --->
## (X) glibc
## Kernel Headers
## (X) Linux 5.15.x kernel headers
## [*] Install glibc utilities
## [*] Enable C++ support
## [*] Build cross gdb for the host
## [*] TUI support
## [*] Python support
## [*] Simulator support
## Filesystem images --->
## [*] ext2/3/4 root filesystem
## ext2/3/4 variant --->
## (X) ext4
## Bootloaders --->
## [*] grub2
## [ ] i386-pc
## [ ] i386-efi
## [*] x86-64-efi
## (boot linux ext4 fat squash4 part_msdos part_gpt normal efi_gop) builtin modules
make -j $(nproc) # 开始编译
运行内核
将编译后的内核压缩文件bzImage和根文件系统rootfs.ext4拷贝至具有qemu运行环境的宿主机中运行:
mkdir kernel && cd kernel
docker cp ubuntu:/root/buildroot-2022.02.11/output/images/rootfs.ext2 .
docker cp ubuntu:/root/linux-5.15.108/arch/x86/boot/bzImage .
使用qemu-system-x86_64运行内核,当有图形界面时,执行:
sudo qemu-system-x86_64 -kernel ./bzImage -hda rootfs.ext2 -append "root=/dev/sda console=ttyS0 nokaslr" -serial stdio
没有图形界面时,将-serial stdio替换为-nographic即可。启动成功后会在终端中输出banner和登录提示,登录名为root,密码默认为空(buildroot进行make menuconfig配置时设置),如下图所示:
使用gdb挂载调试内核
使用qemu的’-s’和’-S’参数使内核可以被gdb挂载调试,执行命令如下:
sudo qemu-system-x86_64 -kernel ./bzImage -hda rootfs.ext2 -append "root=/dev/sda console=ttyS0 nokaslr" -serial stdio -s -S
‘-s’: 让qemu监听在tcp::1234端口上,可以让gdb连接该端口进行调试
‘-S’: 让qemu启动后暂停执行,直到通过gdb传入继续执行(continue)命令
在ubuntu的容器里,安装gdb,执行以下命令挂载qemu,对内核进行调试:
root@824b1b82dfae:~# gdb /root/linux-5.15.108/vmlinux
(gdb) add-auto-load-safe-path /root/linux-5.15.108/scripts/gdb/vmlinux-gdb.py
(gdb) target remote 172.17.0.1:1234
Remote debugging using 172.17.0.1:1234
0x000000000000fff0 in exception_stacks ()
(gdb) c
Continuing.
此处的172.17.0.1替换为qemu执行后,监听tcp 1234端口的ip。
在gdb中可以使用Ctrl + C来暂停qemu,然后就可以正常进行调试了。