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