![为什么 eBPF 堆栈跟踪中的指令指针包含两次具有相同 IP 的 eBPF 程序,以及一个奇怪的不相关 IP?](https://linux22.com/image/230734/%E4%B8%BA%E4%BB%80%E4%B9%88%20eBPF%20%E5%A0%86%E6%A0%88%E8%B7%9F%E8%B8%AA%E4%B8%AD%E7%9A%84%E6%8C%87%E4%BB%A4%E6%8C%87%E9%92%88%E5%8C%85%E5%90%AB%E4%B8%A4%E6%AC%A1%E5%85%B7%E6%9C%89%E7%9B%B8%E5%90%8C%20IP%20%E7%9A%84%20eBPF%20%E7%A8%8B%E5%BA%8F%EF%BC%8C%E4%BB%A5%E5%8F%8A%E4%B8%80%E4%B8%AA%E5%A5%87%E6%80%AA%E7%9A%84%E4%B8%8D%E7%9B%B8%E5%85%B3%20IP%EF%BC%9F.png)
当在 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
看起来像是误解?会不会和蹦床有关……?