bpftrace最新发布的0.17.0加入了对arm平台的支持,所以就想为arm平台编译一版bpftrace。值得注意的是,bpftrace才加入对arm 32位的支持(#2360,#2361),由于之前一直是基于64位系统,所以现在工作的还不是很好,还有一些bug。
yocto环境准备
bpftrace相关的bb在meta-clang。同时我想使用一个真实arm平台的BSP,而不是yocto提供的虚拟机qemuarm,所以我还加入了meta-raspberrypi。考虑到需要克隆很多仓库,所以借助repo工具。
1 2 3 4 5 6 7
| mkdir bpftrace-arm cd bpftrace-arm repo init -u https://gitlab.com/pkemb/yocto-manifest.git -b master repo sync repo start master --all export TEMPLATECONF=${PWD}/meta/meta-pkemb/conf/templates/bpftrace-arm source meta/poky/oe-init-build-env
|
说明:
- pkemb/yocto-manifest默认使用内网的镜像地址。
- 环境变量
TEMPLATECONF用于指定示例配置文件的位置,详细说明参考yocto文档。
repo sync默认会从Google服务器下载最新版的repo工具。由于一些原因,国内无法下载。可以设置环境变量export REPO_URL=https://mirrors.tuna.tsinghua.edu.cn/git/git-repo,从清华源下载。
- 现在(2023年2月12日)meta-clang中的bpftrace版本是0.16.0,0.16.0 ~ 0.17.0有一些关于32位的修改,这些补丁在meta-pkemb中有加入。
修改bb文件
修改bpftrace及其相关依赖的bb文件,在COMPATIBLE_HOST变量中加入arm。
bcc_0.26.0.bb和bpftrace_0.16.0.bb。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@@ -68,4 +68,4 @@ do_install_ptest() { FILES:${PN} += "${PYTHON_SITEPACKAGES_DIR}" FILES:${PN}-doc += "${datadir}/${PN}/man"
-COMPATIBLE_HOST = "(x86_64.*|aarch64.*|powerpc64.*|riscv64.*)-linux" +COMPATIBLE_HOST = "(x86_64.*|aarch64.*|arm.*|powerpc64.*|riscv64.*)-linux"
@@ -54,5 +54,5 @@ EXTRA_OECMAKE = " \ -DENABLE_MAN=OFF \ "
-COMPATIBLE_HOST = "(x86_64.*|aarch64.*|powerpc64.*|riscv64.*)-linux" +COMPATIBLE_HOST = "(x86_64.*|aarch64.*|arm.*|powerpc64.*|riscv64.*)-linux" COMPATIBLE_HOST:libc-musl = "null"
|
libbpf_0.8.0.bb。
1 2 3 4 5 6 7 8 9 10 11 12
|
@@ -12,7 +12,7 @@ SRC_URI = "git://github.com/libbpf/libbpf.git;protocol=https;branch=master" SRCREV = "86eb09863c1c0177e99c2c703092042d3cdba910"
PACKAGE_ARCH = "${MACHINE_ARCH}" -COMPATIBLE_HOST = "(x86_64|i.86|aarch64|riscv64|powerpc64).*-linux" +COMPATIBLE_HOST = "(x86_64|i.86|aarch64|arm|riscv64|powerpc64).*-linux"
S = "${WORKDIR}/git/src"
|
启动编译
yocto是在编译前通过do_fetch任务下载bb指定的源代码,下载很有可能会失败。所以建议把所有的fetch任务跑完之后,再开始编译。建议晚上睡觉前编译,因为clang需要编译非常非常非常久。
1 2 3 4
| # 下载所有的源代码 bitbake bpftrace --runall=fetch # 开始编译 bitbake bpftrace
|
编译成功之后,bpftrace可执行文件在 build/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/bpftrace/0.16.0+gita277ec42102c463d656df8f64eb2f7e87e322210-r0/package/usr/bin。
运行bpftrace
yocto编译时所使用的glibc版本,与平台里的glibc版本可能不一致,所以bpftrace是无法直接运行的。为了将bpftrace跑起来,需要一些技巧,这里提供两个参考的方法。
复制文件到arm平台
为了缩短路径长度,以下相对路径均基于bpftrace的工作目录build/tmp/work/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi/bpftrace/0.16.0+gita277ec42102c463d656df8f64eb2f7e87e322210-r0/。
- 在编译主机打包
recipe-sysroot目录,复制到arm平台并解压。假设是放在arm平台的/root/bpf/recipe-sysroot目录。
- 将编译主机的文件
package/usr/bin/bpftrace复制到arm平台的/root/bpf/recipe-sysroot/usr/bin目录。
方法一:chroot
通过chroot命令,为bpftrace打造一个专属的rootfs,包含bpftrace对应的glibc,以及依赖的库和头文件。
编写wrapper脚本/usr/bin/bpftrace_chroot.sh,内容如下。记得给脚本加可执行权限。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #!/bin/sh
SYSROOT="/root/bpf/recipe-sysroot"
mkdir -p $SYSROOT/proc $SYSROOT/sys
if ! mount | grep -q $SYSROOT/proc; then mount --bind /proc $SYSROOT/proc fi
if ! mount | grep -q $SYSROOT/sys; then mount --bind /sys $SYSROOT/sys fi
if ! mount | grep -q $SYSROOT/sys/kernel/debug; then mount --bind /sys/kernel/debug $SYSROOT/sys/kernel/debug fi
chroot /root/bpf/recipe-sysroot /usr/bin/bpftrace "$@"
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| root@raspberrypi:~# bpftrace_chroot.sh -l '*sleep*' hardware:*sleep*: kprobe:__rpc_sleep_on_priority kprobe:alarm_timer_nsleep kprobe:alarm_timer_nsleep_restart kprobe:alarmtimer_do_nsleep kprobe:alarmtimer_nsleep_wakeup kprobe:brcmf_sdio_bus_sleep kprobe:brcmf_sdio_sleep kprobe:common_nsleep kprobe:do_cpu_nanosleep kprobe:do_nanosleep kprobe:dwc_otg_get_lpm_portsleepstatus kprobe:fscache_object_sleep_till_congested kprobe:gpiod_cansleep ......
|
方法二:patchelf
首先使用patchelf修改bpftrace的解释器,然后修改LD_LIBRARY_PATH。具体步骤如下。
1 2 3 4
| cd /root/bpftrace/recipe-sysroot/usr/bin # 备份一下 cp bpftrace bpftrace_patchelf patchelf --set-interpreter /root/bpf/recipe-sysroot/lib/ld-linux-armhf.so.3 ./bpftrace_patchelf
|
编写wrapper脚本/usr/bin/bpftrace_patchelf.sh,内容如下。记得给脚本加可执行权限。
1 2 3 4 5
| #!/bin/bash
export LD_LIBRARY_PATH=/root/bpf/recipe-sysroot/lib:/root/bpf/recipe-sysroot/usr/lib
/root/bpftrace/recipe-sysroot/usr/bin/bpftrace_patchelf "$@"
|
测试:
1 2 3 4 5 6 7 8 9 10 11 12
| root@raspberrypi:~# bpftrace_patchelf.sh -l '*sleep*' hardware:*sleep*: kprobe:__rpc_sleep_on_priority kprobe:alarm_timer_nsleep kprobe:alarm_timer_nsleep_restart kprobe:alarmtimer_do_nsleep kprobe:alarmtimer_nsleep_wakeup kprobe:brcmf_sdio_bus_sleep kprobe:brcmf_sdio_sleep kprobe:common_nsleep kprobe:do_cpu_nanosleep ......
|
已知问题
无法获取到正确的数值型数据
如下面的命令,pid是一个非常大的值,系统中并没有这个进程。tid、nsecs等参数也是类似的。
1 2 3 4 5 6 7 8 9
| root@raspberrypi:~# bpftrace_patchelf.sh -e 'kprobe:do_nanosleep { printf("PID %s(%d) sleeping...\n", comm, pid); }' sh: relocation error: /root/bpf/recipe-sysroot/lib/libc.so.6: symbol __nptl_set_robust_list_avail version GLIBC_PRIVATE not defined in file ld-linux-armhf.so.3 with link time reference Attaching 1 probe... PID sleep(2128712024) sleeping... PID sleep(2128712024) sleeping... PID sleep(2128712024) sleeping... PID cron(2128712024) sleeping... PID sleep(2128712024) sleeping... PID sleep(2128712024) sleeping...
|
参考