Open3

Linux Kernelのビルドとデバッグ

BEANBEAN

概要

ここでは、QEMUを用いてLinux Kernelを実行し、gdbによってLinux Kernelをデバッグする方法についてまとめます。
Kernelを最低限動かすことを目指しています。

環境

ここの手順は以下の環境を前提とする。

  • OS: "Ubuntu 20.04.4 LTS"
  • GCC: 9.4.0
  • QEMU: 4.2.1
  • GDB: 9.2

必要ソフトウェアのビルド

QEMU上で実行するためには、kernelの他に初期RAMディスクが必要です。
ここでは、busyboxを利用した手順について記します。

Linux Kernelのビルド

流れとしては以下に示すようになる。

  1. Kernelのソース入手
  2. .configの生成
  3. ビルド

Kernel のソース入手

kernel.org からtarなりをwget してください。
git でも良いですが、時間かかるのでtarがおすすめです。

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.4.207.tar.xz
tar -xf linux-5.2.207.tar.xz

.configの生成

.configはホストマシンの/boot/config-5.15.0-41-genericをコピーするとかありますが、
ここでは最小限な.configの生成を目指します。

cd linux-x.x.x
make allnoconfig
make menuconfig

ここでなんかエラー言われたら多分 ncurses-dev がないあたりが考えられます(エラー読んでね)
なので、以下で解決するはずです。

sudo apt install libncurses-dev

Kernel DebugのためにKGDB周辺の機能を有効にします。
ざっと以下のあたりでしょうか。

CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_KDB=y
CONFIG_KALLSYMS_ALL=y
CONFIG_DEBUG_INFO=y

あとはビルドするだけです。

make -j `nproc`

成功すると直下に vmlinuxができているはずです。

BusyBoxのビルドとinitrdの生成

Busyboxを用いてinitrdを作成します。
ちゃんとしたLinuxのシステムはinitrdから/dev/sdaあたりを本ちゃんのRootfsとして利用しますが、ここではKernelが使えればいいので、initrdを用いたLinux Kernelの起動に留めます。

BusyBoxのビルド

https://busybox.net からソースを持ってきます。

cd busybox-x.x.x
make defconfig  
make menuconfig

BusyBoxの.configで CONFIG_STATIC=yにしておきます。

あとはビルドするだけです。

make -j `nproc`

initrdのイメージ作成

まず、busyboxをビルドした成果物を吐き出します。
これには以下のmakeコマンドで実行することで、Busyboxのソースディレクトリ直下に_installというディレクトリが作成されます。

make install

そしてそこに移動し、以下のコマンド群を実行し最低限+アルファの環境に仕上げていきます。

cd _install
mkdir -p etc/init.d proc sys

次にetc/init.d/rcSファイルを作成し、procfsとsysfsをマウントするようにします。

# Result of rcS
cat etc/init.d/rcS
mount -t devtmpfs devtempfs /dev
mount -t proc none /proc
mount -t sysfs none /sys

/sbin/mdev -s

そして、このファイルに実行権限を与えます。

chmod +x etc/init.d/rcS

これらの用意をしたものをcpioを用いてinitrdにします。

cd _install
find . | cpio -o --format=newc > ../rootfs.img

QEMU + GDBでデバッグする

ここまででできたものらを以下のようにQEMUで実行します。

qemu-system-x86_64 -S -s -kernel linux-5.4.207/arch/x86_64/boot/bzImage -initrd busybox-1.35.0/rootfs.img -append "root=/dev/ram rdinit=/sbin/init nokaslr console=ttyS0" -nographic

GDB側を用意します。

gdb linux-5.4.207/vmlinux
(gdb) target remote :1234

あとはGDBでいい感じに遊ぶことができます。