使用 QEMU 调试内核
Table of Contents
最后更新:2022-10-22
1. QEMU
完全模拟硬件,可通过参数来指定硬件配置
需要用到的快捷键:
- Ctrl + Alt + G:捕获输入
调试内核需要的环境:
- QEMU
- 一个 bzImage
- 一个启动镜像,我直接用 http://wiki.qemu.org/Testing 上的 linux-0.2.img.bz2
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