推荐一款轻量级 eBPF 前端工具 ply【转】
转自:https://tinylab.org/ply-intro/
推荐一款轻量级 eBPF 前端工具 ply
By Jianguo Sun of TinyLab.org Oct 11, 2020
1 Overview
ply 是 eBPF 的 front-end 前端工具之一,专为 embedded Linux systems 开发,采用 C 语言编写,只需 libc 和内核支持 BPF 就可以运行,不需要外部 kernel 模块,不需要 LLVM,不需要 python。
ply 由瑞典工程师 Tobias Waldekranz 开发,其项目主页是 PLY Light-weight Dynamic Tracer for Linux 。
使用非常灵活和轻量级,编辑一种类 C 语言的脚本,然后利用内核 eBPF 来收集和探测内核数据,比如打印出内核函数的调用栈,获取内核变量等,是学习内核,进行嵌入式 Linux 系统开发调试的利器!
本文记录 ply 的编译及使用过程,实验例程源码都已上传到 https://github.com/jgsun/buildroot。
2 内核配置
注意: 为顺利使用 ply,内核需要比较新的版本,并且支持 eBPF 和 FTRACE,选择如下配置:
CONFIG_KPROBES=yCONFIG_HAVE_DYNAMIC_FTRACE=yCONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=yCONFIG_HAVE_FTRACE_MCOUNT_RECORD=yCONFIG_FTRACE=yCONFIG_DYNAMIC_FTRACE=yCONFIG_BPF=yCONFIG_BPF_SYSCALL=y
本文实验中所采用内核版本为 Linux v5.8.4。
3 ply 编译
3.1 交叉编译
请提前准备好交叉编译器,大部分 Linux 发行版都提供 ARM64 交叉编译器,直接用包管理工具安装即可,以 Ubuntu 为例:
$ sudo apt-get install gcc-aarch64-linux-gnu
交叉编译步骤举例如下:
$ git clone https://github.com/wkz/ply$ ./autogen.sh// 先安装到本地目录下$ ./configure --host=aarch64-linux-gnu --prefix=~/usr$ make$ make install
查看安装目录 ~/usr:
~/usr$ tree.|-- include| `-- ply| |-- arch.h| |-- buffer.h| |-- func.h| |-- internal.h| |-- ir.h| |-- kallsyms.h| |-- node.h| |-- perf_event.h| |-- ply.h| |-- printxf.h| |-- provider.h| |-- sym.h| |-- syscall.h| |-- type.h| `-- utils.h|-- lib| |-- libply.a| |-- libply.la| |-- libply.so -> libply.so.0.0.0| |-- libply.so.0 -> libply.so.0.0.0| `-- libply.so.0.0.0|-- sbin| `-- ply`-- share`-- doc`-- ply|-- COPYING`-- README.md7 directories, 23 files
将 lib 目录的库文件和 sbin 目录的可执行文件 ply 拷贝到 target 板卡的文件系统即可使用,例如:
主机:
~/usr$ scp -P 22 lib/* root@192.168.122.46:/lib~/usr$ scp -P 22 sbin/ply root@192.168.122.46:~/bin
目标板卡:
root@~/bin# ./ply -vply 2.1.1-11-g6aabe5f (linux-version:267277~4.20.13)root@~/bin# uname -aLinux qemu-aarch64 5.8.4 #4 SMP Fri Oct 16 11:05:52 CST 2020 aarch64 GNU/Linux
3.2 使用 buildroot 编译
ply 项目采用 GNU’s autotools build 系统,非常容易集成到 buildroot,首先在 buildroot 添加 ply package,然后执行 make ply 编译即可。
可以从 buildroot/package/ply 下载,也可以参考下述 patch 修改:
diff --git a/package/Config.in b/package/Config.inindex cb6d8e0e01..7dd278242e 100644--- a/package/Config.in+++ b/package/Config.in@@ -2321,6 +2321,7 @@ menu "System tools"source "package/openrc/Config.in"source "package/openvmtools/Config.in"source "package/pamtester/Config.in"+ source "package/ply/Config.in"source "package/polkit/Config.in"source "package/powerpc-utils/Config.in"source "package/procps-ng/Config.in"diff --git a/package/ply/.Config.in.swp b/package/ply/.Config.in.swpnew file mode 100644index 0000000000..1193f698fbBinary files /dev/null and b/package/ply/.Config.in.swp differdiff --git a/package/ply/Config.in b/package/ply/Config.innew file mode 100644index 0000000000..258a59b6fd--- /dev/null+++ b/package/ply/Config.in@@ -0,0 +1,11 @@+config BR2_PACKAGE_PLY+ bool "ply"+ depends on BR2_x86_64 || BR2_aarch64 || BR2_arm || BR2_ppc # needs <cpuid.h>+ depends on BR2_TOOLCHAIN_USES_UCLIBC || BR2_TOOLCHAIN_USES_GLIBC+ help+ ply dynamically instruments the running kernel to aggregate and+ extract user-defined data. It compiles an input program to one or+ more Linux bpf(2) binaries and attaches them to arbitrary points+ in the kernel using kprobes and tracepoints.++ https://wkz.github.io/ply/diff --git a/package/ply/ply.mk b/package/ply/ply.mknew file mode 100644index 0000000000..298ea4acf2--- /dev/null+++ b/package/ply/ply.mk@@ -0,0 +1,15 @@+################################################################################+#+# ply+#+################################################################################++PLY_VERSION = 2.1.1+PLY_SITE = https://github.com/wkz/ply/releases/download/$(PLY_VERSION)+# fetched from Github, with no configure script+PLY_AUTORECONF = YES+PLY_DEPENDENCIES = host-bison host-flex+PLY_LICENSE = GPL-2.0++PLY_LICENSE_FILES = COPYING++$(eval $(autotools-package))
4 ply 示例
网址 root/ply 有部分示例。clone 编译可直接使用:
$ git clone https://github.com/jgsun/buildroot$ cd buildroot && make qemu_aarch64_virt-fun_defconfig && make$ qemu-system-aarch64 -M virt \-cpu cortex-a57 -nographic -smp 4 -m 512 \-kernel output/images/Image \-append "root=/dev/ram0 console=ttyAMA0 kmemleak=on loglevel=8" \-netdev type=tap,ifname=tap0,id=eth0,script=board/qemu/scripts/qemu-ifup_virbr0,queues=2 \-device virtio-net-pci,netdev=eth0,mac='00:00:00:01:00:01',vectors=6,mq=on
4.1 打印出内核函数的调用栈
本 ply 示例打印出函数 rtnetlink_rcv 的调用栈:
root@~# cat netlink.ply#!/usr/bin/env plykprobe:rtnetlink_rcv{print(stack);}
运行 sshnetlink.ply,然后在另外一个终端通过 ssh 登录 qemu aarch64 board,执行 ip addr show dev eth0 命令:
$ ssh -p 22 root@192.168.122.46root@~# ip addr show dev eth03: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000link/ether 00:00:00:01:00:01 brd ff:ff:ff:ff:ff:ffinet 192.168.122.46/24 brd 192.168.122.255 scope global eth0valid_lft forever preferred_lft foreverinet6 fe80::200:ff:fe01:1/64 scope linkvalid_lft forever preferred_lft forever
netlink.ply 就会打印出 rtnetlink_rcv 的调用栈:
root@~# ./netlink.plyply: activertnetlink_rcvnetlink_sendmsg+408____sys_sendmsg+592___sys_sendmsg+136__sys_sendmsg+112__arm64_sys_sendmsg+40el0_svc_common.constprop.3+144do_el0_svc+116el0_sync_handler+280el0_sync+320rtnetlink_rcvnetlink_sendmsg+408____sys_sendmsg+592___sys_sendmsg+136__sys_sendmsg+112__arm64_sys_sendmsg+40el0_svc_common.constprop.3+144do_el0_svc+116el0_sync_handler+280el0_sync+320rtnetlink_rcvnetlink_sendmsg+408__sys_sendto+224__arm64_sys_sendto+44el0_svc_common.constprop.3+144do_el0_svc+116el0_sync_handler+280el0_sync+320
4.2 获取打开文件的进程信息
本 ply 示例打印出发起系统调用 do_sys_open 打开文件的进程名,进程 pid 和文件名(第一个参数):
#!/usr/bin/env plykprobe:do_sys_open{printf("%v(%v): %s\n",comm, pid, str(arg1));}
运行结果:
root@~/ply# ./opensnoop.plyply: activedropbear ( 128): /dev/urandomdropbear ( 128): /proc/timer_listsyslogd ( 60): /var/log/messagesdropbear ( 128): /proc/interruptsdropbear ( 128): /proc/loadavgdropbear ( 128): /proc/sys/kernel/random/entropy_availdropbear ( 128): /proc/net/netstatdropbear ( 128): /proc/net/devdropbear ( 128): /proc/net/tcpdropbear ( 128): /proc/net/rt_cache

浙公网安备 33010602011771号