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 1024M -smp 4 -kernel linux-5.4.60/arch/x86_64/boot/bzImage -append "root=/dev/sda console=ttyS0 nokaslr" -hda rootfs.img

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

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

-m表示使用设置Guest可以使用的内存空间大小;

-smp表示Guest虚拟机中启用的CPU核心数量;

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

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

-append指定内核启动参数。

这里调试内核使用的是压缩内核bzImage,如果使用它,那么就需要往内核启动参数添加“nokaslr”,因为内核配置的是内存随机化了,所以必须添加,否则无法断点。但是使用的Kernel也可以是未压缩的vmlinux,这样就可以不添加nokaslr参数。对的,没错,就是这么好玩,如果使用未压缩的mlinux似乎没法进入系统,具体原因还没分析,大概率估计和内存相关。

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

target remote :1234

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

 

参考链接:https://tthtlc.wordpress.com/2020/01/28/how-to-create-rootfs-filesystem-for-ubuntu-18-04/

4 replies on “Qemu调试内核环境搭建”

  1. 说道:

    -append “root=/dev/sda console=ttyS0 nokaslr”
    实际测试下这行参数需要调整,否则会报错的,qemu版本5.1。

    这个参数nokaslr需要放在最前面,后面增加init=/bin/sh,即最后是-append “nokaslr root=/dev/sda console=ttyS0 init=/bin/sh”

  2. haolee说道:

    博主两年没更新了,最近终于又开更了,我记得你以前是在cu博客吧

    • JeanLeo说道:

      是的,以前一直在CU,文章敏感字太多了,总会被屏蔽,然后独立搞了个博客,欢迎常来,以后会常更的

发表评论

电子邮件地址不会被公开。 必填项已用*标注