Skip to content

Commit ad86aa6

Browse files
committed
btf: move Datasec fixups
Some Datasec are not correctly populated when parsing BTF from an ELF file (vs. raw vmlinux BTF). To address this we currently do a full pass over all types to find Datasec that need fixing up. Instead, perform the fixup when retrieving a Type from a Spec. Spec loaded from a raw BTF blob are kept unchanged. Signed-off-by: Lorenz Bauer <lmb@isovalent.com>
1 parent 2b5887b commit ad86aa6

File tree

1 file changed

+53
-22
lines changed

1 file changed

+53
-22
lines changed

btf/btf.go

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"io"
1010
"iter"
11+
"maps"
1112
"math"
1213
"os"
1314
"reflect"
@@ -152,13 +153,27 @@ func (mt *mutableTypes) typeIDsByName(name essentialName) []TypeID {
152153
return mt.imm.namedTypes[name]
153154
}
154155

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+
155167
// Spec allows querying a set of Types and loading the set into the
156168
// kernel.
157169
type Spec struct {
158170
*mutableTypes
159171

160172
// String table from ELF.
161173
strings *stringTable
174+
175+
// Additional data from ELF, may be nil.
176+
elf *elfData
162177
}
163178

164179
// LoadSpec opens file and calls LoadSpecFromReader on it.
@@ -219,13 +234,13 @@ func LoadSpecAndExtInfosFromReader(rd io.ReaderAt) (*Spec, *ExtInfos, error) {
219234
// Some ELF symbols (e.g. in vmlinux) may point to virtual memory that is well
220235
// beyond this range. Since these symbols cannot be described by BTF info,
221236
// ignore them here.
222-
func symbolOffsets(file *internal.SafeELFFile) (map[symbol]uint32, error) {
237+
func symbolOffsets(file *internal.SafeELFFile) (map[elfSymbol]uint32, error) {
223238
symbols, err := file.Symbols()
224239
if err != nil {
225240
return nil, fmt.Errorf("can't read symbols: %v", err)
226241
}
227242

228-
offsets := make(map[symbol]uint32)
243+
offsets := make(map[elfSymbol]uint32)
229244
for _, sym := range symbols {
230245
if idx := sym.Section; idx >= elf.SHN_LORESERVE && idx <= elf.SHN_HIRESERVE {
231246
// Ignore things like SHN_ABS
@@ -242,7 +257,7 @@ func symbolOffsets(file *internal.SafeELFFile) (map[symbol]uint32, error) {
242257
}
243258

244259
secName := file.Sections[sym.Section].Name
245-
offsets[symbol{secName, sym.Name}] = uint32(sym.Value)
260+
offsets[elfSymbol{secName, sym.Name}] = uint32(sym.Value)
246261
}
247262

248263
return offsets, nil
@@ -289,9 +304,10 @@ func loadSpecFromELF(file *internal.SafeELFFile) (*Spec, error) {
289304
return nil, err
290305
}
291306

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),
295311
}
296312

297313
return spec, nil
@@ -351,6 +367,7 @@ func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error
351367
make(map[Type]TypeID),
352368
},
353369
rawStrings,
370+
nil,
354371
}, nil
355372
}
356373

@@ -395,19 +412,14 @@ func guessRawBTFByteOrder(r io.ReaderAt) binary.ByteOrder {
395412
return nil
396413
}
397414

398-
type symbol struct {
399-
section string
400-
name string
401-
}
402-
403415
// fixupDatasec attempts to patch up missing info in Datasecs and its members by
404416
// 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
410421
}
422+
elf.fixups[ds] = true
411423

412424
name := ds.Name
413425

@@ -430,7 +442,7 @@ func fixupDatasec(types []Type, sectionSizes map[string]uint32, offsets map[symb
430442
}
431443
}
432444

433-
continue
445+
return nil
434446
case ".kconfig":
435447
// .kconfig has a size of 0 and has all members' offsets set to 0.
436448
// 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
443455
vsi.Type.(*Var).Linkage = GlobalVar
444456
}
445457

446-
continue
458+
return nil
447459
}
448460

449461
if ds.Size != 0 {
450-
continue
462+
return nil
451463
}
452464

453-
ds.Size, ok = sectionSizes[name]
465+
ds.Size, ok = elf.sectionSizes[name]
454466
if !ok {
455467
return fmt.Errorf("data section %s: missing size", name)
456468
}
457469

458470
for i := range ds.Vars {
459471
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}]
461473
if !ok {
462474
return fmt.Errorf("data section %s: missing offset for symbol %s", name, symName)
463475
}
@@ -507,10 +519,21 @@ func (s *Spec) Copy() *Spec {
507519
return nil
508520
}
509521

510-
return &Spec{
522+
cpy := &Spec{
511523
s.copy(),
512524
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+
}
513534
}
535+
536+
return cpy
514537
}
515538

516539
// 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) {
533556
return nil, fmt.Errorf("look up type with ID %d (first ID is %d): %w", id, s.imm.firstTypeID, ErrNotFound)
534557
}
535558

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+
536567
return typ, nil
537568
}
538569

0 commit comments

Comments
 (0)