eBPF程序附加tracepoint时触发空指针异常问题排查
问题描述
我编写的eBPF程序无法附加到tracepoint syscalls/sys_exit_mmap,调用ebpf.NewCollectionWithOptions()时抛出错误:
invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x6ab850]
排查后确认,问题出在e->sys_exit_mmap_ret = (__s32)ctx->ret这行代码——如果将其替换为直接赋值0(不使用ctx),错误就会消失。相关源码片段如下:
struct rb_event { __u16 opcode; union { // ... struct { __s32 sys_exit_mmap_ret; }; }; }; // see /sys/kernel/debug/tracing/events/syscalls/sys_exit_mmap/format struct sys_exit_mmap_ctx { __s64 ret; }; SEC("tracepoint/syscalls/sys_exit_mmap") int sys_exit_mmap( struct sys_exit_mmap_ctx *ctx ) { struct rb_event *e; e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0); if (e == NULL) { return 0; } e->opcode = OPCODE_SYS_EXIT_MMAP; e->sys_exit_mmap_ret = (__s32)ctx->ret; bpf_ringbuf_submit(e, 0); return 0; }
问题根源与修复方案
问题核心是你自定义的struct sys_exit_mmap_ctx和内核实际的tracepoint上下文结构不匹配。
Linux tracepoint的上下文结构并非只有ret字段,它有固定的通用前置元数据结构。以sys_exit_mmap为例,内核实际的上下文结构开头是struct trace_entry(包含时间戳、PID等通用信息),之后才是ret字段。你的结构体直接定义__s64 ret,跳过了前置元数据,导致访问ctx->ret时实际访问的是内核内存中错误的地址,触发段错误。
修复步骤:
- 获取正确的结构体定义:执行以下命令查看
sys_exit_mmap的完整tracepoint结构:
或者用bpftool从BTF中导出更准确的C结构体:cat /sys/kernel/debug/tracing/events/syscalls/sys_exit_mmap/formatbpftool btf dump file /sys/kernel/btf/vmlinux format c | grep -A 25 "struct trace_event_raw_sys_exit" - 替换自定义结构体:将上述命令得到的完整结构体复制到你的eBPF代码中,替换现有的
struct sys_exit_mmap_ctx。 - 正确访问ret字段:在新的结构体中,
ret字段位于通用元数据之后,确保代码中访问的是正确的字段位置。
内容的提问来源于stack exchange,提问作者rookie099
相关产品推荐
相关产品推荐

