在之前的bcc代码中我们知道其程序是分为两部分的,一部分是C语言,另一部分是基于Python的。本篇是关于C语言部分的。
1. 事件和参数
1.1 kprobes
使用kprobe的语法是:
kprobe__kernel_function_name
其中kprobe__是前缀,用于给内核函数创建一个kprobe(内核函数调用的动态跟踪)。也可通过C语言函数定义一个C函数,然后使用python的BPF.attach_kprobe()来关联到内核函数。
例如:
int kprobe__tcp_v4_connect(struct pt_regs *ctx, struct sock *sk)
其中参数struct pt_regs *ctx是寄存器和BPF文件
sock *sk是tcp_v4_connect的第一个参数。
1.2 kretprobes
kretprobes动态跟踪内核函数的返回,语法如下:
kretprobe__kernel_function_name,前缀是kretprobe__。也可以使用python的BPF.attach_kretprobe()来关联C函数到内核函数。
例如:
int kretprobe__tcp_v4_connect(struct pt_regs *ctx)
{ int ret = PT_REGS_RC(ctx); [...]
}
返回值保存在ret中。
1.3 Tracepoints
语法如下:TRACEPOINT_PROBE(category,event)
TRACEPOINT_PROBE是一个宏, tracepiont定义的方式是categroy:event,
可以的参数是通过结构体args获取的,获取参数相关格式的方法是cat文件:
/sys/kernel/debug/tracing/events/category/event/format
结构体args可以在函数中使用例如:
TRACEPOINT_PROBE(random, urandom_read) {
// args is from /sys/kernel/debug/tracing/events/random/urandom_read/format bpf_trace_printk("%d\\n", args->got_bits); return 0;
}
1.4 uprobes
通过python的BPF.attach_uprobe()可以将普通C函数关联到uprobe探针。
参数可以通过PT_REGS_PARM宏来检测。
程序本身名字使用宏PT_REGS_PARM1,第一个参数使用宏PT_REGS_PARM2。
1.5 uretprobes
同uprobes,只不过该探针是在函数返回时候触发。
返回的值通过PT_REGS_RC(ctx)获取,例如:
BPF_HISTOGRAM(dist); int count(struct pt_regs *ctx) { dist.increment(PT_REGS_RC(ctx)); return 0;
}
在直方图dist中,根据增加返回键对应的值。
1.6 USDT probes
User Statically-Defined Tracing用户静态定义的探针,会在应用和库中定义用来提供用户级别追踪。BPF中提供对USDT的支持方法是enable_probe。
使用方法同其他probes,定义C函数,然后通过USDT.enable_probe()来关联USDT probe。
参数可以通过bpf_usdt_readarg(index,ctx,&addr)来读取。
例如:
int