1. bpftrace 介绍
bpftrace 是一个基于 eBPF (Extended Berkeley Packet Filter) 的高级工具,用于动态跟踪系统的各种事件和性能指标。它可以在不需要重新编译内核模块的情况下,以一种安全、高效的方式执行代码,从而提供了丰富的系统跟踪和性能分析能力。
2. bpftrace 使用
2.1. 语法结构
bpftrace 语法结构:
probes /filter/ { action }
probes:事件,tracepoint, kprobe, kretprobe, uprobe。两个特殊事件 BEGIN/END,用于脚本开始和结束处执行。
filter:过滤条件,事件触发时,判断条件,例如:/pid == 3245/,表示pid 为3245的进程执行。
action :具体执行的操作,例如:{ printf("close\n");} 打印close
2.2. probes
2.3. bpftrace 变量
内置变量
bpftrace 脚本常用变量如下:
uid:用户id。
tid:线程id
pid:进程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变量
内置函数
Function Description
printf("...") Print formatted string
time("...") Print formatted time
join(char *arr[]) Join array of strings with a space
str(char *s [, int length]) Return string from s pointer
buf(void *p [, int length]) Return a hexadecimal string from p pointer
strncmp(char *s1, char *s2, int length) Compares two strings up to length
sizeof(expression) Returns the size of the expression
kstack([limit]) Kernel stack trace up to limit frames
ustack([limit]) User-level stack trace up to limit frames
ksym(void *p) Resolve kernel address to symbol
usym(void *p) Resolve user-space address to symbol
kaddr(char *name) Resolve kernel symbol name to address
uaddr(char *name) Resolve user-space symbol name to address
ntop([int af,]int|char[4:16] addr) Convert IP address data to text
reg(char *name) Return register value
cgroupid(char *path) Return cgroupid for /sys/fs/cgroup/... path
time("...") Print formatted time
system("...") Run shell command
cat(char *filename) Print file content
signal(char[] sig | int sig) Send a signal to the current task
override(u64 rc) Override a kernel function return value
exit() Exits bpftrace
@ = count() Count events
@ = sum(x) Sum the value
@ = hist(x) Power-of-2 histogram for x
@ = lhist(x, min, max, step) Linear histogram for x
@ = min(x) Record the minimum value seen
@ = max(x) Record the maximum value seen
@ = stats(x) Return the count, average, and total for this value
delete(@x[key]) Delete the map element
clear(@x) Delete all keys from the map
2.4. bpftrace 基础用法
1)查找探针
使用 bpftrace -l 命令可以列出所有的探针。
比如,我们想检测 tcp的 connect ,可以执行 bpftrace -l "tcp*connect"
2)单行语句
#监控 tcpv4 connect
bpftrace -e 'kprobe:tcp_v4_connect { printf("socket connct comm[%s] pid[%d] \n", comm, pid); }'
下图示例为调用 bpftrace 监控 tcp connect 接口是否被调用,在另外一个窗口调用 curl 访问百度时,监测到的结果。
3)文件形式
除了上面讲的当行语句以外,bpftrace 还支持文件的方式,可以实现复杂度更高的功能。
用法:bpftrace test.bt
#!/usr/sbin/bpftrace
tracepoint:raw_syscalls:sys_enter
/filter/
{
}
3. bpftrace 使用实例
使用 bpftrace 监控正在运行的服务器accept 执行的次数。
#!/usr/sbin/bpftrace
BEGIN
{
printf("Tracing TCP connections for PID %d...\n", $1);
}
kprobe:__sys_accept4
{
if (pid == $1) {
@tcp_accepts[tid] = count();
}
}
END
{
printf("PID %d: TCP connections:\n", $1);
print(@tcp_accepts);
}
可以看到, pid为25822 的服务器接调用了三次 accept 函数。
bpftrace可以使用系统调用拦截技术(如kprobes、tracepoints等)来截获系统调用和其他事件,然后在事件发生时获取到相关的进程信息,比如PID、进程名称等。