qemu + gdb + busybox 内核调试流程

0. 准备

软件版本信息

  • OS: Ubuntu 20.10 / CentOS 8.2.2004
  • gcc: gcc-10.2.0-13(ubuntu 原生)/ gcc-8.3.1-5 (centos 原生)
  • qemu: qemu-5.0.0(ubuntu 源码编译安装)/ qemu-kvm-2.12.0-99 (centos 原生)
  • gdb: gdb-9.2-0(ubuntu 原生)/ gdb-8.2-11 (centos 原生)
  • busybox: busybox-1.33.0(源码编译安装)
  • kernel: linux-4.19.157(编译)/ 5.8.0-26-generic(ubuntu 原生)/ 4.18.0-193(centos 原生)

源码获取地址

1. 安装 qemu

我在 ubuntu 20.10 上使用了编译安装方式,在 centos 8.2.2004 上使用了直接安装方式,具体如下:

方式一:源码编译安装

(1)获取 qemu 源码 qemu-5.0.0.tar.xz
(2)编译安装,命令如下:

apt install bison flex pkg-config libglib2.0-dev libpixman-1-dev -y
xz -d qemu-5.0.0.tar.xz
tar xvf qemu-5.0.0.tar
cd qemu-5.0.0
./configure
make -j4
make install -j4

./configure 过程中可能遇到的报错及解决方法如下:

ERROR: pkg-config binary 'pkg-config' not found   # 安装 pkg-config

ERROR: glib-2.48 gthread-2.0 is required to compile QEMU   # 安装 libglib2.0-dev

ERROR: pixman >= 0.21.8 not present.
       Please install the pixman devel package.   # 安装 libpixman-1-dev

(3)成功安装后,系统中会生成各种 qemu- 开头的命令,如 qemu-system-x86_64

方式二:直接安装

centos 和 ubuntu 都提供了qemu 包,可以直接安装。centos 8.2 上命令如下:

yum install qemu-kvm-core -y
# 安装后执行如下命令
ln -sf /usr/libexec/qemu-kvm /usr/bin/qemu-system-x86_64

这里简单介绍下配置本地 yum 源的方法,当然也可以直接使用网络源:
(1)下载 centos 8.2 iso 到本地,然后通过 vmware 光驱加载或者下载到虚拟机内部
(2)执行如下命令挂载:

# 挂载目录随意,这里在 /mnt 下面创建一个 repo 目录
mkdir -p /mnt/repo

# 如果 iso 通过 vmware 光驱添加,则执行:
mount /dev/sr0 /mnt/repo
# 如果 iso 直接下载到虚拟机内部,则执行:
mount CentOS-8.2.2004-x86_64-dvd1.iso /mnt/repo

# 配置 yum 源
cd /etc/yum.repos.d
mkdir bak
mv *.repo bak
touch local.repo # 内容见下方

yum clean all
yum makecache

local.repo 文件内容如下:

[base]
name=base
baseurl=file:///mnt/repo/BaseOS
enabled=1
gpgcheck=0

[stream]
name=stream
baseurl=file:///mnt/repo/AppStream
enabled=1
gpgcheck=0

2. 安装 gdb

方式一:源码编译安装

网上很多 qemu + gdb 调试内核的帖子中都提到系统自带 gdb 使用时会有如下报错:

Remote 'g' packet reply is too long: 000000000000000020000000000000004000000000000000001006000000000000f009000000000028aece81ffffffff981fc081ffffffff901fc081ffffffff0030c1010000000000000000000000000000000000000000f0b926020000000020f1d281ffffffffb01fc081ffffffff00e0e681ffffffff0010e781ffffffff02fbd281ffffffff9600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000

然后需要修改 gdb 源码重新编译,可参考 《QEMU+GDB调试Linux内核总结(全)》

方式二:直接安装

我在 ubuntu 20.10 和 centos 8.2 中直接使用原生 gdb 都没有遇到这个问题,所以没有重新编译 gdb。

# ubuntu 20.10 命令如下:
apt install gdb -y

# centos 8.2 命令如下:
yum install gdb -y

3. 通过 busybox 制作 initrd

我之前一篇文章 《Linux 启动流程 – BIOS/UEFI & bootloader & kernel & initramfs & systemd》 有介绍 initrd 的作用。initrd 是一个 mini 根文件系统,提供一些必要的工具和驱动,主要起引导作用,帮助 OS 顺利过渡到真实的根文件系统。这里制作的 initrd 不仅起引导作用,同时也是最终的根文件系统,和硬盘分区上的根文件系统不同,它是一个内存文件系统。
下载 busybox 源码 busybox-1.33.0.tar.bz2。编译安装,命令如下:

创建编译目录

命令如下:

apt install libncurses-dev -y
tar jxvf busybox-1.33.0.tar.bz2
mkdir -p busybox-build
cd busybox-1.33.0
make O=../busybox-build defconfig

如果没有安装 libncurses-devmake menuconfig 会报如下错误信息:

make -C /home/busybox/busybox-1.33.0 O=/home/busybox/busybox-build menuconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/basic/split-include
  HOSTCC  scripts/basic/docproc
  GEN     /home/busybox/busybox-build/Makefile
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/kxgettext.o
  HOSTCC  scripts/kconfig/mconf.o
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/mconf
  HOSTCC  scripts/kconfig/lxdialog/checklist.o
<command-line>: fatal error: curses.h: No such file or directory
compilation terminated.
make[4]: *** [scripts/Makefile.host:120: scripts/kconfig/lxdialog/checklist.o] Error 1
make[3]: *** [/home/busybox/busybox-1.33.0/scripts/kconfig/Makefile:14: menuconfig] Error 2
make[2]: *** [/home/busybox/busybox-1.33.0/Makefile:444: menuconfig] Error 2
make[1]: *** [Makefile:112: menuconfig] Error 2
make: *** [Makefile:19: menuconfig] Error 2

生成编译 .config 文件

命令如下:

cd ../busybox-build
make menuconfig

这里需要设置静态编译,编译出的二进制可以独立运行,不依赖其他库。“Setting”(回车进入子菜单) => “Build static binary (no shared libs)” (tab 键选择)。选中后,选择界面下方 Exit 退出,最后会提示保存,选择 Yes,保存 .config。具体过程如下图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

编译安装生成 initrd

命令如下:

# make 和 make install 执行成功后会在 busybox-build 目录下生成 _install 目录
make
make install

# 在 busybox-build 同级目录下创建 rootfs 目录
mkdir rootfs
cd rootfs
cp -ar ../busybox-build/_install/* .

# 创建软连接 init 指向 bin/busybox,内核启动到最后会执行 init 进程
ln -sf bin/busybox init
mkdir -p {sys,proc,dev,etc/init.d}

# 启动脚本,相当于 rc.local
touch etc/init.d/rcS # 内容见下方
chmod 755 etc/init.d/rcS

touch etc/fstab # 内容见下方

# 这里的 pigz 可以多线程压缩,需要安装 pigz,或者使用 gzip 替代。
find . -print0 | cpio --null -ov --format=newc | pigz -9 > ../initrd-busybox.img

rcS 文件内容如下,来自 tinycorelinux/Core-scripts

#!/bin/sh
# RC Script for Tiny Core Linux
# (c) Robert Shingledecker 2004-2012

# Mount /proc.
[ -f /proc/cmdline ] || /bin/mount /proc

# Remount rootfs rw.
/bin/mount -o remount,rw /

# Mount system devices from /etc/fstab.
/bin/mount -a

clear

fstab 文件内容如下:

sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
udev /dev devtmpfs rw,nosuid,noexec,relatime,mode=755 0 0

上述命令执行成功后,会在 busybox-build 同级目录下生成 initrd-busybox.img,即 initrd。上述 initrd 是在 ubuntu 环境上制作的,也可以直接在 centos 使用。

4. 获取内核 vmlinuz 和 vmlinux

方式一:内核源码编译

(1)下载内核源码 linux-4.19.157.tar.xz
(2)编译安装,命令如下:

apt install libelf-dev libssl-dev binutils-dev -y
xz -d linux-4.19.157.tar.xz
tar xvf linux-4.19.157.tar
cd linux-4.19.157

# 生成编译选项文件 .config,和 busybox 流程类似
make menuconfig 

# 编译成功后,源码根目录下会生成带调试信息的 vmlinux 文件,
# 内核文件在 arch/x86/boot 目录下,文件名为 bzImage,即 vmlinuz。
make -j4

方式二:直接从 ubuntu 或 centos 发布件中获取

centos 8.2 获取方式如下

  • vmlinuz: 位于系统 boot 目录下,文件名为 vmlinuz-4.18.0-193.el8.x86_64
  • vmlinux: kernel-debuginfo-4.18.0-193.el8.x86_64.rpm
    可以通过 rpm2cpio kernel-debuginfo-4.18.0-193.el8.x86_64.rpm | cpio -divm 命令解压 rpm 包,vmlinux 位于 ./usr/lib/debug/lib/modules/4.18.0-193.el8.x86_64/vmlinux
  • source: kernel-debuginfo-common-x86_64-4.18.0-193.el8.x86_64.rpm
    可以通过 rpm2cpio kernel-debuginfo-common-x86_64-4.18.0-193.el8.x86_64.rpm | cpio -divm 或者直接安装,gdb 中通过 dir 命令指定源码路径即可。

ubuntu 20.10 获取方式如下

  • vmlinuz: 位于系统 boot 目录下,文件名为 vmlinuz-5.8.0-26-generic
  • vmlinux: linux-image-unsigned-5.8.0-26-generic-dbgsym_5.8.0-26.27_amd64.ddeb
    可以通过 dpkg -X linux-image-unsigned-5.8.0-26-generic-dbgsym_5.8.0-26.27_amd64.ddeb 解压安装包或者直接安装,vmlinux 路径为 ./usr/lib/debug/boot/vmlinux-5.8.0-26-generic
  • source: groovy-src-2.iso 没找到单个源码包,只找到源码包 iso 镜像,镜像中有包名 linux_5.8.0-25.26.diff.gz,版本号不匹配。

5. 调试内核

启动 qemu

命令如下:

qemu-system-x86_64 -kernel /home/kernel/linux-4.19.157/arch/x86/boot/bzImage -initrd /home/busybox/initrd-busybox.img -append "console=ttyS0 nokaslr" -nographic -S -s
  • -kernel 指定内核镜像文件。
  • -initrd 指定 initrd 文件。
  • -append 指定内核启动参数。
  • -nographic 重定向串口 I/O 到 console,该参数和 console=ttyS0 内核启动参数共同作用,使得可以直接在 ssh 连接界面看到内核打印的日志以及登录 shell。
  • -S cpu 启动时暂停。
  • -s 等同于 -gdb tcp::1234 ,启动 gdbserver 并监听 1234 端口。

上述命令执行后,界面会停住,等待 gdb 客户端连接,如下:
在这里插入图片描述

启动 gdb 调试内核

(1)重新起一个 ssh 连接,在已编译完成的内核源码路径下执行命令 gdb ./vmlinux
(2)gdb 中执行命令 target remote :1234,回车后显示如下:
在这里插入图片描述
(3)设置断点 b start_kernel ,然后 continue
在这里插入图片描述
(4)qemu 端回显如下:
在这里插入图片描述
(5)gdb 继续执行 continue,qemu 端显示如下,最终进入 shell,等待执行命令:
在这里插入图片描述
在这里插入图片描述

至此,qemu + gdb + busybox 整个内核调试流程介绍完毕。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值