ebpf通过raw_syscalls:sys_enter/exit tracepoint实现零侵入系统调用追踪,需在vscode中调试用户态加载器、配置libbpf、挂载tracefs并设perf_event_paranoid=-1,避免直接调试内核态程序。

VSCode 本身不直接捕获或追踪系统调用,但配合 eBPF 程序 + 用户态收集器 + VSCode 调试配置,可以实现对任意进程(包括 Python、Go、C 等)运行期系统调用的低开销、高精度、零侵入追踪。关键不在 VSCode,而在它能否帮你高效编写、加载、观察和关联 eBPF 探针行为。
如何用 eBPF tracepoint 捕获目标进程的系统调用
eBPF 最适合追踪系统调用的入口是 raw_syscalls:sys_enter 和 raw_syscalls:sys_exit tracepoint。它们在内核路径最上游触发,参数完整、开销极低,且无需修改目标程序。
- 必须用
SEC("tracepoint/raw_syscalls/sys_enter")声明程序段,不能用SEC("syscall")(后者不是标准钩子) - 结构体参数固定为
struct trace_event_raw_sys_enter *,需通过bpf_probe_read_kernel安全读取args[0]~args[5] - 若只关心某进程,务必在 eBPF 程序开头加过滤:
if (bpf_get_current_pid_tgid() >> 32 != target_pid) return 0;,否则 trace_pipe 会爆炸式刷屏 - 避免在 tracepoint 中调用
bpf_printk多次——每调用一次都是一次内核态字符串拷贝,高频 syscall 下极易拖慢整机
VSCode 中实时查看 syscall 日志的两种可靠方式
不能依赖终端 cat /sys/kernel/debug/tracing/trace_pipe 手动刷新,容易丢帧;也不能用 bpftool prog dump jited 看汇编——那不是运行时日志。
- 推荐方案:用
bpftool+perf双通道输出,在 VSCode 集成终端中运行:sudo bpftool prog tracelog | grep -E "(sys_enter|sys_exit)"(需 eBPF 程序已启用BPF_F_TRACING标志) - 更稳方案:写一个轻量用户态收集器(如用
libbpf的bpf_map__lookup_elem读取 perf ring buffer),再用 VSCode 的launch.json启动它并附加调试:"program": "${workspaceFolder}/tracer" - 切忌把
trace_pipe直接塞进launch.json的program字段——bash 子进程退出后管道就断了,VSCode 会报Unable to launch program
为什么在 VSCode 里调试 eBPF 加载器比调试 eBPF 程序本身更实际
eBPF 程序运行在内核态,无法设断点、无法单步、无法 inspect 变量。所谓“调试 eBPF”,95% 是调试它的用户态加载器(loader):是否正确设置 map、是否传入合法 PID、是否处理 verifier 错误、是否及时读取 perf buffer。
- 在 loader 的
main()中打断点,检查bpf_object__load_skeleton返回值,verifier 报错会直接体现在err或log_buf - 确保
launch.json中启用了"stopAtEntry": false,否则会在 _start 处卡死,错过关键初始化逻辑 - 如果 loader 用
libbpf的bpf_program__attach_tracepoint失败,大概率是内核没开启CONFIG_TRACEPOINTS=y,而不是代码写错了 - 不要在 VSCode 中尝试 “Attach to Process” 到内核——LLDB/GDB 对 BPF 指令无解析能力,只会显示
???
常见 syscall 追踪失败的三个隐藏原因
现象是:eBPF 程序加载成功、bpftool prog show 显示 running,但完全收不到任何 syscall 日志。
-
tracefs未挂载:执行sudo mount -t tracefs nodev /sys/kernel/debug/tracing,很多云主机默认不挂载 - 当前用户无权限读
/sys/kernel/debug/tracing/perf_event_paranoid:需设为-1(sudo sysctl -w kernel.perf_event_paranoid=-1),否则 perf ring buffer 不可用 - eBPF 程序用了
bpf_ktime_get_ns()却忘了在CMakeLists.txt中链接libbpf的helpers,导致 verifier 拒绝加载——错误日志藏在/sys/kernel/debug/tracing/error_log里,VSCode 默认不打开这个路径
真正难的从来不是写一段能跑的 eBPF 代码,而是让 tracepoint 输出稳定、可复现、可关联到具体业务线程。这要求你清楚知道每个 syscall 在内核中的触发路径、验证器对辅助函数的限制边界、以及 VSCode 调试器与内核事件流之间那层看不见的缓冲机制。











