bpf的了解以及bpftrace的简单练习

最近接触到bpf的概念,简单做一些练习,做以下整理,学习笔记。

0:总结

使用ebpf可以实现的功能打开新世界,可以不改变源码的情况下,实现内存,网络,对应接口等各种期望内容的监控。

可以使用bpf直接进行开发,使用clang编译成ebpf字节序后加载进行使用。

使用bcc进行开发实现功能,多是python/lua,对应的demo可以参考githuab.

使用bpftool工具集可以进行加载,查看,卸载等一系列的功能,没有过多研究。

使用bpftrace一行指令已经可以方便实现很多的功能,比如监控文件打开,监控内存申请,监控函数调用次数,在内存,网络,sql调用,以及接口相关都有很多很方便的功能,进行简单的使用测试。

1:了解什么是ebpf,bpf,bcc, bpftool,bpftrace

直接问ai,简单又一些认知。

eBPF 是底层技术,所有这些工具(BPF, BCC, bpftool, BPFtrace)都基于 eBPF 工作。
BPF 是 eBPF 的前身,如今被 eBPF 所取代。
BCC 提供了一套方便的 API 和工具,帮助开发者快速编写和运行 eBPF 程序。
bpftool 用于管理和调试 eBPF 程序,可以查看运行的 eBPF 程序及其相关资源。
BPFtrace 提供了一个高级脚本语言,用于快速编写和运行简单的 eBPF 程序,主要用于追踪和分析。
总之,这些工具和框架都围绕 eBPF 工作,帮助开发者更方便地利用 eBPF 的强大功能。

eBPF(Extended Berkeley Packet Filter)及其相关工具(BPF, BCC, bpftool, BPFtrace)都是用于动态追踪、性能分析和网络调试的技术和工具,尤其是在 Linux 环境中。以下是对它们的介绍以及它们之间的关系:1. eBPF (Extended Berkeley Packet Filter)
eBPF 是 Linux 内核中的一个扩展,它允许用户在内核中运行自定义的字节码程序,而无需修改或重启内核。
最初用于网络数据包过滤,但现在 eBPF 的应用范围已经扩展到了性能监控、安全分析、网络流量控制等多个领域。
eBPF 程序在内核中运行时是安全的,因为它们在执行前会经过内核的验证器验证,以确保不会损坏系统。
2. BPF
BPF 是 Berkeley Packet Filter 的缩写,是 eBPF 的前身。
最早设计用于网络数据包过滤,但功能较为有限,eBPF 则是其增强版。
BPF 程序可以通过系统调用加载到内核中执行,但随着时间的推移,eBPF 逐渐取代了传统 BPF。
3. BCC (BPF Compiler Collection)
BCC 是一个工具集,用于简化 eBPF 程序的编写和运行。
它提供了高级语言(如 Python 和 Lua)的 API,以便用户能够方便地编写 eBPF 程序。
BCC 中包含了许多现成的 eBPF 工具,用于追踪系统事件、网络流量、文件系统等。
使用 BCC 时,用户不需要直接编写 eBPF 字节码,而是通过高级语言和宏来生成和管理 eBPF 程序。
4. bpftool
bpftool 是 eBPF 的管理工具,主要用于查看、加载、卸载和调试 eBPF 程序。
它允许用户列出内核中加载的 eBPF 程序、地图(maps)和统计信息。
bpftool 提供了对内核 eBPF 子系统的细粒度控制和信息查看功能,通常用于开发和调试 eBPF 程序。
5. BPFtrace
BPFtrace 是一个简化的 eBPF 追踪工具,专注于动态追踪和性能分析。
它的语法受 DTrace 启发,更为简洁,用户可以通过简单的脚本编写复杂的追踪逻辑。
相比 BCC,BPFtrace 更加适合快速编写和运行短小的 eBPF 程序,适合于即时性能分析和诊断。

2:使用bpf进行测试,用户在终端上使用ls等指令时,测试demo能进行监控并展示。

使用22.04进行测试时,和已有demo不适配,高版本直接用bcc,bpftrace等进行直接开发吧。

这里用18.04进行环境安装以及demo测试。

2.1 在18.04上安装bpf

不支持直接安装,没有libbpf-dev

ubuntu@ubuntu:~$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.6 LTS
Release:	18.04
Codename:	bionic
ubuntu@ubuntu:~$ sudo apt-get install build-essential
#可以看到 不支持这个库的直接安装
ubuntu@ubuntu:~$ sudo apt install libbpf-dev
E: Unable to locate package libbpf-dev

使用源码安装的方式

#使用源码安装的方式  去linux内核官网找对应系统的源码下载也可以  ()
#方案一  下载linux内核源码,转到对应的版本分治     这个在网络不稳定的情况下,太耗时,分支太多,太大了。
git clone https://github.com/torvalds/linux.git  
cd linux
git checkout v$(uname -r | cut -d'-' -f1)#方案二  发现一个很容易获取系统对应内核源码的方式 这种方式可能获取到的版本比较旧 与当前内核版本有差异 (可以下载指定内核的)
sudo apt-get install linux-source
cd /usr/src
tar xjf linux-source-$(uname -r).tar.bz2
cd linux-source-$(uname -r)

实际操作如下:

ubuntu@ubuntu:~$ cd /usr/src/
ubuntu@ubuntu:/usr/src$ ls
linux-headers-4.15.0-213  linux-headers-4.15.0-213-genericubuntu@ubuntu:/usr/src$ sudo apt-cache search linux-source
ubuntu@ubuntu:/usr/src$ sudo apt-get install linux-source
ubuntu@ubuntu:/usr/src$ ls
linux-headers-4.15.0-213  linux-headers-4.15.0-213-generic  linux-source-4.15.0  linux-source-4.15.0.tar.bz2
ubuntu@ubuntu:/usr/src$ sudo tar xf linux-source-4.15.0.tar.bz2#遇到问题 处理问题  这里直到最后编译成功  连bpftool也编译成功了。
ubuntu@ubuntu:/usr/src/linux-source-4.15.0/tools/bpf$ sudo apt-get install binutils-dev
ubuntu@ubuntu:/usr/src/linux-source-4.15.0/tools/bpf$ sudo apt-get install libreadline-dev
ubuntu@ubuntu:/usr/src/linux-source-4.15.0/tools/bpf$ sudo apt-get install bison
ubuntu@ubuntu:/usr/src/linux-source-4.15.0/tools/bpf$ sudo apt-get install binutils elfutilsroot@ubuntu:/usr/src/linux-source-4.15.0/tools/lib/bpf# makeAuto-detecting system features:
...                        libelf: [ on  ]
...                           bpf: [ on  ]Warning: Kernel ABI header at 'tools/include/uapi/linux/bpf.h' differs from latest version at 'include/uapi/linux/bpf.h'CC       libbpf.oCC       bpf.oLD       libbpf-in.oLINK     libbpf.aLINK     libbpf.so
root@ubuntu:/usr/src/linux-source-4.15.0/tools/lib/bpf# make install
Warning: Kernel ABI header at 'tools/include/uapi/linux/bpf.h' differs from latest version at 'include/uapi/linux/bpf.h'INSTALL  libbpf.aINSTALL  libbpf.so#看起来默认安装在 /usr/local/lib64
root@ubuntu:/# find -name libbpf.a
./usr/local/lib64/libbpf.a
./usr/src/linux-source-4.15.0/tools/lib/bpf/libbpf.a

2.2 进行测试,首先要实现ebpf程序。(目标:使用clang把该程序编译成ebpf字节码。)

eBPF 程序通常是内核态的代码,使用 clang 编译为特定格式的字节码(BPF 字节码),然后加载到内核中。

//bpf_program.c
#include <linux/bpf.h>
#define SEC(NAME) __attribute__((section(NAME), used))static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) = (void *)BPF_FUNC_trace_printk;SEC("tracepoint/syscalls/sys_enter_execve")
int bpf_prog(void *ctx) {char msg[] = "Hello, BPF World!";bpf_trace_printk(msg, sizeof(msg));
return 0;
}char _license[] SEC("license") = "GPL";

使用clang把该程序编译成ebpf字节码:

ubuntu@ubuntu:~/bpf_test/bpf$ sudo apt-get install clang
ubuntu@ubuntu:~/bpf_test/bpf$ clang -O2 -target bpf -c bpf_program.c -I /usr/include/x86_64-linux-gnu/ -o bpf_program.o

2.3 编写用户空间程序,加载上面的ebpf程序,并执行。

这里的内核版本提供了bpf_load.h,使用这个接口进行使用。(高版本已经不提供了,实现可能有差异,不研究了)

#include "bpf_load.h"
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>#define DEBUGFS "/sys/kernel/debug/tracing/"void myread_trace_pipe(void)
{int trace_fd;trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0);if (trace_fd < 0)return;while (1) {static char buf[4096];ssize_t sz;sz = read(trace_fd, buf, sizeof(buf) - 1);if (sz > 0) {buf[sz] = 0;puts(buf);}}
}int main(int argc, char **argv) {if (load_bpf_file("bpf_program.o") != 0) {printf("The kernel didn't load the BPF program\\n");return -1;}myread_trace_pipe();return 0;
}

2.4 借助对应makefile进行编译

注意:这里使用了内核下的 bpf_load.c

CLANG = clangEXECABLE = monitor-exec#这里之际使用了内核提供给的bpf_load.c 借助libbpf
BPFCODE = bpf_program
BPFTOOLS = /usr/src/linux-source-4.15.0/samples/bpf
BPFLOADER = $(BPFTOOLS)/bpf_load.c
BPFLIB = /usr/src/linux-source-4.15.0/tools/lib/bpf/libbpf.c #/usr/include/linux/types.h:5:10: fatal error: 'asm/types.h' file not found  这个与我ubuntu有关吧
CCINCLUDE += -I/usr/include/x86_64-linux-gnu/CCINCLUDE += -I/usr/src/linux-source-4.15.0/tools/testing/selftests/bpfLOADINCLUDE += -I/usr/src/linux-source-4.15.0/samples/bpf
LOADINCLUDE += -I/usr/src/linux-source-4.15.0/tools/lib
LOADINCLUDE += -I/usr/src/linux-source-4.15.0/tools/perf
LOADINCLUDE += -I/usr/src/linux-source-4.15.0/tools/include
LIBRARY_PATH = -L/usr/local/lib64
BPFSO = -lbpfCFLAGS += $(shell grep -q "define HAVE_ATTR_TEST 1" /usr/src/linux-source-4.15.0/tools/perf/perf-sys.h && echo "-DHAVE_ATTR_TEST=0").PHONY: clean $(CLANG) bpfload buildclean:rm -f *.o *.so $(EXECABLE)build: ${BPFCODE.c} ${BPFLOADER}$(CLANG) -O2 -target bpf -c $(BPFCODE:=.c) $(CCINCLUDE) -o ${BPFCODE:=.o}bpfload: buildclang $(CFLAGS) -o $(EXECABLE) -lelf $(LOADINCLUDE) $(LIBRARY_PATH) $(BPFSO) $(BPFLIB) $(BPFLOADER)  loader.c$(EXECABLE): bpfload.DEFAULT_GOAL := $(EXECABLE)

2.4 运行测试(运行ls时触发到监控打印Hello, BPF World)

ubuntu@ubuntu:~/bpf_test/bpf$ make
clang -O2 -target bpf -c bpf_program.c -I/usr/include/x86_64-linux-gnu/ -I/usr/src/linux-source-4.15.0/tools/testing/selftests/bpf -o bpf_program.o
clang  -o monitor-exec -lelf -I/usr/src/linux-source-4.15.0/samples/bpf -I/usr/src/linux-source-4.15.0/tools/lib -I/usr/src/linux-source-4.15.0/tools/perf -I/usr/src/linux-source-4.15.0/tools/include -L/usr/local/lib64 -lbpf /usr/src/linux-source-4.15.0/tools/lib/bpf/libbpf.c  /usr/src/linux-source-4.15.0/samples/bpf/bpf_load.c  loader.c#默认安装在/usr/local/lib64
ubuntu@ubuntu:~/bpf_test/bpf$ sudo ./monitor-exec 
./monitor-exec: error while loading shared libraries: libbpf.so: cannot open shared object file: No such file or directory
ubuntu@ubuntu:~/bpf_test/bpf$ ldconfig /usr/local/lib64
/sbin/ldconfig.real: Can't create temporary cache file /etc/ld.so.cache~: Permission denied
ubuntu@ubuntu:~/bpf_test/bpf$ sudo ldconfig /usr/local/lib64
ubuntu@ubuntu:~/bpf_test/bpf$ sudo ./monitor-exec <...>-11425 [000] ....  4464.404847: 0x00000001: Hello, BPF World!<...>-11426 [000] ....  4466.860991: 0x00000001: Hello, BPF World!bash-11427 [001] ....  4470.069820: 0x00000001: Hello, BPF World!#这里执行后,在另外的终端上 执行ls 就会触发上面的逻辑,其他的逻辑可以扩展。

3:bcc和bpftool

基于libbpf进行调用外,可以使用bcc调用python/lua脚本进行实现。 安装后,bcc其实有一些可以直接使用的功能。可以参考开源库bcc下对应的example。

bpftool是一个工具,可以用于查看、加载、卸载、和调试 eBPF 程序的功能。(最好从github上源码入手) ubuntu@ubuntu:/$ sudo apt install -y linux-tools-$(uname -r)

ubuntu@ubuntu:~$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 22.04.2 LTS
Release:	22.04
Codename:	jammyubuntu@ubuntu:~$ sudo apt-get install build-essential #可以使用源码进行安装  git clone https://github.com/libbpf/libbpf.git   
#可以在内核源码中直接安装吧?
ubuntu@ubuntu:/usr/lib$ sudo apt install libbpf-dev
ubuntu@ubuntu:~$ cd /usr/lib
ubuntu@ubuntu:/usr/lib$ sudo find /usr/lib -name libbpf.so
/usr/lib/x86_64-linux-gnu/libbpf.so
ubuntu@ubuntu:/usr/lib$ ls -ls /usr/include/bpf/
total 28820 -rw-r--r-- 1 root root  17992 Dec  1  2022 bpf_core_read.h4 -rw-r--r-- 1 root root   3750 Dec  1  2022 bpf_endian.h12 -rw-r--r-- 1 root root  10066 Dec  1  2022 bpf.h
148 -rw-r--r-- 1 root root 149473 Dec  1  2022 bpf_helper_defs.h8 -rw-r--r-- 1 root root   7679 Dec  1  2022 bpf_helpers.h20 -rw-r--r-- 1 root root  19194 Dec  1  2022 bpf_tracing.h16 -rw-r--r-- 1 root root  12856 Dec  1  2022 btf.h4 -rw-r--r-- 1 root root   1421 Dec  1  2022 libbpf_common.h36 -rw-r--r-- 1 root root  33279 Dec  1  2022 libbpf.h4 -rw-r--r-- 1 root root   1525 Dec  1  2022 libbpf_legacy.h4 -rw-r--r-- 1 root root   2894 Dec  1  2022 skel_internal.h12 -rw-r--r-- 1 root root   8608 Dec  1  2022 xsk.h#终于搞清楚了 ,内核一些低版本,提供了使用bpf_load.h对ebpf的一些封装,可以使用,高一些的版本,是没有这个文件的,可以直接用ebpf来实现。
#bpf_load.h 是内核中的一个头文件,常见于 samples/bpf 和 tools/testing/selftests/bpf 目录中,提供了简化加载 eBPF 程序并管理 eBPF maps 的 API。#这使得用户空间程序可以更轻松地与 eBPF 程序交互并加载到内核中#本来想基于22.04试试bpf的安装后运行,发现和18.04有点差异,18.04有已有demo,可正常运行,但22.04相关高版本内核不提供bpf_load.h,主要了解逻辑,不关注了。sudo apt install build-essential \libelf-dev \libz-dev \libcap-dev \binutils-dev \pkg-config#终于知道这几个库用在哪里用了  make报错依次解决  手动编译流程~   git clone https://github.com/libbpf/bpftool.git 下载?        
root@ubuntu:/usr/src/linux-source-5.15.0/tools/bpf/bpftool# sudo apt-get install binutils-dev
root@ubuntu:/usr/src/linux-source-5.15.0/tools/bpf/bpftool# sudo apt-get install libcap-dev
root@ubuntu:/usr/src/linux-source-5.15.0/tools/bpf/bpftool# sudo apt-get install llvm
#直接在刚才下载linux源码的位置处编译bpftool
root@ubuntu:/usr/src/linux-source-5.15.0/tools/bpf/bpftool# makeAuto-detecting system features:
...                        libbfd: [ on  ]
...        disassembler-four-args: [ on  ]
...                          zlib: [ on  ]
...                        libcap: [ on  ]
...               clang-bpf-co-re: [ on  ]
。。。
root@ubuntu:/usr/src/linux-source-5.15.0/tools/bpf/bpftool# ./bpftool --version
./bpftool v5.15.163
features: libbfd, skeletons#上面bpf的测试在22.04 编译不过啊   高版本已经不提供用bpf_load.h 了 

4:bpftrace的安装练习

bpftrace 一行指令已经实现很多功能,可以参考github进行学习。

bpftrace 可以说实现监控网络,内存等各种功能,根据业务可以思考。

思考探测内核函数,用户可执行程序中接口,so接口,静态库接口。

在这里插入图片描述

4.1 安装bpftrace (ubuntu 22.04)

#基于前面已经安装过一系列的组件   可以参考网络或者源码安装 这里初入门了解
root@ubuntu:/usr/src/linux-source-5.15.0/tools/bpf/bpftool# apt install bpftrace
root@ubuntu:/usr/src/linux-source-5.15.0/tools/bpf/bpftool# bpftrace --version
bpftrace v0.14.0

4.2 简单了解bpftrace 相关语法。

4.2.1 结构语法及参数介绍

在这里插入图片描述

在这里插入图片描述

4.2.2 常用内置变量
内置变量
bpftrace 脚本常用变量如下:uid:用户 id。tid:线程 idpid:进程 id。cpu:cpu id。cgroup:cgroup id.probe:当前的 trace 点。comm:进程名字。nsecs:纳秒级别的时间戳。kstack:内核栈描述curtask:当前进程的 task_struct 地址。args:获取该 kprobe 或者 tracepoint 的参数列表arg0:获取该 kprobe 的第一个变量,tracepoint 不可用arg1:获取该 kprobe 的第二个变量,tracepoint 不可用arg2:获取该 kprobe 的第三个变量,tracepoint 不可用retval: kretprobe 中获取函数返回值args->ret: kretprobe 中获取函数返回值自定义变量以'$'标志起来定义与引用变量,例如:$idx = 0;
Map 变量Map 变量是用于内核向用户空间传递数据的一种存储结构,定义方式是以'@'符号作为标志@path[tid] = nsecs;@path[pid, $fd] = nsecs;Bpftrace 默认在结束时会打印从内核接收到的 map 变量
内置函数exit():退出 bpftrace 程序str(char *):转换一个指针到 string 类型system(format[, arguments ...]):运行一个 shell 命令join(char *str[]):打印一个字符串列表并在每个前面加上空格,比如可以用 来输出 args->argvksym(addr):用于转换一个地址到内核 symbolkaddr(char *name):通过 symbol 转换为内核地址print(@m [, top [, div]]):可选择参数打印 map 中的 top n 个数据,数据可选择除以一个 div 值buf(void *p [, int length])strncmp(char *s1, char *s2, int length)sizeof(expression)ustack([limit])ksym(void *p)kstack([limit])usym(void *p)kaddr(char *name)uaddr(char *name)ntop([int af,]int|char[4:16] addr)reg(char *name)cgroupid(char *path)bpftrace 内置了 map 对象操作函数,用于传递数据给 map 变量。count():用于计算次数sum(int n):用于累加计算avg(int n):用于计算平均值min(int n):用于计算最小值max(int n):用于计算最大值hist(int n):数据分布直方图(范围为 2 的幂次增长)lhist(int n):数据线性直方图delete(@m[key]):删除 map 中的对应的 key 数据clear(@m):删除 map 中的所有数据zero(@m):map 中的所有值设置为 0

4.3 简单练习bpf的相关一行指令

#统计调用read的次数
root@ubuntu:/home/ubuntu# bpftrace -e 't:syscalls:sys_enter_read {@[probe]=count(); }'
Attaching 1 probe...
^C@[tracepoint:syscalls:sys_enter_read]: 94#统计write调用的次数
root@ubuntu:/home/ubuntu#  bpftrace -e 't:syscalls:sys_enter_write {@[probe]=count();}'
Attaching 1 probe...
^C@[tracepoint:syscalls:sys_enter_write]: 22#统计调用read 按参数 输出 数据分布直方图展示   ssize_t read(int fd, void *buf, size_t count);
root@ubuntu:/home/ubuntu# bpftrace -e 't:syscalls:sys_enter_read {@=hist(args->count);}'
Attaching 1 probe...
^C@: 
[1K, 2K)              29 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[2K, 4K)               0 |                                                    |
[4K, 8K)               0 |                                                    |
[8K, 16K)              0 |                                                    |
[16K, 32K)             4 |@@@@@@@                                             |
[32K, 64K)             0 |                                                    |
[64K, 128K)            0 |                                                    |
[128K, 256K)           0 |                                                    |
[256K, 512K)           4 |@@@@@@@                                             |#追踪openat 系统调用  打开文件的入口   统计进程名和打开的文件 
root@ubuntu:/home/ubuntu# bpftrace -e 't:syscalls:sys_enter_openat { printf("%s–> %s\n", comm,str(args->filename)); }'
Attaching 1 probe...
irqbalance–> /proc/interrupts
irqbalance–> /proc/stat
vmtoolsd–> /proc/meminfo
vmtoolsd–> /proc/vmstat
vmtoolsd–> /proc/stat
vmtoolsd–> /proc/zoneinfo
vmtoolsd–> /proc/uptime
vmtoolsd–> /proc/diskstats#需要查找文件时触发  追踪内核函数 lookup_fast 的调用次数
root@ubuntu:/home/ubuntu#  bpftrace -e 'kprobe:lookup_fast { @[comm, pid] = count(); }'
Attaching 1 probe...
^C@[systemd-network, 847]: 3
@[systemd, 1]: 6
@[irqbalance, 879]: 8
@[cron, 871]: 15
@[vmtoolsd, 762]: 24
@[snapd, 885]: 148#统计阻塞 io 事件   表示捕获所有与块设备相关的 tracepoint 事件 并记录每个 tracepoint 被触发的次数
root@ubuntu:/home/ubuntu#  bpftrace -e 't:block:* { @[probe] = count(); }'
Attaching 18 probes...
^C@[tracepoint:block:block_rq_complete]: 17
@[tracepoint:block:block_rq_issue]: 17#统计 阻塞 io 操作数据大小     block_rq_issue用于捕获块设备的 I/O 请求被发出的事件
root@ubuntu:/home/ubuntu#  bpftrace -e 't:block:block_rq_issue { @bytes = hist(args->bytes); }'
Attaching 1 probe...
^C@bytes: 
[8, 16)                4 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|#追踪块设备的 I/O 请求完成事件 block_rq_complete,并打印出那些包含错误的请求的相关信息
root@ubuntu:/home/ubuntu#  bpftrace -e 't:block:block_rq_complete /args->error/ {printf("dev %d type %s error %d\n", args->dev, args->rwbs, args->error); }'
Attaching 1 probe...
^C
root@ubuntu:/home/ubuntu#  bpftrace -e 't:block:block_rq_complete {printf("dev %d type %s error %d\n", args->dev, args->rwbs, args->error); }'
Attaching 1 probe...
dev 0 type N error 0
dev 0 type N error 0
dev 0 type N error 0#启动的进程名与命令行参数
root@ubuntu:/home/ubuntu# bpftrace -e 'tracepoint:syscalls:sys_enter_execve { join(args->argv); }'
Attaching 1 probe...
ls --color=auto
ls --color=auto
ls --color=auto
ls --color=auto
cat 1#追踪所有系统调用的进入点 统计次数
root@ubuntu:/home/ubuntu# bpftrace -e 'tracepoint:raw_syscalls:sys_enter{ @[pid, comm] = count(); }'
Attaching 1 probe...
^C@[882, rsyslogd]: 3
@[871, cron]: 6
@[889, pool-udisksd]: 6
@[889, udisksd]: 12
@[887, systemd-logind]: 15
@[749, systemd-timesyn]: 15
@[849, systemd-resolve]: 15
@[847, systemd-network]: 20
@[1316, sshd]: 24
@[1627, bash]: 33
@[1, systemd]: 46
@[762, HangDetector]: 52
@[879, irqbalance]: 70
@[1593, sshd]: 74
@[1594, bash]: 76
@[1627, ls]: 121
@[885, snapd]: 181
@[569, multipathd]: 324
@[1620, bpftrace]: 525
@[762, vmtoolsd]: 3969#追踪进程上下文切换事件,并统计每个上下文切换期间的内核堆栈信息的出现次数 
root@ubuntu:/home/ubuntu# bpftrace -e 'tracepoint:sched:sched_switch { @[kstack] = count(); }'
Attaching 1 probe...
^C@[__schedule+855__schedule+855schedule+105schedule_timeout+135msleep+45usb_port_suspend+908usb_generic_driver_suspend+67usb_suspend_both+506usb_runtime_suspend+47__rpm_callback+74rpm_callback+103rpm_suspend+356__pm_runtime_suspend+73usb_runtime_idle+58rpm_idle+195pm_runtime_work+141process_one_work+552worker_thread+83kthread+295ret_from_fork+31
]: 1bpftrace -e 'u:/lib/x86_64-linux-gnu/libpthread2.31.so:pthread_create { printf("%s by %s (%d)\n", probe, comm, pid ); }'
sudo find -name libpthread*
ldd ./usr/lib32/libpthread.so.0
ldd ./usr/lib/x86_64-linux-gnu/libpthread.so.0
nm -D ./usr/lib/x86_64-linux-gnu/libpthread.so.0
ldd ./usr/lib/x86_64-linux-gnu/libpthread.so.0
nm -D lib/x86_64-linux-gnu/libc.so.6|grep thread_createroot@ubuntu:/# ldconfig -p | grep libpthreadlibpthread.so.0 (libc6,x86-64, OS ABI: Linux 3.2.0) => /lib/x86_64-linux-gnu/libpthread.so.0libpthread.so.0 (libc6, OS ABI: Linux 3.2.0) => /lib32/libpthread.so.0#进程创建 pthread_create	探测  (写了个测试代码调用pthread_create)
root@ubuntu:/# bpftrace -e 'u:/lib/x86_64-linux-gnu/libc.so.6:pthread_create { printf("%s by %s (%d)\n", probe, comm, pid ); }'
Attaching 1 probe...
uprobe:/lib/x86_64-linux-gnu/libc.so.6:pthread_create by pthread (17916)
uprobe:/lib/x86_64-linux-gnu/libc.so.6:pthread_create by pthread (17918)
uprobe:/lib/x86_64-linux-gnu/libc.so.6:pthread_create by pthread (17920)#内核堆栈跟踪的内存分配情况 统计内存分配总字节数root@ubuntu:/# bpftrace -e 't:kmem:kmem_cache_alloc { @bytes[kstack] = sum(args->bytes_alloc); }'
Attaching 1 probe...
^C^C@bytes[kmem_cache_alloc+623kmem_cache_alloc+623__sigqueue_alloc+123__send_signal+614send_signal+233do_send_sig_info+96__kill_pgrp_info+133kill_pgrp+53isig+150n_tty_receive_signal_char+27n_tty_receive_char_special+1086n_tty_receive_buf_standard+326__receive_buf+507n_tty_receive_buf_common+139n_tty_receive_buf2+20tty_ldisc_receive_buf+31tty_port_default_receive_buf+66flush_to_ldisc+170process_one_work+552worker_thread+83kthread+295ret_from_fork+31
]: 80#统计malloc的调用次数  
root@ubuntu:/#  bpftrace -e 'u:/lib/x86_64-linux-gnu/libc.so.6:malloc {@[ustack, comm] = sum(arg0); }'
Attaching 1 probe...
^C@[__libc_malloc+0
, bpftrace]: 4
@[__libc_malloc+00x55e8989dbcc00x55e8989d74000x8148535554415541
, bpftrace]: 8
@[__libc_malloc+0
, bpftrace]: 8
@[__libc_malloc+0
, bpftrace]: 24
@[__libc_malloc+00x5618bcac89f00x20
, sshd]: 448#统计进程发生缺页中断  写了个mmap 分配内存并访问 触发缺页中断
root@ubuntu:/# bpftrace -e 't:exceptions:page_fault_user { @[ustack, comm] = count(); }'
Attaching 1 probe...
^CERROR: failed to look up stack id -17 (pid -1): -1
@[0x7fc0b22a57e1
, bash]: 1
@[0x7f5cafa996100x69622f3d4c4c4548
, mmap]: 1

4.4 使用脚本进行练习

4.4.1 探测打开文件 输出对应文件名
#脚本进行测试  首先测试 探测打开文件的名称或者路径 
root@ubuntu:/# bpftrace -e '
kprobe:vfs_open {$path = (struct path *)arg0;$dentry = $path->dentry;printf("open path: %s\n", str($dentry->d_name.name));
}'
#写入文件
ubuntu@ubuntu:~/test$ cat fs.bt 
#include <linux/path.h>
#include <linux/dcache.h>kprobe:vfs_open {// printf("open path :%s \n",str((struct path*)arg0)->dentry->d_name.name); //不能直接打印 要提取到用户空间$path = (struct path *)arg0;$dentry = $path->dentry;printf("open path: %s\n", str($dentry->d_name.name));
}root@ubuntu:/home/ubuntu/test# bpftrace fs.bt 
Attaching 1 probe...
open path: interrupts
open path: stat
open path: smp_affinity
open path: smp_affinity
4.4.2 探测tcp连接的网络五元组。
//探测五元组   除了accept  还可以其他相关 比如tcp的状态,比如connect recv send按需求处理#include <linux/socket.h>
#include <net/sock.h>
#include <linux/types.h>// BEGIN 
// { 
// 	printf("hello\n"); 
// }//梳理 kprobe和kretprobe区别 
kprobe:inet_csk_accept
{printf("inet_csk_accept\n"); 
}kretprobe:inet_csk_accept
{$sk = (struct sock*)retval;$inet_family = $sk->__sk_common.skc_family;$daddr = ntop(0);$saddr = ntop(0);if ($inet_family == AF_INET) {$daddr = ntop($sk->__sk_common.skc_daddr);$saddr = ntop($sk->__sk_common.skc_rcv_saddr);		}$sport = $sk->__sk_common.skc_num;$dport = $sk->__sk_common.skc_dport; //大小端转换 不提供类型 自处理$dport_num = ((($dport <<8) &0xFF00 )| (($dport>>8)&0xFF)) &0xFFFF;printf(" tcp_accept: %-16s:%d %d--> %-16s:%d\n", $daddr, $dport, $dport_num, $saddr, $sport);
}

使用网络助手进行连接 测试结果:

测试结果: 写了一个tcp的服务端程序  用网络助手进行连接,测试可以打印: 注意大小端转换。
root@ubuntu:/home/ubuntu/test# bpftrace accept.bt 
Attaching 2 probes...
inet_csk_accepttcp_accept: 192.168.40.1    :1782 62982--> 192.168.40.137  :6666
inet_csk_accepttcp_accept: 192.168.40.1    :2038 62983--> 192.168.40.137  :6666
inet_csk_accepttcp_accept: 192.168.40.1    :6902 63002--> 192.168.40.137  :6666
4.4.3 探测mysql执行的语句 以及对应的耗时。

mysql.bt

uprobe:/usr/sbin/mysqld:*dispatch_command*
{@start = nsecs;@sql = str(*arg1);
}uretprobe:/usr/sbin/mysqld:*dispatch_command*
/@start/
{$dur = nsecs - @start;printf("%u %s \n", $dur, @sql);
}

mysql执行结果: 可以看到对应的mysql执行语句 以及对应的耗时

root@ubuntu:/home/ubuntu/test# bpftrace mysql.bt 
WARNING: Addrspace is not set
Attaching 2 probes...
1175223 show databases 
12474975 CREATE DATABASE `mytest2` 
12438296 CREATE DATABASE mytest3 
541816 CREATE DATABASE 'mytest3'    #这种正常的单引号 创建会失败#mysql创建后,第一次登录mysql可以直接登录,要给root手动设置密码。    set password for root@localhost = password('123456');  #这次用的这个密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456';
FLUSH PRIVILEGES;

参考,手头已有文档以及网络:

eBPF 入门开发实践教程一:Hello World,基本框架和开发流程 - eunomia

如何在 Ubuntu 上配置 eBPF 开发环境 | YaoYao’s Blog

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

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

相关文章

王者荣耀改重复名(java源码)

王者荣耀改重复名 项目简介 “王者荣耀改重复名”是一个基于 Spring Boot 的应用程序&#xff0c;用于生成王者荣耀游戏中的唯一名称。通过简单的接口和前端页面&#xff0c;用户可以输入旧名称并获得一个新的、不重复的名称。 功能特点 生成新名称&#xff1a;提供一个接口…

C++基础知识7 list

list 1. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.2.5 list modifiers1.2.6 list的迭代器失效 2.1 模拟实现list 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 l…

aspcms 获取webshell漏洞复现

1.通过访问/admin_aspcms/login.asp来到后台 使用admin 123456 登录 2.点击扩展功能-幻灯片设置-保存&#xff0c;同时进行抓包 3.修改数据包中的slideTextStatus字段&#xff0c;将其更改为 1%25><%25Eval(Request (chr(65)))%25><%25 密码为a 4.访问木马的地…

面试官:讲一讲Spring MVC源码解析

好看的皮囊千篇一律、有趣的灵魂万里挑一 文章持续更新&#xff0c;可以微信搜索【小奇JAVA面试】第一时间阅读&#xff0c;回复【资料】获取福利&#xff0c;回复【项目】获取项目源码&#xff0c;回复【简历模板】获取简历模板&#xff0c;回复【学习路线图】获取学习路线图。…

wopop靶场漏洞挖掘练习

1、SQL注入漏洞 1、在搜索框输入-1 union select 1,2,3# 2、输入-1 union select 1,2,database()# &#xff0c;可以得出数据库名 3、输入-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schematest#&#xff0c;可以得出数据库中…

C++ | Leetcode C++题解之第405题数字转换为十六进制数

题目&#xff1a; 题解&#xff1a; class Solution { public:string toHex(int num) {if (num 0) {return "0";}string sb;for (int i 7; i > 0; i --) {int val (num >> (4 * i)) & 0xf;if (sb.length() > 0 || val > 0) {char digit val …

JDBC实现对单表数据增、删、改、查

文章目录 API介绍获取 Statement 对象Statement的API介绍使用步骤案例代码 JDBC实现对单表数据查询ResultSet的原理ResultSet获取数据的API使用JDBC查询数据库中的数据的步骤案例代码 API介绍 获取 Statement 对象 在java.sql.Connection接口中有如下方法获取到Statement对象…

汽车电子笔记之-013:旋变硬解码ADI芯片AD2S1210使用记录(从零开始到软件实现)

目录 1、概述 2、技术规格 3、芯片引脚 4、旋变信号格式 5、使用过程只是要点分析 5.1、程序注意点分析 5.1.1、SPI配置时序 5.1.2、问题一&#xff1a;SPI时序问题 5.1.3、问题二&#xff1a;SPI读取时序&#xff08;配置模式&#xff09; 5.1.4、问题三&#xff1a…

削峰+限流:秒杀场景下的高并发写请求解决方案

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 哈喽,大家好!我是小米,一个29岁、活泼积极、热衷分享技术的码农。今天和大家聊一聊应对高并发的写请求这个主题,尤其是在大促、秒杀这种场景下,系统…

非线性规划及其MATLAB实现

目录 引言 非线性规划的基本模型 非线性规划的求解方法 非线性规划的MATLAB实现 例子&#xff1a;多目标优化问题的非线性规划求解 表格总结&#xff1a;MATLAB常用非线性规划函数 实例&#xff1a;使用MATLAB求解非线性投资决策问题 结论 引言 非线性规划&#xff08;…

ES6解构赋值详解;全面掌握:JavaScript解构赋值的终极指南

目录 全面掌握&#xff1a;JavaScript解构赋值的终极指南 一、数组解构赋值 1、基本用法 2、跳过元素 3、剩余元素 4、默认值 二、对象解构赋值 1、基本用法 2、变量重命名 3、默认值 4、嵌套解构 三、复杂的嵌套结构解构 四、函数参数解构赋值 1、对象解构作为函…

C/C++实现植物大战僵尸(PVZ)(打地鼠版)

&#x1f680;欢迎互三&#x1f449;&#xff1a;程序猿方梓燚 &#x1f48e;&#x1f48e; &#x1f680;关注博主&#xff0c;后期持续更新系列文章 &#x1f680;如果有错误感谢请大家批评指出&#xff0c;及时修改 &#x1f680;感谢大家点赞&#x1f44d;收藏⭐评论✍ 游戏…

2022高教社杯全国大学生数学建模竞赛C题 问题一(1) Python代码演示

目录 问题 11.1 对这些玻璃文物的表面风化与其玻璃类型、纹饰和颜色的关系进行分析数据探索 -- 单个分类变量的绘图树形图条形图扇形图雷达图Cramer’s V 相关分析统计检验列联表分析卡方检验Fisher检验绘图堆积条形图分组条形图分类模型Logistic回归随机森林import matplotlib…

GAN的损失函数和二元交叉熵损失的对应及代码

以下解释为GPT生成 这里有个问题&#xff0c;使用二元交叉熵&#xff0c;的时候生成器的损失如何体现 看代码 import torch import torch.nn as nn import torch.optim as optim# 设置设备为GPU或CPU device torch.device("cuda" if torch.cuda.is_available() el…

EndnoteX9安装及使用教程

EndnoteX9安装及使用教程 一、EndNote安装 1.1 下载 这里提供一个下载链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1RlGJksQ67YDIhz4tBmph6Q 提取码&#xff1a;5210 解压完成后&#xff0c;如下所示&#xff1a; 1.2 安装 双击右键进行安装 安装比较简单…

【C++11 —— 线程库】

C11 —— 线程库 thread类介绍线程函数参数原子性操作库(atomic)lock_guard与unique_lockmutex的种类lock_guardunique_lock 两个线程交替打印奇偶数 thread类介绍 在C11之前&#xff0c;涉及到多线程的问题&#xff0c;都是和平台相关的&#xff0c;比如windows和Linux下各有…

AI 时代程序员的应变之道

一、AI 浪潮来袭&#xff0c;编程界风云变幻 随着 AIGC 大语言模型如 ChatGPT、Midjourney、Claude 等的涌现&#xff0c;AI 辅助编程工具日益普及&#xff0c;程序员的工作方式正经历着深刻的变革。 分析公司 OReilly 日前发布的《2023 Generative AI in the Enterprise》报告…

【Linux基础】冯诺依曼体系结构操作系统的理解

目录 前言一&#xff0c;冯诺依曼体系1. 为什么有内存结构?2. 对硬件中数据流动的再理解 二&#xff0c;操作系统(Operator System)1. 概念2. 操作系统结构的层状划分3. 操作系统对硬件管理的理解4. 用户与操作系统的关系的理解5. 系统调用和库函数的关系6. 为什么要有操作系统…

策略路由与路由策略的区别

&#x1f423;个人主页 可惜已不在 &#x1f424;这篇在这个专栏 华为_可惜已不在的博客-CSDN博客 &#x1f425;有用的话就留下一个三连吧&#x1f63c; 目录 一、主体不同 二、方式不同 三、规则不同 四、定义和基本概念 一、主体不同 1、路由策略&#xff1a;是为了改…

android 删除系统原有的debug.keystore,系统运行的时候,重新生成新的debug.keystore,来完成App的运行。

1、先上一个图&#xff1a;这个是keystore无效的原因 之前在安装这个旧版本android studio的时候呢&#xff0c;安装过一版最新的android studio&#xff0c;然后通过模拟器跑过测试的demo。 2、运行旧的项目到模拟器的时候&#xff0c;就报错了&#xff1a; Execution failed…