内核调试 · 2020-08-30 0

Qemu调试内核环境搭建

近期学习了一下Qemu的使用,发现Qemu功能很强大,提供的能力较多,同时也为使用增加的难度,尤其是那堆参数。同样是由于那堆参数,可以构造出很复杂的模拟环境来。不过构造模拟环境不是这次的重点,这次重点是如何快速搭建一个可以调试内核的环境来。

此次使用的系统环境是Ubuntu 20.04版本。通过sudo su -切换到root用户上进行操作,从安全角度来说不推荐,可以基于普通用户加sudo去操作需要特权的命令。所以下面的命令都是默认没有带sudo的,根据具体情况自行添加。

  • 安装Qemu及编译内核

首先,基于刚安装完毕的Ubuntu系统,我们需要把Qemu安装起来。Qemu的主要安装命令可以用:

apt install qemu qemu-kvm bridge-utils virt-manager

接着,我们需要把编译内核的必备软件给安装起来。

apt install bison flex libelf-dev libssl-dev build-essential libncurses-dev

好了,基本上可以编译内核了。可以通过make menuconfig配置好内核选项,建议把文件系统都编译到内核中,而不是使用模块的方式去编译。主要是避免调试内核的时候,找不到文件系统模块,然后系统挂掉了,没法继续往下跑了。这里我选择了ext4文件系统,因为我将要构造一个ext4的文件系统的环境。

这就是编译好的结果:

  • 构造rootfs

我们可以开始构造rootfs,一个让系统能够跑起来所依赖的根文件系统。Qemu不像前面使用VMWare那样,安装系统后,在Guest机器内编译安装内核,然后修改虚拟机参数什么的。Qemu在使用上,这点很好玩。它可以将调试的内核和运行的文件系统分离,这就意味着,构造一个rootfs之后,可以随意使用不同的内核去拉起系统,也就是说可以复用同一个rootfs去调试任意的内核。

首先,我们需要在下面的地址从ubuntu的发布件下载一个base的压缩包。这是一个基础的文件系统目录结构和一些通用配置文件。

http://cdimage.ubuntu.com/cdimage/ubuntu-base/releases/20.04/release/

根据自己需要吧,如果想模拟ARM环境可以下载ubuntu-base-20.04-base-arm64.tar.gz,在此下载了ubuntu-base-20.04-base-amd64.tar.gz压缩包。

接着我们需要使用下面命令创建一个镜像文件:

dd if=/dev/zero of=rootfs.img bs=1024 count=1M

由于还需要安装其他软件,所以就构造了一个1G大小的,当然可以按需构造。反正失败了还可以重来。

创建好空的镜像文件后,我们需要对它进行格式化。

mkfs.ext4 -F -L linuxroot rootfs.img

在此将它格式化为ext4的格式。

再接着我们将该镜像文件作为磁盘挂载起来。先来创建一个挂载的目录:

mkdir /mnt/tmpdir

挂载上去:

mount -o loop rootfs.img /mnt/tmpdir/

紧接着我们将刚刚下载的压缩包ubuntu-base-20.04-base-amd64.tar.gz解压到该镜像文件系统中。使用命令:

tar zxvf ubuntu-base-20.04-base-amd64.tar.gz -C /mnt/tmpdir/

挂载好后,我们需要往它上面安装软件,为了能够使用上apt命令去安装软件,因此需要在chroot切换根环境前,把所需的DNS配置及各种内存文件系统挂载上去。

cp /etc/resolv.conf /mnt/tmpdir/etc/

mount -t proc /proc /mnt/tmpdir/proc

mount -t sysfs /sys /mnt/tmpdir/sys

mount -o bind /dev /mnt/tmpdir/dev

mount -o bind /dev/pts /mnt/tmpdir/dev/pts

挂载好后,我们要切换根文件系统了。

chroot /mnt/tmpdir

切换完成后,现在就在rootfs文件系统中了,可以开始我们的程序安装:

apt-get update

apt-get install \

language-pack-en-base \

sudo \

ssh \

net-tools \

ethtool \

wireless-tools \

ifupdown \

network-manager \

iputils-ping \

rsyslog \

htop \

vim \

xinit xorg \

alsa-utils \

–no-install-recommends

可以根据自己基于上述安装的软件上,增加所需的一些软件。

软件安装完毕后,为了能够登录系统,我们添加一个用户:

useradd jean

这里的jean是我们需要添加的普通用户,可以改成自己的用户名。别忘了还要passwd jean去为这个用户设置密码。当然如果你想要用root登录系统,还需要给root去添加一个root的密码。

设置好用户后,设置hostname信息:

echo “jeanhost” > /etc/hostname

修改/etc/hosts配置路由信息:

127.0.0.1 localhost

127.0.0.1 jeanhost

修改/etc/X11/Xwrapper.config文件,允许所有人使用X用户界面:

allowed_users=anybody

通过以下命令设置时区:

dpkg-reconfigure tzdata

修改/etc/group为声卡驱动添加group用户组权限:

audio:x:29:pulse,username

修改/etc/group为图形驱动添加group用户组权限:

video:x:44:username

至此搞定了基本的rootfs文件系统了。

开始卸载问题系统了:

umount /mnt/tmpdir/proc/

umount /mnt/tmpdir/sys/

umount /mnt/tmpdir/dev/pts/

umount /mnt/tmpdir/dev/

umount /mnt/tmpdir/

  • 调试内核

可以开始调试内核了。使用命令:

qemu-system-x86_64 -s -S -m 4096M -kernel linux-5.4.60/vmlinux -append “root=/dev/sda console=ttyS0” -hda rootfs.img

-s是-gdb tcp::1234缩写,监听1234端口,在GDB中可以通过target remote localhost:1234连接;

-S表示加载后立即暂停,等待调试指令。不设置这个选项内核会直接执行;

-kernel指定编译好的调试版内核文件vmlinux;

-had指定构建的rootfs镜像文件;

-append指定内核启动参数。

Kernel是未压缩的vmlinux?是的,没看错,就是这么好玩。

在启动虚拟机后,我们可以通过gdb vmlinux直接调试内核,然后使用命令:

target remote :1234

接入要调试的虚拟机。可以开始正常调试了。