bpftrace技术1-常用命令
bpftrace是什么
一种追踪内核态和用户态的新技术
看可以跟踪哪些内核函数
1 | bpftrace -l | grep kprobe |
跟踪内核函数例子
是否调用
跟踪 net/ipv4/netfilter/ip_tables.c looks promising 的两个函数: compat_do_ipt_get_ctl 和 do_ipt_get_ctl。
1 | bpftrace -e 'kprobe:do_ipt_get_ctl { printf("function was called!\n"); }' |
compat_do_ipt_get_ctl 函数签名如下
1 | static int compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) |
调用命令,pid,入参
建立test.bpf文件 1
2
3
4
5
6
kprobe:do_ipt_get_ctl
{
printf("called by %s (pid: %d). and: %d\n", comm, pid, ((sock *)arg0)->__sk_common.skc_family);
}
执行结果如下
1 | ~ |
2 的含义解释如下
1 | /usr/src/linux-headers-4.19.0-8-common/include/linux/socket.h |
打印入参
1 | bpftrace -e 'kprobe:vfs_open { printf("open path: %s\n", str(((path *)arg0)->dentry->d_name.name)); }' |
打印返回值
使用默认变量retval。
内核函数返回值
使用 kretprobe跟踪内核函数的返回值。例如,跟踪 vfs_read的返回值(读取的字节数或错误码): 1
bpftrace -e 'kretprobe:vfs_read { printf("vfs_read returned: %d\n", retval); }'
用户空间函数返回值
使用 uretprobe跟踪用户空间函数的返回值。例如,跟踪一个名为 myfunc的函数的返回值: 1
bpftrace -e 'uretprobe:/path/to/binary:myfunc { printf("myfunc returned: %d\n", retval); }'
结合入口和返回探针
测量函数执行时间或关联参数与返回值。这可以通过在函数入口(如 kprobe/uprobe)记录时间戳(tid是内置变量,代表线程id),然后在返回探针中计算差值来实现。例如: 1
2
3
4
5
6bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs; }
kretprobe:vfs_read /@start[tid]/ {
$duration = nsecs - @start[tid];
printf("vfs_read took %d ns, returned %d\n", $duration, retval);
delete(@start[tid]);
}'
过滤条件
可以在返回探针上添加过滤条件,例如只处理特定进程或返回值范围的调用。使用 /<filter>/语法。例如,只打印返回值大于0的 vfs_read调用: 1
bpftrace -e 'kretprobe:vfs_read /retval > 0/ { printf("vfs_read returned: %d\n", retval); }'