@@ -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.
5546type 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