From 16c2fb04a35b95471a32e2f60800c6a4afa4a2b7 Mon Sep 17 00:00:00 2001 From: Jussi Maki Date: Thu, 17 Feb 2022 12:34:51 +0100 Subject: [PATCH] btf: Implement support for bitfield relocations This adds support for relocating bitfields, e.g. rewriting of the load offset and bit shifts for accessing the field. The implementation is mostly following libbpf, but does not include the loop for doubling the size of the load as that should not be necessary when one assumes that loads must be aligned and that a bitfield cannot be larger than the variable type. Signed-off-by: Jussi Maki --- elf_reader_test.go | 3 + internal/btf/core.go | 170 +++++++++++++++---- internal/btf/core_test.go | 87 +++++++--- internal/btf/ext_info.go | 4 +- internal/btf/testdata/relocs.c | 1 + internal/btf/testdata/relocs_read-eb.elf | Bin 1968 -> 9280 bytes internal/btf/testdata/relocs_read-el.elf | Bin 1968 -> 9280 bytes internal/btf/testdata/relocs_read.c | 71 +++++++- internal/btf/testdata/relocs_read_tgt-eb.elf | Bin 1272 -> 2272 bytes internal/btf/testdata/relocs_read_tgt-el.elf | Bin 1272 -> 2288 bytes internal/btf/testdata/relocs_read_tgt.c | 19 ++- 11 files changed, 289 insertions(+), 66 deletions(-) diff --git a/elf_reader_test.go b/elf_reader_test.go index 3ec5faa49..c1e5beefb 100644 --- a/elf_reader_test.go +++ b/elf_reader_test.go @@ -739,6 +739,9 @@ func TestLibBPFCompat(t *testing.T) { case "btf__core_reloc_type_id___missing_targets.o", "btf__core_reloc_flavors__err_wrong_name.o": valid = false + case "btf__core_reloc_ints___err_bitfield.o": + // Bitfields are now valid. + valid = true default: valid = !strings.Contains(name, "___err_") } diff --git a/internal/btf/core.go b/internal/btf/core.go index 317e7c311..3694d2c36 100644 --- a/internal/btf/core.go +++ b/internal/btf/core.go @@ -1,6 +1,7 @@ package btf import ( + "encoding/binary" "errors" "fmt" "math" @@ -17,7 +18,7 @@ import ( // COREFixup is the result of computing a CO-RE relocation for a target. type COREFixup struct { - Kind COREKind + Kind FixupKind Local uint32 Target uint32 Poison bool @@ -41,8 +42,8 @@ func (f COREFixup) apply(ins *asm.Instruction) error { switch class := ins.OpCode.Class(); class { case asm.LdXClass, asm.StClass, asm.StXClass: - if want := int16(f.Local); want != ins.Offset { - return fmt.Errorf("invalid offset %d, expected %d", ins.Offset, want) + if want := f.Local; !f.Kind.bitfield && int16(want) != ins.Offset { + return fmt.Errorf("invalid offset %d, expected %d", ins.Offset, f.Local) } if f.Target > math.MaxInt16 { @@ -56,8 +57,8 @@ func (f COREFixup) apply(ins *asm.Instruction) error { return fmt.Errorf("not a dword-sized immediate load") } - if want := int64(f.Local); want != ins.Constant { - return fmt.Errorf("invalid immediate %d, expected %d", ins.Constant, want) + if want := f.Local; !f.Kind.bitfield && int64(want) != ins.Constant { + return fmt.Errorf("invalid immediate %d, expected %d (fixup: %v)", ins.Constant, want, f) } ins.Constant = int64(f.Target) @@ -74,8 +75,8 @@ func (f COREFixup) apply(ins *asm.Instruction) error { return fmt.Errorf("invalid source %s", src) } - if want := int64(f.Local); want != ins.Constant { - return fmt.Errorf("invalid immediate %d, expected %d", ins.Constant, want) + if want := f.Local; !f.Kind.bitfield && int64(want) != ins.Constant { + return fmt.Errorf("invalid immediate %d, expected %d (fixup: %v, kind: %v, ins: %v)", ins.Constant, want, f, f.Kind, ins) } if f.Target > math.MaxInt32 { @@ -92,7 +93,7 @@ func (f COREFixup) apply(ins *asm.Instruction) error { } func (f COREFixup) isNonExistant() bool { - return f.Kind.checksForExistence() && f.Target == 0 + return f.Kind.coreKind.checksForExistence() && f.Target == 0 } type COREFixups map[uint64]COREFixup @@ -138,11 +139,11 @@ func (fs COREFixups) Apply(insns asm.Instructions) (asm.Instructions, error) { return cpy, nil } -// COREKind is the type of CO-RE relocation -type COREKind uint32 +// coreKind is the type of CO-RE relocation as specified in BPF source code. +type coreKind uint32 const ( - reloFieldByteOffset COREKind = iota /* field byte offset */ + reloFieldByteOffset coreKind = iota /* field byte offset */ reloFieldByteSize /* field size in bytes */ reloFieldExists /* field existence in target kernel */ reloFieldSigned /* field signedness (0 - unsigned, 1 - signed) */ @@ -156,7 +157,11 @@ const ( reloEnumvalValue /* enum value integer value */ ) -func (k COREKind) String() string { +func (k coreKind) checksForExistence() bool { + return k == reloEnumvalExists || k == reloTypeExists || k == reloFieldExists +} + +func (k coreKind) String() string { switch k { case reloFieldByteOffset: return "byte_off" @@ -187,8 +192,20 @@ func (k COREKind) String() string { } } -func (k COREKind) checksForExistence() bool { - return k == reloEnumvalExists || k == reloTypeExists || k == reloFieldExists +// FixupKind is the type of CO-RE relocation. +type FixupKind struct { + coreKind coreKind + + // the relocation is for a bitfield. This disables some validation. + bitfield bool +} + +func (fk FixupKind) String() string { + ck := fk.coreKind.String() + if fk.bitfield { + return ck + " (bitfield)" + } + return ck } func coreRelocate(local, target *Spec, relos CORERelos) (COREFixups, error) { @@ -208,7 +225,7 @@ func coreRelocate(local, target *Spec, relos CORERelos) (COREFixups, error) { } result[uint64(relo.insnOff)] = COREFixup{ - relo.kind, + FixupKind{coreKind: relo.kind}, uint32(relo.typeID), uint32(relo.typeID), false, @@ -241,7 +258,7 @@ func coreRelocate(local, target *Spec, relos CORERelos) (COREFixups, error) { relos := relosByID[id] targets := target.namedTypes[newEssentialName(localTypeName)] - fixups, err := coreCalculateFixups(localType, targets, relos) + fixups, err := coreCalculateFixups(local.byteOrder, localType, targets, relos) if err != nil { return nil, fmt.Errorf("relocate %s: %w", localType, err) } @@ -262,7 +279,7 @@ var errImpossibleRelocation = errors.New("impossible relocation") // // The best target is determined by scoring: the less poisoning we have to do // the better the target is. -func coreCalculateFixups(local Type, targets []Type, relos CORERelos) ([]COREFixup, error) { +func coreCalculateFixups(byteOrder binary.ByteOrder, local Type, targets []Type, relos CORERelos) ([]COREFixup, error) { localID := local.ID() local, err := copyType(local, skipQualifiersAndTypedefs) if err != nil { @@ -281,7 +298,7 @@ func coreCalculateFixups(local Type, targets []Type, relos CORERelos) ([]COREFix score := 0 // lower is better fixups := make([]COREFixup, 0, len(relos)) for _, relo := range relos { - fixup, err := coreCalculateFixup(local, localID, target, targetID, relo) + fixup, err := coreCalculateFixup(byteOrder, local, localID, target, targetID, relo) if err != nil { return nil, fmt.Errorf("target %s: %w", target, err) } @@ -317,7 +334,7 @@ func coreCalculateFixups(local Type, targets []Type, relos CORERelos) ([]COREFix // targets at all. Poison everything! bestFixups = make([]COREFixup, len(relos)) for i, relo := range relos { - bestFixups[i] = COREFixup{Kind: relo.kind, Poison: true} + bestFixups[i] = COREFixup{Kind: FixupKind{coreKind: relo.kind}, Poison: true} } } @@ -326,15 +343,15 @@ func coreCalculateFixups(local Type, targets []Type, relos CORERelos) ([]COREFix // coreCalculateFixup calculates the fixup for a single local type, target type // and relocation. -func coreCalculateFixup(local Type, localID TypeID, target Type, targetID TypeID, relo CORERelocation) (COREFixup, error) { +func coreCalculateFixup(byteOrder binary.ByteOrder, local Type, localID TypeID, target Type, targetID TypeID, relo CORERelocation) (COREFixup, error) { fixup := func(local, target uint32) (COREFixup, error) { - return COREFixup{relo.kind, local, target, false}, nil + return COREFixup{FixupKind{coreKind: relo.kind}, local, target, false}, nil } poison := func() (COREFixup, error) { if relo.kind.checksForExistence() { return fixup(1, 0) } - return COREFixup{relo.kind, 0, 0, true}, nil + return COREFixup{Kind: FixupKind{coreKind: relo.kind}, Local: 0, Target: 0, Poison: true}, nil } zero := COREFixup{} @@ -390,7 +407,22 @@ func coreCalculateFixup(local Type, localID TypeID, target Type, targetID TypeID return fixup(uint32(localValue.Value), uint32(targetValue.Value)) } - case reloFieldByteOffset, reloFieldByteSize, reloFieldExists: + case reloFieldSigned: + switch local.(type) { + case *Enum: + return fixup(1, 1) + case *Int: + return COREFixup{ + FixupKind{coreKind: relo.kind}, + uint32(local.(*Int).Encoding & Signed), + uint32(target.(*Int).Encoding & Signed), + false, + }, nil + default: + return fixup(0, 0) + } + + case reloFieldByteOffset, reloFieldByteSize, reloFieldExists, reloFieldLShiftU64, reloFieldRShiftU64: if _, ok := target.(*Fwd); ok { // We can't relocate fields using a forward declaration, so // skip it. If a non-forward declaration is present in the BTF @@ -405,13 +437,20 @@ func coreCalculateFixup(local Type, localID TypeID, target Type, targetID TypeID if err != nil { return zero, fmt.Errorf("target %s: %w", target, err) } + fixupField := func(local, target uint32) (COREFixup, error) { + fixupKind := FixupKind{ + coreKind: relo.kind, + bitfield: localField.bitfieldSize > 0 || targetField.bitfieldSize > 0, + } + return COREFixup{Kind: fixupKind, Local: local, Target: target, Poison: false}, nil + } switch relo.kind { case reloFieldExists: return fixup(1, 1) case reloFieldByteOffset: - return fixup(localField.offset/8, targetField.offset/8) + return fixupField(localField.offset/8, targetField.offset/8) case reloFieldByteSize: localSize, err := Sizeof(localField.Type) @@ -423,9 +462,23 @@ func coreCalculateFixup(local Type, localID TypeID, target Type, targetID TypeID if err != nil { return zero, err } + return fixupField(uint32(localSize), uint32(targetSize)) + + case reloFieldLShiftU64: + var target uint32 + if byteOrder == binary.LittleEndian { + target = 64 - (targetField.bitfieldOffset + targetField.bitfieldSize - targetField.offset) + } else { + targetSize, err := Sizeof(targetField.Type) + if err != nil { + return zero, err + } + target = (8-uint32(targetSize))*8 + (targetField.bitfieldOffset - targetField.offset) + } + return fixupField(0, target) - return fixup(uint32(localSize), uint32(targetSize)) - + case reloFieldRShiftU64: + return fixupField(0, 64-targetField.bitfieldSize) } } @@ -509,8 +562,18 @@ func (ca coreAccessor) enumValue(t Type) (*EnumValue, error) { } type coreField struct { - Type Type + Type Type + + // offset is the load offset of the field in bytes. offset uint32 + + // bitfieldOffset is optional and is the offset of the bitfield in bits. + // Used with bitfieldSize to compute the shifts required to pull the bitfield + // out from the word loaded from 'offset'. + bitfieldOffset uint32 + + // bitfieldSize is the size of the bitfield in bits. + bitfieldSize uint32 } func adjustOffset(base uint32, t Type, n int) (uint32, error) { @@ -527,7 +590,7 @@ func adjustOffset(base uint32, t Type, n int) (uint32, error) { // // Returns the field and the offset of the field from the start of // target in bits. -func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreField, _ error) { +func coreFindField(local Type, localAcc coreAccessor, target Type) (coreField, coreField, error) { // The first index is used to offset a pointer of the base type like // when accessing an array. localOffset, err := adjustOffset(0, local, localAcc[0]) @@ -579,10 +642,6 @@ func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreFie return coreField{}, coreField{}, err } - if targetMember.BitfieldSize > 0 { - return coreField{}, coreField{}, fmt.Errorf("field %q is a bitfield: %w", targetMember.Name, ErrNotSupported) - } - local = localMember.Type localMaybeFlex = acc == len(localMembers)-1 localOffset += localMember.OffsetBits @@ -590,6 +649,51 @@ func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreFie targetMaybeFlex = last targetOffset += targetMember.OffsetBits + if targetMember.BitfieldSize == 0 && localMember.BitfieldSize == 0 { + break + } + + targetSize, err := Sizeof(target) + if err != nil { + return coreField{}, coreField{}, + fmt.Errorf("could not get target size: %w", err) + } + + targetBitfieldOffset := targetOffset + var targetBitfieldSize uint32 + + if targetMember.BitfieldSize > 0 { + // From the target BTF, we know the word size of the field containing the target bitfield + // and we know the bitfields offset in bits, and since we know the load is aligned, we can + // compute the load offset by: + // 1) convert the bit offset to bytes with a flooring division, yielding "byte" aligned offset. + // 2) dividing and multiplying that offset by the load size, yielding the target load size aligned offset. + targetBitfieldSize = targetMember.BitfieldSize + targetOffset = 8 * (targetOffset / 8 / uint32(targetSize) * uint32(targetSize)) + + // As sanity check, verify that the bitfield is captured by the chosen load. This should only happen + // if one of the two assumptions are broken: the bitfield size is smaller than the type of the variable + // and that the loads are aligned. + if targetOffset > targetBitfieldOffset || + targetOffset+uint32(targetSize)*8 < targetBitfieldOffset+targetMember.BitfieldSize { + return coreField{}, coreField{}, + fmt.Errorf("could not find load for bitfield: load of %d bytes at %d does not capture bitfield of size %d at %d", + targetSize, targetOffset, targetMember.BitfieldSize, targetBitfieldOffset) + } + } else { + // Going from a bitfield to a normal field. Since the original BTF had it as a bitfield, we'll + // need to "emulate" a bitfield in target to compute the shifts correctly. + targetBitfieldSize = uint32(targetSize * 8) + } + + if err := coreAreMembersCompatible(local, target); err != nil { + return coreField{}, coreField{}, err + } + + return coreField{local, localOffset, localMember.OffsetBits, localMember.BitfieldSize}, + coreField{target, targetOffset, targetBitfieldOffset, targetBitfieldSize}, + nil + case *Array: // For arrays, acc is the index in the target. targetType, ok := target.(*Array) @@ -634,7 +738,7 @@ func coreFindField(local Type, localAcc coreAccessor, target Type) (_, _ coreFie } } - return coreField{local, localOffset}, coreField{target, targetOffset}, nil + return coreField{local, localOffset, 0, 0}, coreField{target, targetOffset, 0, 0}, nil } // coreFindMember finds a member in a composite type while handling anonymous diff --git a/internal/btf/core_test.go b/internal/btf/core_test.go index 593dded26..c67142211 100644 --- a/internal/btf/core_test.go +++ b/internal/btf/core_test.go @@ -233,14 +233,24 @@ func TestCOREFindField(t *testing.T) { aFields := []Member{ {Name: "foo", Type: ptr, OffsetBits: 1}, {Name: "bar", Type: u16, OffsetBits: 2}, + {Name: "baz", Type: u32, OffsetBits: 32, BitfieldSize: 3}, + {Name: "quux", Type: u32, OffsetBits: 35, BitfieldSize: 10}, + {Name: "quuz", Type: u32, OffsetBits: 45, BitfieldSize: 8}, } bFields := []Member{ {Name: "foo", Type: ptr, OffsetBits: 10}, {Name: "bar", Type: u32, OffsetBits: 20}, {Name: "other", OffsetBits: 4}, + // baz is separated out from the other bitfields + {Name: "baz", Type: u32, OffsetBits: 64, BitfieldSize: 3}, + // quux's type changes u32->u16 + {Name: "quux", Type: u16, OffsetBits: 96, BitfieldSize: 10}, + // quuz becomes a normal field + {Name: "quuz", Type: u16, OffsetBits: 112}, } - aStruct := &Struct{Members: aFields, Size: 2} - bStruct := &Struct{Members: bFields, Size: 7} + + aStruct := &Struct{Members: aFields, Size: 48} + bStruct := &Struct{Members: bFields, Size: 80} aArray := &Array{Nelems: 4, Type: u16} bArray := &Array{Nelems: 3, Type: u32} @@ -340,83 +350,83 @@ func TestCOREFindField(t *testing.T) { aArray, bArray, coreAccessor{0, 0}, - coreField{u16, 0}, - coreField{u32, 0}, + coreField{u16, 0, 0, 0}, + coreField{u32, 0, 0, 0}, }, { "array[1]", aArray, bArray, coreAccessor{0, 1}, - coreField{u16, bits(aArray.Type)}, - coreField{u32, bits(bArray.Type)}, + coreField{u16, bits(aArray.Type), 0, 0}, + coreField{u32, bits(bArray.Type), 0, 0}, }, { "array[0] with base offset", aArray, bArray, coreAccessor{1, 0}, - coreField{u16, bits(aArray)}, - coreField{u32, bits(bArray)}, + coreField{u16, bits(aArray), 0, 0}, + coreField{u32, bits(bArray), 0, 0}, }, { "array[2] with base offset", aArray, bArray, coreAccessor{1, 2}, - coreField{u16, bits(aArray) + 2*bits(aArray.Type)}, - coreField{u32, bits(bArray) + 2*bits(bArray.Type)}, + coreField{u16, bits(aArray) + 2*bits(aArray.Type), 0, 0}, + coreField{u32, bits(bArray) + 2*bits(bArray.Type), 0, 0}, }, { "flex array", &Struct{Members: []Member{{Name: "foo", Type: &Array{Nelems: 0, Type: u16}}}}, &Struct{Members: []Member{{Name: "foo", Type: &Array{Nelems: 0, Type: u32}}}}, coreAccessor{0, 0, 9000}, - coreField{u16, bits(u16) * 9000}, - coreField{u32, bits(u32) * 9000}, + coreField{u16, bits(u16) * 9000, 0, 0}, + coreField{u32, bits(u32) * 9000, 0, 0}, }, { "struct.0", aStruct, bStruct, coreAccessor{0, 0}, - coreField{ptr, 1}, - coreField{ptr, 10}, + coreField{ptr, 1, 0, 0}, + coreField{ptr, 10, 0, 0}, }, { "struct.0 anon", aStruct, &Struct{Members: anon(bStruct, 23)}, coreAccessor{0, 0}, - coreField{ptr, 1}, - coreField{ptr, 23 + 10}, + coreField{ptr, 1, 0, 0}, + coreField{ptr, 23 + 10, 0, 0}, }, { "struct.0 with base offset", aStruct, bStruct, coreAccessor{3, 0}, - coreField{ptr, 3*bits(aStruct) + 1}, - coreField{ptr, 3*bits(bStruct) + 10}, + coreField{ptr, 3*bits(aStruct) + 1, 0, 0}, + coreField{ptr, 3*bits(bStruct) + 10, 0, 0}, }, { "struct.1", aStruct, bStruct, coreAccessor{0, 1}, - coreField{u16, 2}, - coreField{u32, 20}, + coreField{u16, 2, 0, 0}, + coreField{u32, 20, 0, 0}, }, { "struct.1 anon", aStruct, &Struct{Members: anon(bStruct, 1)}, coreAccessor{0, 1}, - coreField{u16, 2}, - coreField{u32, 1 + 20}, + coreField{u16, 2, 0, 0}, + coreField{u32, 1 + 20, 0, 0}, }, { "union.1", &Union{Members: aFields, Size: 32}, &Union{Members: bFields, Size: 32}, coreAccessor{0, 1}, - coreField{u16, 2}, - coreField{u32, 20}, + coreField{u16, 2, 0, 0}, + coreField{u32, 20, 0, 0}, }, { "interchangeable composites", @@ -431,8 +441,29 @@ func TestCOREFindField(t *testing.T) { }, }, coreAccessor{0, 0, 0, 0}, - coreField{u16, 0}, - coreField{u16, 0}, + coreField{u16, 0, 0, 0}, + coreField{u16, 0, 0, 0}, + }, + { + "struct.2 (bitfield baz)", + aStruct, bStruct, + coreAccessor{0, 2}, + coreField{u32, 32, 32, 3}, + coreField{u32, 64, 64, 3}, + }, + { + "struct.3 (bitfield quux)", + aStruct, bStruct, + coreAccessor{0, 3}, + coreField{u32, 35, 35, 10}, + coreField{u16, 96, 96, 10}, + }, + { + "struct.4 (bitfield quuz)", + aStruct, bStruct, + coreAccessor{0, 4}, + coreField{u32, 45, 45, 3}, + coreField{u16, 112, 112, 16}, }, } @@ -522,10 +553,10 @@ func TestCORERelocation(t *testing.T) { } for offset, relo := range relos { - if relo.Local != relo.Target { + if want := relo.Local; !relo.Kind.bitfield && want != relo.Target { // Since we're relocating against ourselves both values // should match. - t.Errorf("offset %d: local %v doesn't match target %d", offset, relo.Local, relo.Target) + t.Errorf("offset %d: local %v doesn't match target %d (kind %s)", offset, relo.Local, relo.Target, relo.Kind) } } }) diff --git a/internal/btf/ext_info.go b/internal/btf/ext_info.go index be614e782..39ce7b068 100644 --- a/internal/btf/ext_info.go +++ b/internal/btf/ext_info.go @@ -435,14 +435,14 @@ type bpfCORERelo struct { InsnOff uint32 TypeID TypeID AccessStrOff uint32 - Kind COREKind + Kind coreKind } type CORERelocation struct { insnOff uint32 typeID TypeID accessor coreAccessor - kind COREKind + kind coreKind } type CORERelos []CORERelocation diff --git a/internal/btf/testdata/relocs.c b/internal/btf/testdata/relocs.c index 24fae514c..7b559a076 100644 --- a/internal/btf/testdata/relocs.c +++ b/internal/btf/testdata/relocs.c @@ -238,3 +238,4 @@ __section("socket_filter/err_ambiguous") int err_ambiguous() { __section("socket_filter/err_ambiguous_flavour") int err_ambiguous_flavour() { return bpf_core_type_id_kernel(struct ambiguous___flavour); } + diff --git a/internal/btf/testdata/relocs_read-eb.elf b/internal/btf/testdata/relocs_read-eb.elf index d5e6c328fcf4b1176678ac2a9524831c6b15a187..b13859d74d14d535f8ae0ed4ad94b4f4531e8cb0 100644 GIT binary patch literal 9280 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 literal 1968 zcmb_cy=xRf6n}TQd|ZqWMdL@~77BMDcNgu{$Pq|Lks?I|3t_Xjw=qX9w{dqOib^7q z#zN9qt6*timr~1sg{IQVf565<5SyI8-|oygw?we;!JGGf?`z)7zS+&0`PqCvCq2r^ zPw1AR=YcXS^s(kmO&)N4bdP!8v`P0;B^xIF_D~=FLJH!??%v zfk{um)JMSFmc%;5cI|y#Ye-rhB~jot-FTz19)-81qJn!$DpfdwsN=P(4YgcVL9Cjd z@~TnL4*l3=M#UG`^^}TQjSUsJZmHA>Tb*{R6O_vivK_l@sq8$EVyvPKUpcX}9EQ#m zEU`4i6Mw~vq;_Reimhd*`J z^NH6)>PH|;8b1?RoPf^3q@S1rR@eBA$kHk3H#LSxXay_dKZ>lgC-%YtAkqF+LopuK{^~Es-c9^V8Ec_cHeQ zAH+V%q~u?is>xc{I`7k_5eslU|CY~tB#oz{x7zs&u$uf{fL7k8GPj*^*ztURHnu|Z zGdll-Wu$7y&jDxWQil&LX=Mkp2sZO)`sdkMo4!M6;JY^R{QP&DeM~;>{Js1o-)twJ pbiOgz`Io}(JZDq3xb#thc_jP1SzL!9$)}^A3i}%0>bL)?_Zvjpwj2Ne diff --git a/internal/btf/testdata/relocs_read-el.elf b/internal/btf/testdata/relocs_read-el.elf index 50b6c886afd898eb161686124941557a9b8b9493..78b9c32acbdcf1141da8c8301154968bbeda15c3 100644 GIT binary patch literal 9280 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 diff --git a/internal/btf/testdata/relocs_read.c b/internal/btf/testdata/relocs_read.c index ccb4f499a..0f6cb4f1e 100644 --- a/internal/btf/testdata/relocs_read.c +++ b/internal/btf/testdata/relocs_read.c @@ -1,7 +1,10 @@ #include "../../../testdata/common.h" +#include "bpf_core_read.h" #define core_access __builtin_preserve_access_index +char _license[] __attribute__((section(("license")), used)) = "GPL"; + // Struct with the members declared in the wrong order. Accesses need // a successful CO-RE relocation against the type in relocs_read_tgt.c // for the test below to pass. @@ -10,6 +13,21 @@ struct s { char a; }; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long u64; + +// Struct with bitfields. +struct bits { + int x; + u8 a:4, b:2; + u16 c:1; + unsigned int d:2; + enum { ZERO = 0, ONE = 1 } e:1; + u64 f:16, g:30; +}; + // Perform a read from a subprog to ensure CO-RE relocations // occurring there are tracked and executed in the final linked program. __attribute__((noinline)) int read_subprog() { @@ -21,8 +39,57 @@ __attribute__((noinline)) int read_subprog() { if (core_access(foo.a) == 0) return __LINE__; - if (core_access(foo.b) == 1) - return __LINE__; + if (core_access(foo.b) == 1) + return __LINE__; + + struct bits bar; + char *p = (char *)&bar; + /* Target: + * [4] STRUCT 'bits' size=8 vlen=7 + * 'b' type_id=5 bits_offset=0 bitfield_size=2 + * 'a' type_id=5 bits_offset=2 bitfield_size=4 + * 'd' type_id=7 bits_offset=6 bitfield_size=2 + * 'c' type_id=9 bits_offset=8 bitfield_size=1 + * 'e' type_id=11 bits_offset=9 bitfield_size=1 + * 'f' type_id=9 bits_offset=16 + * 'g' type_id=12 bits_offset=32 bitfield_size=30 + */ + *p++ = 0xff; // a, b, d + *p++ = 0x00; // c, e + *p++ = 0x56; // f + *p++ = 0x56; // f +#ifdef __BIG_ENDIAN__ + *p++ = 0x55; // g + *p++ = 0x44; // g + *p++ = 0x33; // g + *p++ = 0x22; // g +#else + *p++ = 0x22; // g + *p++ = 0x33; // g + *p++ = 0x44; // g + *p++ = 0x55; // g +#endif + + if (BPF_CORE_READ_BITFIELD(&bar, a) != (1<<4)-1) + return __LINE__; + + if (BPF_CORE_READ_BITFIELD(&bar, b) != (1<<2)-1) + return __LINE__; + + if (BPF_CORE_READ_BITFIELD(&bar, d) != (1<<2)-1) + return __LINE__; + + if (BPF_CORE_READ_BITFIELD(&bar, c) != 0) + return __LINE__; + + if (BPF_CORE_READ_BITFIELD(&bar, e) != 0) + return __LINE__; + + if (BPF_CORE_READ_BITFIELD(&bar, f) != 0x5656) + return __LINE__; + + if (BPF_CORE_READ_BITFIELD(&bar, g) != 0x15443322) + return __LINE__; return 0; } diff --git a/internal/btf/testdata/relocs_read_tgt-eb.elf b/internal/btf/testdata/relocs_read_tgt-eb.elf index b0effd5f86f2c6f01c7945a480f91c5fda96e4c2..c09e1d0a53c0a7be2574de5ddc55fb34ffa2c755 100644 GIT binary patch literal 2272 zcmb_dJ!lj`6n>lJlAK13KZQup6`PC7CH^A*U=Sh-!H5Wo1kTOgnuOe4WOq-D@h5_% zV5OB{z(Na)R4OQ>NTHyhU?GA^dM)g1g6H?`&YY9+?EK)n_rCYu%)Xi3nY+sa_hN|3`fBAMx6a z#`DzXbbM}W`kXd5>EqY4-c(0h>NZ)^_*!XV#M>+_v}vEx?5|1nGX{aXsgZ9Fl40vp z>FmSSkR8-3(jez^k}8oFSQk2j0*1)(TOw_+?chZ)lQbX_(nk}NG1vyD74{OC#X#0y z2A9Ln!d_t<#7@gquw!HTtm`ZUIQAwV2+%NmN9AblsT|ksf)7=08T>~o$6h!;C!^2W zr_{g;kY#hmoF7&HtmS%Ef&|w|pQWGF+}xvf8LPxntd`4@l8=MSvE+LY3Brn3>KTqN z^u$3F7rof)34_vv9~HvDD;DCBIPY_$n~cnLyHk?Q`V(PL@O(drqFgSD!>S*yLV&lqU<-T|55-*q&-89dQ1EbiUk3+@2v?*eyAB*}EyFo>&R#ckA@>dW1R0eir``rC4`N5neCAz1F; zBFOz)4yrAbX83$RjAcM#HFzNXRFZn?<08{turna_S9~&?U}u%q`S(U%zkANT3gmP6 z{^vo$1x=k(`V}mJbCKk=?o;{=EO8R#c&*PW{SKBG1)10SqS7B=iD{5|t!Lo#2-{&=4z4ykzMu-W!!oCz-Dhd;g_%EZX|CPO zPh0xFrJq>(rKR6m`m?3KTY7P+PVPISAE(R8TkCZWTKNG>4_Ufo>8o|U$htIM9;E1rU3~u#@G)q6~BV5Ag2h+6msVCi;|EFoW>*H^wl}g&t3B zz;RR2#QiW~*7N+D+Nf*hJ^{|{)YgB^`d&nNwi_U$`#gpu*QV=qd_7`3WBlJ~fDFH5 wz@g>0&ijeb<2&K!Kpkh!K(v{i(bzx)+S1NHI00hD0Ln*aa+ delta 364 zcmaDL_=9tT9uw1#i3akb|F$bIfI+bkoMxQN!>Gi?5Caqd;l{}pjM}PsEDQ`xKpqGe z05K~NgFq1wgV-EETrxR@DQvPovy!PbLoq`lLlQ%BMq&|zft3Le8#26}&j?h+pa3F( zKm>|yfOG&5>r9@*EFZ}XWPyMn5L+`aSb*3dvq5}M1_m2>AgzJK2f0T8h`E6n#FhYJ zpi>ztffxi7fEdKDo&1nZeXvewh~%f>BBL3(8Mrj7Ta(ORq3n%iypOkQNYB{Kh!<<9uM zP2!(#5^ueJcR#IH?fB{~9S7d~8sk{$vYZ}v*3N2v1O<=*YyL8TN4TfkxRsA>BpR{2 zq6I&x{qxYeu)TTg4oE2!J2hm?@iw-z##x0DB(F93-FMK_BhAGg#DM zbtQiRwhxN>+(p=}mUEXh-Vb{Px(ynL?7s>NDR8^48CT5i@_j#AF3|s3b2>)(O>GNOs96#G}K09pA%#%Lf`^3iFm~t}L$fVk=*B7Of z#TPRv4IvUIjj%Q}l}!(2ahg@bEF4PW+Cr38k~pkZvYD(Dv1MRd76*gN($^O)BylB- zqBu>9#WYKrQ5H*2VirxuE>mW8kLJwXp;35_Yq@Bfh4oLu&bM z)|5TwI#68xoS`;z-V~Q#GSuc@JpRMuyB;xk%6hi%Wt+I4q)w1|umIJGJsa&}d_$XkwwDg>A4fOe-jM zHe#p$$tD(oRGx2Q^5A3U%{+FO?H7jrW0i;8ODeO!S(be=jnpYms*yQU4h~?Idy-9) zES#f7GN1k~TjPd