本文介绍如何使用 `libbpf` 编写 `Tracepoint` 程序。
Tracepoint
`Tracepoint` 定义在内核源码树的 `/include/trace/events/` 目录下。
本文以 `exec` 为例,其定义在 `sched.h` 中:
/*
* Tracepoint for exec:
*/
TRACE_EVENT(sched_process_exec,
TP_PROTO(struct task_struct *p, pid_t old_pid,
struct linux_binprm *bprm),
TP_ARGS(p, old_pid, bprm),
TP_STRUCT__entry(
__string( filename, bprm->filename )
__field( pid_t, pid )
__field( pid_t, old_pid )
),
TP_fast_assign(
__assign_str(filename, bprm->filename);
__entry->pid = p->pid;
__entry->old_pid = old_pid;
),
TP_printk("filename=%s pid=%d old_pid=%d", __get_str(filename),
__entry->pid, __entry->old_pid)
);
在一个运行的系统中,我们可以在 `/sys/kernel/debug/tracing/events` 目录下看到所有的 Tracepoint。
具体的,在 `sched/sched_process_exec/format` 文件中,`exec` Tracepoint 的参数格式如下:
name: sched_process_exec
ID: 308
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:__data_loc char[] filename; offset:8; size:4; signed:1;
field:pid_t pid; offset:12; size:4; signed:1;
field:pid_t old_pid; offset:16; size:4; signed:1;
print fmt: "filename=%s pid=%d old_pid=%d", __get_str(filename), REC->pid, REC->old_pid
注意:前 8 个字节在 Tracepoint 中不可访问。关于这一点,后面我们有时间再讨论。
上面的 `__data_loc` 字段需要特殊处理,参考后文给出的示例。
在 `sched/sched_process_exec` 这个路径中,`sched` 我们称之为 `category`,`sched_process_exec` 则为 `event`。
libbpf 与 Tracepoint
开门见山,使用 `libbpf`,一个针对上述 Tracepoint 的 `BPF` 函数可以这样写:
```c
SEC("tp/sched/sched_process_exec")
int handle_exec(struct trace_event_raw_sched_process_exec *ctx)
{
bpf_printk("pid = %d, old_pid = %d", ctx->pid, ctx->old_pid);
...
}
```
如前文所述,`SEC` 的定义表明这是一个 `BPF` 入口函数,格式为 `tp/${category}/${event}`。
`tp` 是 `tracepoint` 的缩写,写成 `tracepoint` 也是可以的。
`${category}/${event}` 如上文所述,替换成具体的 Tracepoint 名称即可。
参数类型 `struct trace_event_raw_sched_process_exec` 是怎么来的呢?
你当然可以按照上一节中的 `format` 文件自己写一个结构体,`BCC` 就是这么做的。
当然,我们不需要这么麻烦,只需要生成一个 `vmlinux.h` 头文件并引用即可:
```shell
$ bpftool btf dump file /sys/kernel/btf/vmlinux format c > vmlinux.h
```
这里有一个新概念:BTF。我们留待后文讨论。
完整示例参见:https://github.com/libbpf/libbpf-bootstrap#bootstrap
结语
本文简单介绍了 Tracepoint 的参数格式及相应 libbpf 示例。
时间仓促,本文挖了很多坑,后面慢慢填。欢迎大家留言交流。