寻找插桩点
# 列出所有 tracepoint 插桩点
bpftrace -l "tracepoint:*:*"
确定函数上下文
跟踪点程序的上下文是指向结构体的指针,每个跟踪事件的上下文都不相同,通过如下命令可读取到对应事件的上下文
cat /sys/kernel/tracing/events/sched/sched_process_exec/format
# 一般输出如下
name: sched_process_exec
ID: 322
# 下面每一行就是一个参数,也代表了插桩点的上下文
format:
# 这一个区域不能在bpf中进行输出
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;
# 这个区域的参数可以在bpf程序中进行输出
field:__data_loc char[] filename; offset:8; size:4; signed:0;
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
定义插桩函数
自定义上下文
根据函数上下文可以重构上下文结构体,并定义插桩函数:
// 根据上下文重构结构体
struct raw_exec_ctx {
u16 common_type;
u8 common_flags;
u8 common_preempt_count;
int common_pid;
u32 __data_loc_filename;
pid_t pid;
pid_t old_pid;
};
SEC("tp/sched/sched_process_exec")
int handle_exec(struct raw_exec_ctx *ctx)
{
...
bpf_printk("filename:%d pid:%d old_pid:%d\n", ctx->__data_loc_filename, ctx->pid, ctx->old_pid);
...
return 0;
}
使用vmlinux定义好的上下文
在 vmlinux.h 中也会定义部分 tracepoint 插桩点的上下文结构体,一般定义格式为`trace_event_raw_*`,`*`表示要插桩的函数,但 vmlinux.h 中不一定定义了所有的插桩函数上下文结构体,所以推荐还是使用自定义上下文。
SEC("tp/sched/sched_process_exec")
int handle_exec(struct trace_event_raw_sched_process_exec *ctx)
{
...
bpf_printk("filename:%d pid:%d old_pid:%d\n", ctx->__data_loc_filename, ctx->pid, ctx->old_pid);
...
return 0;
}