diff --git a/elf_reader.go b/elf_reader.go index 749c68379..c64fe9090 100644 --- a/elf_reader.go +++ b/elf_reader.go @@ -1239,7 +1239,7 @@ func (ec *elfCode) loadDataSections() error { return fmt.Errorf("data section %s: variable %s size in datasec (%d) doesn't match ELF symbol size (%d)", sec.Name, name, v.Size, ev.size) } - ev.t = vt.Type + ev.t = vt } } } diff --git a/syscalls.go b/syscalls.go index 31c2589d0..25c84c3c5 100644 --- a/syscalls.go +++ b/syscalls.go @@ -179,10 +179,18 @@ var haveObjName = internal.NewFeatureTest("object names", func() error { MapName: sys.NewObjName("feature_test"), } + // Tolerate EPERM as this runs during ELF loading which is potentially + // unprivileged. Only EINVAL is conclusive, thrown from CHECK_ATTR. fd, err := sys.MapCreate(&attr) - if err != nil { + if errors.Is(err, unix.EPERM) { + return nil + } + if errors.Is(err, unix.EINVAL) { return internal.ErrNotSupported } + if err != nil { + return err + } _ = fd.Close() return nil @@ -201,10 +209,19 @@ var objNameAllowsDot = internal.NewFeatureTest("dot in object names", func() err MapName: sys.NewObjName(".test"), } + // Tolerate EPERM, otherwise MapSpec.Name has its dots removed when run by + // unprivileged tools. (bpf2go, other code gen). Only EINVAL is conclusive, + // thrown from bpf_obj_name_cpy(). fd, err := sys.MapCreate(&attr) - if err != nil { + if errors.Is(err, unix.EPERM) { + return nil + } + if errors.Is(err, unix.EINVAL) { return internal.ErrNotSupported } + if err != nil { + return err + } _ = fd.Close() return nil diff --git a/variable.go b/variable.go index 114673e54..837cd5bfe 100644 --- a/variable.go +++ b/variable.go @@ -19,7 +19,7 @@ type VariableSpec struct { size uint64 m *MapSpec - t btf.Type + t *btf.Var } // Set sets the value of the VariableSpec to the provided input using the host's @@ -75,14 +75,28 @@ func (s *VariableSpec) Size() uint64 { return s.size } +// MapName returns the name of the underlying MapSpec. +func (s *VariableSpec) MapName() string { + return s.m.Name +} + +// Offset returns the offset of the variable in the underlying MapSpec. +func (s *VariableSpec) Offset() uint64 { + return s.offset +} + // Constant returns true if the VariableSpec represents a variable that is // read-only from the perspective of the BPF program. func (s *VariableSpec) Constant() bool { return s.m.readOnly() } -// Type returns the BTF Type of the variable. -func (s *VariableSpec) Type() btf.Type { +// Type returns the [btf.Var] representing the variable in its data section. +// This is useful for inspecting the variable's decl tags and the type +// information of the inner type. +// +// Returns nil if the original ELF object did not contain BTF information. +func (s *VariableSpec) Type() *btf.Var { return s.t } @@ -122,12 +136,12 @@ type Variable struct { name string offset uint64 size uint64 - t btf.Type + t *btf.Var mm *Memory } -func newVariable(name string, offset, size uint64, t btf.Type, mm *Memory) (*Variable, error) { +func newVariable(name string, offset, size uint64, t *btf.Var, mm *Memory) (*Variable, error) { if mm != nil { if int(offset+size) > mm.Size() { return nil, fmt.Errorf("offset %d(+%d) is out of bounds", offset, size) @@ -159,8 +173,12 @@ func (v *Variable) ReadOnly() bool { return v.mm.ReadOnly() } -// Type returns the BTF Type of the variable. -func (v *Variable) Type() btf.Type { +// Type returns the [btf.Var] representing the variable in its data section. +// This is useful for inspecting the variable's decl tags and the type +// information of the inner type. +// +// Returns nil if the original ELF object did not contain BTF information. +func (v *Variable) Type() *btf.Var { return v.t } diff --git a/variable_test.go b/variable_test.go index 541bb5e7e..73f36cc47 100644 --- a/variable_test.go +++ b/variable_test.go @@ -111,7 +111,7 @@ func TestVariable(t *testing.T) { typ := obj.BSS.Type() qt.Assert(t, qt.IsNotNil(typ)) - i, ok := btf.As[*btf.Int](typ) + i, ok := btf.As[*btf.Int](typ.Type) qt.Assert(t, qt.IsTrue(ok)) qt.Assert(t, qt.Equals(i.Size, 4))