Repository: cilium/ebpf
Pull request #735 (2022-07-11 09:14:50)

btf: add Enum.Size
Contrary to the documentation in btf.rst a BTF_KIND_ENUM can carry a size.
This is used by the kernel to shrink the size of enums, for example:

    enum netfs_io_source {
        NETFS_FILL_WITH_ZEROES,
        NETFS_DOWNLOAD_FROM_SERVER,
        NETFS_READ_FROM_CACHE,
        NETFS_INVALID_READ,
    } __mode(byte);


Patch:
diff --git a/btf/format.go b/btf/format.go
index c773312..e7688a2 100644
--- a/btf/format.go
+++ b/btf/format.go
@@ -65,7 +65,20 @@ func (gf *GoFormatter) writeTypeDecl(name string, typ Type) error {
 
 	switch v := skipQualifiers(typ).(type) {
 	case *Enum:
-		fmt.Fprintf(&gf.w, "type %s int32", name)
+		fmt.Fprintf(&gf.w, "type %s ", name)
+		switch v.Size {
+		case 1:
+			gf.w.WriteString("int8")
+		case 2:
+			gf.w.WriteString("int16")
+		case 4:
+			gf.w.WriteString("int32")
+		case 8:
+			gf.w.WriteString("int64")
+		default:
+			return fmt.Errorf("%s: invalid enum size %d", typ, v.Size)
+		}
+
 		if len(v.Values) == 0 {
 			return nil
 		}
diff --git a/btf/types.go b/btf/types.go
index 61ae98f..402a363 100644
--- a/btf/types.go
+++ b/btf/types.go
@@ -271,12 +271,14 @@ type Member struct {
 
 // Enum lists possible values.
 type Enum struct {
-	Name   string
+	Name string
+	// Size of the enum value in bytes.
+	Size   uint32
 	Values []EnumValue
 }
 
 func (e *Enum) Format(fs fmt.State, verb rune) {
-	formatType(fs, verb, e, "values=", len(e.Values))
+	formatType(fs, verb, e, "size=", e.Size, "values=", len(e.Values))
 }
 
 func (e *Enum) TypeName() string { return e.Name }
@@ -289,7 +291,7 @@ type EnumValue struct {
 	Value int32
 }
 
-func (e *Enum) size() uint32    { return 4 }
+func (e *Enum) size() uint32    { return e.Size }
 func (e *Enum) walk(*typeDeque) {}
 func (e *Enum) copy() Type {
 	cpy := *e
@@ -960,7 +962,7 @@ func inflateRawTypes(rawTypes []rawType, baseTypes types, rawStrings *stringTabl
 					Value: btfVal.Val,
 				})
 			}
-			typ = &Enum{name, vals}
+			typ = &Enum{name, raw.Size(), vals}
 
 		case kindForward:
 			if raw.KindFlag() {


Test patch:
diff --git a/btf/format_test.go b/btf/format_test.go
index 9669b1e..0cbe519 100644
--- a/btf/format_test.go
+++ b/btf/format_test.go
@@ -24,7 +24,8 @@ func TestGoTypeDeclaration(t *testing.T) {
 		{&Int{Size: 8}, "type t uint64"},
 		{&Typedef{Name: "frob", Type: &Int{Size: 8}}, "type t uint64"},
 		{&Int{Size: 16}, "type t uint128"},
-		{&Enum{Values: []EnumValue{{"FOO", 32}}}, "type t int32; const ( tFOO t = 32; )"},
+		{&Enum{Values: []EnumValue{{"FOO", 32}}, Size: 4}, "type t int32; const ( tFOO t = 32; )"},
+		{&Enum{Values: []EnumValue{{"BAR", 1}}, Size: 1}, "type t int8; const ( tBAR t = 1; )"},
 		{&Array{Nelems: 2, Type: &Int{Size: 1}}, "type t [2]uint8"},
 		{
 			&Union{
@@ -131,7 +132,7 @@ func TestGoTypeDeclaration(t *testing.T) {
 }
 
 func TestGoTypeDeclarationNamed(t *testing.T) {
-	e1 := &Enum{Name: "e1"}
+	e1 := &Enum{Name: "e1", Size: 4}
 	s1 := &Struct{
 		Name: "s1",
 		Size: 4,
diff --git a/btf/types_test.go b/btf/types_test.go
index 49e25d3..5a80db4 100644
--- a/btf/types_test.go
+++ b/btf/types_test.go
@@ -16,9 +16,9 @@ func TestSizeof(t *testing.T) {
 	}{
 		{0, (*Void)(nil)},
 		{1, &Int{Size: 1}},
-		{4, &Enum{}},
+		{8, &Enum{Size: 8}},
 		{0, &Array{Type: &Pointer{Target: (*Void)(nil)}, Nelems: 0}},
-		{12, &Array{Type: &Enum{}, Nelems: 3}},
+		{12, &Array{Type: &Enum{Size: 4}, Nelems: 3}},
 	}
 
 	for _, tc := range testcases {