29
29
// ID represents the unique ID of a BTF object.
30
30
type ID = sys.BTFID
31
31
32
- // Spec allows querying a set of Types and loading the set into the
33
- // kernel.
34
- type Spec struct {
32
+ // immutableTypes is a set of types which musn't be changed.
33
+ type immutableTypes struct {
35
34
// All types contained by the spec, not including types from the base in
36
35
// case the spec was parsed from split BTF.
37
36
types []Type
@@ -44,13 +43,132 @@ type Spec struct {
44
43
45
44
// Types indexed by essential name.
46
45
// Includes all struct flavors and types with the same name.
47
- namedTypes map [essentialName ][]Type
46
+ namedTypes map [essentialName ][]TypeID
47
+
48
+ // Byte order of the types. This affects things like struct member order
49
+ // when using bitfields.
50
+ byteOrder binary.ByteOrder
51
+ }
52
+
53
+ func (s * immutableTypes ) typeByID (id TypeID ) (Type , bool ) {
54
+ if id < s .firstTypeID {
55
+ return nil , false
56
+ }
57
+
58
+ index := int (id - s .firstTypeID )
59
+ if index >= len (s .types ) {
60
+ return nil , false
61
+ }
62
+
63
+ return s .types [index ], true
64
+ }
65
+
66
+ // mutableTypes is a set of types which may be changed.
67
+ type mutableTypes struct {
68
+ imm immutableTypes
69
+ copies map [Type ]Type // map[orig]copy
70
+ copiedTypeIDs map [Type ]TypeID //map[copy]origID
71
+ }
72
+
73
+ // add a type to the set of mutable types.
74
+ //
75
+ // Copies type and all of its children once. Repeated calls with the same type
76
+ // do not copy again.
77
+ func (mt * mutableTypes ) add (typ Type , typeIDs map [Type ]TypeID ) Type {
78
+ return modifyGraphPreorder (typ , func (t Type ) (Type , bool ) {
79
+ cpy , ok := mt .copies [t ]
80
+ if ok {
81
+ // This has been copied previously, no need to continue.
82
+ return cpy , false
83
+ }
84
+
85
+ cpy = t .copy ()
86
+ mt .copies [t ] = cpy
87
+
88
+ if id , ok := typeIDs [t ]; ok {
89
+ mt .copiedTypeIDs [cpy ] = id
90
+ }
91
+
92
+ // This is a new copy, keep copying children.
93
+ return cpy , true
94
+ })
95
+ }
96
+
97
+ // copy a set of mutable types.
98
+ func (mt * mutableTypes ) copy () mutableTypes {
99
+ mtCopy := mutableTypes {
100
+ mt .imm ,
101
+ make (map [Type ]Type , len (mt .copies )),
102
+ make (map [Type ]TypeID , len (mt .copiedTypeIDs )),
103
+ }
104
+
105
+ copies := make (map [Type ]Type , len (mt .copies ))
106
+ for orig , copy := range mt .copies {
107
+ // NB: We make a copy of copy, not orig, so that changes to mutable types
108
+ // are preserved.
109
+ copyOfCopy := mtCopy .add (copy , mt .copiedTypeIDs )
110
+ copies [orig ] = copyOfCopy
111
+ }
112
+
113
+ // mtCopy.copies is currently map[copy]copyOfCopy, replace it with
114
+ // map[orig]copyOfCopy.
115
+ mtCopy .copies = copies
116
+ return mtCopy
117
+ }
118
+
119
+ func (mt * mutableTypes ) typeID (typ Type ) (TypeID , error ) {
120
+ if _ , ok := typ .(* Void ); ok {
121
+ // Equality is weird for void, since it is a zero sized type.
122
+ return 0 , nil
123
+ }
124
+
125
+ id , ok := mt .copiedTypeIDs [typ ]
126
+ if ! ok {
127
+ return 0 , fmt .Errorf ("no ID for type %s: %w" , typ , ErrNotFound )
128
+ }
129
+
130
+ return id , nil
131
+ }
132
+
133
+ func (mt * mutableTypes ) typeByID (id TypeID ) (Type , bool ) {
134
+ immT , ok := mt .imm .typeByID (id )
135
+ if ! ok {
136
+ return nil , false
137
+ }
138
+
139
+ return mt .add (immT , mt .imm .typeIDs ), true
140
+ }
141
+
142
+ func (mt * mutableTypes ) anyTypesByName (name string ) ([]Type , error ) {
143
+ immTypes := mt .imm .namedTypes [newEssentialName (name )]
144
+ if len (immTypes ) == 0 {
145
+ return nil , fmt .Errorf ("type name %s: %w" , name , ErrNotFound )
146
+ }
147
+
148
+ // Return a copy to prevent changes to namedTypes.
149
+ result := make ([]Type , 0 , len (immTypes ))
150
+ for _ , id := range immTypes {
151
+ immT , ok := mt .imm .typeByID (id )
152
+ if ! ok {
153
+ return nil , fmt .Errorf ("no type with ID %d" , id )
154
+ }
155
+
156
+ // Match against the full name, not just the essential one
157
+ // in case the type being looked up is a struct flavor.
158
+ if immT .TypeName () == name {
159
+ result = append (result , mt .add (immT , mt .imm .typeIDs ))
160
+ }
161
+ }
162
+ return result , nil
163
+ }
164
+
165
+ // Spec allows querying a set of Types and loading the set into the
166
+ // kernel.
167
+ type Spec struct {
168
+ mutableTypes
48
169
49
170
// String table from ELF.
50
171
strings * stringTable
51
-
52
- // Byte order of the ELF we decoded the spec from, may be nil.
53
- byteOrder binary.ByteOrder
54
172
}
55
173
56
174
// LoadSpec opens file and calls LoadSpecFromReader on it.
@@ -181,7 +299,7 @@ func loadSpecFromELF(file *internal.SafeELFFile) (*Spec, error) {
181
299
return nil , err
182
300
}
183
301
184
- err = fixupDatasec (spec .types , sectionSizes , offsets )
302
+ err = fixupDatasec (spec .imm . types , sectionSizes , offsets )
185
303
if err != nil {
186
304
return nil , err
187
305
}
@@ -197,7 +315,7 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error
197
315
)
198
316
199
317
if base != nil {
200
- if base .firstTypeID != 0 {
318
+ if base .imm . firstTypeID != 0 {
201
319
return nil , fmt .Errorf ("can't use split BTF as base" )
202
320
}
203
321
@@ -217,16 +335,22 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error
217
335
typeIDs , typesByName := indexTypes (types , firstTypeID )
218
336
219
337
return & Spec {
220
- namedTypes : typesByName ,
221
- typeIDs : typeIDs ,
222
- types : types ,
223
- firstTypeID : firstTypeID ,
224
- strings : rawStrings ,
225
- byteOrder : bo ,
338
+ mutableTypes {
339
+ immutableTypes {
340
+ types ,
341
+ typeIDs ,
342
+ firstTypeID ,
343
+ typesByName ,
344
+ bo ,
345
+ },
346
+ make (map [Type ]Type ),
347
+ make (map [Type ]TypeID ),
348
+ },
349
+ rawStrings ,
226
350
}, nil
227
351
}
228
352
229
- func indexTypes (types []Type , firstTypeID TypeID ) (map [Type ]TypeID , map [essentialName ][]Type ) {
353
+ func indexTypes (types []Type , firstTypeID TypeID ) (map [Type ]TypeID , map [essentialName ][]TypeID ) {
230
354
namedTypes := 0
231
355
for _ , typ := range types {
232
356
if typ .TypeName () != "" {
@@ -238,13 +362,15 @@ func indexTypes(types []Type, firstTypeID TypeID) (map[Type]TypeID, map[essentia
238
362
}
239
363
240
364
typeIDs := make (map [Type ]TypeID , len (types ))
241
- typesByName := make (map [essentialName ][]Type , namedTypes )
365
+ typesByName := make (map [essentialName ][]TypeID , namedTypes )
242
366
243
367
for i , typ := range types {
368
+ id := firstTypeID + TypeID (i )
369
+ typeIDs [typ ] = id
370
+
244
371
if name := newEssentialName (typ .TypeName ()); name != "" {
245
- typesByName [name ] = append (typesByName [name ], typ )
372
+ typesByName [name ] = append (typesByName [name ], id )
246
373
}
247
- typeIDs [typ ] = firstTypeID + TypeID (i )
248
374
}
249
375
250
376
return typeIDs , typesByName
@@ -492,17 +618,9 @@ func fixupDatasecLayout(ds *Datasec) error {
492
618
493
619
// Copy creates a copy of Spec.
494
620
func (s * Spec ) Copy () * Spec {
495
- types := copyTypes (s .types , nil )
496
- typeIDs , typesByName := indexTypes (types , s .firstTypeID )
497
-
498
- // NB: Other parts of spec are not copied since they are immutable.
499
621
return & Spec {
500
- types ,
501
- typeIDs ,
502
- s .firstTypeID ,
503
- typesByName ,
622
+ s .mutableTypes .copy (),
504
623
s .strings ,
505
- s .byteOrder ,
506
624
}
507
625
}
508
626
@@ -519,8 +637,8 @@ func (sw sliceWriter) Write(p []byte) (int, error) {
519
637
// nextTypeID returns the next unallocated type ID or an error if there are no
520
638
// more type IDs.
521
639
func (s * Spec ) nextTypeID () (TypeID , error ) {
522
- id := s .firstTypeID + TypeID (len (s .types ))
523
- if id < s .firstTypeID {
640
+ id := s .imm . firstTypeID + TypeID (len (s . imm .types ))
641
+ if id < s .imm . firstTypeID {
524
642
return 0 , fmt .Errorf ("no more type IDs" )
525
643
}
526
644
return id , nil
@@ -533,40 +651,17 @@ func (s *Spec) nextTypeID() (TypeID, error) {
533
651
func (s * Spec ) TypeByID (id TypeID ) (Type , error ) {
534
652
typ , ok := s .typeByID (id )
535
653
if ! ok {
536
- return nil , fmt .Errorf ("look up type with ID %d (first ID is %d): %w" , id , s .firstTypeID , ErrNotFound )
654
+ return nil , fmt .Errorf ("look up type with ID %d (first ID is %d): %w" , id , s .imm . firstTypeID , ErrNotFound )
537
655
}
538
656
539
657
return typ , nil
540
658
}
541
659
542
- func (s * Spec ) typeByID (id TypeID ) (Type , bool ) {
543
- if id < s .firstTypeID {
544
- return nil , false
545
- }
546
-
547
- index := int (id - s .firstTypeID )
548
- if index >= len (s .types ) {
549
- return nil , false
550
- }
551
-
552
- return s .types [index ], true
553
- }
554
-
555
660
// TypeID returns the ID for a given Type.
556
661
//
557
662
// Returns an error wrapping ErrNoFound if the type isn't part of the Spec.
558
663
func (s * Spec ) TypeID (typ Type ) (TypeID , error ) {
559
- if _ , ok := typ .(* Void ); ok {
560
- // Equality is weird for void, since it is a zero sized type.
561
- return 0 , nil
562
- }
563
-
564
- id , ok := s .typeIDs [typ ]
565
- if ! ok {
566
- return 0 , fmt .Errorf ("no ID for type %s: %w" , typ , ErrNotFound )
567
- }
568
-
569
- return id , nil
664
+ return s .mutableTypes .typeID (typ )
570
665
}
571
666
572
667
// AnyTypesByName returns a list of BTF Types with the given name.
@@ -577,21 +672,7 @@ func (s *Spec) TypeID(typ Type) (TypeID, error) {
577
672
//
578
673
// Returns an error wrapping ErrNotFound if no matching Type exists in the Spec.
579
674
func (s * Spec ) AnyTypesByName (name string ) ([]Type , error ) {
580
- types := s .namedTypes [newEssentialName (name )]
581
- if len (types ) == 0 {
582
- return nil , fmt .Errorf ("type name %s: %w" , name , ErrNotFound )
583
- }
584
-
585
- // Return a copy to prevent changes to namedTypes.
586
- result := make ([]Type , 0 , len (types ))
587
- for _ , t := range types {
588
- // Match against the full name, not just the essential one
589
- // in case the type being looked up is a struct flavor.
590
- if t .TypeName () == name {
591
- result = append (result , t )
592
- }
593
- }
594
- return result , nil
675
+ return s .mutableTypes .anyTypesByName (name )
595
676
}
596
677
597
678
// AnyTypeByName returns a Type with the given name.
@@ -689,7 +770,7 @@ type TypesIterator struct {
689
770
690
771
// Iterate returns the types iterator.
691
772
func (s * Spec ) Iterate () * TypesIterator {
692
- return & TypesIterator {spec : s , id : s .firstTypeID }
773
+ return & TypesIterator {spec : s , id : s .imm . firstTypeID }
693
774
}
694
775
695
776
// Next returns true as long as there are any remaining types.
0 commit comments