本机环境 Win7 + VMware 14 Pro
1.安装Qemu,Ubuntu包管理器中的二进制版本比较老了,这里选择源码安装2.12.0版本。
具体的安装教程可以参考这篇文章《QEMU 2.10.1 编译安装》,写的非常详细。
2.下载、编译目标的内核版本
这里下载的是4.4.1版本的Linux内核 linux-4.4.1.tar.xz
解压 编译

xz - d linux-4.4.1.tar.xz
tar -xvf linux-4.4.1.tar
cd linux-4.4.1
make menuconfig

确保以下三个选项是勾选上的:
1 2 3
|
kernel hacking –> Kernel debugging kernel hacking –> Compile- time checks and compiler options –> compile the kernel with debug info kernel hacking –> Compile- time checks and compiler options -> compile the kernel with frame pointers
|
在多核平台上使用-j 参数来加快编译
3.制作根文件系统
先了解以下几个文件的区别,参考这篇文章
1 2 3 4 5 6 7
|
vmlinux 是ELF文件,即编译出来的最原始的文件。
vmlinuz 应该是由ELF文件vmlinux经过OBJCOPY后,并经过压缩后的文件
zImage 是vmlinuz经过 gzip 压缩后的文件,适用于小内核
bzImage 是vmlinuz经过 gzip 压缩后的文件,适用于大内核
|
新建一个目录用于存放生成的内核文件,以及根文件系统:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
mkdir ~ /Desktop/kernel-debug
cp . /arch/x86/boot/bzImage ~ /Desktop/kernel-debug
cd ~ /Desktop/kernel-debug
dd if = /dev/zero of=rootfs.img bs=1M count=20
mkfs -t ext3 rootfs.img
mkdir rootfs
sudo mount -t ext3 -o loop rootfs.img rootfs
sudo mkdir rootfs /dev rootfs /proc rootfs /sys
|
给系统安装基本的命令行工具,比如ls,这里选择了BusyBox,下载的BusyBox源码
1 2 3 4 5 6 7 8 9 10
|
cd ~ /Desktop/kernel-debug <br> tar -jxvf busybox-1.28.3. tar .bz2<br> cd busybox-1.28.3<br> make menuconfig<br> make -j make install CONFIG_PREFIX=~ /Desktop/kernel-debug/rootfs <br> sudo umount ~ /Desktop/kernel-debug/rootfs
|
4.启动Qemu虚拟机
1
|
sudo qemu-system-x86_64 -S -kernel ~ /Desktop/kernel-debug/bzImage -hda ~ /Desktop/kernel-debug/rootfs .img -append "root=/dev/sda init=/bin/ash"
|
此时启动的Qemu处于Pasued状态,单机黑色区域,让Qemu接收输入,按下ctrl+ alt + 2,切换到控制台。
注意之后可以通过ctrl + alt + G 来让qemu释放鼠标以及键盘输入。

启动gdbserver,监听到8888端口,便于用GDB来远程调试。

5.使用GDB连接到gdbserver进行调试
由于GDB用的不太熟悉,这里使用图形化的调试工具DDD,可以通过以下命令安装:
1 2 3 4 5
|
sudo apt-get install ddd cd linux-4.4.1 ddd vmlinux
|
在GDB命令处,连接到Qemu中的GDB server:target remote 127.0.0.1:8888,这个时候Qemu中的Linux系统是处于Paused状态的。
连接之后可以在菜单栏Status-->BackTrace...中看到堆栈信息。

输入continue,让Qemu中的Linux系统运行起来,可以在Qemu中按下ctrl+Alt+1,切换到虚拟机的命令行界面,可以看到这个时候虚拟机已经正常运行起来了。

这里对Linux创建进程的系统调用下断点,观察调用栈:
在fork.c文件中的_do_fork函数处下断点:

切换到Qemu,使用ctrl+Alt+1回到Linux的控制台,运行ls,这时候shell会创建ls进程,这个时候ddd就会断下来了:

【作者】张昺华
【新浪微博】 张昺华--sky
【微信公众号】 张昺华