1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
|
//go:build !windows
package gen
import (
"cmp"
"slices"
"github.com/cilium/ebpf"
"github.com/cilium/ebpf/btf"
)
// CollectGlobalTypes finds all types which are used in the global scope.
//
// This currently includes the types of variables, map keys and values.
func CollectGlobalTypes(spec *ebpf.CollectionSpec) []btf.Type {
var types []btf.Type
types = collectMapTypes(types, spec.Maps)
types = collectVariableTypes(types, spec.Variables)
slices.SortStableFunc(types, func(a, b btf.Type) int {
return cmp.Compare(a.TypeName(), b.TypeName())
})
return types
}
// collectMapTypes collects all types used by MapSpecs.
func collectMapTypes(types []btf.Type, maps map[string]*ebpf.MapSpec) []btf.Type {
for _, m := range maps {
if m.Key != nil && m.Key.TypeName() != "" {
types = addType(types, m.Key)
}
if m.Value != nil && m.Value.TypeName() != "" {
types = addType(types, m.Value)
}
}
return types
}
// collectVariableTypes collects all types used by VariableSpecs.
func collectVariableTypes(types []btf.Type, vars map[string]*ebpf.VariableSpec) []btf.Type {
for _, vs := range vars {
v := vs.Type()
if v == nil {
continue
}
types = addType(types, v.Type)
}
return types
}
// addType adds a type to types if not already present. Types that don't need to
// be generated are not added to types.
func addType(types []btf.Type, incoming btf.Type) []btf.Type {
incoming = selectType(incoming)
if incoming == nil {
return types
}
// Strip only the qualifiers (not typedefs) from the incoming type. Retain
// typedefs since they carry the name of the anonymous type they point to,
// without which we can't generate a named Go type.
incoming = btf.QualifiedType(incoming)
if incoming.TypeName() == "" {
return types
}
exists := func(existing btf.Type) bool {
return existing.TypeName() == incoming.TypeName()
}
if !slices.ContainsFunc(types, exists) {
types = append(types, incoming)
}
return types
}
func selectType(t btf.Type) btf.Type {
// Obtain a concrete type with qualifiers and typedefs stripped.
switch ut := btf.UnderlyingType(t).(type) {
case *btf.Struct, *btf.Union, *btf.Enum:
return t
// Collect the array's element type. Note: qualifiers on array-type variables
// typically appear after the array, e.g. a const volatile int[4] is actually
// an array of const volatile ints.
case *btf.Array:
return selectType(ut.Type)
}
return nil
}
|