diff --git a/Makefile b/Makefile index eb2b0c7..2f13b79 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ export GOPROXY = direct CURDIR := $(abspath .) TESTDATADIR := $(CURDIR)/test-data +ELFPARSERDIR := $(CURDIR)/pkg/elfparser BPFTOOL := bpftool CLANG := clang LOGFILE_PATH ?= stdout @@ -48,7 +49,8 @@ TARGETS := \ $(TESTDATADIR)/recoverydata \ $(TESTDATADIR)/test-kprobe \ $(TESTDATADIR)/xdp \ - $(TESTDATADIR)/ring_buffer + $(TESTDATADIR)/ring_buffer \ + $(ELFPARSERDIR)/test-data/test %.bpf.elf: %.bpf.c $(CLANG) $(CLANG_INCLUDE) $(BPF_CFLAGS) -c $< -o $@ @@ -74,3 +76,4 @@ unit-test: ## Run unit tests clean: -@rm -f $(TESTDATADIR)/vmlinux.h -@rm -f $(TESTDATADIR)/*.elf + -@rm -f $(ELFPARSERDIR)/test-data/*.elf diff --git a/pkg/elfparser/elf.go b/pkg/elfparser/elf.go index c919315..7edd7db 100644 --- a/pkg/elfparser/elf.go +++ b/pkg/elfparser/elf.go @@ -50,6 +50,7 @@ var sdkCache = cache.Get() type BpfSDKClient interface { IncreaseRlimit() error LoadBpfFile(path, customizedPinPath string) (map[string]BpfData, map[string]ebpf_maps.BpfMap, error) + LoadBpfFromReader(r io.ReaderAt, customizedPinPath string) (map[string]BpfData, map[string]ebpf_maps.BpfMap, error) RecoverGlobalMaps() (map[string]ebpf_maps.BpfMap, error) RecoverAllBpfProgramsAndMaps() (map[string]BpfData, error) } @@ -122,26 +123,35 @@ func newElfLoader(elfFile *elf.File, bpfmapapi ebpf_maps.BpfMapAPIs, bpfprogapi return elfloader } -func (b *bpfSDKClient) LoadBpfFile(path, customizedPinPath string) (map[string]BpfData, map[string]ebpf_maps.BpfMap, error) { - bpfFile, err := os.Open(path) +// LoadBpfFromReader loads ELF file from io.ReaderAt and parses an ELF file into BPF objects +func (b *bpfSDKClient) LoadBpfFromReader(r io.ReaderAt, customizedPinPath string) ( + map[string]BpfData, + map[string]ebpf_maps.BpfMap, + error, +) { + elfFile, err := elf.NewFile(r) if err != nil { - log.Infof("LoadBpfFile failed to open") return nil, nil, err } - defer bpfFile.Close() - elfFile, err := elf.NewFile(bpfFile) + elfLoader := newElfLoader(elfFile, b.mapApi, b.progApi, customizedPinPath) + bpfLoadedProg, bpfLoadedMaps, err := elfLoader.doLoadELF() if err != nil { return nil, nil, err } - elfLoader := newElfLoader(elfFile, b.mapApi, b.progApi, customizedPinPath) + return bpfLoadedProg, bpfLoadedMaps, nil +} - bpfLoadedProg, bpfLoadedMaps, err := elfLoader.doLoadELF() +func (b *bpfSDKClient) LoadBpfFile(path, customizedPinPath string) (map[string]BpfData, map[string]ebpf_maps.BpfMap, error) { + bpfFile, err := os.Open(path) if err != nil { + log.Infof("LoadBpfFile failed to open") return nil, nil, err } - return bpfLoadedProg, bpfLoadedMaps, nil + defer bpfFile.Close() + + return b.LoadBpfFromReader(bpfFile, customizedPinPath) } func (e *elfLoader) loadMap(parsedMapData []ebpf_maps.CreateEBPFMapInput) (map[string]ebpf_maps.BpfMap, error) { diff --git a/pkg/elfparser/elf_test.go b/pkg/elfparser/elf_test.go index 056feb6..f539594 100644 --- a/pkg/elfparser/elf_test.go +++ b/pkg/elfparser/elf_test.go @@ -15,7 +15,9 @@ package elfparser import ( + "bytes" "debug/elf" + _ "embed" "errors" "os" "sort" @@ -668,3 +670,17 @@ func TestProgType(t *testing.T) { }) } } + +//go:embed test-data/test.bpf.elf +var elfBytes []byte + +func TestLoadBpfFromEmbeddedElf(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("Test requires root privileges.") + } + + bpfSDKclient := New() + r := bytes.NewReader(elfBytes) + _, _, err := bpfSDKclient.LoadBpfFromReader(r, "") + assert.NoError(t, err) +} diff --git a/pkg/elfparser/test-data/test.bpf.c b/pkg/elfparser/test-data/test.bpf.c new file mode 100644 index 0000000..f049b83 --- /dev/null +++ b/pkg/elfparser/test-data/test.bpf.c @@ -0,0 +1,9 @@ +#include + +#include +#include + +SEC("kprobe") +int test_kprobe(struct pt_regs *ctx) { return 0; } + +char _license[] SEC("license") = "GPL"; diff --git a/pkg/elfparser/test-data/test.bpf.elf b/pkg/elfparser/test-data/test.bpf.elf new file mode 100644 index 0000000..94fed33 Binary files /dev/null and b/pkg/elfparser/test-data/test.bpf.elf differ