bpftrace 无法定义函数,但提供了约 30 个内置函数,可以在 bpftrace 脚本的任意位置调用它们。这里介绍几个最常用的内置函数,完整的列表可以参考官方文档(https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md)
printf
熟悉 C 语言的同学会很熟悉,bpftrace 的 printf
函数行为与 C 语言基本一致,区别在于,它只支持有限的格式化字符,不如 C 语言支持的那么多。
printf(fmt, ...)
- fmt,格式化字符串,它决定了以什么格式输出内容,也决定了可变参数的数量和类型;
- 数量和类型可变的参数。
下面是一个官方示例:
# bpftrace -e 'tracepoint:syscalls:sys_enter_execve { printf("%s called %s\n", comm, str(args->filename)); }'
Attaching 1 probe...
bash called /bin/ls
bash called /usr/bin/man
代码中的两个 %s
表示后续还有 2 个参数,并且它们都是字符串。输出时,%s
会被替换为这两个字符串。
一般可以借助 printf
将需要的内容打印到标准输出。
time
time
函数用于打印当前时间,可以通过参数中的格式化字符串指定,如果没有指定格式化字符串,那么默认个时是%H:%M:%S\n
.
time(fmt)
time
函数完全兼容 strftime
的格式化字符,下面列出一些常用项,这里有完整的格式化字符清单(https://linux.die.net/man/3/strftime)。
%S
秒,00-60;%M
分钟,00-59;%I
小时,01-12;%H
小时,00-23;%d
每月的第几天,01-31;%w
星期,0-6, 0 指 星期日;%m
月份,01-12;%y
年份,00-99;%Y
完整的年份;
注意: 格式化字符结尾不要忘记换行,否则不会自动清空缓冲区到标准输出,就看不到输出了。
下面通过定时器,每秒输出当前时间,注意格式化字符尾部的 \n
。
# bpftrace -e 'interval:s:1 {time("%Y %H:%M:%S\n");}'
Attaching 1 probe...
2022 01:39:13
2022 01:39:14
2022 01:39:15
system
该函数可以调用 shell,用于 probe 触发其他用户态可执行程序非常有用。
下面是一个简单的例子,定时调用 `ps. 查看当前进程:
# bpftrace --unsafe -e 'kprobe:do_nanosleep { system("ps -p %d\n", pid); }'
Attaching 1 probe...
PID TTY TIME CMD
1339 ? 00:00:15 iscsid
PID TTY TIME CMD
1339 ? 00:00:15 iscsid
ustack
当使用 uprobe
时,很可能需要关注用户进程的 stack 情况,ustack
函数接受 2 个参数:
- mode,stack 模式,可选 bpftrace、perf;
- limit,一个整数,获取 stack 的最大深度;
这两个参数可以同时使用,或者只用 1 个。下面是一个官方示例:
# bpftrace -e 'uprobe:bash:readline { printf("%s\n", ustack(perf, 3)); }'
Attaching 1 probe...
5649feec4090 readline+0 (/home/mmarchini/bash/bash/bash)
5649fee2bfa6 yy_readline_get+451 (/home/mmarchini/bash/bash/bash)
5649fee2bdc6 yy_getc+13 (/home/mmarchini/bash/bash/bash)