内核篇1:docker + Qemu搭建内核开发与调试环境

内核篇1:docker + Qemu搭建内核开发与调试环境

MidCHeck 2,438 2023-04-20

俗话说,工欲善其事必先利其器,有一个好用的开发与调试环境对内核学习来说事半功倍,因此在这里记录一下内核开发环境的搭建。

开发环境安装

开发环境我选择使用基于docker的ubuntu环境,ubuntu对开发友好,开发过程中常用的库也都能使用包管理工具apt下载到,而且该docker环境支持的架构也比较多,很适合跨平台开发,支持的架构如下:
image

安装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配置时设置),如下图所示:
image-1682398116423

使用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,然后就可以正常进行调试了。


# Linux内核 # QEMU # gdb # docker # buildroot