编译eBPF代码报错:struct pt_regs无'si'成员
问题:x86_64架构下编译eBPF代码时PT_REGS_PARM2宏报错
环境与代码
我在x86_64架构下尝试编译以下eBPF代码:
#include "vmlinux.h" #include <bpf/bpf_helpers.h> #include <bpf/bpf_tracing.h> SEC("kprobe/do_sys_openat2") int kprobe__do_sys_openat2(struct pt_regs *ctx) { char file_name[256]; bpf_probe_read(file_name, sizeof(file_name), PT_REGS_PARM2(ctx)); char fmt[] = "open file %s\n."; bpf_trace_printk(fmt, sizeof(fmt), &file_name); return 0; }
使用如下Makefile构建:
OUTPUT = ./output LIBBPF = ../libbpf LIBBPF_SRC = $(abspath $(LIBBPF)/src) LIBBPF_OBJ = $(abspath $(OUTPUT)/libbpf.a) CC = gcc CLANG = clang ARCH := $(shell uname -m) # ARCH := $(subst x86_64,amd64,$(ARCH)) GOARCH := $(ARCH) BPFTOOL = $(shell which bpftool || /bin/false) BTFFILE = /sys/kernel/btf/vmlinux DBGVMLINUX = /usr/lib/debug/boot/vmlinux-$(shell uname -r) GIT = $(shell which git || /bin/false) VMLINUXH = vmlinux.h # libbpf LIBBPF_OBJDIR = $(abspath ./$(OUTPUT)/libbpf) LIBBPF_DESTDIR = $(abspath ./$(OUTPUT)) CFLAGS = -ggdb -gdwarf -O2 -Wall -fpie -Wno-unused-variable -Wno-unused-function LDFLAGS = BPF_CFLAGS_STATIC = "-I$(abspath $(OUTPUT))" BPF_LDFLAGS_STATIC = "-lelf -lz $(LIBBPF_OBJ)" CGO_CFLAGS_STATIC = "-I$(abspath $(OUTPUT))" CGO_LDFLAGS_STATIC = "-lelf -lz $(LIBBPF_OBJ)" CGO_EXTLDFLAGS_STATIC = '-w -extldflags "-static"' CGO_CFGLAGS_DYN = "-I. -I/usr/include/" CGO_LDFLAGS_DYN = "-lelf -lz -lbpf" CGO_EXTLDFLAGS_DYN = '-w' ## program .PHONY: $(PROGRAM) .PHONY: $(PROGRAM).bpf.c PROGRAM = main all: $(MAKE) -C . $(PROGRAM) # vmlinux header file .PHONY: vmlinuxh vmlinuxh: $(VMLINUXH) $(VMLINUXH): $(OUTPUT) ifeq ($(wildcard $(BPFTOOL)),) @echo "ERROR: could not find bpftool" @exit 1 endif @if [ -f $(DBGVMLINUX) ]; then \ echo "INFO: found dbg kernel, generating $(VMLINUXH) from $(DBGVMLINUX)"; \ $(BPFTOOL) btf dump file $(DBGVMLINUX) format c > $(VMLINUXH); \ fi @if [ ! -f $(BTFFILE) ] && [ ! -f $(DBGVMLINUX) ]; then \ echo "ERROR: kernel does not seem to support BTF"; \ exit 1; \ fi @if [ ! -f $(VMLINUXH) ]; then \ echo "INFO: generating $(VMLINUXH) from $(BTFFILE)"; \ $(BPFTOOL) btf dump file $(BTFFILE) format c > $(VMLINUXH); \ fi # static libbpf generation for the git submodule .PHONY: libbpf libbpf: $(LIBBPF_OBJ) $(LIBBPF_OBJ): $(LIBBPF_SRC) $(wildcard $(LIBBPF_SRC)/*.[ch]) | $(OUTPUT)/libbpf CC="$(CC)" CFLAGS="$(CFLAGS)" LD_FLAGS="$(LDFLAGS)" \ $(MAKE) -C $(LIBBPF_SRC) \ BUILD_STATIC_ONLY=1 \ OBJDIR=$(LIBBPF_OBJDIR) \ DESTDIR=$(LIBBPF_DESTDIR) \ INCLUDEDIR= LIBDIR= UAPIDIR= prefix= libdir= install $(LIBBPF_SRC): ifeq ($(wildcard $@), ) echo "INFO: updating submodule 'libbpf'" $(GIT) submodule update --init --recursive endif # output dir $(OUTPUT): mkdir -p $(OUTPUT) $(OUTPUT)/libbpf: mkdir -p $(OUTPUT)/libbpf ## program bpf dependency $(PROGRAM).bpf.o: $(PROGRAM).bpf.c | vmlinuxh $(CLANG) $(CFLAGS) -target bpf -D__TARGET_ARCH_x86 -I. -I$(OUTPUT) -c $< -o $@ ## GO example .PHONY: $(PROGRAM) $(PROGRAM): libbpf | $(PROGRAM).bpf.o CC=$(CLANG) \ CGO_CFLAGS=$(CGO_CFLAGS_STATIC) \ CGO_LDFLAGS=$(CGO_LDFLAGS_STATIC) \ GOARCH=$(GOARCH) \ go build \ -tags netgo -ldflags $(CGO_EXTLDFLAGS_STATIC) \ -o $(PROGRAM) ./$(PROGRAM).go ## clean clean: $(MAKE) -C $(LIBBPF_SRC) clean rm -rf $(OUTPUT) rm -rf $(VMLINUXH) rm -rf $(PROGRAM) $(PROGRAM)-*static $(PROGRAM)-*dynamic rm -rf $(PROGRAM).bpf.o $(PROGRAM).o
编译错误
编译时出现如下错误:
error: no member named 'si' in 'struct pt_regs' bpf_probe_read(file_name, sizeof(file_name), PT_REGS_PARM2(ctx)); ^~~~~~~~~~~~~~~~~~ ./output/bpf/bpf_tracing.h:273:46: note: expanded from macro 'PT_REGS_PARM2' #define PT_REGS_PARM2(x) (__PT_REGS_CAST(x)->__PT_PARM2_REG) ~~~~~~~~~~~~~~~~~ ^ ./output/bpf/bpf_tracing.h:78:24: note: expanded from macro '__PT_PARM2_REG' #define __PT_PARM2_REG si ^
经排查,错误源于bpf_tracing.h中PT_REGS_PARM2宏的定义,该宏展开后会访问struct pt_regs的si成员,但x86_64架构对应的struct pt_regs中并无此成员。想请教是Makefile中的架构指定有误,还是bpf_tracing.h的代码存在问题?
解答
问题出在Makefile中编译eBPF目标文件时的架构定义错误:
在编译$(PROGRAM).bpf.o的规则里,你使用了-D__TARGET_ARCH_x86,但x86_64架构对应的正确宏应该是__TARGET_ARCH_x86_64。
bpf_tracing.h中的__PT_PARM2_REG宏会根据目标架构选择对应的寄存器:
- 32位x86架构下,第二个参数存在
si寄存器中 - 64位x86_64架构下,第二个参数存在
rdi寄存器中
由于你错误定义了32位x86的架构宏,导致宏展开后访问了不存在的si成员。
修复步骤
修改Makefile中编译$(PROGRAM).bpf.o的规则:
$(PROGRAM).bpf.o: $(PROGRAM).bpf.c | vmlinuxh $(CLANG) $(CFLAGS) -target bpf -D__TARGET_ARCH_x86_64 -I. -I$(OUTPUT) -c $< -o $@
或者更通用的写法,根据系统架构自动设置:
$(PROGRAM).bpf.o: $(PROGRAM).bpf.c | vmlinuxh $(CLANG) $(CFLAGS) -target bpf -D__TARGET_ARCH_$(ARCH) -I. -I$(OUTPUT) -c $< -o $@
这样编译时会正确匹配x86_64架构的寄存器定义,PT_REGS_PARM2宏会展开为访问rdi成员,与struct pt_regs的定义一致,解决编译错误。
另外,还可以检查下libbpf子模块是否为最新版本,确保bpf_tracing.h中的架构相关宏定义是正确的,但核心问题还是架构宏的错误定义。
内容的提问来源于stack exchange,提问作者imawful
相关产品推荐
相关产品推荐

