From d63bb5595582a00b5dcd639760d52b07fb4f4965 Mon Sep 17 00:00:00 2001 From: Lorenz Bauer Date: Tue, 24 Aug 2021 17:26:53 +0200 Subject: [PATCH 1/4] btf: allow finding type by name alone Add a function which allows finding a type by name alone. This is useful for code that doesn't care about the concrete type returned. --- internal/btf/btf.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/internal/btf/btf.go b/internal/btf/btf.go index df4f78efd..3d72be2b3 100644 --- a/internal/btf/btf.go +++ b/internal/btf/btf.go @@ -635,6 +635,22 @@ func (s *Spec) AnyTypesByName(name string) ([]Type, error) { return result, nil } +// AnyTypeByName returns a Type with the given name. +// +// Returns an error if multiple types of that name exist. +func (s *Spec) AnyTypeByName(name string) (Type, error) { + types, err := s.AnyTypesByName(name) + if err != nil { + return nil, err + } + + if len(types) > 1 { + return nil, fmt.Errorf("found multiple types: %v", types) + } + + return types[0], nil +} + // TypeByName searches for a Type with a specific name. Since multiple // Types with the same name can exist, the parameter typ is taken to // narrow down the search in case of a clash. From abce994db1b1e324943ca09fc1940d680cdf55dc Mon Sep 17 00:00:00 2001 From: Lorenz Bauer Date: Fri, 28 Jan 2022 12:21:38 +0000 Subject: [PATCH 2/4] btf: export UnderlyingType Export an infallible version of skipQualifiersAndTypedef. Circular types / very long chains of qualifiers or typedefs are a corner case that shouldn't really happen, so let's not burden the callers with this detail. --- internal/btf/types.go | 20 +++++++++++++++ internal/btf/types_test.go | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/internal/btf/types.go b/internal/btf/types.go index a6b5a10aa..c23c3e7a6 100644 --- a/internal/btf/types.go +++ b/internal/btf/types.go @@ -990,3 +990,23 @@ func newEssentialName(name string) essentialName { } return essentialName(name) } + +// UnderlyingType skips qualifiers and Typedefs. +// +// May return typ verbatim if too many types have to be skipped to protect against +// circular Types. +func UnderlyingType(typ Type) Type { + result := typ + for depth := 0; depth <= maxTypeDepth; depth++ { + switch v := (result).(type) { + case qualifier: + result = v.qualify() + case *Typedef: + result = v.Type + default: + return result + } + } + // Return the original argument, since we can't find an underlying type. + return typ +} diff --git a/internal/btf/types_test.go b/internal/btf/types_test.go index 88658d559..a53f2dd47 100644 --- a/internal/btf/types_test.go +++ b/internal/btf/types_test.go @@ -249,3 +249,55 @@ func newCyclicalType(n int) Type { ptr.Target = prev return ptr } + +func TestUnderlyingType(t *testing.T) { + wrappers := []struct { + name string + fn func(Type) Type + }{ + {"const", func(t Type) Type { return &Const{Type: t} }}, + {"volatile", func(t Type) Type { return &Volatile{Type: t} }}, + {"restrict", func(t Type) Type { return &Restrict{Type: t} }}, + {"typedef", func(t Type) Type { return &Typedef{Type: t} }}, + } + + for _, test := range wrappers { + t.Run(test.name+" cycle", func(t *testing.T) { + root := &Volatile{} + root.Type = test.fn(root) + + got := UnderlyingType(root) + qt.Assert(t, got, qt.Equals, root) + }) + } + + for _, test := range wrappers { + t.Run(test.name, func(t *testing.T) { + want := &Int{} + got := UnderlyingType(test.fn(want)) + qt.Assert(t, got, qt.Equals, want) + }) + } +} + +func BenchmarkUnderlyingType(b *testing.B) { + b.Run("no unwrapping", func(b *testing.B) { + v := &Int{} + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + UnderlyingType(v) + } + }) + + b.Run("single unwrapping", func(b *testing.B) { + v := &Typedef{Type: &Int{}} + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + UnderlyingType(v) + } + }) +} From 600d4f0b97358cf5e251859cb5cc3251b2241531 Mon Sep 17 00:00:00 2001 From: Lorenz Bauer Date: Tue, 23 Nov 2021 16:30:36 +0000 Subject: [PATCH 3/4] collection: expose BTF spec --- collection.go | 11 +++++++++++ elf_reader.go | 2 +- elf_reader_test.go | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/collection.go b/collection.go index fb32ada88..0e0dc5322 100644 --- a/collection.go +++ b/collection.go @@ -27,6 +27,9 @@ type CollectionSpec struct { Maps map[string]*MapSpec Programs map[string]*ProgramSpec + // The BTF used by maps and programs. + BTF *btf.Spec + // ByteOrder specifies whether the ELF was compiled for // big-endian or little-endian architectures. ByteOrder binary.ByteOrder @@ -409,6 +412,10 @@ func (cl *collectionLoader) loadMap(mapName string) (*Map, error) { return nil, fmt.Errorf("missing map %s", mapName) } + if mapSpec.BTF != nil && cl.coll.BTF != mapSpec.BTF.Spec { + return nil, fmt.Errorf("map %s: BTF doesn't match collection", mapName) + } + m, err := newMapWithOptions(mapSpec, cl.opts.Maps, cl.handles) if err != nil { return nil, fmt.Errorf("map %s: %w", mapName, err) @@ -434,6 +441,10 @@ func (cl *collectionLoader) loadProgram(progName string) (*Program, error) { return nil, fmt.Errorf("cannot load program %s: program type is unspecified", progName) } + if progSpec.BTF != nil && cl.coll.BTF != progSpec.BTF.Spec() { + return nil, fmt.Errorf("program %s: BTF doesn't match collection", progName) + } + progSpec = progSpec.Copy() // Rewrite any reference to a valid map in the program's instructions, diff --git a/elf_reader.go b/elf_reader.go index bbc883108..bde05f5f5 100644 --- a/elf_reader.go +++ b/elf_reader.go @@ -164,7 +164,7 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) { return nil, fmt.Errorf("load programs: %w", err) } - return &CollectionSpec{maps, progs, ec.ByteOrder}, nil + return &CollectionSpec{maps, progs, btfSpec, ec.ByteOrder}, nil } func loadLicense(sec *elf.Section) (string, error) { diff --git a/elf_reader_test.go b/elf_reader_test.go index cbb24e9af..01a35df14 100644 --- a/elf_reader_test.go +++ b/elf_reader_test.go @@ -143,7 +143,7 @@ func TestLoadCollectionSpec(t *testing.T) { return false }), cmpopts.IgnoreTypes(new(btf.Map), new(btf.Program)), - cmpopts.IgnoreFields(CollectionSpec{}, "ByteOrder"), + cmpopts.IgnoreFields(CollectionSpec{}, "ByteOrder", "BTF"), cmpopts.IgnoreFields(ProgramSpec{}, "Instructions", "ByteOrder"), cmpopts.IgnoreUnexported(ProgramSpec{}), cmpopts.IgnoreMapEntries(func(key string, _ *MapSpec) bool { From b07a66c699a268369075fc35d4013191ceff1aa5 Mon Sep 17 00:00:00 2001 From: Lorenz Bauer Date: Fri, 28 Jan 2022 15:50:13 +0000 Subject: [PATCH 4/4] cmd/bpf2go: generate types from BTF Use GoFormatter to generate type definitions for types used as map keys and values. Allow users to emit additional types via a command line flag. --- cmd/bpf2go/README.md | 6 ++ cmd/bpf2go/main.go | 60 +++++++++++-- cmd/bpf2go/main_test.go | 35 ++++++++ cmd/bpf2go/output.go | 161 +++++++++++++++++++++++++++++----- cmd/bpf2go/output_test.go | 60 +++++++++++++ cmd/bpf2go/test/api_test.go | 38 +++++++- cmd/bpf2go/test/test_bpfeb.go | 14 +++ cmd/bpf2go/test/test_bpfeb.o | Bin 1704 -> 2528 bytes cmd/bpf2go/test/test_bpfel.go | 14 +++ cmd/bpf2go/test/test_bpfel.o | Bin 1704 -> 2528 bytes cmd/bpf2go/testdata/minimal.c | 28 ++++-- 11 files changed, 376 insertions(+), 40 deletions(-) create mode 100644 cmd/bpf2go/output_test.go diff --git a/cmd/bpf2go/README.md b/cmd/bpf2go/README.md index 3a89d9a5e..b3a732303 100644 --- a/cmd/bpf2go/README.md +++ b/cmd/bpf2go/README.md @@ -23,6 +23,12 @@ across a project, e.g. to set specific C flags: By exporting `$BPF_CFLAGS` from your build system you can then control all builds from a single location. +## Generated types + +`bpf2go` generates Go types for all map keys and values by default. You can +disable this behaviour using `-no-global-types`. You can add to the set of +types by specifying `-type foo` for each type you'd like to generate. + ## Examples See [examples/kprobe](../../examples/kprobe/main.go) for a fully worked out example. diff --git a/cmd/bpf2go/main.go b/cmd/bpf2go/main.go index 4ff3c1fd8..6f7e61ec1 100644 --- a/cmd/bpf2go/main.go +++ b/cmd/bpf2go/main.go @@ -10,6 +10,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "runtime" "sort" "strings" @@ -78,6 +79,8 @@ func run(stdout io.Writer, pkg, outputDir string, args []string) (err error) { fs.StringVar(&b2g.tags, "tags", "", "list of Go build tags to include in generated files") flagTarget := fs.String("target", "bpfel,bpfeb", "clang target to compile for") fs.StringVar(&b2g.makeBase, "makebase", "", "write make compatible depinfo files relative to `directory`") + fs.Var(&b2g.cTypes, "type", "`Name` of a type to generate a Go declaration for, may be repeated") + fs.BoolVar(&b2g.skipGlobalTypes, "no-global-types", false, "Skip generating types for map keys and values, etc.") fs.SetOutput(stdout) fs.Usage = func() { @@ -193,6 +196,44 @@ func run(stdout io.Writer, pkg, outputDir string, args []string) (err error) { return nil } +// cTypes collects the C type names a user wants to generate Go types for. +// +// Names are guaranteed to be unique, and only a subset of names is accepted so +// that we may extend the flag syntax in the future. +type cTypes []string + +var _ flag.Value = (*cTypes)(nil) + +func (ct *cTypes) String() string { + if ct == nil { + return "[]" + } + return fmt.Sprint(*ct) +} + +const validCTypeChars = `[a-z0-9_]` + +var reValidCType = regexp.MustCompile(`(?i)^` + validCTypeChars + `+$`) + +func (ct *cTypes) Set(value string) error { + if !reValidCType.MatchString(value) { + return fmt.Errorf("%q contains characters outside of %s", value, validCTypeChars) + } + + i := sort.SearchStrings(*ct, value) + if i >= len(*ct) { + *ct = append(*ct, value) + return nil + } + + if (*ct)[i] == value { + return fmt.Errorf("duplicate type %q", value) + } + + *ct = append((*ct)[:i], append([]string{value}, (*ct)[i:]...)...) + return nil +} + type bpf2go struct { stdout io.Writer // Absolute path to a .c file. @@ -209,7 +250,10 @@ type bpf2go struct { strip string disableStripping bool // C flags passed to the compiler. - cFlags []string + cFlags []string + skipGlobalTypes bool + // C types to include in the generatd output. + cTypes cTypes // Go tags included in the .go tags string // Base directory of the Makefile. Enables outputting make-style dependencies @@ -282,12 +326,14 @@ func (b2g *bpf2go) convert(tgt target, arches []string) (err error) { } defer removeOnError(goFile) - err = writeCommon(writeArgs{ - pkg: b2g.pkg, - ident: b2g.ident, - tags: tags, - obj: objFileName, - out: goFile, + err = output(outputArgs{ + pkg: b2g.pkg, + ident: b2g.ident, + cTypes: b2g.cTypes, + skipGlobalTypes: b2g.skipGlobalTypes, + tags: tags, + obj: objFileName, + out: goFile, }) if err != nil { return fmt.Errorf("can't write %s: %s", goFileName, err) diff --git a/cmd/bpf2go/main_test.go b/cmd/bpf2go/main_test.go index 8492b8696..56884d281 100644 --- a/cmd/bpf2go/main_test.go +++ b/cmd/bpf2go/main_test.go @@ -12,6 +12,7 @@ import ( "strings" "testing" + qt "github.com/frankban/quicktest" "github.com/google/go-cmp/cmp" ) @@ -243,3 +244,37 @@ func TestConvertGOARCH(t *testing.T) { t.Fatal("Can't target GOARCH:", err) } } + +func TestCTypes(t *testing.T) { + var ct cTypes + valid := []string{ + "abcdefghijklmnopqrstuvqxyABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_", + "y", + } + for _, value := range valid { + if err := ct.Set(value); err != nil { + t.Fatalf("Set returned an error for %q: %s", value, err) + } + } + qt.Assert(t, ct, qt.ContentEquals, cTypes(valid)) + + for _, value := range []string{ + "", + " ", + " frood", + "foo\nbar", + ".", + ",", + "+", + "-", + } { + ct = nil + if err := ct.Set(value); err == nil { + t.Fatalf("Set did not return an error for %q", value) + } + } + + ct = nil + qt.Assert(t, ct.Set("foo"), qt.IsNil) + qt.Assert(t, ct.Set("foo"), qt.IsNotNil) +} diff --git a/cmd/bpf2go/output.go b/cmd/bpf2go/output.go index 56559a8b9..6eeafc3a1 100644 --- a/cmd/bpf2go/output.go +++ b/cmd/bpf2go/output.go @@ -5,13 +5,15 @@ import ( "fmt" "go/token" "io" - "os" + "io/ioutil" "path/filepath" + "sort" "strings" "text/template" "github.com/cilium/ebpf" "github.com/cilium/ebpf/internal" + "github.com/cilium/ebpf/internal/btf" ) const ebpfModule = "github.com/cilium/ebpf" @@ -32,6 +34,13 @@ import ( "{{ .Module }}" ) +{{- if .Types }} +{{- range $type := .Types }} +{{ $.TypeDeclaration (index $.TypeNames $type) $type }} + +{{ end }} +{{- end }} + // {{ .Name.Load }} returns the embedded CollectionSpec for {{ .Name }}. func {{ .Name.Load }}() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader({{ .Name.Bytes }}) @@ -173,15 +182,15 @@ func (n templateName) Bytes() string { } func (n templateName) Specs() string { - return n.maybeExport(string(n) + "Specs") + return string(n) + "Specs" } func (n templateName) ProgramSpecs() string { - return n.maybeExport(string(n) + "ProgramSpecs") + return string(n) + "ProgramSpecs" } func (n templateName) MapSpecs() string { - return n.maybeExport(string(n) + "MapSpecs") + return string(n) + "MapSpecs" } func (n templateName) Load() string { @@ -193,36 +202,39 @@ func (n templateName) LoadObjects() string { } func (n templateName) Objects() string { - return n.maybeExport(string(n) + "Objects") + return string(n) + "Objects" } func (n templateName) Maps() string { - return n.maybeExport(string(n) + "Maps") + return string(n) + "Maps" } func (n templateName) Programs() string { - return n.maybeExport(string(n) + "Programs") + return string(n) + "Programs" } func (n templateName) CloseHelper() string { return "_" + toUpperFirst(string(n)) + "Close" } -type writeArgs struct { - pkg string - ident string - tags []string - obj string - out io.Writer +type outputArgs struct { + pkg string + ident string + tags []string + cTypes []string + skipGlobalTypes bool + obj string + out io.Writer } -func writeCommon(args writeArgs) error { - obj, err := os.ReadFile(args.obj) +func output(args outputArgs) error { + obj, err := ioutil.ReadFile(args.obj) if err != nil { return fmt.Errorf("read object file contents: %s", err) } - spec, err := ebpf.LoadCollectionSpecFromReader(bytes.NewReader(obj)) + rd := bytes.NewReader(obj) + spec, err := ebpf.LoadCollectionSpecFromReader(rd) if err != nil { return fmt.Errorf("can't load BPF from ELF: %s", err) } @@ -242,21 +254,68 @@ func writeCommon(args writeArgs) error { programs[name] = internal.Identifier(name) } + // Collect any types which we've been asked for explicitly. + cTypes, err := collectCTypes(spec.BTF, args.cTypes) + if err != nil { + return err + } + + typeNames := make(map[btf.Type]string) + for _, cType := range cTypes { + typeNames[cType] = args.ident + internal.Identifier(cType.TypeName()) + } + + // Collect map key and value types, unless we've been asked not to. + if !args.skipGlobalTypes { + for _, typ := range collectMapTypes(spec.Maps) { + switch btf.UnderlyingType(typ).(type) { + case *btf.Datasec: + // Avoid emitting .rodata, .bss, etc. for now. We might want to + // name these types differently, etc. + continue + + case *btf.Int: + // Don't emit primitive types by default. + continue + } + + typeNames[typ] = args.ident + internal.Identifier(typ.TypeName()) + } + } + + // Ensure we don't have conflicting names and generate a sorted list of + // named types so that the output is stable. + types, err := sortTypes(typeNames) + if err != nil { + return err + } + + gf := &btf.GoFormatter{ + Names: typeNames, + Identifier: internal.Identifier, + } + ctx := struct { - Module string - Package string - Tags []string - Name templateName - Maps map[string]string - Programs map[string]string - File string + *btf.GoFormatter + Module string + Package string + Tags []string + Name templateName + Maps map[string]string + Programs map[string]string + Types []btf.Type + TypeNames map[btf.Type]string + File string }{ + gf, ebpfModule, args.pkg, args.tags, templateName(args.ident), maps, programs, + types, + typeNames, filepath.Base(args.obj), } @@ -268,6 +327,62 @@ func writeCommon(args writeArgs) error { return internal.WriteFormatted(buf.Bytes(), args.out) } +func collectCTypes(types *btf.Spec, names []string) ([]btf.Type, error) { + var result []btf.Type + for _, cType := range names { + typ, err := types.AnyTypeByName(cType) + if err != nil { + return nil, err + } + result = append(result, typ) + } + return result, nil +} + +// collectMapTypes returns a list of all types used as map keys or values. +func collectMapTypes(maps map[string]*ebpf.MapSpec) []btf.Type { + var result []btf.Type + for _, m := range maps { + if m.BTF == nil { + continue + } + + if m.BTF.Key != nil && m.BTF.Key.TypeName() != "" { + result = append(result, m.BTF.Key) + } + + if m.BTF.Value != nil && m.BTF.Value.TypeName() != "" { + result = append(result, m.BTF.Value) + } + } + return result +} + +// sortTypes returns a list of types sorted by their (generated) Go type name. +// +// Duplicate Go type names are rejected. +func sortTypes(typeNames map[btf.Type]string) ([]btf.Type, error) { + var types []btf.Type + var names []string + for typ, name := range typeNames { + i := sort.SearchStrings(names, name) + if i >= len(names) { + types = append(types, typ) + names = append(names, name) + continue + } + + if names[i] == name { + return nil, fmt.Errorf("type name %q is used multiple times", name) + } + + types = append(types[:i], append([]btf.Type{typ}, types[i:]...)...) + names = append(names[:i], append([]string{name}, names[i:]...)...) + } + + return types, nil +} + func tag(str string) string { return "`ebpf:\"" + str + "\"`" } diff --git a/cmd/bpf2go/output_test.go b/cmd/bpf2go/output_test.go new file mode 100644 index 000000000..bf7daabd6 --- /dev/null +++ b/cmd/bpf2go/output_test.go @@ -0,0 +1,60 @@ +package main + +import ( + "testing" + + "github.com/cilium/ebpf/internal/btf" + qt "github.com/frankban/quicktest" +) + +func TestOrderTypes(t *testing.T) { + a := &btf.Int{} + b := &btf.Int{} + c := &btf.Int{} + + for _, test := range []struct { + name string + in map[btf.Type]string + out []btf.Type + }{ + { + "order", + map[btf.Type]string{ + a: "foo", + b: "bar", + c: "baz", + }, + []btf.Type{b, c, a}, + }, + } { + t.Run(test.name, func(t *testing.T) { + result, err := sortTypes(test.in) + qt.Assert(t, err, qt.IsNil) + qt.Assert(t, len(result), qt.Equals, len(test.out)) + for i, o := range test.out { + if result[i] != o { + t.Fatalf("Index %d: expected %p got %p", i, o, result[i]) + } + } + }) + } + + for _, test := range []struct { + name string + in map[btf.Type]string + }{ + { + "duplicate names", + map[btf.Type]string{ + a: "foo", + b: "foo", + }, + }, + } { + t.Run(test.name, func(t *testing.T) { + result, err := sortTypes(test.in) + qt.Assert(t, err, qt.IsNotNil) + qt.Assert(t, result, qt.IsNil) + }) + } +} diff --git a/cmd/bpf2go/test/api_test.go b/cmd/bpf2go/test/api_test.go index 5f2d53e4e..76f57157e 100644 --- a/cmd/bpf2go/test/api_test.go +++ b/cmd/bpf2go/test/api_test.go @@ -1,14 +1,16 @@ package test import ( + "reflect" "testing" + "unsafe" - // Raise RLIMIT_MEMLOCK - _ "github.com/cilium/ebpf/internal/testutils" + "github.com/cilium/ebpf/internal/testutils" ) func TestLoadingSpec(t *testing.T) { spec, err := loadTest() + testutils.SkipIfNotSupported(t, err) if err != nil { t.Fatal("Can't load spec:", err) } @@ -20,7 +22,9 @@ func TestLoadingSpec(t *testing.T) { func TestLoadingObjects(t *testing.T) { var objs testObjects - if err := loadTestObjects(&objs, nil); err != nil { + err := loadTestObjects(&objs, nil) + testutils.SkipIfNotSupported(t, err) + if err != nil { t.Fatal("Can't load objects:", err) } defer objs.Close() @@ -33,3 +37,31 @@ func TestLoadingObjects(t *testing.T) { t.Error("Loading returns an object with nil maps") } } + +func TestTypes(t *testing.T) { + if testEHOOPY != 0 { + t.Error("Expected testEHOOPY to be 0, got", testEHOOPY) + } + if testEFROOD != 1 { + t.Error("Expected testEFROOD to be 0, got", testEFROOD) + } + + e := testE(0) + if size := unsafe.Sizeof(e); size != 4 { + t.Error("Expected size of exampleE to be 4, got", size) + } + + bf := testBarfoo{} + if size := unsafe.Sizeof(bf); size != 16 { + t.Error("Expected size of exampleE to be 16, got", size) + } + if reflect.TypeOf(bf.Bar).Kind() != reflect.Int64 { + t.Error("Expected testBarfoo.Bar to be int64") + } + if reflect.TypeOf(bf.Baz).Kind() != reflect.Bool { + t.Error("Expected testBarfoo.Baz to be bool") + } + if reflect.TypeOf(bf.Boo) != reflect.TypeOf(e) { + t.Error("Expected testBarfoo.Boo to be exampleE") + } +} diff --git a/cmd/bpf2go/test/test_bpfeb.go b/cmd/bpf2go/test/test_bpfeb.go index 1c366127e..2f99ba39a 100644 --- a/cmd/bpf2go/test/test_bpfeb.go +++ b/cmd/bpf2go/test/test_bpfeb.go @@ -13,6 +13,20 @@ import ( "github.com/cilium/ebpf" ) +type testBarfoo struct { + Bar int64 + Baz bool + _ [3]byte + Boo testE +} + +type testE int32 + +const ( + testEHOOPY testE = 0 + testEFROOD testE = 1 +) + // loadTest returns the embedded CollectionSpec for test. func loadTest() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_TestBytes) diff --git a/cmd/bpf2go/test/test_bpfeb.o b/cmd/bpf2go/test/test_bpfeb.o index c445a7a0fe8098241cf5bbc16d8e8c6ea60dec87..d5c25f79cbb085e77adaa12a1a68ca47c07a1cce 100644 GIT binary patch literal 2528 zcmbtVO=}cE5bfP0Ch;rrTk$f2prB6FgNTAmf(Z(dgcyY=GMQ{fU7X#CGn3#7>Vh8f z2fPV-^k;bR;@OKA@dxNh1i_2G*Hg8&gTaFZuj`{?EFo~qYtrYAM?9kvtb z&A`~SXuUwj?PlBlQET^xNHVMO&W@5YBJ17w&37Uuq} zk`HVKD5rs~KmeQpxc(w=PI9-vo{+N)K?m?>#jjyaOM~XQJ>WVZ)8;1Z0U!WEU=Zj6 zF+k26;Qn?DkZpj?qXFS(tl?mcjR0?DQP$7y$&V4?jdFkDovgPLwoQ=_-2=ZYMEQ;H zg}1xHv-f8UR_^mjc>9F+1&5KN7@0C2=Ds4%GgJ1K%AV(d*sS{xCwEtm(`*+e49Dl@ z#uvh?mv2ml^9!?+VTdYSnwgnhFjI3gGZ)QLl-*8KD&V16f}N!8J4~kb>|mFgNYlg= zot4*djiXMbBDsEEc|&33aD zC4R#UXK}HbwY^p+Y^3eHh}wmB%*%^xwNaE29|t;b8h3H5Fie__xSeCS-*n@WjgP%^ z<7X-NF-n)0<4Hw$Bg8bY2vB(Aj{vPat4T1%Tc@i~9i@%7da z+DOoAe`8%hlU3sZ);NTQ)Klq_^mjXPd0zG_t|IQVvrQrYG2(nbu6T~a9IXhym^tFt zzQN{OmUGnk#>tm`>dIH272;mPH^*UfE%k$nKU?t^EB=c5gPVtjw-~>OAE3{&IPoXu zr+hkpbcWk9WNBmChLL9VlVq(GM$5}t-n`?qn~#->Xvz3_r)9PDm+n?}JkImK!g^@E zSzA{E*KusEA48{rf8_@xI--5T&^18w<=%SCu2}AV3@M*>%kisyyG{axec_6`KVOZm zSKa@WBzdA$x%nLgHDBjdzbTEra~crs^7&un`VO`4hd5m)NYmx>f2aE0LhtX2@fwhFzPzgyr`?_JYAit$vms$TvtJ1f2z literal 1704 zcmbtUOHUL*5UyQ7K=AFsL=SV*L^ELGPJ;~zg$>etk-KYpqhM#?g0Z2l#!3t zYUnsEQ(vqq@>b=;r44G#A62$AAt4zB6KqmTjYvFU0q!nf4N z802F&94g{k$H0_x8b>_#RmM4hxTjAZe%zwmOOln+PSVokQtUN%O)23_7|xWYC|hwE&vcS3 z>BMQ+l*!zb-8>6s=cKt4=MqKpYiskH(fZQkg=k}Qbs>s?rAgCdg^{iOcGQXYqn2q) z+21#^Yx+@r(IL2owyg7tjrTr2!q>cyj@5)E0XQZv;yu8@O5#M!YD*r8Vrt5 zmGlzqS;bfibkLTA5Ic4n>|^I(UlqB*_WzxbeN<3z_II3%+&uHk6|r-({*QoD`oy~c zvK{3n)nDU%rS9UdX^^uU&K{qbl&~~Cv@JJjcz0tlq@k^}_0sN!X?oC!;#Mn1b-hM~ zMVXiJmV`yWW2MehRUYg7FY$1CW$jz>=WFCw(Azi-rbgg$) zWBm09xp?XqJ$pFcemd}L9~o}RpKl$AKc9wJu~QkfuRaLfkDnT{z0mrc8txp<=jY!8 zc+~wR{8|%wkX*;bx%%-Qu7KTN1=Xh!7Z(8KU&H^6|~6erR3(Fmhk5;lB9izk`@zze{_d$`h4N4Dx>hU)g+A diff --git a/cmd/bpf2go/test/test_bpfel.go b/cmd/bpf2go/test/test_bpfel.go index 9f93826eb..a19190bbf 100644 --- a/cmd/bpf2go/test/test_bpfel.go +++ b/cmd/bpf2go/test/test_bpfel.go @@ -13,6 +13,20 @@ import ( "github.com/cilium/ebpf" ) +type testBarfoo struct { + Bar int64 + Baz bool + _ [3]byte + Boo testE +} + +type testE int32 + +const ( + testEHOOPY testE = 0 + testEFROOD testE = 1 +) + // loadTest returns the embedded CollectionSpec for test. func loadTest() (*ebpf.CollectionSpec, error) { reader := bytes.NewReader(_TestBytes) diff --git a/cmd/bpf2go/test/test_bpfel.o b/cmd/bpf2go/test/test_bpfel.o index e89a2253d280b68d6f3761d59ef5425d22f40959..0320088a312913439a2fb44cf544559f69b5ecec 100644 GIT binary patch literal 2528 zcmbVN-)j_C6h6C&nvF?pw6%&aBM1s@C)$Tn6l4rdP>3YND5OOulg(%sXLsVvB)A22 zK_C1F`c`Nk{WE;<#pk~CMf?NwsT2fX^!x6dyL-I^g&z3s`EkE<@45G$*?qXMwAgGk z#7aZn%E+@(k&XQ$J2GY@Gcqm5JaY0y&GX~^**bnm=YOwVxq4;ISl%)^`+4=}>xLXt zTF?|Bnxn;|T^J{49{{nu+5?40KMsJqpWG8Va}rwDW~4cR;WRCg ziB_$-$vBT30+Sm19(oFhfFA&^zX6;FAQJ~M%o|f0TrnAF04YGuGvF=&nVH65^I%RlG3?f{sYB4u0f^}i>}jdy-uRp>f_MQyW)5Sp zB$$(5FlE2)yXZl~AjCRx~)R*_aaMK9>~<96OFtE5*2-vnh#x-A z(BJUOVU^xPpA~5q&aW+obUx|~w`It(jcFQ2n>Ea`-EN$0Z53tbw$pAQ zR;rRs3Cn)hXzee%Tix+m*8f(#3xap*O5{3@&HHlY9Gp+(M=lw*?Gqcm4uko8Lstgs z`1_ITN*4}e`rN~*Cu-R~vJ?LP{A%{v|1V7lR9ofe_c7tuMD8;Vkn`Tbd@lcs{224z zY2JX2BR-e^JO0^8ALzwB)m;7;k!S0-_wpTL_PN7aM+6d2dY+HnnVp?E@2ka?rLkH~9BT4IMwau6e5#N1 zrd69VB`4*py5FgMxZJYw;3nd%;=s5oa7g^Ax@2r_SP8ZA@o?`n_`YzAYdzP zjMCbwxc@jvIS&FZhde6mY0V`Yu%VA%fHdG_u`bV5_aHOXn~*P6e+Kzl^+U+FATT`V zLt#&&Hhbrfg*;971b+b5_Zh@}tp5a^0Beyb$)y{`xk)A4ZSR;|{8`_h%}thf!aSVq zMM=~PW4|qvsmTXv;?2!Vdpk@e2o~1X7B+(QeXgKQKw2MkW((?#AI(CW9o4wi46vSR35e#U+K22}kO& zbbwbNFM)F)!B$Lx93R11odL_f^RTaiV>j^gFVux!$?x!Bo-6rz0C5vMYmc<1?LD=} z*3U^4u)U|MRdR)e&XjEWu7Lz~E;T{I*%OUP@pH3}v85*V@3xkF8ahhbFP*L*$9ugX z>~vCew=^g}%hNpE6hAxYS*dx7&KIZs|1WDM`9CS6SvE>K?^Oo-^tX7|cNfFqmvI{g z<4ezoU0&5q)$_QwjEgXiif`$r;T+Yj=3CczT^@>U)xK2@teAM|it~qos?6&r>F(jy ztMT`+@aNYn@