使用 QEMU 调试内核

Table of Contents

最后更新:2022-10-22

1. QEMU

完全模拟硬件,可通过参数来指定硬件配置

需要用到的快捷键:

  • Ctrl + Alt + G:捕获输入

调试内核需要的环境:

2. 开启内核 KGDB

Linux 内核源码开启 KGDB 支持:

Kernel Hacking ---> KGDB: kernel debugger ---> KGDB: use kgdb over the serial console

3. 用 QEMU 启动内核

运行:

$ qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -hda linux-0.2.img -append "root=/dev/sda"

SDA 的内容就是 linux-0.2.img,启动后可以查看内核版本来确定是否正确:

$ cat /proc/version

因为 linux-0.2.img 里没有 uname 命令。

4. GDB 远程调试

qemu 启动时加上 -S 参数,然后启动后会挂载 CPU,按 Ctrl+Alt+2 切换到 QEMU monitor,输入:

$ gdbserver tcp::1234

嫌麻烦可以加 -s 参数进入调试模式。

在宿主机上调试:

$ gdb vmlinux

输入:

(gdb) target remote localhost:1234

下个断点:

b start_kernel

再继续运行:

(gdb) c

需要注意的是,在 QEMU 中启动 x86_64 的镜像,宿主机也是 x86_64 的架构时,GDB 远程调试会报出以下错误:

Remote 'g' packet reply is too long

我改成 i386 架构运行就没问题了:

$ qemu-system-i386  -kernel ./arch/i386/boot/bzImage -hda ~/下载/linux-0.2.img -append 'root=/dev/sda'  -S -gdb tcp::1234

5. 在 64 位上借助 QEMU 运行 32 位内核

系统中需要安装好 32 位的 GCC、glibc、glibc-static

1、编译Linux内核:

make ARCH=i386 defconfig
make oldconfig
make -j16

2、下载 BusyBox(https://busybox.net/downloads/), 解压并进入源码目录:

make menuconfig,设置编译选项:

Settings -->
    [*] Build static binary (no shared libs)
    (-m32) Additional CFLAGS   <--- 设置 -m32 参数,编译成 32 位程序
    (-m32) Additional LDFLAGS  <--- 设置 -m32 参数,链接成 32 位程序

然后编译 BusyBox:

make -j8
make install

编译结果会存储在 _install 目录中,找个目录,把 _install 复制过去:

cp -r ../busybox/busybox-1.35.0/_install rootfs

接着执行以下命令:

cd rootfs
rm linuxrc
ln -s bin/busybox init
mkdir dev
sudo mknod -m 600 dev/console c 5 1
mkdir etc
cat << EOF > etc/inittab
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
EOF
mkdir etc/init.d
touch etc/init.d/rcS
chmod +x etc/init.d/rcS
cat << EOF > etc/init.d/rcS
#!/bin/sh
export PATH=/sbin:/bin:/usr/bin;/usr/sbin;
export HOSTNAME=dhd
echo "start..."
EOF
find . | cpio -o -H newc | gzip > ../rootfs.img

最后用 QEMU 启动:

qemu-system-i386 -m 1024M -kernel ../linux-5.8.8/arch/x86/boot/bzImage -initrd rootfs.img