github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/btf/btf.go (about) 1 package btf 2 3 import ( 4 "bufio" 5 "debug/elf" 6 "encoding/binary" 7 "errors" 8 "fmt" 9 "io" 10 "math" 11 "os" 12 "reflect" 13 "sync" 14 15 "github.com/cilium/ebpf/internal" 16 "github.com/cilium/ebpf/internal/sys" 17 ) 18 19 const btfMagic = 0xeB9F 20 21 // Errors returned by BTF functions. 22 var ( 23 ErrNotSupported = internal.ErrNotSupported 24 ErrNotFound = errors.New("not found") 25 ErrNoExtendedInfo = errors.New("no extended info") 26 ErrMultipleMatches = errors.New("multiple matching types") 27 ) 28 29 // ID represents the unique ID of a BTF object. 30 type ID = sys.BTFID 31 32 // immutableTypes is a set of types which musn't be changed. 33 type immutableTypes struct { 34 // All types contained by the spec, not including types from the base in 35 // case the spec was parsed from split BTF. 36 types []Type 37 38 // Type IDs indexed by type. 39 typeIDs map[Type]TypeID 40 41 // The ID of the first type in types. 42 firstTypeID TypeID 43 44 // Types indexed by essential name. 45 // Includes all struct flavors and types with the same name. 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 mu *sync.RWMutex // protects copies below 70 copies map[Type]Type // map[orig]copy 71 copiedTypeIDs map[Type]TypeID // map[copy]origID 72 } 73 74 // add a type to the set of mutable types. 75 // 76 // Copies type and all of its children once. Repeated calls with the same type 77 // do not copy again. 78 func (mt *mutableTypes) add(typ Type, typeIDs map[Type]TypeID) Type { 79 mt.mu.RLock() 80 cpy, ok := mt.copies[typ] 81 mt.mu.RUnlock() 82 83 if ok { 84 // Fast path: the type has been copied before. 85 return cpy 86 } 87 88 // modifyGraphPreorder copies the type graph node by node, so we can't drop 89 // the lock in between. 90 mt.mu.Lock() 91 defer mt.mu.Unlock() 92 93 return copyType(typ, typeIDs, mt.copies, mt.copiedTypeIDs) 94 } 95 96 // copy a set of mutable types. 97 func (mt *mutableTypes) copy() mutableTypes { 98 mtCopy := mutableTypes{ 99 mt.imm, 100 &sync.RWMutex{}, 101 make(map[Type]Type, len(mt.copies)), 102 make(map[Type]TypeID, len(mt.copiedTypeIDs)), 103 } 104 105 // Prevent concurrent modification of mt.copiedTypeIDs. 106 mt.mu.RLock() 107 defer mt.mu.RUnlock() 108 109 copiesOfCopies := make(map[Type]Type, len(mt.copies)) 110 for orig, copy := range mt.copies { 111 // NB: We make a copy of copy, not orig, so that changes to mutable types 112 // are preserved. 113 copyOfCopy := copyType(copy, mt.copiedTypeIDs, copiesOfCopies, mtCopy.copiedTypeIDs) 114 mtCopy.copies[orig] = copyOfCopy 115 } 116 117 return mtCopy 118 } 119 120 func (mt *mutableTypes) typeID(typ Type) (TypeID, error) { 121 if _, ok := typ.(*Void); ok { 122 // Equality is weird for void, since it is a zero sized type. 123 return 0, nil 124 } 125 126 mt.mu.RLock() 127 defer mt.mu.RUnlock() 128 129 id, ok := mt.copiedTypeIDs[typ] 130 if !ok { 131 return 0, fmt.Errorf("no ID for type %s: %w", typ, ErrNotFound) 132 } 133 134 return id, nil 135 } 136 137 func (mt *mutableTypes) typeByID(id TypeID) (Type, bool) { 138 immT, ok := mt.imm.typeByID(id) 139 if !ok { 140 return nil, false 141 } 142 143 return mt.add(immT, mt.imm.typeIDs), true 144 } 145 146 func (mt *mutableTypes) anyTypesByName(name string) ([]Type, error) { 147 immTypes := mt.imm.namedTypes[newEssentialName(name)] 148 if len(immTypes) == 0 { 149 return nil, fmt.Errorf("type name %s: %w", name, ErrNotFound) 150 } 151 152 // Return a copy to prevent changes to namedTypes. 153 result := make([]Type, 0, len(immTypes)) 154 for _, id := range immTypes { 155 immT, ok := mt.imm.typeByID(id) 156 if !ok { 157 return nil, fmt.Errorf("no type with ID %d", id) 158 } 159 160 // Match against the full name, not just the essential one 161 // in case the type being looked up is a struct flavor. 162 if immT.TypeName() == name { 163 result = append(result, mt.add(immT, mt.imm.typeIDs)) 164 } 165 } 166 return result, nil 167 } 168 169 // Spec allows querying a set of Types and loading the set into the 170 // kernel. 171 type Spec struct { 172 mutableTypes 173 174 // String table from ELF. 175 strings *stringTable 176 } 177 178 // LoadSpec opens file and calls LoadSpecFromReader on it. 179 func LoadSpec(file string) (*Spec, error) { 180 fh, err := os.Open(file) 181 if err != nil { 182 return nil, err 183 } 184 defer fh.Close() 185 186 return LoadSpecFromReader(fh) 187 } 188 189 // LoadSpecFromReader reads from an ELF or a raw BTF blob. 190 // 191 // Returns ErrNotFound if reading from an ELF which contains no BTF. ExtInfos 192 // may be nil. 193 func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) { 194 file, err := internal.NewSafeELFFile(rd) 195 if err != nil { 196 if bo := guessRawBTFByteOrder(rd); bo != nil { 197 return loadRawSpec(io.NewSectionReader(rd, 0, math.MaxInt64), bo, nil) 198 } 199 200 return nil, err 201 } 202 203 return loadSpecFromELF(file) 204 } 205 206 // LoadSpecAndExtInfosFromReader reads from an ELF. 207 // 208 // ExtInfos may be nil if the ELF doesn't contain section metadata. 209 // Returns ErrNotFound if the ELF contains no BTF. 210 func LoadSpecAndExtInfosFromReader(rd io.ReaderAt) (*Spec, *ExtInfos, error) { 211 file, err := internal.NewSafeELFFile(rd) 212 if err != nil { 213 return nil, nil, err 214 } 215 216 spec, err := loadSpecFromELF(file) 217 if err != nil { 218 return nil, nil, err 219 } 220 221 extInfos, err := loadExtInfosFromELF(file, spec) 222 if err != nil && !errors.Is(err, ErrNotFound) { 223 return nil, nil, err 224 } 225 226 return spec, extInfos, nil 227 } 228 229 // symbolOffsets extracts all symbols offsets from an ELF and indexes them by 230 // section and variable name. 231 // 232 // References to variables in BTF data sections carry unsigned 32-bit offsets. 233 // Some ELF symbols (e.g. in vmlinux) may point to virtual memory that is well 234 // beyond this range. Since these symbols cannot be described by BTF info, 235 // ignore them here. 236 func symbolOffsets(file *internal.SafeELFFile) (map[symbol]uint32, error) { 237 symbols, err := file.Symbols() 238 if err != nil { 239 return nil, fmt.Errorf("can't read symbols: %v", err) 240 } 241 242 offsets := make(map[symbol]uint32) 243 for _, sym := range symbols { 244 if idx := sym.Section; idx >= elf.SHN_LORESERVE && idx <= elf.SHN_HIRESERVE { 245 // Ignore things like SHN_ABS 246 continue 247 } 248 249 if sym.Value > math.MaxUint32 { 250 // VarSecinfo offset is u32, cannot reference symbols in higher regions. 251 continue 252 } 253 254 if int(sym.Section) >= len(file.Sections) { 255 return nil, fmt.Errorf("symbol %s: invalid section %d", sym.Name, sym.Section) 256 } 257 258 secName := file.Sections[sym.Section].Name 259 offsets[symbol{secName, sym.Name}] = uint32(sym.Value) 260 } 261 262 return offsets, nil 263 } 264 265 func loadSpecFromELF(file *internal.SafeELFFile) (*Spec, error) { 266 var ( 267 btfSection *elf.Section 268 sectionSizes = make(map[string]uint32) 269 ) 270 271 for _, sec := range file.Sections { 272 switch sec.Name { 273 case ".BTF": 274 btfSection = sec 275 default: 276 if sec.Type != elf.SHT_PROGBITS && sec.Type != elf.SHT_NOBITS { 277 break 278 } 279 280 if sec.Size > math.MaxUint32 { 281 return nil, fmt.Errorf("section %s exceeds maximum size", sec.Name) 282 } 283 284 sectionSizes[sec.Name] = uint32(sec.Size) 285 } 286 } 287 288 if btfSection == nil { 289 return nil, fmt.Errorf("btf: %w", ErrNotFound) 290 } 291 292 offsets, err := symbolOffsets(file) 293 if err != nil { 294 return nil, err 295 } 296 297 if btfSection.ReaderAt == nil { 298 return nil, fmt.Errorf("compressed BTF is not supported") 299 } 300 301 spec, err := loadRawSpec(btfSection.ReaderAt, file.ByteOrder, nil) 302 if err != nil { 303 return nil, err 304 } 305 306 err = fixupDatasec(spec.imm.types, sectionSizes, offsets) 307 if err != nil { 308 return nil, err 309 } 310 311 return spec, nil 312 } 313 314 func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder, base *Spec) (*Spec, error) { 315 var ( 316 baseStrings *stringTable 317 firstTypeID TypeID 318 err error 319 ) 320 321 if base != nil { 322 if base.imm.firstTypeID != 0 { 323 return nil, fmt.Errorf("can't use split BTF as base") 324 } 325 326 baseStrings = base.strings 327 328 firstTypeID, err = base.nextTypeID() 329 if err != nil { 330 return nil, err 331 } 332 } 333 334 types, rawStrings, err := parseBTF(btf, bo, baseStrings, base) 335 if err != nil { 336 return nil, err 337 } 338 339 typeIDs, typesByName := indexTypes(types, firstTypeID) 340 341 return &Spec{ 342 mutableTypes{ 343 immutableTypes{ 344 types, 345 typeIDs, 346 firstTypeID, 347 typesByName, 348 bo, 349 }, 350 &sync.RWMutex{}, 351 make(map[Type]Type), 352 make(map[Type]TypeID), 353 }, 354 rawStrings, 355 }, nil 356 } 357 358 func indexTypes(types []Type, firstTypeID TypeID) (map[Type]TypeID, map[essentialName][]TypeID) { 359 namedTypes := 0 360 for _, typ := range types { 361 if typ.TypeName() != "" { 362 // Do a pre-pass to figure out how big types by name has to be. 363 // Most types have unique names, so it's OK to ignore essentialName 364 // here. 365 namedTypes++ 366 } 367 } 368 369 typeIDs := make(map[Type]TypeID, len(types)) 370 typesByName := make(map[essentialName][]TypeID, namedTypes) 371 372 for i, typ := range types { 373 id := firstTypeID + TypeID(i) 374 typeIDs[typ] = id 375 376 if name := newEssentialName(typ.TypeName()); name != "" { 377 typesByName[name] = append(typesByName[name], id) 378 } 379 } 380 381 return typeIDs, typesByName 382 } 383 384 func guessRawBTFByteOrder(r io.ReaderAt) binary.ByteOrder { 385 buf := new(bufio.Reader) 386 for _, bo := range []binary.ByteOrder{ 387 binary.LittleEndian, 388 binary.BigEndian, 389 } { 390 buf.Reset(io.NewSectionReader(r, 0, math.MaxInt64)) 391 if _, err := parseBTFHeader(buf, bo); err == nil { 392 return bo 393 } 394 } 395 396 return nil 397 } 398 399 // parseBTF reads a .BTF section into memory and parses it into a list of 400 // raw types and a string table. 401 func parseBTF(btf io.ReaderAt, bo binary.ByteOrder, baseStrings *stringTable, base *Spec) ([]Type, *stringTable, error) { 402 buf := internal.NewBufferedSectionReader(btf, 0, math.MaxInt64) 403 header, err := parseBTFHeader(buf, bo) 404 if err != nil { 405 return nil, nil, fmt.Errorf("parsing .BTF header: %v", err) 406 } 407 408 rawStrings, err := readStringTable(io.NewSectionReader(btf, header.stringStart(), int64(header.StringLen)), 409 baseStrings) 410 if err != nil { 411 return nil, nil, fmt.Errorf("can't read type names: %w", err) 412 } 413 414 buf.Reset(io.NewSectionReader(btf, header.typeStart(), int64(header.TypeLen))) 415 types, err := readAndInflateTypes(buf, bo, header.TypeLen, rawStrings, base) 416 if err != nil { 417 return nil, nil, err 418 } 419 420 return types, rawStrings, nil 421 } 422 423 type symbol struct { 424 section string 425 name string 426 } 427 428 // fixupDatasec attempts to patch up missing info in Datasecs and its members by 429 // supplementing them with information from the ELF headers and symbol table. 430 func fixupDatasec(types []Type, sectionSizes map[string]uint32, offsets map[symbol]uint32) error { 431 for _, typ := range types { 432 ds, ok := typ.(*Datasec) 433 if !ok { 434 continue 435 } 436 437 name := ds.Name 438 439 // Some Datasecs are virtual and don't have corresponding ELF sections. 440 switch name { 441 case ".ksyms": 442 // .ksyms describes forward declarations of kfunc signatures. 443 // Nothing to fix up, all sizes and offsets are 0. 444 for _, vsi := range ds.Vars { 445 _, ok := vsi.Type.(*Func) 446 if !ok { 447 // Only Funcs are supported in the .ksyms Datasec. 448 return fmt.Errorf("data section %s: expected *btf.Func, not %T: %w", name, vsi.Type, ErrNotSupported) 449 } 450 } 451 452 continue 453 case ".kconfig": 454 // .kconfig has a size of 0 and has all members' offsets set to 0. 455 // Fix up all offsets and set the Datasec's size. 456 if err := fixupDatasecLayout(ds); err != nil { 457 return err 458 } 459 460 // Fix up extern to global linkage to avoid a BTF verifier error. 461 for _, vsi := range ds.Vars { 462 vsi.Type.(*Var).Linkage = GlobalVar 463 } 464 465 continue 466 } 467 468 if ds.Size != 0 { 469 continue 470 } 471 472 ds.Size, ok = sectionSizes[name] 473 if !ok { 474 return fmt.Errorf("data section %s: missing size", name) 475 } 476 477 for i := range ds.Vars { 478 symName := ds.Vars[i].Type.TypeName() 479 ds.Vars[i].Offset, ok = offsets[symbol{name, symName}] 480 if !ok { 481 return fmt.Errorf("data section %s: missing offset for symbol %s", name, symName) 482 } 483 } 484 } 485 486 return nil 487 } 488 489 // fixupDatasecLayout populates ds.Vars[].Offset according to var sizes and 490 // alignment. Calculate and set ds.Size. 491 func fixupDatasecLayout(ds *Datasec) error { 492 var off uint32 493 494 for i, vsi := range ds.Vars { 495 v, ok := vsi.Type.(*Var) 496 if !ok { 497 return fmt.Errorf("member %d: unsupported type %T", i, vsi.Type) 498 } 499 500 size, err := Sizeof(v.Type) 501 if err != nil { 502 return fmt.Errorf("variable %s: getting size: %w", v.Name, err) 503 } 504 align, err := alignof(v.Type) 505 if err != nil { 506 return fmt.Errorf("variable %s: getting alignment: %w", v.Name, err) 507 } 508 509 // Align the current member based on the offset of the end of the previous 510 // member and the alignment of the current member. 511 off = internal.Align(off, uint32(align)) 512 513 ds.Vars[i].Offset = off 514 515 off += uint32(size) 516 } 517 518 ds.Size = off 519 520 return nil 521 } 522 523 // Copy creates a copy of Spec. 524 func (s *Spec) Copy() *Spec { 525 return &Spec{ 526 s.mutableTypes.copy(), 527 s.strings, 528 } 529 } 530 531 type sliceWriter []byte 532 533 func (sw sliceWriter) Write(p []byte) (int, error) { 534 if len(p) != len(sw) { 535 return 0, errors.New("size doesn't match") 536 } 537 538 return copy(sw, p), nil 539 } 540 541 // nextTypeID returns the next unallocated type ID or an error if there are no 542 // more type IDs. 543 func (s *Spec) nextTypeID() (TypeID, error) { 544 id := s.imm.firstTypeID + TypeID(len(s.imm.types)) 545 if id < s.imm.firstTypeID { 546 return 0, fmt.Errorf("no more type IDs") 547 } 548 return id, nil 549 } 550 551 // TypeByID returns the BTF Type with the given type ID. 552 // 553 // Returns an error wrapping ErrNotFound if a Type with the given ID 554 // does not exist in the Spec. 555 func (s *Spec) TypeByID(id TypeID) (Type, error) { 556 typ, ok := s.typeByID(id) 557 if !ok { 558 return nil, fmt.Errorf("look up type with ID %d (first ID is %d): %w", id, s.imm.firstTypeID, ErrNotFound) 559 } 560 561 return typ, nil 562 } 563 564 // TypeID returns the ID for a given Type. 565 // 566 // Returns an error wrapping [ErrNotFound] if the type isn't part of the Spec. 567 func (s *Spec) TypeID(typ Type) (TypeID, error) { 568 return s.mutableTypes.typeID(typ) 569 } 570 571 // AnyTypesByName returns a list of BTF Types with the given name. 572 // 573 // If the BTF blob describes multiple compilation units like vmlinux, multiple 574 // Types with the same name and kind can exist, but might not describe the same 575 // data structure. 576 // 577 // Returns an error wrapping ErrNotFound if no matching Type exists in the Spec. 578 func (s *Spec) AnyTypesByName(name string) ([]Type, error) { 579 return s.mutableTypes.anyTypesByName(name) 580 } 581 582 // AnyTypeByName returns a Type with the given name. 583 // 584 // Returns an error if multiple types of that name exist. 585 func (s *Spec) AnyTypeByName(name string) (Type, error) { 586 types, err := s.AnyTypesByName(name) 587 if err != nil { 588 return nil, err 589 } 590 591 if len(types) > 1 { 592 return nil, fmt.Errorf("found multiple types: %v", types) 593 } 594 595 return types[0], nil 596 } 597 598 // TypeByName searches for a Type with a specific name. Since multiple Types 599 // with the same name can exist, the parameter typ is taken to narrow down the 600 // search in case of a clash. 601 // 602 // typ must be a non-nil pointer to an implementation of a Type. On success, the 603 // address of the found Type will be copied to typ. 604 // 605 // Returns an error wrapping ErrNotFound if no matching Type exists in the Spec. 606 // Returns an error wrapping ErrMultipleTypes if multiple candidates are found. 607 func (s *Spec) TypeByName(name string, typ interface{}) error { 608 typeInterface := reflect.TypeOf((*Type)(nil)).Elem() 609 610 // typ may be **T or *Type 611 typValue := reflect.ValueOf(typ) 612 if typValue.Kind() != reflect.Ptr { 613 return fmt.Errorf("%T is not a pointer", typ) 614 } 615 616 typPtr := typValue.Elem() 617 if !typPtr.CanSet() { 618 return fmt.Errorf("%T cannot be set", typ) 619 } 620 621 wanted := typPtr.Type() 622 if wanted == typeInterface { 623 // This is *Type. Unwrap the value's type. 624 wanted = typPtr.Elem().Type() 625 } 626 627 if !wanted.AssignableTo(typeInterface) { 628 return fmt.Errorf("%T does not satisfy Type interface", typ) 629 } 630 631 types, err := s.AnyTypesByName(name) 632 if err != nil { 633 return err 634 } 635 636 var candidate Type 637 for _, typ := range types { 638 if reflect.TypeOf(typ) != wanted { 639 continue 640 } 641 642 if candidate != nil { 643 return fmt.Errorf("type %s(%T): %w", name, typ, ErrMultipleMatches) 644 } 645 646 candidate = typ 647 } 648 649 if candidate == nil { 650 return fmt.Errorf("%s %s: %w", wanted, name, ErrNotFound) 651 } 652 653 typPtr.Set(reflect.ValueOf(candidate)) 654 655 return nil 656 } 657 658 // LoadSplitSpecFromReader loads split BTF from a reader. 659 // 660 // Types from base are used to resolve references in the split BTF. 661 // The returned Spec only contains types from the split BTF, not from the base. 662 func LoadSplitSpecFromReader(r io.ReaderAt, base *Spec) (*Spec, error) { 663 return loadRawSpec(r, internal.NativeEndian, base) 664 } 665 666 // TypesIterator iterates over types of a given spec. 667 type TypesIterator struct { 668 spec *Spec 669 id TypeID 670 done bool 671 // The last visited type in the spec. 672 Type Type 673 } 674 675 // Iterate returns the types iterator. 676 func (s *Spec) Iterate() *TypesIterator { 677 return &TypesIterator{spec: s, id: s.imm.firstTypeID} 678 } 679 680 // Next returns true as long as there are any remaining types. 681 func (iter *TypesIterator) Next() bool { 682 if iter.done { 683 return false 684 } 685 686 var ok bool 687 iter.Type, ok = iter.spec.typeByID(iter.id) 688 iter.id++ 689 iter.done = !ok 690 return !iter.done 691 }