为raspberrypi编译bpftrace调试工具

基于eBPF的嵌入式应用调试

笔者之前写过几篇有关于使用eBPF调试Linux内核和应用的博客,其中提到,在嵌入式设备上使用BCC或bpftrace是不可行的;主要原因在于嵌入式设备的资源有限,而这两个调试工具依赖python/clang/llvm等库,需要将脚本编译为eBPF字节码加载入Linux内核来执行。然而,随着嵌入式设备的性能越来越强,板载资源越来越多,在嵌入式设备上运行bpftrace工具已成为可能。本文整理了笔者为raspberrypi 4设备编译bpftrace工具的过程,按照这些操作,笔者为工作中的嵌入式设备也制作了可用的bpftrace调试工具。

另外,22.04版本的Ubuntu系统自带的bpftrace已经不能用了,主要的原因是它不带符号表(strip -s);本文的内容也可用于PC端的bpftrace工具编译构建:

root@ubuntu:/usr/sbin# uname -a
Linux ubuntu 5.15.0-97-generic #107-Ubuntu SMP Wed Feb 7 13:26:48 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
root@ubuntu:/usr/sbin# ./execsnoop.bt
Attaching 3 probes...
ERROR: Could not resolve symbol: /proc/self/exe:BEGIN_trigger

编译使用的设备

首先,笔者使用的raspberrypi 4可插入两张TF卡,两张卡分别安装了debian系统和笔者编译的openwrt系统,二者的Linux内核版本大致相同,均为6.1版本。其次,树莓派设备的内存大小为2GB,这一点非常重要;因为bcc/bpftrace是由C++编写的,编译过程非常耗内存(笔者使用clang编译器构建)。最后,笔者是为了在openwrt系统中使用bpftrace,因此要求在构建openwrt系统时,选择glibc库。

零,安装clang编译器

编译在是树莓派的debian系统上完成的。需要按照apt.llvm.org的说明操作来安装,笔者选择了安装clang-10编译器:

wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
./llvm.sh 10

之后,我们需要在debian安装其他依赖库(而不编译所有的依赖库,否则耗时太久了)。以下需要安装的库,是在raspberrypi/openwrt系统上缺少的,后面会直接复制到安装有openwrt系统的TF卡上:

sudo apt install flex bison zlib1g-dev liblzma-dev libbz2-dev cmake \libzstd-dev dwarves build-essential python3-setuptools libpython3-dev

一,编译elfutils

笔者下载了最新版本的elfutils,它提供了libelf依赖库,该软件包的配置、编译操作如下:

../configure --prefix=/opt/bpftrace CC=clang-10 CXX=clang++-10 \CFLAGS='-Wall -fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -Wno-unused-parameter' \CXXFLAGS='-Wall -fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -Wno-unused-parameter' \--disable-nls --enable-libdebuginfod=dummy --disable-debuginfod --with-zlib --with-lzma \--with-bzlib --with-zstd LDFLAGS='-Wl,-rpath=/opt/bpftrace/lib'
make && sudo make install

以上配置完成后,再执行make && sudo make install即可安装。

二,编译libbpf库

这里需要强调的是,依笔者的经验,libbpf库以及bcc、bpftrace版本的选择,不能任意;一定要根据Linux内核版本来选择。例如,树苺派的Linux内核版本为6.1,那么确认该版本内核的(初始)发布日期(是2023年初发布的),然后选择时间上相近的libbpf库。这里笔者选择的版本为libbpf-1.2.2。然而工作中,笔者因使用的嵌入式设备比较老,使用的版本为0.1.1

该库的编译操作如下:

cd $HOME ; tar -zxf libbpf-1.2.2.tar.gz
cd libbpf-1.2.2/src
make V=1 PREFIX=/opt/bpftrace CC=clang-10 CFLAGS='-fPIC -O2 -ggdb -Wall -fno-omit-frame-pointer -I/opt/bpftrace/include' LDFLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib'
sudo make V=1 PREFIX=/opt/bpftrace CC=clang-10 CFLAGS='-fPIC -O2 -ggdb -Wall -fno-omit-frame-pointer -I/opt/bpftrace/include' LDFLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' install

注意,以上编译的库在debian/arm64系统下会被安装到/opt/bpftrace/lib64路径下,需要移到/opt/bpftrace/lib路径下,并修改/opt/bpftrace/lib/pkgconfig/libbpf.pc文件。

三,安装cereal头文件

早期的bpftrace工具不依赖该库,但现在是需要了,笔者选择了cereal-1.3.2.tar.gz版本:

mkdir -p build_aarch64 && cd build_aarch64
cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=/opt/bpftrace \-DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 \-DCMAKE_C_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer' \-DCMAKE_CXX_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer' \-DBUILD_DOC=OFF -DBUILD_SANDBOX=OFF -DSKIP_PERFORMANCE_COMPARISON=ON -DBUILD_TESTS=OFF ..
sudo make install

注意,该库以头文件的形式提供,以上不会有动态库编译生成。

四,编译bcc

bcc的版本为v0.27.0,笔者已验证最新版本的bcc编译得到的bpftrace存在异常。需要注意的是,笔者下载的源代码文件名为bcc-src-with-submodule.tar.gz。以下是配置、编译安装的操作:

mkdir -p build_aarch64 && cd build_aarch64
cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=/opt/bpftrace \-DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 \-DCMAKE_C_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -I/opt/bpftrace/include' \-DCMAKE_CXX_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -I/opt/bpftrace/include' \-DCMAKE_EXE_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DCMAKE_MODULE_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DCMAKE_SHARED_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DENABLE_LLVM_SHARED=ON -DENABLE_TESTS=OFF -DRUN_LUA_TESTS=OFF -DENABLE_LIBDEBUGINFOD=OFF ..
make && sudo make install

编译完成后,笔者删除了所有的静态库(因为笔者希望所有的库是动态链接的):sudo rm -rf /opt/bpftrace/lib/*.a。注意,这个编译过程比较耗时,大约持继在一小时以上。因rasbperrypi 4内存有2GB,上面可以make -j2来编译加速。

五,编译bpftrace

笔者选择的bpftrace版本为v0.17.1(正如上面提到的,笔者验证最新版本的bpftracearm64/linux-6.1系统下运行不正常。配置、编译安装的操作如下:

mkdir -p build_aarch64 && cd build_aarch64
cmake -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=/opt/bpftrace \-DCMAKE_C_COMPILER=clang-10 -DCMAKE_CXX_COMPILER=clang++-10 \-DCMAKE_C_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -I/opt/bpftrace/include -I${HOME}/libbpf-1.2.2/include -I${HOME}/libbpf-1.2.2/include/uapi' \-DCMAKE_CXX_FLAGS='-fPIC -O2 -D_GNU_SOURCE -ggdb -fno-omit-frame-pointer -I/opt/bpftrace/include -I${HOME}/libbpf-1.2.2/include -I${HOME}/libbpf-1.2.2/include/uapi' \-DCMAKE_EXE_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DCMAKE_MODULE_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DCMAKE_SHARED_LINKER_FLAGS='-L/opt/bpftrace/lib -Wl,-rpath=/opt/bpftrace/lib' \-DUSE_SYSTEM_BPF_BCC=ON -DSTATIC_LINKING=OFF -DALLOW_UNSAFE_PROBE=ON -DBUILD_TESTING=OFF ..
make && sudo make install

需要注意的是,上面的编译选项,直接指定了libbpf-1.2.2头文件包含的路径。至此,笔者的编译就结束了,接下来将编译结果复制到安装有openwrt系统的TF卡中。

在raspberrypi/openwrt系统下使用bpftrace

首先,除了/opt/bpftrace外,笔者从树莓派的debian系统中复制了以下库到openwrt系统:

root@OpenWrt:/lib/aarch64-linux-gnu# ls -lh -t | head -n 8
-rw-r--r--    1 root     root       64.8M Sep  9 22:40 libLLVM-10.so.1
-rw-r--r--    1 root     root       65.0K Sep  9 22:42 libbz2.so.1.0
-rw-r--r--    1 root     root       27.7M Sep  9 22:41 libclang-10.so.1
-rw-r--r--    1 root     root      179.1K Sep  9 22:43 libedit.so.2
-rw-r--r--    1 root     root       30.2K Sep  9 22:42 libffi.so.6
-rw-r--r--    1 root     root      130.2K Sep  9 22:41 liblzma.so.5
-rw-r--r--    1 root     root      158.6K Sep  9 22:43 libtinfo.so.5
-rw-r--r--    1 root     root      405.8K Sep  9 22:41 libzstd.so.1

然后,笔者为树莓派的内核使能了相关的内核选项,详见此处的详细说明。还有,bpftrace的正常运行,可能还需要访问内核的头文件,这就需要使能CONFIG_IKHEADERS=m,在树莓派启动后,手动加载该内核模块:insmod kheaders.ko。最后,笔者在树莓派的openwrt系统下使用bpftrace的结果如下:

root@OpenWrt:~# insmod kheaders.ko
module is already loaded - kheaders
root@OpenWrt:~# uname -a
Linux OpenWrt 6.1.50 #0 SMP Fri Sep  1 21:45:47 2023 aarch64 GNU/Linux
root@OpenWrt:~# /opt/bpftrace/bin/bpftrace --info
SystemOS: Linux 6.1.50 #0 SMP Fri Sep  1 21:45:47 2023Arch: aarch64Buildversion: v0.17.1LLVM: 10.0.1unsafe uprobe: nobfd: nolibdw (DWARF support): yeslibbpf: failed to find valid kernel BTF
Kernel helpersprobe_read: yesprobe_read_str: yesprobe_read_user: yesprobe_read_user_str: yesprobe_read_kernel: yesprobe_read_kernel_str: yesget_current_cgroup_id: yessend_signal: yesoverride_return: noget_boot_ns: yesdpath: noskboutput: noKernel featuresInstruction limit: 1000000Loop support: yesbtf: nomap batch: yesuprobe refcount (depends on Build:bcc bpf_attach_uprobe refcount): yesMap typeshash: yespercpu hash: yesarray: yespercpu array: yesstack_trace: yesperf_event_array: yesProbe typeskprobe: yestracepoint: yesperf_event: yeskfunc: noiter:task: noiter:task_file: nokprobe_multi: noraw_tp_special: yesroot@OpenWrt:~# cd /opt/bpftrace/share/bpftrace/tools/
root@OpenWrt:/opt/bpftrace/share/bpftrace/tools# ls
bashreadline.bt    gethostlatency.bt  runqlen.bt         tcpdrop.bt
biolatency.bt      killsnoop.bt       setuids.bt         tcplife.bt
biosnoop.bt        loads.bt           ssllatency.bt      tcpretrans.bt
biostacks.bt       mdflush.bt         sslsnoop.bt        tcpsynbl.bt
bitesize.bt        naptime.bt         statsnoop.bt       threadsnoop.bt
capable.bt         old                swapin.bt          undump.bt
cpuwalk.bt         oomkill.bt         syncsnoop.bt       vfscount.bt
dcsnoop.bt         opensnoop.bt       syscount.bt        vfsstat.bt
doc                pidpersec.bt       tcpaccept.bt       writeback.bt
execsnoop.bt       runqlat.bt         tcpconnect.bt      xfsdist.bt
root@OpenWrt:/opt/bpftrace/share/bpftrace/tools# /opt/bpftrace/bin/bpftrace ./execsnoop.bt
libbpf: failed to find valid kernel BTF
libbpf: failed to find valid kernel BTF
Attaching 3 probes...
TIME(ms)   PID   ARGS
26138      2490  /etc/init.d/firewall reload
26168      2502  readlink /etc/init.d/firewall
26170      2503  basename /etc/init.d/firewall
26172      2504  flock -n 1000
26174      2505  flock 1000
26178      2506  readlink /etc/init.d/firewall
26181      2507  readlink /etc/init.d/firewall
26183      2508  basename /etc/init.d/firewall
26186      2509  flock -n 1000
26188      2510  fw4 reload
26191      2511  flock -x 1000
26193      2512  rm -f /var/run/fw4.state
26195      2513  utpl -S /usr/share/firewall4/main.uc
26195      2514  nft -f /dev/stdin
26303      2515  sh -c /usr/sbin/nft --terse --json list flowtables inet
26305      2515  /usr/sbin/nft --terse --json list flowtables inet
26393      2516  utpl -S /usr/share/firewall4/main.uc
29341      2517  /etc/init.d/firewall status
29371      2529  readlink /etc/init.d/firewall
29373      2530  basename /etc/init.d/firewall
29375      2531  flock -n 1000
29377      2532  flock 1000
29381      2533  readlink /etc/init.d/firewall
29384      2534  basename /etc/init.d/firewall
29387      2537  jsonfilter -e @["firewall"]
29388      2539  jshn -w
29391      2540  ubus call service list { "name": "firewall" }
29397      2543  jsonfilter -e $.instances
63078      2544  /etc/init.d/network status
63108      2556  readlink /etc/init.d/network
63110      2557  basename /etc/init.d/network
63112      2558  flock -n 1000
63114      2559  flock 1000
63118      2560  readlink /etc/init.d/network
63121      2561  basename /etc/init.d/network
63124      2564  jsonfilter -e @["network"]
63125      2566  jshn -w
63128      2567  ubus call service list { "name": "network" }
63134      2570  jsonfilter -e $.instances
63137      2571  jsonfilter -s { "instance1": { "running": true, "pid": 769, "command": [ "\/sbin\/netifd" ], "term_timeout": 5,
"limits": { "core": "unlimited" }, "respawn": { "threshold": 3600, "timeout": 5, "retry": 5 } } } -e $[*].running
^C
root@OpenWrt:/opt/bpftrace/share/bpftrace/tools#

至此,可以说明我们编译的bpftrace工具可以正常工作了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/717864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Scratch 第十六课-弹珠台游戏

第十六课-弹珠台游戏 大家好,今天我们一起做一款弹珠台scratch游戏,我们也可以叫它弹球游戏!这款游戏在刚出来的时候非常火爆。小朋友们要认真学习下! 这节课的学习目标 物体碰撞如何处理转向问题。复习键盘对角色的控制方式。…

STL-内存的配置与释放

STL-内存的配置与释放 STL有两级空间配置器,默认是使用第二级。第二级空间配置器会在某些情况下去调用第一级空间配置器。空间配置器都是在allocate函数内分配内存,在deallocate函数内释放内存。 第一级空间配置器 第一级配置器只是对malloc函数和fre…

【自然语言处理】BitNet b1.58:1bit LLM时代

论文地址:https://arxiv.org/pdf/2402.17764.pdf 相关博客 【自然语言处理】BitNet b1.58:1bit LLM时代 【自然语言处理】【长文本处理】RMT:能处理长度超过一百万token的Transformer 【自然语言处理】【大模型】MPT模型结构源码解析(单机版)…

如何在 Mac 上成功轻松地恢复 Excel 文件

Microsoft Excel 的 Mac 版本始终略落后于 Windows 版本,这也许可以解释为什么如此多的用户渴望学习如何在 Mac 上恢复 Excel 文件。 但导致重要电子表格不可用的不仅仅是 Mac 版 Excel 的不完全稳定性。用户有时会失去注意力并删除错误的文件,存储设备…

2024-03-03 c++

🌸 MFC进度条控件 | Progress Control 1。新建MFC项目(基于对话框、静态库) 2。添加控件,删除初始的3个多余控件 加1个progress control,修改其marquee为true,添加变量:变量名为test_progress。…

Angular基础---HelloWorld---Day1

文章目录 1. 创建Angular 项目2.对Angular架构的最基本了解3.创建并引用新的组件(component)4.对Angular架构新的认识(多组件)5.组件中业务逻辑文件的编辑(ts文件)6.标签中属性的绑定(1) ID的绑定(2) class…

String和String Builder

String和StringBuilder的区别 String类 String类代表字符串。java程序中所有字符串文字(例如“abc”)都被实现为此类的实例。 String类源码是用final修饰的,它们的值在创建后不能被更改。字符串缓冲区支持可变字符串。 String对象是不可变…

STM32 (2)

1.stm32编程模型 将C语言程序烧录到芯片中会存储在单片机的flsah存储器中,给芯片上电后,Flash中的程序会逐条进入到CPU中去执行,进而CPU去控制各种模块(即外设)去实现各种功能。 2.寄存器和寄存器编程 CPU通过控制其…

Apache POI的简单介绍与应用

介绍 Apache POI 是一个处理Miscrosoft Office各种文件格式的开源项目。我们可以使用 POI 在 Java 程序中对Miscrosoft Office各种文件进行读写操作。PS: 一般情况下,POI 都是用于操作 Excel 文件,如图: Apache POI 的应用场景&…

SQL无列名注入

SQL无列名注入 ​ 前段时间,队里某位大佬发了一个关于sql注入无列名的文章,感觉好像很有用,特地研究下。 关于 information_schema 数据库: ​ 对于这一个库,我所知晓的内容并不多,并且之前总结SQL注入的…

设计模式-桥接模式实践案例

桥接模式(Bridge Pattern)是一种结构型设计模式,用于将抽象与实现分离,使它们可以独立地变化。这种模式通过提供一个桥接结构,可以将实现接口的实现部分和抽象层中可变化的部分分离开来。 以下是一个使用 Java 实现桥…

【数据结构】_包装类与泛型

目录 1. 包装类 1.1 基本数据类型和对应的包装类 1.2 (自动)装箱和(自动)拆箱 1.2.1 装箱与拆箱 1.2.2 自动(显式)装箱与自动(显式)拆箱 1.3 valueOf()方法 2. 泛型类 2.1 泛…

【深度学习笔记】计算机视觉——目标检测和边界框

目标检测和边界框 前面的章节(例如 sec_alexnet— sec_googlenet)介绍了各种图像分类模型。 在图像分类任务中,我们假设图像中只有一个主要物体对象,我们只关注如何识别其类别。 然而,很多时候图像里有多个我们感兴趣…

某大型制造企业数字化转型规划方案(附下载)

目录 一、项目背景和目标 二、业务现状 1. 总体应用现状 2. 各模块业务问题 2.1 设计 2.2 仿真 2.3 制造 2.4 服务 2.5 管理 三、业务需求及预期效果 1. 总体业务需求 2. 各模块业务需求 2.1 设计 2.2 仿真 2.3 制造 2.4 服务 2.5 管理 四、…

在vue中对keep-alive的理解,它是如何实现的,具体缓存的是什么?

对keep-alive的理解,它是如何实现的,具体缓存的是什么? (1)keep-alive有以下三个属性:注意:keep-alive 包裹动态组件时,会缓存不活动的组件实例。主要流程 (2&#xff09…

数字化转型导师坚鹏:证券公司数字化营销

证券公司数字化营销 ——借力数字化技术实现零售业务的批量化、精准化、场景化、智能化营销 课程背景: 很多证券公司存在以下问题: 不知道如何提升证券公司数字化营销能力? 不知道证券公司如何开展数字化营销工作? 不知道…

胎神游戏集第二期

延续上一期 一、海岛奇胎 #include<bits/stdc.h> #include<windows.h> #include<stdio.h> #include<conio.h> #include<time.h> using namespace std; typedef BOOL (WINAPI *PROCSETCONSOLEFONT)(HANDLE, DWORD); PROCSETCONSOLEFONT SetCons…

Linux 安装pip和换源

一 配置文档 Linux和macOS&#xff1a; 全局配置&#xff1a;/etc/pip.conf 用户级配置&#xff1a;~/.pip/pip.conf 或 ~/.config/pip/pip.conf 二 下载 和 安装 # pip 安装 wget https://bootstrap.pypa.io/get-pip.py python get-pip.py 三 查看和升级 pip -Vpython -m…

GO语言学习笔记(与Java的比较学习)(十一)

协程与通道 什么是协程 一个应用程序是运行在机器上的一个进程&#xff1b;进程是一个运行在自己内存地址空间里的独立执行体。一个进程由一个或多个操作系统线程组成&#xff0c;这些线程其实是共享同一个内存地址空间的一起工作的执行体。 并行是一种通过使用多处理器以提…

Java虚拟机 - JVM

JVM的内存区域划分 JVM它其实也是一个进程,进程运行的过程中,会从操作系统中申请一些资源.内存就是其中的一种.这些内存就支撑了java程序的运行.JVM从系统中申请的一大块内存,会根据实际情况和使用用途来划分出不同的空间,这个就是区域划分.它一般分为 堆区, 栈区, 程序计数器…