Repository: cilium/ebpf
Pull request #333 (2021-06-29 11:23:27)

btf: expose Var and Func linkage
Expose the linkage of Var and Func types. Of course, BTF encodes these
in different ways and has separate types for them. So we inherit this
decision and introduce separate types for var and func linkage.


Patch:
diff --git a/internal/btf/btf.go b/internal/btf/btf.go
index 5286d83..5da9e11 100644
--- a/internal/btf/btf.go
+++ b/internal/btf/btf.go
@@ -377,7 +377,7 @@ func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
 	for _, raw := range s.rawTypes {
 		switch {
 		case opts.StripFuncLinkage && raw.Kind() == kindFunc:
-			raw.SetLinkage(linkageStatic)
+			raw.SetLinkage(StaticFunc)
 		}
 
 		if err := raw.Marshal(&buf, opts.ByteOrder); err != nil {
@@ -779,7 +779,7 @@ var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() err
 	types.Func.SetKind(kindFunc)
 	types.Func.SizeType = 1 // aka FuncProto
 	types.Func.NameOff = 1
-	types.Func.SetLinkage(linkageGlobal)
+	types.Func.SetLinkage(GlobalFunc)
 
 	btf := marshalBTF(&types, strings, internal.NativeEndian)
 
diff --git a/internal/btf/btf_types.go b/internal/btf/btf_types.go
index 6d75cd6..a5ef945 100644
--- a/internal/btf/btf_types.go
+++ b/internal/btf/btf_types.go
@@ -6,6 +6,8 @@ import (
 	"io"
 )
 
+//go:generate stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage
+
 // btfKind describes a Type.
 type btfKind uint8
 
@@ -31,14 +33,23 @@ const (
 	kindDatasec
 )
 
-// btfFuncLinkage describes BTF function linkage metadata.
-type btfFuncLinkage uint8
+// FuncLinkage describes BTF function linkage metadata.
+type FuncLinkage int
 
 // Equivalent of enum btf_func_linkage.
 const (
-	linkageStatic btfFuncLinkage = iota
-	linkageGlobal
-	// linkageExtern // Currently unused in libbpf.
+	StaticFunc FuncLinkage = iota // static
+	GlobalFunc                    // global
+	ExternFunc                    // extern
+)
+
+// VarLinkage describes BTF variable linkage metadata.
+type VarLinkage int
+
+const (
+	StaticVar VarLinkage = iota // static
+	GlobalVar                   // global
+	ExternVar                   // extern
 )
 
 const (
@@ -144,11 +155,11 @@ func (bt *btfType) KindFlag() bool {
 	return bt.info(btfTypeKindFlagMask, btfTypeKindFlagShift) == 1
 }
 
-func (bt *btfType) Linkage() btfFuncLinkage {
-	return btfFuncLinkage(bt.info(btfTypeVlenMask, btfTypeVlenShift))
+func (bt *btfType) Linkage() FuncLinkage {
+	return FuncLinkage(bt.info(btfTypeVlenMask, btfTypeVlenShift))
 }
 
-func (bt *btfType) SetLinkage(linkage btfFuncLinkage) {
+func (bt *btfType) SetLinkage(linkage FuncLinkage) {
 	bt.setInfo(uint32(linkage), btfTypeVlenMask, btfTypeVlenShift)
 }
 
diff --git a/internal/btf/btf_types_string.go b/internal/btf/btf_types_string.go
new file mode 100644
index 0000000..0e0c17d
--- /dev/null
+++ b/internal/btf/btf_types_string.go
@@ -0,0 +1,44 @@
+// Code generated by "stringer -linecomment -output=btf_types_string.go -type=FuncLinkage,VarLinkage"; DO NOT EDIT.
+
+package btf
+
+import "strconv"
+
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[StaticFunc-0]
+	_ = x[GlobalFunc-1]
+	_ = x[ExternFunc-2]
+}
+
+const _FuncLinkage_name = "staticglobalextern"
+
+var _FuncLinkage_index = [...]uint8{0, 6, 12, 18}
+
+func (i FuncLinkage) String() string {
+	if i < 0 || i >= FuncLinkage(len(_FuncLinkage_index)-1) {
+		return "FuncLinkage(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _FuncLinkage_name[_FuncLinkage_index[i]:_FuncLinkage_index[i+1]]
+}
+func _() {
+	// An "invalid array index" compiler error signifies that the constant values have changed.
+	// Re-run the stringer command to generate them again.
+	var x [1]struct{}
+	_ = x[StaticVar-0]
+	_ = x[GlobalVar-1]
+	_ = x[ExternVar-2]
+}
+
+const _VarLinkage_name = "staticglobalextern"
+
+var _VarLinkage_index = [...]uint8{0, 6, 12, 18}
+
+func (i VarLinkage) String() string {
+	if i < 0 || i >= VarLinkage(len(_VarLinkage_index)-1) {
+		return "VarLinkage(" + strconv.FormatInt(int64(i), 10) + ")"
+	}
+	return _VarLinkage_name[_VarLinkage_index[i]:_VarLinkage_index[i+1]]
+}
diff --git a/internal/btf/types.go b/internal/btf/types.go
index 9b7eca2..62aa31b 100644
--- a/internal/btf/types.go
+++ b/internal/btf/types.go
@@ -380,11 +380,12 @@ func (r *Restrict) copy() Type {
 type Func struct {
 	TypeID
 	Name
-	Type Type
+	Type    Type
+	Linkage FuncLinkage
 }
 
 func (f *Func) String() string {
-	return fmt.Sprintf("func#%d[%q proto=#%d]", f.TypeID, f.Name, f.Type.ID())
+	return fmt.Sprintf("func#%d[%s %q proto=#%d]", f.TypeID, f.Linkage, f.Name, f.Type.ID())
 }
 
 func (f *Func) walk(tdq *typeDeque) { tdq.push(&f.Type) }
@@ -433,12 +434,12 @@ type FuncParam struct {
 type Var struct {
 	TypeID
 	Name
-	Type Type
+	Type    Type
+	Linkage VarLinkage
 }
 
 func (v *Var) String() string {
-	// TODO: Linkage
-	return fmt.Sprintf("var#%d[%q]", v.TypeID, v.Name)
+	return fmt.Sprintf("var#%d[%s %q]", v.TypeID, v.Linkage, v.Name)
 }
 
 func (v *Var) walk(tdq *typeDeque) { tdq.push(&v.Type) }
@@ -803,7 +804,7 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type,
 			typ = restrict
 
 		case kindFunc:
-			fn := &Func{id, name, nil}
+			fn := &Func{id, name, nil, raw.Linkage()}
 			fixup(raw.Type(), kindFuncProto, &fn.Type)
 			typ = fn
 
@@ -828,7 +829,8 @@ func inflateRawTypes(rawTypes []rawType, rawStrings stringTable) (types []Type,
 			typ = fp
 
 		case kindVar:
-			v := &Var{id, name, nil}
+			variable := raw.data.(*btfVariable)
+			v := &Var{id, name, nil, VarLinkage(variable.Linkage)}
 			fixup(raw.Type(), kindUnknown, &v.Type)
 			typ = v
 


Test patch:
diff --git a/internal/btf/btf_test.go b/internal/btf/btf_test.go
index 7c1c8d2..22c7d5a 100644
--- a/internal/btf/btf_test.go
+++ b/internal/btf/btf_test.go
@@ -61,7 +61,7 @@ func TestParseVmlinux(t *testing.T) {
 			if u8int.Offset != 0 {
 				t.Fatalf("incorrect int offset of an __u8 int: expected: 0 actual: %d", u8int.Offset)
 			}
-			return
+			break
 		}
 	}
 }
@@ -79,7 +79,7 @@ func TestParseCurrentKernelBTF(t *testing.T) {
 }
 
 func TestLoadSpecFromElf(t *testing.T) {
-	testutils.Files(t, testutils.Glob(t, "../../testdata/loader-clang-9-*.elf"), func(t *testing.T, file string) {
+	testutils.Files(t, testutils.Glob(t, "../../testdata/loader-e*.elf"), func(t *testing.T, file string) {
 		fh, err := os.Open(file)
 		if err != nil {
 			t.Fatal(err)
@@ -117,6 +117,24 @@ func TestLoadSpecFromElf(t *testing.T) {
 			t.Error("FindType doesn't return ErrNotFound:", err)
 		}
 
+		var fn Func
+		if err := spec.FindType("global_fn", &fn); err != nil {
+			t.Error("Can't find global_fn():", err)
+		} else {
+			if fn.Linkage != GlobalFunc {
+				t.Error("Expected global linkage:", fn)
+			}
+		}
+
+		var v Var
+		if err := spec.FindType("key3", &v); err != nil {
+			t.Error("Cant find key3:", err)
+		} else {
+			if v.Linkage != GlobalVar {
+				t.Error("Expected global linkage:", v)
+			}
+		}
+
 		if spec.byteOrder != internal.NativeEndian {
 			return
 		}