qemu搭建虚拟的aarch64环境开发ebpf

一、背景

        需求在嵌入式环境下进行交叉编译,学习ebpf相关技术,所以想搭建一个不依赖硬件环境的学习环境。

本文使用的环境版本:

宿主机: Ubuntu24.02

libbpf-bootstrap源码:

https://github.com/libbpf/libbpf-bootstrap

Linux内核源码:Linux 5.4.123  

下载地址:

Index of /kernel/linux/kernel/v5.x/https://mirror.bjtu.edu.cn/kernel/linux/kernel/v5.x/https://mirror.bjtu.edu.cn/kernel/linux/kernel/v5.x/

交叉编译链:gcc-linaro-7.5.0-2019.12-x86_64_aarch64

Linaro Releases

Buildroot版本:buildroot-2024.02.9

下载地址:

Buildroot - Making Embedded Linux Easy

Qemu安装:

qemu-system-aarch64启动Linux内核 - PolarisZg - 博客园

二、调试环境搭建

2.1 内核支持ebpf配置

ws@ws-pc:~/qemu/aarch64/linux-5.4.123$ make ARCH=arm64 menuconfig

除了上述配置,还需要开启kprobe、uprobe、tracing、debugfs、bfp相关配置。最终好用的config如上传的附件。

如果内核配置模块未启用,会导致类似如下报错。

上述报错在源码中debug定位,最后会发现失败在相关 syscall中,补全就好。

2.2 buildroot编译rootfs文件系统

        制作rootfs根文件系统的方式目前流行的有三种,一种是直接使用busybox直接制作,这种系统占用内存小,适合嵌入式系统上运行,但是缺少很多工具,不便于学习;第二种是使用buildroot直接源码编译制作,简单可定制化;第三种是基于ubuntu等开源系统的最小包,在此基础上追加制作。本文选择使用buildroot的方式,编译出来的roofs提供给qemu使用,由于是虚拟板子没有串口,所以bulidroot一定要选择支持ssh 或者 telent的方式登陆,这样后面才可以有多个终端登陆。

制作教程资料很多,本文在制作时,没有制作内核,交叉编译链使用的系统自带的:

基于Linux的Buildroot 制作根文件系统(rootfs)_buildroot制作根文件系统-优快云博客

基本配置:

设置root权限的登陆密码:

取消内核编译:

open SSH相关需要打开,打开server,这样可以ssh登陆:

文件系统选择的ext4:

还需要执行,在busybox添加一下telnet:

make busybox-menuconfig

2.3 qemu安装启动内核

命令行直接安装qemu: 教程也很多,就直接安装就好了

sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager -y

注意网络net使用 tap的方式,可以让qemu出现网卡:

宿主机上需要进行如下网络配置,开发板可以直接访问公网,但是DHCP没有自动获取到IP,所以板子启动之后还需要手动设置以下IP:

qemu aarch64虚拟机创建好后,使用NAT连接网络 - wswang - 博客园

Documentation/Networking/NAT - QEMU

#!/bin/sh
#-initrd /home/ws/qemu/aarch64/rootfs.cpio.gz \
#        -kernel /home/ws/qemu/aarch64/rootfs/kernel_5.4_rootfs/Image \

qemu-system-aarch64 \
        -machine virt,virtualization=true,gic-version=3 \
        -nographic \
        -m size=4096M \
        -cpu cortex-a76 \
        -net tap -net nic \
        -smp 4 \
        -kernel /home/ws/qemu/aarch64/linux-5.4.123/arch/arm64/boot/Image \
        -drive file=/home/ws/qemu/aarch64/rootfs/kernel_5.4_rootfs/rootfs.ext4,if=none,format=raw,id=hd0 \
        -device virtio-blk-device,drive=hd0 \
        -append "rootwait root=/dev/vda rw console=ttyAMA0 rdinit=/linuxrc"
#! /bin/sh
ifconfig eth0 192.168.53.10 netmask 255.255.255.0 up
mount -t nfs -o nolock,vers=3 192.168.53.1:/home/ws/qemu /mnt

有了网络之后,就可以设置虚拟开发板和宿主机之间的nfs,教程如下:

Qemu - 百问网嵌入式Linux wiki

2.4 gdbserver远程debug

      由于环境搭建过程中遇到很多奇奇怪怪的错误,但是提示报错的原因又很少不准确,所以需求搭建一个vscode+gdb的远程调试工具,来debug libbpf-bootstrap工程。

一开始是使用交叉编译环境,使用源码编译的方式来搭建,但是发现高版本的又需要交叉编译库,低版本的编译出来gdbserver在开发版上执行报错,所以还了一种简单的方式来搭建。

宿主机安装 gdb-multiarch:

sudo apt-get update
sudo apt-get install gdb-multiarch

which gdb-multiarch

目标机直接下载其他人编译好的版本:(下载可能需要梯子)

https://github.com/skyedai910/gdbserver-all-in-one/releases

设置vscode相关设置:

指定要debug的进程minimal_legacy,在指定使用的gdb工具,使用witch可以看到安装路径。在指定远程调试的gdb地址和端口号。

{
    // 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": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/aarch64/rohc-2.3.1/build_aarch64/sbin/rohc_sniffer", 
            "args": ["-m 512 --rohc-version 1 --stat largecid wlP2p33s0"],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "Set Disassembly Flavor to Intel",
                    "text": "-gdb-set disassembly-flavor intel",
                    "ignoreFailures": true
                }
            ],
            "miDebuggerPath": "/usr/bin/gdb-multiarch",
            "miDebuggerServerAddress": "192.168.31.113:12345"
        }
    ]
}
orangepi@orangepi5plus:~/ROHC/build_aarch64/sbin$ sudo ./gdbserver 192.168.31.106:12345 sudo ./rohc_sniffer -m 512 --rohc-version 1 --stat largecid wlP2p33s0


-g -Oo 

将gdbserver拷贝到目标开发板的nfs路径下,远程执行。

打开内核的编译优化,两处地方加上-O0,否则单步调试的时候会乱跳:

2.5 libbpf-bootstrap编译

bilibili有位up主讲的非常好,这里引用一下:

libbpf-bootstrap交叉编译_libbpf-bootstrap arm-优快云博客

这里同时分享以下我的编译脚本:

gcc_7.5.sh

#! /bin/sh
export PATH=/home/ws/chain_tools/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

2.5.1  zlib-1.3.1 zlib编译

make_zlib.sh

cd zlib-1.3.1
source ~/env/gcc_7.5.sh
#export PATH=$PATH:/usr/bin/
export CC=aarch64-linux-gnu-gcc
./configure --prefix=$PWD/_install
make -j16
make install

2.5.2 elfutils-0.192 编译

make_elfutils.sh

cd elfutils-0.192
# 参考当前目录下的 INSTALL 文档 和 网上资料
source ~/env/gcc_7.5.sh
export CFLAGS="-fPIC -I /home/ws/qemu/ebpf_arm64/zlib-1.3.1/_install/include"
export LDFLAGS="-L /home/ws/qemu/ebpf_arm64/zlib-1.3.1/_install/lib -Wl,-rpath-link,/home/ws/qemu/ebpf_arm64/zlib-1.3.1/_install/lib"
./configure --prefix=$PWD/_install --build=x86_64-linux-gnu \
        --host=aarch64-linux-gnu \
    CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ \
    --disable-nls --disable-rpath --disable-libdebuginfod --disable-debuginfod \
    --with-zlib=/home/ws/qemu/ebpf_arm64/zlib-1.3.1/_install/lib
make -j16
make install

2.5.3 libbpf的example编译

在这个example的编译Makefile和cMake最好需要了解以下原理,这里推进一个up主的视频:

03-09-libbpf样例程序Makefile脚本解读_哔哩哔哩_bilibili

make_libbpf.sh

#!/bin/sh
cd ./libbpf-bootstrap/examples/c

source ~/env/gcc_7.5.sh
export ARCH=arm64

export CROSS_COMPILE=aarch64-linux-gnu-
export EXTRA_CFLAGS="-fPIC -I /home/ws/qemu/ebpf_arm64/elfutils-0.192/_install/include -I /home/ws/qemu/ebpf_arm64/zlib-1.3.1/_install/include"
export EXTRA_LDFLAGS="-L /home/ws/qemu/ebpf_arm64/elfutils-0.192/_install/lib -Wl,-rpath-link,/home/ws/qemu/ebpf_arm64/elfutils-0.192/_install/lib -L /home/ws/qemu/ebpf_arm64/zlib-1.3.1/_install/lib -Wl,-rpath-link,/home/ws/qemu/ebpf_arm64/zlib-1.3.1/_install/lib"

#make -j16 V=1
make minimal_legacy  V=1

make_libbpf_clean.sh

#!/bin/sh
cd /home/ws/qemu/ebpf_arm64/libbpf-bootstrap/examples/c
make clean

cd /home/ws/qemu/ebpf_arm64/libbpf-bootstrap/libbpf/src
make clean

cd /home/ws/qemu/ebpf_arm64/libbpf-bootstrap/bpftool/src
make clean

三、遇到的问题

3.1 高版本内核编译时生成BTF失败

Linux 5.19在编译的时候,生成BTF文件失败,但是Linux 5.4.123内核的时候能够成功。

BTF: .tmp_vmlinux.btf: pahole (pahole) is not available Failed to generate BTF for vmlinux Try to disable CONFIG_DEBUG_INFO_BTF make: *** [Makefile:1100:vmlinux] 错误 1

原因:Ubuntu 24.04 apt-get install默认安装的pohole 版本过高,需要降低到v1.22版本

源码编译安装:下载对应版本的源码编译安装,注意tag版本

https://github.com/acmel/dwarves/tree/v1.22

git clone --recurse-submodules https://github.com/acmel/dwarves.git

git checkout tags/v1.22

git switch -c v1.22

cd dwarves
mkdir build
cd build
cmake -D__LIB=lib -DBUILD_SHARED_LIBS=OFF ..
sudo make install

安装完成之后需要更新一下动态库,如果安装错了,需要卸载:

#!/bin/bash

# 定义要删除的文件和目录列表
files=(
    "/usr/local/bin/codiff"
    "/usr/local/bin/ctracer"
    "/usr/local/bin/dtagnames"
    "/usr/local/bin/pahole"
    "/usr/local/bin/pdwtags"
    "/usr/local/bin/pfunct"
    "/usr/local/bin/pglobal"
    "/usr/local/bin/prefcnt"
    "/usr/local/bin/scncopy"
    "/usr/local/bin/syscse"
    "/usr/local/lib/libdwarves.so.1.0.0"
    "/usr/local/lib/libdwarves.so.1"
    "/usr/local/lib/libdwarves.so"
    "/usr/local/lib/libdwarves_emit.so.1.0.0"
    "/usr/local/lib/libdwarves_emit.so.1"
    "/usr/local/lib/libdwarves_emit.so"
    "/usr/local/lib/libdwarves_reorganize.so.1.0.0"
    "/usr/local/lib/libdwarves_reorganize.so.1"
    "/usr/local/lib/libdwarves_reorganize.so"
    "/usr/local/include/dwarves/dwarves.h"
    "/usr/local/include/dwarves/dwarves_emit.h"
    "/usr/local/include/dwarves/dwarves_reorganize.h"
    "/usr/local/include/dwarves/dutil.h"
    "/usr/local/include/dwarves/gobuffer.h"
    "/usr/local/include/dwarves/list.h"
    "/usr/local/include/dwarves/rbtree.h"
    "/usr/local/include/dwarves/btf_encoder.h"
    "/usr/local/include/dwarves/config.h"
    "/usr/local/include/dwarves/ctf.h"
    "/usr/local/include/dwarves/elfcreator.h"
    "/usr/local/include/dwarves/elf_symtab.h"
    "/usr/local/include/dwarves/hash.h"
    "/usr/local/include/dwarves/libctf.h"
    "/usr/local/share/man/man1/pahole.1"
    "/usr/local/bin/ostra-cg"
    "/usr/local/share/dwarves/runtime/python/ostra.py"
    "/usr/local/bin/btfdiff"
    "/usr/local/bin/fullcircle"
    "/usr/local/share/dwarves/runtime/Makefile"
    "/usr/local/share/dwarves/runtime/ctracer_relay.c"
    "/usr/local/share/dwarves/runtime/ctracer_relay.h"
    "/usr/local/share/dwarves/runtime/linux.blacklist.cu"
)

# 循环删除文件和目录
for file in "${files[@]}"; do
    if [ -f "$file" ]; then
        echo "Deleting file: $file"
        rm -f "$file"
    elif [ -d "$file" ]; then
        echo "Deleting directory: $file"
        rm -rf "$file"
    fi
done

# 清理动态库缓存
echo "Updating dynamic library cache..."
sudo /sbin/ldconfig

echo "Uninstallation complete."

3.2 执行时报错 object 'minimal_legacy_': failed (-22) to create BPF token from '/sys/fs/bpf', skipping optional step

一开始不确定是否是该原因导致无法加载,后面是将libbpf和bpftool仓库都降低了版本之后编译解决。

Tags · libbpf/bpftool · GitHub

Tags · libbpf/libbpf · GitHub

切换到指定版本的方式:

git checkout tags/v7.3.0

git switch -c v7.3.0

# bpftool下面有子仓库,使用下面命令能够自动更新子仓库
git submodule update --init

3.3 编译libbpf example程序的时候,报错编译链存在问题

需要将两处cc改为gcc,否则使用的编译链是cc结尾,本人安装的交叉编译链下没有这个。

3.4 报错/sys/fs/bpf failed (-22) to create BPF token from '/sys/fs/bpf', skipping optional step...

内核配置里面有相关的模块没有使能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值