使用QEMU(8.2.10)调试ARM64 Linux内核6.6.30

1. 环境及目标

环境:Ubuntu 24.04.1 LTS

目标:在x86的设备上,调试ARM64的Linux内核


2. qemu的编译安装

2.1 qemu下载

通过网址https://download.qemu.org/进行相应版本选择下载,我们选择比较新的版本,8.2.10进行下载

复制代码
wget https://download.qemu.org/qemu-8.2.10.tar.xz
tar -xvf qemu-8.2.10.tar.xz
cd qemu-8.2.10/

2.2. 安装依赖

2.2.1 配置ubuntu 24.04的源

vim /etc/apt/sources.list.d/ubuntu.sources

复制代码
Types: deb deb-src
URIs: http://mirrors.ustc.edu.cn/ubuntu/
Suites: noble noble-updates noble-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

2.2.2 安装依赖包

复制代码
apt update
apt install make bison flex build-essential libncurses-dev libssl-dev pkg-config ninja-build libglib2.0-dev libpixman-1-dev libcap-dev libncurses5-dev gcc-arm-linux-gnueabi zlib1g-dev libglib2.0-dev python3-pip slirp libslirp0

2.2.3 安装sphinx

复制代码
apt install python3-sphinx python3-msmb-theme python3-dask-sphinx-theme

2.2.4 ninja

复制代码
apt-get install re2c
git clone https://github.com/ninja-build/ninja.git
cd ninja && ./configure.py --bootstrap  
cp ./ninja /usr/bin/
ninja --version

2.2.5 libcap-ng

virtio-9p (virtfs) on Linux requires libcap-ng-devel and libattr-devel

复制代码
wget https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/libcap-ng/0.8.5-1/libcap-ng_0.8.5.orig.tar.gz
apt install dh-autoreconf
tar -xvf tar -xvf libcap-ng_0.8.5.orig.tar.gz
cd libcap-ng-0.8.5/
./autogen.sh
./configure
make
make install

2.3 qemu编译安装

复制代码
./configure --target-list=aarch64-softmmu,aarch64-linux-user  --enable-slirp
make -j16
make install

注:打开--enable-slirp开关对上层组件的主要影响是qemu增加了一种user mode的网络后端实现,该网络后端的实现是在用户态实现的一套tcp/ip协议栈。qemu下-netdev多了一个user的选项参数。user mode的网络简单、独立性好、无需 root 权限、虚拟机网络隔离,但是缺点也很明显:网络性能差、不支持 ICMP 协议,也就 ping 不通、外部网络不能直接访问虚拟机,可以用于一般的测试场景。

3. 内核编译

3.1 下载kernel

复制代码
git clone  https://android.googlesource.com/kernel/common
git checkout -b android15-6.6-pkvm_experimental origin/android15-6.6-pkvm_experimental

3.2 交叉编译

交叉编译ARM64 Linux内核,编译完毕后,对应目录会有生成的内核镜像:

复制代码
ARCH=arm64 make CROSS_COMPILE=aarch64-linux-gnu-  O=build menuconfig

Kernel Features
  -> [ ] Randomize the address of the kernel image
Device Drivers 
  -> Block devices
     <*>   RAM block device support
        (16)    Default number of RAM disks (NEW)
        (65536) Default RAM disk size (kbytes)

交叉编译

复制代码
ARCH=arm64 make CROSS_COMPILE=aarch64-linux-gnu-  O=build -j16
  • O=build 表示编译的文件输出到build目录,不跟源码混在一起

    root@kernel:~/common# file build/arch/arm64/boot/Image
    build/arch/arm64/boot/Image: Linux kernel ARM64 boot executable Image, little-endian, 4K pages


4. busybox文件系统制作

参考《aarch64环境下编译kvmtool,基于kvmtool启动最小linux(busybox)》

交叉编译aarch64 BusyBox,安装交叉编译环境依赖

复制代码
apt-get install gcc-aarch64-linux-gnu

下载buysbox源码

复制代码
wget https://busybox.net/downloads/busybox-1.35.0.tar.bz2
tar -xvf busybox-1.35.0.tar.bz2
cd busybox-1.35.0/

把busybox配置为静态编译,这样busybox在运行的时候就不需要额外的动态链接库

复制代码
-> Settings
  -> Build Options
    -> Build BusyBox as a static binary (no shared libs)
Networking Utilities -->
    [ ] tc  

交叉编译BusyBox可执行文件,并输出到_install目录:

复制代码
ARCH=arm64 make CROSS_COMPILE=aarch64-linux-gnu- menuconfig
ARCH=arm64 make CROSS_COMPILE=aarch64-linux-gnu-  -j16
ARCH=arm64 make CROSS_COMPILE=aarch64-linux-gnu- install

5. GDB调试

5.1 安装gdb-multiarch

复制代码
apt install gdb-multiarch

5.2 启动虚拟机

复制代码
qemu-system-aarch64   -nographic -M virt -cpu cortex-a57 -smp 2 -m 4G   --kernel common/build/arch/arm64/boot/Image   -append "nokaslr root=/dev/ram0 rdinit=/linuxrc console=ttyAMA0"   -initrd busybox-1.35.0/rootfs.cpio.gz -s -S 
  • nokaslr 表示关闭地址随机化
  • -S 在启动时冻结CPU(使用'c'开始执行)
  • -s -gdb tcp::1234的简写

上面的命令会停止,新开一个终端,使用如下命令调试:

复制代码
cd ~/common/build
# vmlinux 是编译内核时生成的调试文件
gdb-multiarch vmlinux
# 连接 qemu 进行调试:
target remote :1234
# 设置断点
b start_kernel
# 执行内核
c

6. 问题记录

  • libslirp GnuTLS recv error (-110): The TLS connection was non-properly terminated.

    Cloning into 'slirp'...
    fatal: unable to access 'https://gitlab.freedesktop.org/slirp/libslirp.git/': GnuTLS recv error (-110): The TLS connection was non-properly terminated.

    ../meson.build:945:10: ERROR: Git command failed: ['/usr/bin/git', 'clone', 'https://gitlab.freedesktop.org/slirp/libslirp.git', 'slirp']

    A full log can be found at /root/qemu-8.2.10/build/meson-logs/meson-log.txt

    ERROR: meson setup failed

解决方法:

由于无法访问https://gitlab.freedesktop.org/slirp/libslirp.git,将其改成

https://gitlab.com/qemu-project/libslirp.git

vim ./subprojects/slirp.wrap

复制代码
[wrap-git]
url = https://gitlab.com/qemu-project/libslirp.git 
revision = 26be815b86e8d49add8c9a8b320239b9594ff03d

[provide]
slirp = libslirp_dep
  • busybox CROSS_COMPILE 编译出错

    root@kernel:~/busybox-1.35.0# ARCH=aarch64 make CROSS_COMPILE=aarch64-linux-gnu- install -j16
    CC networking/tc.o
    CC networking/tftp.o
    CC networking/tls.o
    CC networking/tls_aes.o
    CC networking/tls_fe.o
    CC networking/tls_aesgcm.o
    CC networking/tls_pstm.o
    CC networking/tls_pstm_montgomery_reduce.o
    CC networking/tls_pstm_mul_comba.o
    CC networking/tls_pstm_sqr_comba.o
    CC networking/tls_rsa.o
    CC networking/tls_sp_c32.o
    CC networking/traceroute.o
    CC networking/tunctl.o
    networking/tc.c: In function 'cbq_print_opt':
    networking/tc.c:236:27: error: 'TCA_CBQ_MAX' undeclared (first use in this function); did you mean 'TCA_CBS_MAX'?
    236 | struct rtattr *tb[TCA_CBQ_MAX+1];
    | ^~~~~~~~~~~
    | TCA_CBS_MAX
    networking/tc.c:236:27: note: each undeclared identifier is reported only once for each function it appears in
    networking/tc.c:249:16: error: 'TCA_CBQ_RATE' undeclared (first use in this function); did you mean 'TCA_TBF_RATE64'?
    249 | if (tb[TCA_CBQ_RATE]) {
    | ^~~~~~~~~~~~
    | TCA_TBF_RATE64
    networking/tc.c:255:16: error: 'TCA_CBQ_LSSOPT' undeclared (first use in this function)
    255 | if (tb[TCA_CBQ_LSSOPT]) {
    | ^~~~~~~~~~~~~~
    networking/tc.c:256:61: error: invalid application of 'sizeof' to incomplete type 'struct tc_cbq_lssopt'
    256 | if (RTA_PAYLOAD(tb[TCA_CBQ_LSSOPT]) < sizeof(*lss))
    | ^
    networking/tftp.c: In function 'tftpd_main':
    networking/tftp.c:886:15: warning: 'local_file' is used uninitialized [-Wuninitialized]
    886 | char *local_file = local_file;
    | ^~~~~~~~~~
    networking/tftp.c:886:15: note: 'local_file' was declared here
    886 | char *local_file = local_file;
    | ^~~~~~~~~~
    CC networking/vconfig.o
    networking/tc.c:261:16: error: 'TCA_CBQ_WRROPT' undeclared (first use in this function)
    261 | if (tb[TCA_CBQ_WRROPT]) {
    | ^~~~~~~~~~~~~~
    networking/tc.c:262:61: error: invalid application of 'sizeof' to incomplete type 'struct tc_cbq_wrropt'
    262 | if (RTA_PAYLOAD(tb[TCA_CBQ_WRROPT]) < sizeof(*wrr))
    | ^
    networking/tc.c:267:16: error: 'TCA_CBQ_FOPT' undeclared (first use in this function)
    267 | if (tb[TCA_CBQ_FOPT]) {
    | ^~~~~~~~~~~~
    networking/tc.c:268:59: error: invalid application of 'sizeof' to incomplete type 'struct tc_cbq_fopt'
    268 | if (RTA_PAYLOAD(tb[TCA_CBQ_FOPT]) < sizeof(*fopt))
    | ^
    CC networking/wget.o
    networking/tc.c:273:16: error: 'TCA_CBQ_OVL_STRATEGY' undeclared (first use in this function)
    273 | if (tb[TCA_CBQ_OVL_STRATEGY]) {
    | ^~~~~~~~~~~~~~~~~~~~
    networking/tc.c:274:67: error: invalid application of 'sizeof' to incomplete type 'struct tc_cbq_ovl'
    274 | if (RTA_PAYLOAD(tb[TCA_CBQ_OVL_STRATEGY]) < sizeof(*ovl))
    | ^
    networking/tc.c:277:50: error: invalid application of 'sizeof' to incomplete type 'struct tc_cbq_ovl'
    277 | (unsigned) sizeof(*ovl));
    | ^
    networking/tc.c:293:23: error: invalid use of undefined type 'struct tc_cbq_lssopt'
    293 | if (lss && lss->flags) {
    | ^~
    networking/tc.c:296:24: error: invalid use of undefined type 'struct tc_cbq_lssopt'
    296 | if (lss->flags&TCF_CBQ_LSS_BOUNDED) {
    | ^~
    CC networking/whois.o
    CC networking/zcip.o
    networking/tc.c:296:32: error: 'TCF_CBQ_LSS_BOUNDED' undeclared (first use in this function)
    296 | if (lss->flags&TCF_CBQ_LSS_BOUNDED) {
    | ^~~~~~~~~~~~~~~~~~~
    networking/tc.c:300:24: error: invalid use of undefined type 'struct tc_cbq_lssopt'
    300 | if (lss->flags&TCF_CBQ_LSS_ISOLATED) {
    | ^~
    networking/tc.c:300:32: error: 'TCF_CBQ_LSS_ISOLATED' undeclared (first use in this function)
    300 | if (lss->flags&TCF_CBQ_LSS_ISOLATED) {
    | ^~~~~~~~~~~~~~~~~~~~
    networking/tc.c:308:24: error: invalid use of undefined type 'struct tc_cbq_wrropt'
    308 | if (wrr->priority != TC_CBQ_MAXPRIO)
    | ^~
    networking/tc.c:308:38: error: 'TC_CBQ_MAXPRIO' undeclared (first use in this function)
    308 | if (wrr->priority != TC_CBQ_MAXPRIO)
    | ^~~~~~~~~~~~~~
    networking/tc.c:309:46: error: invalid use of undefined type 'struct tc_cbq_wrropt'
    309 | printf("prio %u", wrr->priority);
    | ^~
    networking/tc.c:313:43: error: invalid use of undefined type 'struct tc_cbq_wrropt'
    313 | printf("/%u ", wrr->cpriority);
    | ^~
    networking/tc.c:314:32: error: invalid use of undefined type 'struct tc_cbq_wrropt'
    314 | if (wrr->weight != 1) {
    | ^~
    networking/tc.c:315:65: error: invalid use of undefined type 'struct tc_cbq_wrropt'
    315 | print_rate(buf, sizeof(buf), wrr->weight);
    | ^~
    networking/tc.c:318:32: error: invalid use of undefined type 'struct tc_cbq_wrropt'
    318 | if (wrr->allot)
    | ^~
    networking/tc.c:319:57: error: invalid use of undefined type 'struct tc_cbq_wrropt'
    319 | printf("allot %ub ", wrr->allot);
    | ^~
    networking/tc.c:236:24: warning: unused variable 'tb' [-Wunused-variable]
    236 | struct rtattr *tb[TCA_CBQ_MAX+1];
    | ^~
    make[1]: *** [scripts/Makefile.build:197: networking/tc.o] Error 1
    make[1]: *** Waiting for unfinished jobs....
    networking/wget.c: In function 'retrieve_file_data':
    networking/wget.c:1085:33: warning: ignoring return value of 'ftruncate' declared with attribute 'warn_unused_result' [-Wunused-result]
    1085 | ftruncate(G.output_fd, pos);
    | ^~~~~~~~~~~~~~~~~~~~~~~~~~~
    make: *** [Makefile:744: networking] Error 2

解决方法

修改 BusyBox 的配置文件

make menuconfig取消 tc 这个工具的编译,

复制代码
Networking Utilities -->
    [ ] tc 

7. 参考文献

https://blog.csdn.net/nanhai_happy/article/details/124941074?spm=1011.2415.3001.5331

https://zhuanlan.zhihu.com/p/624853021

https://blog.csdn.net/thisinnocence/article/details/127931774

https://blog.csdn.net/nanhai_happy/article/details/146915229?spm=1001.2014.3001.5502

https://blog.csdn.net/nanhai_happy/article/details/124835581

相关推荐
哈哈幸运17 分钟前
MySQL运维三部曲初级篇:从零开始打造稳定高效的数据库环境
linux·运维·数据库·mysql·性能优化
soulermax29 分钟前
数字ic后端设计从入门到精通2(含fusion compiler, tcl教学)
java·linux·服务器
黑心老人33 分钟前
Mac OS系统下kernel_task占用大量CPU资源导致系统卡顿
linux·运维·服务器·macos
Thomas_YXQ38 分钟前
Unity3D ILRuntime与Scripting Backend整合指南
服务器·开发语言·unity·unity3d
光算科技1 小时前
服务器在国外国内用户访问慢会影响谷歌排名吗?
运维·服务器·c++
Zenexus1 小时前
Linux学习笔记协议篇(六):SPI FLASH设备驱动
linux·笔记·arm
口嗨农民工1 小时前
ubuntu18.04启动不了修复
linux·运维·ubuntu
塔能物联运维1 小时前
双轮驱动能源革命:能源互联网与分布式能源赋能工厂能效跃迁
大数据·运维
辣个蓝人QEX2 小时前
【ZYNQ MP开发】Linux下使用bootgen命令生成BOOT.bin报错架构不对问题探究
linux·arm开发·xilinx·zynq·mpsoc·bootgen·u-boot移植
Vesan,2 小时前
无人机飞控运行在stm32上的RTOS实时操作系统上,而不是linux这种非实时操作系统的必要性
linux·stm32·无人机