- 建立Qemu aarch64仿真开发环境
主机平台:Ubuntu 20.04.2 LTS
工作目录:
export WORK_DIR=/home/tom/hdd/linux-qemu/repos
1.1 安装qemu-system-aarch64
sudo apt-get install qemu-system-aarch64
Note: 也可以下载qemu源码自行编译安装,具体请参考[1]的2.2节.
1.2 通过buidroot搭建initramfs cpio文件系统
我们使用buildroot软件包[3]来制作rootfs文件系统映像,下载buildroot软件包,并进入配置界面:
wget https://buildroot.org/downloads/buildroot-2021.08.tar.bz2 tar xvf buildroot-2021.02.4.tar.bz2 cd buildroot-2021.02.4 make menuconfig
1.2.1 配置模板ARM64目标平台
Target options->AArch64(little endian)
Target options-> Target Architecture Variant (cortex-A57
示意图如下:
1.2.2 配置交叉编译器
Toolchain->Toolchain type 选择“External toolchain”:
Toolchain->Toolchain选择"Arm AArch64 2020.11”:
Note: 选择Linaro AArch64 2018.05版本也是可以的。
1.2.3 配置登录用户名和密码
System configuration-> Enable root login with password, 并且设置root密码,这里设置为"adsf”:
1.2.4 配置Linux 控制台
System configuration-> Run a getty (login prompt) after boot->TTY port设置为"ttyAMA0"。
1.2.5 配置目标平台常用工具包
Target packages->选择Show packages that are also provided by busybox:
Target packages-> Debugging, profiling and benchmark可以选择自己感兴趣的工具,这里选择strace:
1.2.4 配置文件系统格式
Filesystem images选择cpio the root filesystem (for use as an initial RAM filesystem):
1.2.5 编译buildroot文件系统
cd $WORK_DIR/buildroot-2021.08 make
buildroot-2021.08/output/images目录下会生成两个系统映像:
1.3编译ARM64平台的Linux Kernel
安装交叉工具链
sudo apt install gcc-aarch64-linux-gnu
下载Linux内核,并生成默认的配置文件:
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.14.6.tar.xz tar xvf linux-5.14.6.tar.xz cd linux-5.14.6 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
在产生的linux-5.14.6/.config文件中修改以下三个选项:
CONFIG_CMDLINE="console=ttyAMA0" CONFIG_INITRAMFS_SOURCE="/home/tom/hdd/linux-qemu/repos/buildroot-2021.08/output/images/rootfs.cpio" CONFIG_DEBUG_INFO=y
编译kernel:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j4
在编译的过程中会出现需要用户配置选项的交互输入,则一路默认回车键,直到出现交互输入Built-in initramfs compression mode时,因为我们编译initramfs文件系统时,没有选择压缩模式,所以这里选择8:
继续回车,直到遇到Kernel command line type交互输入时,选择1:
其余一路回车直到配置结束.
然后再次运行编译命令:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j4
生成vmlinux,Image,Image.gz示意图如下:
Note: Linux原始镜像为vmlinux,后续可能是Image、Image.gz、uImage镜像, 处理过程是
- 通过link-vmlinux.sh生成vmlinux和map文件。
- 通过objcopy移除vmlinux中不必要段,输出binary格式Image。
- 对Image进行压缩,输出不同格式的压缩文件,比如gzip对应的gz。
- 对gz加上uboot头信息,生成uImage文件。
ARM64平台则仅支持Image.gz和Image
1.4启动 Qemu Linux系统
qemu-system-aarch64 \ -machine virt \ -cpu cortex-a57 \ -machine type=virt \ -nographic -smp 1 \ -m 2048 \ -kernel ./arch/arm64/boot/Image \ --append "console=ttyAMA0"
示意图如下:
2.调试ARM64平台的Linux Kernel
2.1 在主机和Qemu ARM64平台虚拟机间共享文件
在buildroot-2021.08/.config文件中更新选项:
BR2_ROOTFS_OVERLAY="/home/tom/hdd/linux-qemu/repos/buildroot-files"
然后再次编译buildroot和Linux kernel
cd $WORK_DIR/buildroot-2021.08/ make cd $WORK_DIR/linux-5.14.6 make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j4
启动Linux Kernel后,我们就可以看到拷贝的文件:
2.2 调试ptrace()系统调用的示例
示例代码:
#include <stdio.h> #include <stdlib.h> #include <sys/ptrace.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> int main(int argc, const char *argv[]) { int pid; if ((pid = fork() == 0)) { // The child process does a PTRACE_TRACEME, // While being traced, the tracee will stop each time a signal is delivered, // even if the signal is being ignored. ptrace(PTRACE_TRACEME, 0, NULL, NULL); execl("/bin/ls", "ls", "-l", NULL); } else { // block parent process until any of its children has finished. wait(NULL); // to tell child process to run until the next system call (enter or exit) // until the child process exits. ptrace(PTRACE_SYSCALL, pid, 0, 0); ptrace(PTRACE_CONT, pid, NULL, NULL); } return 0; }
编译示例代码(因为我们运行的目标平台是ARM64,所以这里必须使用交叉编译器):
cd $WORK_DIR/buildroot-files aarch64-linux-gnu-gcc simple_trace.c -o simple_trace
示意图如下:
2.3调试内核并截获ptrace系统调用
启动Qemu Linux并冻结CPU等待gdb调试运行.
cd $WORK_DIR/ linux-5.14.6 qemu-system-aarch64 \ -machine virt \ -cpu cortex-a57 \ -machine type=virt \ -nographic -smp 1 \ -m 2048 \ -kernel ./arch/arm64/boot/Image \ --append "console=ttyAMA0" \ -s -S
-S:冻结CPU等待gdb的continue命令
-s: 是"-gdb tcp::1234"的简写,意思是通过本机的1234端口接听gdb命令
打开另外一个终端,输入命令
cd $WORK_DIR/ linux-5.14.6 gdb-multiarch ./vmlinux
备注:
如果gdb-multiarch没安装的化,使用命令
sudo apt-get intall gdb-multiarch
安装gdb-multiarch。
在gdb 命令窗口输入:
set architecture aarch64 target remote localhost:1234 continue
这样qemu上的Linux会收到gdb输入的continue命令,继续运行,我们在Linux 终端输入命令:
cat /proc/kallsyms |grep sys_ptrace
cat /proc/kallsyms |grep sys_ptrace |
获取系统调用服务例程sys_ptrace()的入口地址,这里是0xffff80001008fea8:
在gdb命令中,我们在地址0xffff80001008fea8设置断点,然后在Linux中运行我们的示例:
就会在gdb中截获这个断点,这样我们可以用gdb命令调试指定的例程,比如这里的sys_ptrace。示意图如下:
大伙在搭建的过程中,如果遇到问题,欢迎留言或者mail to cwsun@prtos.org
参考文献
[1]http://www.prtos.org/xen_on_arm64_and_qemu/
[2]https://www.cnblogs.com/arnoldlu/p/14102272.html
评论