Skip to content

Commit

Permalink
btf: add limited support for BTF_KIND_DECL_TAG and BTF_KIND_TYPE_TAG
Browse files Browse the repository at this point in the history
Parse decl and type tags from BTF so that we can read BTF on new kernels.
The new types are not exported since the encoding of declTag.Index especially
is cumbersome to use. We can export the types later if necessary.

Treat typeTag as a qualifier, since accoriding to the BTF documentation it
is usually used in a chain of types:

    ptr -> [type_tag]*
        -> [const | volatile | restrict | typedef]*
        -> base_type

Updates cilium#713
  • Loading branch information
lmb committed Jul 25, 2022
1 parent 70812e3 commit 110e43a
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 63 deletions.
87 changes: 28 additions & 59 deletions btf/btf_types.go
Expand Up @@ -6,33 +6,36 @@ import (
"io"
)

//go:generate go run golang.org/x/tools/cmd/stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage
//go:generate go run golang.org/x/tools/cmd/stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage,btfKind

// btfKind describes a Type.
type btfKind uint8

// Equivalents of the BTF_KIND_* constants.
const (
kindUnknown btfKind = iota
kindInt
kindPointer
kindArray
kindStruct
kindUnion
kindEnum
kindForward
kindTypedef
kindVolatile
kindConst
kindRestrict
kindUnknown btfKind = iota // Unknown
kindInt // Int
kindPointer // Pointer
kindArray // Array
kindStruct // Struct
kindUnion // Union
kindEnum // Enum
kindForward // Forward
kindTypedef // Typedef
kindVolatile // Volatile
kindConst // Const
kindRestrict // Restrict
// Added ~4.20
kindFunc
kindFuncProto
kindFunc // Func
kindFuncProto // FuncProto
// Added ~5.1
kindVar
kindDatasec
kindVar // Var
kindDatasec // Datasec
// Added ~5.13
kindFloat
kindFloat // Float
// Added 5.16
kindDeclTag // DeclTag
kindTypeTag // TypeTag
)

// FuncLinkage describes BTF function linkage metadata.
Expand Down Expand Up @@ -85,47 +88,6 @@ type btfType struct {
SizeType uint32
}

func (k btfKind) String() string {
switch k {
case kindUnknown:
return "Unknown"
case kindInt:
return "Integer"
case kindPointer:
return "Pointer"
case kindArray:
return "Array"
case kindStruct:
return "Struct"
case kindUnion:
return "Union"
case kindEnum:
return "Enumeration"
case kindForward:
return "Forward"
case kindTypedef:
return "Typedef"
case kindVolatile:
return "Volatile"
case kindConst:
return "Const"
case kindRestrict:
return "Restrict"
case kindFunc:
return "Function"
case kindFuncProto:
return "Function Proto"
case kindVar:
return "Variable"
case kindDatasec:
return "Section"
case kindFloat:
return "Float"
default:
return fmt.Sprintf("Unknown (%d)", k)
}
}

func mask(len uint32) uint32 {
return (1 << len) - 1
}
Expand Down Expand Up @@ -283,6 +245,10 @@ type btfParam struct {
Type TypeID
}

type btfDeclTag struct {
ComponentIdx uint32
}

func readTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32) ([]rawType, error) {
var header btfType
// because of the interleaving between types and struct members it is difficult to
Expand Down Expand Up @@ -325,6 +291,9 @@ func readTypes(r io.Reader, bo binary.ByteOrder, typeLen uint32) ([]rawType, err
case kindDatasec:
data = make([]btfVarSecinfo, header.Vlen())
case kindFloat:
case kindDeclTag:
data = new(btfDeclTag)
case kindTypeTag:
default:
return nil, fmt.Errorf("type id %v: unknown kind: %v", id, header.Kind())
}
Expand Down
37 changes: 36 additions & 1 deletion btf/btf_types_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

85 changes: 85 additions & 0 deletions btf/types.go
Expand Up @@ -541,6 +541,45 @@ func (f *Float) copy() Type {
return &cpy
}

// declTag associates metadata with a declaration.
type declTag struct {
Type Type
Value string
// The index this tag refers to in the target type. For composite types,
// a value of -1 indicates that the tag refers to the whole type. Otherwise
// it indicates which member or argument the tag applies to.
Index int
}

func (dt *declTag) Format(fs fmt.State, verb rune) {
formatType(fs, verb, dt, "type=", dt.Type, "value=", dt.Value, "index=", dt.Index)
}

func (dt *declTag) TypeName() string { return "" }
func (dt *declTag) walk(td *typeDeque) { td.push(&dt.Type) }
func (dt *declTag) copy() Type {
cpy := *dt
return &cpy
}

// typeTag associates metadata with a type.
type typeTag struct {
Type Type
Value string
}

func (tt *typeTag) Format(fs fmt.State, verb rune) {
formatType(fs, verb, tt, "type=", tt.Type, "value=", tt.Value)
}

func (tt *typeTag) TypeName() string { return "" }
func (tt *typeTag) qualify() Type { return tt.Type }
func (tt *typeTag) walk(td *typeDeque) { td.push(&tt.Type) }
func (tt *typeTag) copy() Type {
cpy := *tt
return &cpy
}

// cycle is a type which had to be elided since it exceeded maxTypeDepth.
type cycle struct {
root Type
Expand Down Expand Up @@ -576,6 +615,7 @@ var (
_ qualifier = (*Const)(nil)
_ qualifier = (*Restrict)(nil)
_ qualifier = (*Volatile)(nil)
_ qualifier = (*typeTag)(nil)
)

// Sizeof returns the size of a type in bytes.
Expand Down Expand Up @@ -903,6 +943,7 @@ func inflateRawTypes(rawTypes []rawType, baseTypes types, rawStrings *stringTabl
return members, nil
}

var declTags []*declTag
for i, raw := range rawTypes {
var (
id = typeIDOffset + TypeID(i)
Expand Down Expand Up @@ -1045,6 +1086,28 @@ func inflateRawTypes(rawTypes []rawType, baseTypes types, rawStrings *stringTabl
case kindFloat:
typ = &Float{name, raw.Size()}

case kindDeclTag:
btfIndex := raw.data.(*btfDeclTag).ComponentIdx
if uint64(btfIndex) > math.MaxInt {
return nil, fmt.Errorf("type id %d: index exceeds int", id)
}

index := int(btfIndex)
if btfIndex == math.MaxUint32 {
index = -1
}

dt := &declTag{nil, name, index}
fixup(raw.Type(), &dt.Type)
typ = dt

declTags = append(declTags, dt)

case kindTypeTag:
tt := &typeTag{nil, name}
fixup(raw.Type(), &tt.Type)
typ = tt

default:
return nil, fmt.Errorf("type id %d: unknown kind: %v", id, raw.Kind())
}
Expand Down Expand Up @@ -1083,6 +1146,28 @@ func inflateRawTypes(rawTypes []rawType, baseTypes types, rawStrings *stringTabl
}
}

for _, dt := range declTags {
switch t := dt.Type.(type) {
case *Var, *Typedef:
if dt.Index != -1 {
return nil, fmt.Errorf("type %s: index %d is not -1", dt, dt.Index)
}

case composite:
if dt.Index >= len(t.members()) {
return nil, fmt.Errorf("type %s: index %d exceeds members of %s", dt, dt.Index, t)
}

case *Func:
if dt.Index >= len(t.Type.(*FuncProto).Params) {
return nil, fmt.Errorf("type %s: index %d exceeds params of %s", dt, dt.Index, t)
}

default:
return nil, fmt.Errorf("type %s: decl tag for type %s is not supported", dt, t)
}
}

return types, nil
}

Expand Down
4 changes: 4 additions & 0 deletions btf/types_test.go
Expand Up @@ -134,6 +134,9 @@ func TestType(t *testing.T) {
Vars: []VarSecinfo{{Type: &Void{}}},
}
},
func() Type { return &Float{} },
func() Type { return &declTag{Type: &Void{}} },
func() Type { return &typeTag{Type: &Void{}} },
func() Type { return &cycle{&Void{}} },
}

Expand Down Expand Up @@ -331,6 +334,7 @@ func TestUnderlyingType(t *testing.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} }},
{"type tag", func(t Type) Type { return &typeTag{Type: t} }},
}

for _, test := range wrappers {
Expand Down
3 changes: 0 additions & 3 deletions elf_reader_test.go
Expand Up @@ -740,9 +740,6 @@ func TestLibBPFCompat(t *testing.T) {
case "bloom_filter_map.o", "bloom_filter_map.linked3.o",
"bloom_filter_bench.o", "bloom_filter_bench.linked3.o":
t.Skip("Skipping due to missing MapExtra field in MapSpec")
case "btf_type_tag.o", "btf_type_tag.linked3.o", "test_btf_decl_tag.o",
"test_btf_decl_tag.linked3.o":
t.Skip("Skipping due to missing support for BTF_KIND_TYPE_TAG and BTF_KIND_DECL_TAG")
case "netif_receive_skb.linked3.o":
t.Skip("Skipping due to possible bug in upstream CO-RE generation")
}
Expand Down

0 comments on commit 110e43a

Please sign in to comment.