首页 > 其他分享 >推荐一款轻量级 eBPF 前端工具 ply

推荐一款轻量级 eBPF 前端工具 ply

时间:2023-05-29 17:33:51浏览次数:52  
标签:package -- eBPF ply sys el0 Config 轻量级

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=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_FTRACE=y
CONFIG_DYNAMIC_FTRACE=y
CONFIG_BPF=y
CONFIG_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.md
7 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

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.in
index 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.swp
new file mode 100644
index 0000000000..1193f698fb
Binary files /dev/null and b/package/ply/.Config.in.swp differ
diff --git a/package/ply/Config.in b/package/ply/Config.in
new file mode 100644
index 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.mk
new file mode 100644
index 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 的调用栈:ddd

root@~# cat netlink.ply
#!/usr/bin/env ply
kprobe:rtnetlink_rcv
{
            print(stack);
}

运行 sshnetlink.ply,然后在另外一个终端通过 ssh 登录 qemu aarch64 board,执行 ip addr show dev eth0 命令:

$ ssh -p 22 root@192.168.122.46
root@~# ip addr show dev eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:00:00:01:00:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.46/24 brd 192.168.122.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::200:ff:fe01:1/64 scope link
       valid_lft forever preferred_lft forever

netlink.ply 就会打印出 rtnetlink_rcv 的调用栈:

root@~# ./netlink.ply
ply: active
        rtnetlink_rcv
        netlink_sendmsg+408
        ____sys_sendmsg+592
        ___sys_sendmsg+136
        __sys_sendmsg+112
        __arm64_sys_sendmsg+40
        el0_svc_common.constprop.3+144
        do_el0_svc+116
        el0_sync_handler+280
        el0_sync+320
        rtnetlink_rcv
        netlink_sendmsg+408
        ____sys_sendmsg+592
        ___sys_sendmsg+136
        __sys_sendmsg+112
        __arm64_sys_sendmsg+40
        el0_svc_common.constprop.3+144
        do_el0_svc+116
        el0_sync_handler+280
        el0_sync+320
        rtnetlink_rcv
        netlink_sendmsg+408
        __sys_sendto+224
        __arm64_sys_sendto+44
        el0_svc_common.constprop.3+144
        do_el0_svc+116
        el0_sync_handler+280
        el0_sync+320

4.2 获取打开文件的进程信息

本 ply 示例打印出发起系统调用 do_sys_open 打开文件的进程名,进程 pid 和文件名(第一个参数):

#!/usr/bin/env ply
kprobe:do_sys_open
{
            printf("%v(%v): %s\n",
               comm, pid, str(arg1));
}

运行结果:

root@~/ply# ./opensnoop.ply
ply: active
dropbear       (  128): /dev/urandom
dropbear       (  128): /proc/timer_list
syslogd        (   60): /var/log/messages
dropbear       (  128): /proc/interrupts
dropbear       (  128): /proc/loadavg
dropbear       (  128): /proc/sys/kernel/random/entropy_avail
dropbear       (  128): /proc/net/netstat
dropbear       (  128): /proc/net/dev
dropbear       (  128): /proc/net/tcp
dropbear       (  128): /proc/net/rt_cache

标签:package,--,eBPF,ply,sys,el0,Config,轻量级
From: https://www.cnblogs.com/linhaostudy/p/17441129.html

相关文章

  • Android平台如何实现外部RTSP|RTMP流注入轻量级RTSP服务模块(内网RTSP网关)
     技术背景今天分享的是外部RTSP或RTMP流,拉取后注入到本地轻量级RTSP服务模块,供内网小并发场景下使用,这里我们叫做内网RTSP网关模块。内网RTSP网关模块,系内置轻量级RTSP服务模块扩展,完成外部RTSP/RTMP数据拉取并注入到轻量级RTSP服务模块工作,多个内网客户端直接访问内网轻量级RTSP......
  • Numpy_矩阵的multiply_python的属性以及类特性_装饰器——@property_@classmethod_@st
    Python类中有三个常用的装饰器分别是@property(使一个方法可以被当成属性调用,常用于直接返回某一不想被修改的属性)@classmethod(将一个方法定义为类方法,其中第一个参数要修改为cls,使得该方法可以不用实例化即可被调用)@staticmethod(静态方法,类似于类方法,也可以不用实例化,......
  • 深入理解 apply()方法
      apply(thisArg)apply(thisArg,argsArray)thisArg在 func 函数运行时使用的 this 值。请注意,this 可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。argsArray 可选一个数组或......
  • Forest轻量级框架的声明式使用
    1.Forest框架声明式接口的基础使用1.1构建接口​在Forest中,所有的HTTP请求信息都要绑定到某一个接口的方法上,不需要编写具体的代码去发送请求。请求发送方通过调用事先定义好HTTP请求信息的接口方法,自动去执行HTTP发送请求的过程,其具体发送请求信息就是该方法对......
  • ICML 2023 | 轻量级视觉Transformer (ViT) 的预训练实践手册
    前言 本文介绍一下最近被ICML2023接收的文章:ACloserLookatSelf-SupervisedLightweightVisionTransformers.文章聚焦在轻量级ViT的预训练上,相当于为相关方向的研究提供了一个benchmark,相关的代码与模型也都会开源,方便后续大家在这一方向上继续探索。文章的研究也打破......
  • ebpf 单行程序学习
    ebpf单行程序学习背景公司方神借给我一本:《BPF之巅:洞悉linux系统和应用性能》纸质书拿回家晚上在沙发上看了几天。感觉书很厚看的不是很系统。仅能凭自己的感觉总结一下这些天的读书感悟。本来计划是2023年的春节7天长假系统的学习ebpf但是因为学习Linux内核参数耽......
  • javascript的 this 详解以及apply与call的用法意义及区别
    [color=red][b]关于JavaScript中apply与call的用法意义及区别[/b][/color][url]http://www.cnitblog.com/yemoo/archive/2007/11/30/37070.aspx[/url][color=red][b]JAVASCRIPTTHIS详解[/b][/color]在面向对象编程语言中,对于this关键字我们是非常熟悉的。比如C++、C#和Java等都......
  • 用go设计开发一个自己的轻量级登录库/框架吧(拓展篇)
    给自己的库/框架拓展一下吧(拓展篇)主库:weloe/token-go:alightloginlibrary.扩展库:weloe/token-go-extensions(github.com)本篇给主库扩展一个Adapter提供简单的外部数据存储。思路一个库/框架往往不能完成所有事情,需要其他库/框架的支持才能达到更加完善的效果。本篇会......
  • apply()和call()
    apply()和call()二者都是用来改变上下文执行,只是传递的参数不一样Function.apply(obj,args)方法能接收两个参数obj:这个对象将代替Function类里this对象args:这个是数组,它将作为参数传给Function(args-->arguments)apply是将args数组一个一个与Function类中的参数一一对应 Functio......
  • call()与apply()的作用与区别
    1.概念每个函数都包含两个非继承而来的方法:apply()和call()。call与apply都属于Function.prototype的一个方法,所以每个function实例都有call、apply属性;2.作用call()方法和apply()方法的作用相同:改变this指向。3.区别他们的区别在于接收参数的方式不同:call():第一个参数是this值没有变......