当在 eBPF 程序中获取内核堆栈跟踪时,我得到了重复且看似奇怪的条目:有人可以解释一下吗?
让我们从相关的 eBPF 程序片段开始;首先,我声明了一个堆栈跟踪图,如下所示:
struct {
__uint(type, BPF_MAP_TYPE_STACK_TRACE);
__type(key, u32);
__type(value, stack);
__uint(max_entries, 1 << 14);
} stacks SEC(".maps");
在 eBPF 程序(稍后附加到cap_capable
)中,我按如下方式存储堆栈跟踪,然后将堆栈跟踪 ID 发送到用户空间:
kstackid = bpf_get_stackid(ctx, &stacks, 0);
用户空间方面在 Go 中,使用 Cilium 非常有用ebpf Go 模块。为了读取特定堆栈回溯的指令指针,我执行以下操作:
ips := make([]uint64, MaxStackDepth)
if err := objs.Stacks.Lookup(event.Kstackid, ips); err != nil {
slog.Error("looking up kernel stack trace", "error", err)
continue
}
l := len(ips)
for idx, ip := range ips {
if ip == 0 {
l = idx
break
}
}
ev := Event{
bpfCapevent: event,
KernelStack: ips[:l],
}
现在,当我使用来自的数据解析指令指针时,/proc/kallsyms
最终会得到一个如下所示的堆栈,还会显示 IP:
bpf_prog_47f71ae01d77a0b5_fentry_cap_capable ffffffffc00860ed
bpf_prog_47f71ae01d77a0b5_fentry_cap_capable ffffffffc00860ed
udp_tunnel_nic_init_module ffffffffc0e2004f
cap_capable ffffffff9ea9b1a5
- 为什么会有二fentry 的 IP 地址
cap_capable
?它们都是相同的返回地址,那么这里发生了什么? cap_capable
我的 eBPF 程序之间的中间函数是什么,udp_tunnel_nic_init_module
看起来像是误解?会不会和蹦床有关……?