8
8
"fmt"
9
9
"io"
10
10
"iter"
11
+ "maps"
11
12
"math"
12
13
"os"
13
14
"reflect"
@@ -152,13 +153,27 @@ func (mt *mutableTypes) typeIDsByName(name essentialName) []TypeID {
152
153
return mt .imm .namedTypes [name ]
153
154
}
154
155
156
+ type elfData struct {
157
+ sectionSizes map [string ]uint32
158
+ symbolOffsets map [elfSymbol ]uint32
159
+ fixups map [Type ]bool
160
+ }
161
+
162
+ type elfSymbol struct {
163
+ section string
164
+ name string
165
+ }
166
+
155
167
// Spec allows querying a set of Types and loading the set into the
156
168
// kernel.
157
169
type Spec struct {
158
170
* mutableTypes
159
171
160
172
// String table from ELF.
161
173
strings * stringTable
174
+
175
+ // Additional data from ELF, may be nil.
176
+ elf * elfData
162
177
}
163
178
164
179
// LoadSpec opens file and calls LoadSpecFromReader on it.
@@ -219,13 +234,13 @@ func LoadSpecAndExtInfosFromReader(rd io.ReaderAt) (*Spec, *ExtInfos, error) {
219
234
// Some ELF symbols (e.g. in vmlinux) may point to virtual memory that is well
220
235
// beyond this range. Since these symbols cannot be described by BTF info,
221
236
// ignore them here.
222
- func symbolOffsets (file * internal.SafeELFFile ) (map [symbol ]uint32 , error ) {
237
+ func symbolOffsets (file * internal.SafeELFFile ) (map [elfSymbol ]uint32 , error ) {
223
238
symbols , err := file .Symbols ()
224
239
if err != nil {
225
240
return nil , fmt .Errorf ("can't read symbols: %v" , err )
226
241
}
227
242
228
- offsets := make (map [symbol ]uint32 )
243
+ offsets := make (map [elfSymbol ]uint32 )
229
244
for _ , sym := range symbols {
230
245
if idx := sym .Section ; idx >= elf .SHN_LORESERVE && idx <= elf .SHN_HIRESERVE {
231
246
// Ignore things like SHN_ABS
@@ -242,7 +257,7 @@ func symbolOffsets(file *internal.SafeELFFile) (map[symbol]uint32, error) {
242
257
}
243
258
244
259
secName := file .Sections [sym .Section ].Name
245
- offsets [symbol {secName , sym .Name }] = uint32 (sym .Value )
260
+ offsets [elfSymbol {secName , sym .Name }] = uint32 (sym .Value )
246
261
}
247
262
248
263
return offsets , nil
@@ -289,9 +304,10 @@ func loadSpecFromELF(file *internal.SafeELFFile) (*Spec, error) {
289
304
return nil , err
290
305
}
291
306
292
- err = fixupDatasec (spec .imm .types , sectionSizes , offsets )
293
- if err != nil {
294
- return nil , err
307
+ spec .elf = & elfData {
308
+ sectionSizes ,
309
+ offsets ,
310
+ make (map [Type ]bool ),
295
311
}
296
312
297
313
return spec , nil
@@ -351,6 +367,7 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error
351
367
make (map [Type ]TypeID ),
352
368
},
353
369
rawStrings ,
370
+ nil ,
354
371
}, nil
355
372
}
356
373
@@ -395,19 +412,14 @@ func guessRawBTFByteOrder(r io.ReaderAt) binary.ByteOrder {
395
412
return nil
396
413
}
397
414
398
- type symbol struct {
399
- section string
400
- name string
401
- }
402
-
403
415
// fixupDatasec attempts to patch up missing info in Datasecs and its members by
404
416
// supplementing them with information from the ELF headers and symbol table.
405
- func fixupDatasec (types []Type , sectionSizes map [string ]uint32 , offsets map [symbol ]uint32 ) error {
406
- for _ , typ := range types {
407
- ds , ok := typ .(* Datasec )
408
- if ! ok {
409
- continue
417
+ func (elf * elfData ) fixupDatasec (typ Type ) error {
418
+ if ds , ok := typ .(* Datasec ); ok {
419
+ if elf .fixups [ds ] {
420
+ return nil
410
421
}
422
+ elf .fixups [ds ] = true
411
423
412
424
name := ds .Name
413
425
@@ -430,7 +442,7 @@ func fixupDatasec(types []Type, sectionSizes map[string]uint32, offsets map[symb
430
442
}
431
443
}
432
444
433
- continue
445
+ return nil
434
446
case ".kconfig" :
435
447
// .kconfig has a size of 0 and has all members' offsets set to 0.
436
448
// Fix up all offsets and set the Datasec's size.
@@ -443,21 +455,21 @@ func fixupDatasec(types []Type, sectionSizes map[string]uint32, offsets map[symb
443
455
vsi .Type .(* Var ).Linkage = GlobalVar
444
456
}
445
457
446
- continue
458
+ return nil
447
459
}
448
460
449
461
if ds .Size != 0 {
450
- continue
462
+ return nil
451
463
}
452
464
453
- ds .Size , ok = sectionSizes [name ]
465
+ ds .Size , ok = elf . sectionSizes [name ]
454
466
if ! ok {
455
467
return fmt .Errorf ("data section %s: missing size" , name )
456
468
}
457
469
458
470
for i := range ds .Vars {
459
471
symName := ds .Vars [i ].Type .TypeName ()
460
- ds .Vars [i ].Offset , ok = offsets [ symbol {name , symName }]
472
+ ds .Vars [i ].Offset , ok = elf . symbolOffsets [ elfSymbol {name , symName }]
461
473
if ! ok {
462
474
return fmt .Errorf ("data section %s: missing offset for symbol %s" , name , symName )
463
475
}
@@ -507,10 +519,21 @@ func (s *Spec) Copy() *Spec {
507
519
return nil
508
520
}
509
521
510
- return & Spec {
522
+ cpy := & Spec {
511
523
s .copy (),
512
524
s .strings ,
525
+ nil ,
526
+ }
527
+
528
+ if s .elf != nil {
529
+ cpy .elf = & elfData {
530
+ s .elf .sectionSizes ,
531
+ s .elf .symbolOffsets ,
532
+ maps .Clone (s .elf .fixups ),
533
+ }
513
534
}
535
+
536
+ return cpy
514
537
}
515
538
516
539
// nextTypeID returns the next unallocated type ID or an error if there are no
@@ -533,6 +556,14 @@ func (s *Spec) TypeByID(id TypeID) (Type, error) {
533
556
return nil , fmt .Errorf ("look up type with ID %d (first ID is %d): %w" , id , s .imm .firstTypeID , ErrNotFound )
534
557
}
535
558
559
+ if s .elf == nil {
560
+ return typ , nil
561
+ }
562
+
563
+ if err := s .elf .fixupDatasec (typ ); err != nil {
564
+ return nil , err
565
+ }
566
+
536
567
return typ , nil
537
568
}
538
569
0 commit comments