Skip to content

Commit a3ac2c8

Browse files
committed
remove structOpsSpec, and merged loadStructOpsMaps into associateStructOpsRelocs
Signed-off-by: shun159 <[email protected]>
1 parent 558dc8b commit a3ac2c8

File tree

1 file changed

+88
-120
lines changed

1 file changed

+88
-120
lines changed

elf_reader.go

Lines changed: 88 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -41,30 +41,20 @@ type ksymMeta struct {
4141
Name string
4242
}
4343

44-
type structOpsSpec struct {
45-
name string
46-
// section index of .struct_ops / .struct_ops.link
47-
secIdx elf.SectionIndex
48-
// byte offset of the variable in that section
49-
userOff uint64
50-
userSize uint64
51-
}
52-
5344
// elfCode is a convenience to reduce the amount of arguments that have to
5445
// be passed around explicitly. You should treat its contents as immutable.
5546
type elfCode struct {
5647
*internal.SafeELFFile
57-
sections map[elf.SectionIndex]*elfSection
58-
license string
59-
version uint32
60-
btf *btf.Spec
61-
extInfo *btf.ExtInfos
62-
maps map[string]*MapSpec
63-
vars map[string]*VariableSpec
64-
kfuncs map[string]*btf.Func
65-
ksyms map[string]struct{}
66-
kconfig *MapSpec
67-
structOps map[string]*structOpsSpec
48+
sections map[elf.SectionIndex]*elfSection
49+
license string
50+
version uint32
51+
btf *btf.Spec
52+
extInfo *btf.ExtInfos
53+
maps map[string]*MapSpec
54+
vars map[string]*VariableSpec
55+
kfuncs map[string]*btf.Func
56+
ksyms map[string]struct{}
57+
kconfig *MapSpec
6858
}
6959

7060
// LoadCollectionSpec parses an ELF file into a CollectionSpec.
@@ -166,7 +156,6 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
166156
vars: make(map[string]*VariableSpec),
167157
kfuncs: make(map[string]*btf.Func),
168158
ksyms: make(map[string]struct{}),
169-
structOps: make(map[string]*structOpsSpec),
170159
}
171160

172161
symbols, err := f.Symbols()
@@ -184,10 +173,6 @@ func LoadCollectionSpecFromReader(rd io.ReaderAt) (*CollectionSpec, error) {
184173
return nil, fmt.Errorf("load maps: %w", err)
185174
}
186175

187-
if err := ec.loadStructOpsMaps(); err != nil {
188-
return nil, fmt.Errorf("struct_ops maps: %w", err)
189-
}
190-
191176
if err := ec.loadBTFMaps(); err != nil {
192177
return nil, fmt.Errorf("load BTF maps: %w", err)
193178
}
@@ -1417,27 +1402,44 @@ func (ec *elfCode) loadKsymsSection() error {
14171402
return nil
14181403
}
14191404

1420-
// loadStructOpsMapsFromSections creates StructOps MapSpecs from DataSec sections
1421-
// ".struct_ops" and ".struct_ops.link" found in the object BTF.
1422-
func (ec *elfCode) loadStructOpsMaps() error {
1405+
// associateStructOpsRelocs handles `.struct_ops.link`
1406+
// and associates the target function with the correct struct member in the map.
1407+
func (ec *elfCode) associateStructOpsRelocs(
1408+
progs map[string]*ProgramSpec,
1409+
relSecs map[elf.SectionIndex]*elf.Section,
1410+
symbols []elf.Symbol,
1411+
) error {
1412+
willAttachToMap := make(map[string]bool)
1413+
14231414
for secIdx, sec := range ec.sections {
14241415
if sec.kind != structOpsSection {
14251416
continue
14261417
}
14271418

1428-
// Retrieve raw data from the ELF section.
1429-
// This data contains the initial values for the struct_ops map.
14301419
userData, err := sec.Data()
14311420
if err != nil {
14321421
return fmt.Errorf("failed to read section data: %w", err)
14331422
}
14341423

1435-
// Process the struct_ops section to create the map
1424+
// Resolve the BTF datasec describing variables in this section.
14361425
var ds *btf.Datasec
14371426
if err := ec.btf.TypeByName(sec.Name, &ds); err != nil {
14381427
return fmt.Errorf("datasec %s: %w", sec.Name, err)
14391428
}
14401429

1430+
// Set flags for .struct_ops.link (BPF_F_LINK).
1431+
flags := uint32(0)
1432+
if sec.Name == structOpsLinkSec {
1433+
flags = sys.BPF_F_LINK
1434+
}
1435+
1436+
type structOpsMapOfsSize struct {
1437+
userOff uint64
1438+
userSize uint64
1439+
}
1440+
1441+
ofsSizes := make(map[string]structOpsMapOfsSize)
1442+
14411443
for _, vsi := range ds.Vars {
14421444
varType := btf.UnderlyingType(vsi.Type).(*btf.Var)
14431445
mapName := varType.Name
@@ -1447,115 +1449,81 @@ func (ec *elfCode) loadStructOpsMaps() error {
14471449
return fmt.Errorf("var %s: expect struct, got %T", varType.Name, varType.Type)
14481450
}
14491451

1450-
flags := uint32(0)
1451-
if sec.Name == structOpsLinkSec {
1452-
flags = sys.BPF_F_LINK
1453-
}
1454-
14551452
userSize := uint64(userType.Size)
14561453
userOff := uint64(vsi.Offset)
14571454
if userOff+userSize > uint64(len(userData)) {
14581455
return fmt.Errorf("%s exceeds section", mapName)
14591456
}
14601457

1461-
ec.structOps[mapName] =
1462-
&structOpsSpec{
1463-
name: mapName,
1464-
secIdx: secIdx,
1465-
userOff: userOff,
1466-
userSize: userSize,
1467-
}
1468-
1469-
ec.maps[mapName] =
1470-
&MapSpec{
1471-
Name: mapName,
1472-
Type: StructOpsMap,
1473-
Key: &btf.Int{Size: 4},
1474-
KeySize: 4,
1475-
Value: userType,
1476-
Flags: flags,
1477-
MaxEntries: 1,
1478-
Contents: []MapKV{
1479-
{
1480-
Key: uint32(0),
1481-
Value: append([]byte(nil), userData[userOff:userOff+userSize]...),
1482-
},
1458+
// Register the MapSpec for this struct_ops instance.
1459+
ec.maps[mapName] = &MapSpec{
1460+
Name: mapName,
1461+
Type: StructOpsMap,
1462+
Key: &btf.Int{Size: 4},
1463+
KeySize: 4,
1464+
Value: userType,
1465+
Flags: flags,
1466+
MaxEntries: 1,
1467+
Contents: []MapKV{
1468+
{
1469+
Key: uint32(0),
1470+
Value: append([]byte(nil), userData[userOff:userOff+userSize]...),
14831471
},
1484-
}
1472+
},
1473+
}
1474+
ofsSizes[mapName] =
1475+
structOpsMapOfsSize{userOff, userSize}
14851476
}
1486-
}
1487-
1488-
return nil
1489-
}
1490-
1491-
// associateStructOpsRelocs handles `.struct_ops.link`
1492-
// and associates the target function with the correct struct member in the map.
1493-
func (ec *elfCode) associateStructOpsRelocs(
1494-
progs map[string]*ProgramSpec,
1495-
relSecs map[elf.SectionIndex]*elf.Section,
1496-
symbols []elf.Symbol,
1497-
) error {
1498-
willAttachToMap := make(map[string]bool)
14991477

1500-
for _, sec := range relSecs {
1501-
if !(sec.Type == elf.SHT_REL) {
1502-
continue
1503-
}
1478+
// Process relo sections that target this struct_ops section.
1479+
for relSecIdx, relSec := range relSecs {
1480+
if elf.SectionIndex(relSec.Info) != elf.SectionIndex(secIdx) {
1481+
continue
1482+
}
15041483

1505-
targetIdx := elf.SectionIndex(sec.Info)
1506-
targetSec, ok := ec.sections[targetIdx]
1507-
if !(ok && strings.HasPrefix(targetSec.Name, ".struct_ops")) {
1508-
continue
1509-
}
1484+
if !(relSec.Type == elf.SHT_REL) {
1485+
continue
1486+
}
15101487

1511-
// Load the relocations from the relocation section
1512-
rels, err := ec.loadSectionRelocations(sec, symbols)
1513-
if err != nil {
1514-
return fmt.Errorf("failed to load relocations for section %s: %w", sec.Name, err)
1515-
}
1488+
// Load relocation entries (offset -> symbol).
1489+
rels, err := ec.loadSectionRelocations(relSec, symbols)
1490+
if err != nil {
1491+
return fmt.Errorf("failed to load relocations for section %s (relIdx=%d -> target=%d): %w",
1492+
relSec.Name, relSecIdx, secIdx, err)
1493+
}
15161494

1517-
for relOff, sym := range rels {
1518-
var ms *MapSpec
1519-
var meta *structOpsSpec
1495+
for relOff, sym := range rels {
1496+
var ms *MapSpec
1497+
var msName string
1498+
var baseOff uint64
15201499

1521-
for _, mapSpec := range ec.maps {
1522-
if mapSpec.Type != StructOpsMap || len(mapSpec.Contents) == 0 {
1523-
continue
1500+
for mapName, ofsSz := range ofsSizes {
1501+
if relOff >= ofsSz.userOff && relOff < ofsSz.userOff+ofsSz.userSize {
1502+
baseOff = ofsSz.userOff
1503+
ms = ec.maps[mapName]
1504+
msName = mapName
1505+
break
1506+
}
15241507
}
15251508

1526-
stOps, ok := ec.structOps[mapSpec.Name]
1527-
if !ok {
1528-
continue
1509+
if ms == nil || ms.Type != StructOpsMap {
1510+
return fmt.Errorf("struct_ops map %s not found or wrong type", msName)
15291511
}
15301512

1531-
if uint64(targetIdx) == uint64(stOps.secIdx) &&
1532-
stOps.userOff <= relOff &&
1533-
(relOff-stOps.userOff) < stOps.userSize {
1534-
meta = stOps
1535-
ms = mapSpec
1513+
userSt, ok := btf.As[*btf.Struct](ms.Value)
1514+
if !ok {
1515+
return fmt.Errorf("map %s value is not a btf.Struct", ms.Name)
15361516
}
1537-
}
15381517

1539-
if ms == nil {
1540-
return fmt.Errorf("no struct_ops map found for secIdx %d and relOffset %d", targetIdx, relOff)
1541-
}
1542-
1543-
// Member bit offset inside the user struct
1544-
moff := btf.Bits((relOff - meta.userOff) * 8)
1545-
1546-
userSt, ok := btf.As[*btf.Struct](ms.Value)
1547-
if !ok {
1548-
return fmt.Errorf("provided value is not a btf.Struct")
1549-
}
1550-
1551-
// Find the member at moff and ensure it's a pointer to a FuncProto.
1552-
if memberName, found := structOpsFuncPtrMemberAtOffset(userSt, moff); found {
1553-
p, ok := progs[sym.Name]
1554-
if !(ok && p.Type == StructOps) {
1555-
return fmt.Errorf("program %q not found or not StructOps", sym.Name)
1518+
moff := btf.Bits((relOff - baseOff) * 8)
1519+
if memberName, ok := structOpsFuncPtrMemberAtOffset(userSt, moff); ok {
1520+
p, ok := progs[sym.Name]
1521+
if !(ok && p.Type == StructOps) {
1522+
return fmt.Errorf("program %s not found or not StructOps", sym.Name)
1523+
}
1524+
p.AttachTo = userSt.Name + ":" + memberName
1525+
willAttachToMap[sym.Name] = true
15561526
}
1557-
p.AttachTo = userSt.Name + ":" + memberName
1558-
willAttachToMap[sym.Name] = true
15591527
}
15601528
}
15611529
}

0 commit comments

Comments
 (0)