qemu+gdb+vscode环境搭建
1. 环境准备
1.1 安装基础软件
apt-get install vim
apt-get install vim-scripts
apt-get install vim-gtk
apt-get install fcitx (中文输入法需要)
apt-get install fcitx-libs (中文输入法需要)
apt-get install kolourpaint4(图片编辑软件)
apt-get install rar (压缩、解压文件)
apt-get install unrar
apt-get install wine (模拟win系统环境)
apt-get install hexedit (16进制编辑器)
apt-get install net-tools(网络相关工具)
apt-get install wireshark (可选,抓包软件)
1.2 安装开发软件
apt-get install libncurses5-dev
apt-get install libelf-dev
apt-get install libssl-dev
apt-get install bison
apt-get install git
apt-get install gcc-arm-linux-gnueabi
apt-get install build-essential
apt-get install ninja-build
apt-get install libpixman-1-dev
apt-get install flex(编译用到的词法分析器)
1.3 安装qemu
1)安装qemu
方法一:版本可能较老,但安装速度快
apt-get install qemu-system-x86 (安装x86架构qemu执行程序)
apt install qemu-system-arm (安装arm架构qemu执行程序)
方法二:安装新版本,编译时间长(编译后,生成所有架构的qemu执行程序)
wget https://download.qemu.org/qemu-6.1.0-rc4.tar.xz
tar xvjf qemu-6.1.0-rc4.tar.xz
cd qemu-6.1.0-rc4
./configure
make
2)安装qume工具
apt install qemu-utils
2. 制作rootfs
2.1 buildroot制作rootfs
root@linux:~#wget https://buildroot.org/downloads/buildroot-2020.02.8.tar.gz
root@linux:~#tar zxvf buildroot-2020.02.8.tar.gz && cd buildroot-2020.02.8
root@linux:~#export ARCH=x86_64
root@linux:~#export FORCE_UNSAFE_CONFIGURE=1
root@linux:~#make menuconfig
Toolchain --->
# 编译一些package会用到,比如f2fstools
[*] Enable WCHAR support
System configuration --->
# 系统启动后,密码为空,回车登录shell
[*] Enable root login with password
( ) Root password
# 设置eth0接口为DHCP,如果不设置,qemu启动kernel镜像后,需要手动配置网络
(eth0) Network interface to configure through DHCP
Target packages --->
Filesystem and flash utilities --->
# 格式化f2fs用到
[*] f2fs-tools
Filesystem images --->
[ ] ext2/3/4 root filesystem
# 设置rootfs的文件系统类型
[*] f2fs root filesystem
root@linux:~#make
编译时间较长,等编译完成后,在output/images目录中生成rootfs.f2fs文件。将该文件拷贝到内核源码目录即可,如下:
root@linux:/home/gsf/linux-5.10.3# ls| grep f2fs
rootfs.f2fs
注意点:
1)修改buildroot-2020.02.8/package目录下的package,重新编译前,需要删除output/build/目录中对应的package,否则编译出来的rootfs.f2fs不会包含改动。
2.2 busybox制作rootfs
-
编译_install目录
root@linux:/home/gsf/source-code/busybox-1.33.0# export ARCH=arm
root@linux:/home/gsf/source-code/busybox-1.33.0# export CROSS_COMPILE=arm-linux-guneabi-
root@linux:/home/gsf/source-code/busybox-1.33.0# make menuconfig
Settings –> Build Options –> [*] Build static binary (no shared libs)。若没有编译成静态库,需要将宿主机/bin、/sbin目录中的动态库文件拷贝到_install目录中。为了简化,编译成静态库即可。
root@linux:/home/gsf/source-code/busybox-1.33.0# make install
编译完成后,会在当前目录中生成一个_install目录。将其拷贝到linux源码根目录。
-
制作rootfs用到的文件
-
将busybox的提供的example中的etc目录拷贝到_install中,,并稍作修改。
root@linux:/home/gsf/debug/kernel/linux-5.10.3# cp …/busybox-1.33.0/examples/bootfloppy/etc ./_install/ -R
修改1:./_install/etc/inittab
tty2::askfirst:-/bin/sh ---------> ::askfirst:-/bin/sh
修改2:./_install/etc/fstab 增加下面3行
sysfs /sys sysfs defaults 0 0 tmpfs /dev tmpfs defaults 0 0 tmpfs /tmp tmpfs defaults 0 0
修改3:./_install/etc/ini.d增加2行,注意顺序,改成下面的样子
#! /bin/sh
mkdir /proc /sys /tmp
/bin/mount -a
mdev -s
-
在_install目录中创建基本目录
root@linux:/home/gsf/debug/kernel/linux-5.10.3/_install# mkdir dev mnt
-
在dev目录创建设备节点:
mknod console c 5 1 mknod null c 1 1
3. kernel编译及运行
3.1 编译内核
内核源码:linux-5.10.3
root@linux:/home/gsf/linux-5.10.3# export ARCH=“x86_64”
root@linux:/home/gsf/linux-5.10.3# make x86_64_defconfig
root@linux:/home/gsf/linux-5.10.3# make menuconfig
Processor type and features --->
[ ] Randomize the address of the kernel image (KASLR) 不要选
Drevice Drivers --->
NVME Support
<*> NVM Express block device
[*] NVMe multipath support
[*] NVMe hardware monitoring
<*> NVM Express over Fabrics FC host driver
<*> NVM Express over Fabrics TCP host driver
File systems --->
<*> F2FS filesystem support
[*] F2FS Status Information (NEW)
[*] F2FS extended attributes (NEW)
[*] F2FS Access Control Lists (NEW)
Network File Systems--->
<*> NFS client support
<*> NFS client support for NFS version 2
<*> NFS client support for NFS version 3
[*] NFS client support for the NFSv3 ACL protocol extension
<*> NFS client support for NFS version 4
<*> SMB3 and CIFS support (advanced network filesystem)
Kernel hacking --->
Compile-time checks and compiler options --->
[*] Compile the kernel with debug info
[*] Provide GDB scripts for kernel debugging
注:高版本改成了
Kernel hacking --->
Compile-time checks and compiler options --->
Debug information (Disable debug information) --->
(X)Generate DWARF Version 5 debuginfo
[*] Provide GDB scripts for kernel debugging
root@linux:/home/gsf/linux-5.10.3#make -j4 bzImage
3.2 启动内核
qemu启动内核后,如果想退出,可以在qemu中执行Ctlr+A,然后按x键。
也可以在ubuntu另一个终端 killall qemu-system-x86_64(不建议)。
-
仅rootfs启动
最简单的启动,资源很少,无disk,无网络。
qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -drive file=rootfs.f2fs,if=ide,format=raw -nographic -append "root=/dev/sda console=ttyS0"
启动完成后,用户名输入root,登录系统查看信息,f2fs已经挂载:
# cat /proc/mounts
/dev/root / f2fs rw,lazytime,relatime,background_gc=on,discard,no_heap,user_xattr,inline_xattr,acl,inline_data,inline_dentry,flush_merge,exte0
devtmpfs /dev devtmpfs rw,relatime,size=48612k,nr_inodes=12153,mode=755
-
挂载 scsi disk(格式化成ext4)启动
- 制作ext4镜像
root@linux:/home/gsf/linux-5.10.3#dd if=/dev/zero of=ext4.img bs=1M count=256
root@linux:/home/gsf/linux-5.10.3# mkfs.ext4 ext4.img
- 执行qemu命令
qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -drive file=rootfs.f2fs,if=ide,format=raw,id=myid0 --nographic -append "root=/dev/sda console=ttyS0" -hdb ext4.img
系统启动后,输入root用户名登录系统。
- 修改挂载表
创建目录
# mkdir /mnt/scsimp
并在/etc/fstab文件中增加一行:
/dev/sdb /mnt/scsimp ext4 defaults 0 0
- reboot重新模拟出来的系统(不是自己的电脑系统),可以看到ext4已经挂载
# cat /proc/mounts
……
sysfs /sys sysfs rw,relatime 0 0
/dev/sdb /mnt/scsimp ext4 rw,relatime 0 0
-
挂载 scsi disk(格式化成ext4)+ nvme disk(格式化成f2fs)
- 制作ext4镜像
root@linux:/home/gsf/linux-5.10.3#dd if=/dev/zero of=ext4.img bs=1M count=25
root@linux:/home/gsf/linux-5.10.3# mkfs.ext4 ext4.img
- 制作nvme的模拟磁盘
root@linux:/home/gsf/linux-5.10.3#qemu-img create -f raw disk.qcow 1G
- 执行qemu命令
qemu启动后,红字部分在/dev/目录下生成了nmve0,nvme0n1两个文件(如果没有生成,按第二节设置kenel编译config文件,打开nvme相关配置)。
qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -drive file=rootfs.f2fs,if=ide,format=raw,id=myid0 –nographic -append “root=/dev/sda console=ttyS0” -hdb ext4.img
-device nvme,drive=nvme1,serial=deadbeaf,num_queues=8 -drive file=disk.qcow,if=none,id=nvme1 -smp 4
- 登录启动的linux系统
创建目录
# mkdir /mnt/scsimp
# mkdir /mnt/nvmemp
并在/etc/fstab文件中增加两行:
/dev/sdb /mnt/scsimp ext4 defaults 0 0
/dev/nvme0n1p1 /mnt/nvmemp f2fs defaults 0 0 -------后面会将disk.qcow格式化成f2fs,所以这里按f2fs挂载
格式化nvme disk
#
fdisk /dev/nvme0n1
Device contains neither a valid DOS partition table, nor Sun, SGI, OSF
or GPT disklabelBuilding a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that the previous content
won’t be recoverable.
Command (m for help):
n
Partition type
p primary partition (1-4)
e extended
p
Partition number (1-4):
1
First sector (32-2097151, default 32): ————回车,默认即可
Using default value 32
Last sector or +size{,K,M,G,T} (32-2097151, desfault 2097151):
————回车,默认即可Using default value 2097151
Command (m for help):
w
The partition table has been altered.
Calling ioctl() to re-read partition table
[ 131.575409] nvme0n1: p1
格式化成功后,出现/dev/nvme0n1p1设备,这就是刚fdisk新建的分区
格式化新建的nvme分区
mkfs.f2fs -L nvmedisk /dev/nvme0n1p1
(这里也可以格式化成其他文件系统)
注:如果没有mkfs.f2fs工具,请参考 上面部分2.制作rootfs
- reboot重启qemu模拟出来的系统(不是自己的电脑系统),登录后,可以看到scsi、nvme disk已经挂载
# cat /proc/mounts
……
sysfs /sys sysfs rw,relatime 0 0
/dev/sdb /mnt/scsimp ext4 rw,relatime 0 0
/dev/nvme0n1p1 /mnt/nvmemp f2fs rw,relatime 0 0
另外,还可以看到系统中有5个nvme队列。nvme0q0是管理队列。nvme0q1~4是IO队列每个核一个(我们的qemu命令指定了num_queues=8、smp 4参数)。
# cat /proc/interrupts
# cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
0: 183 0 0 0 IO-APIC 2-edge timer
1: 0 0 9 0 IO-APIC 1-edge i8042
……
24: 6 0 0 0 PCI-MSI 65536-edge nvme0q0
25: 0 0 0 11 PCI-MSI 65537-edge nvme0q1
26: 0 0 0 0 PCI-MSI 65538-edge nvme0q2
27: 0 0 0 0 PCI-MSI 65539-edge nvme0q3
28: 0 0 0 0 PCI-MSI 65540-edge nvme0q4
3.3 qemu参数说明
qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -drive file=rootfs.f2fs,if=ide,format=raw,id=myid0 –nographic -append “root=/dev/sda console=ttyS0” -hdb ext4.img -device nvme,drive=nvme1,serial=deadbeaf,num_queues=8 -drive file=disk.qcow2,if=none,id=nvme1 -smp 4 -s
-kernel 要运行的内核镜像
-drive 理解成一个虚拟的disk。
drive option之 file:代表该disk的文件,由“qemu-img create -f 格式”生成。
drive option之 if:interface,指定disk的接口,有ide, scsi, sd, mtd, floppy,
pflash, virtio, none这些类型。drive option之 format:format:代码disk的file的格式,创建文件时由qemu-img create -f指定。
drive option之 id:一个字符串标识。有多个dirve时,通过id来识别用哪个drive。
–nographic:关闭图形调试,将打印信息输出到串口。
-append :kernel的命令行参数。
append之root:rootfs存储设备。
append之console:串口名称。
-hdb:创建一个hard disk。注意,字符串hdb不是/dev/hdb(这个个IDE disk),这里的hdb启动后,是/dev/sdb(scsi disk)。hdb image可以通过mkfs格式化成需要的文件系统。
-device:创建一个总线设备。将子参数drive=id指定的disk挂在总线下。
devie值num_queues:nvme的队列深度。
-smp:多核数量。
-s:监听gdb端口, gdb程序可以通过1234这个端口连上来。下文配置图形化调试需要
4. vscode 图形化调试环境配置
vscode中集成了GDB功能,我们可以用它来图形化的调试linux kernel
4.1 vscode配置
首先我们添加vscode的gdb配置文件(.vscode/launch.json):
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "kernel debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/vmlinux",
"cwd": "${workspaceFolder}",
"MIMode": "gdb",
"miDebuggerPath":"/usr/bin/gdb-multiarch",
"miDebuggerServerAddress": "localhost:1234"
}
]
}
这里对几个重点参数做一些说明:
program: 调试的符号文件
miDebuggerPath:gdb的路径, 这里需要注意的是,由于我们是arm64内核,因此需要用gdb-multiarch来进行调试
miDebuggerServerAddress:对端地址,qemu会默认使用1234这个端口
配置完成之后,可以直接启动GDB, 连接上linux kernel
4.2 qemu配置
为了能够图形化调试,qemu启动时需要加上-s参数,默认使用1234端口