btf.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. package btf
  2. import (
  3. "bufio"
  4. "bytes"
  5. "debug/elf"
  6. "encoding/binary"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "math"
  11. "os"
  12. "reflect"
  13. "github.com/cilium/ebpf/internal"
  14. "github.com/cilium/ebpf/internal/sys"
  15. "github.com/cilium/ebpf/internal/unix"
  16. )
  17. const btfMagic = 0xeB9F
  18. // Errors returned by BTF functions.
  19. var (
  20. ErrNotSupported = internal.ErrNotSupported
  21. ErrNotFound = errors.New("not found")
  22. ErrNoExtendedInfo = errors.New("no extended info")
  23. )
  24. // ID represents the unique ID of a BTF object.
  25. type ID = sys.BTFID
  26. // Spec represents decoded BTF.
  27. type Spec struct {
  28. // Data from .BTF.
  29. rawTypes []rawType
  30. strings *stringTable
  31. // All types contained by the spec. For the base type, the position of
  32. // a type in the slice is its ID.
  33. types types
  34. // Type IDs indexed by type.
  35. typeIDs map[Type]TypeID
  36. // Types indexed by essential name.
  37. // Includes all struct flavors and types with the same name.
  38. namedTypes map[essentialName][]Type
  39. byteOrder binary.ByteOrder
  40. }
  41. type btfHeader struct {
  42. Magic uint16
  43. Version uint8
  44. Flags uint8
  45. HdrLen uint32
  46. TypeOff uint32
  47. TypeLen uint32
  48. StringOff uint32
  49. StringLen uint32
  50. }
  51. // typeStart returns the offset from the beginning of the .BTF section
  52. // to the start of its type entries.
  53. func (h *btfHeader) typeStart() int64 {
  54. return int64(h.HdrLen + h.TypeOff)
  55. }
  56. // stringStart returns the offset from the beginning of the .BTF section
  57. // to the start of its string table.
  58. func (h *btfHeader) stringStart() int64 {
  59. return int64(h.HdrLen + h.StringOff)
  60. }
  61. // LoadSpec opens file and calls LoadSpecFromReader on it.
  62. func LoadSpec(file string) (*Spec, error) {
  63. fh, err := os.Open(file)
  64. if err != nil {
  65. return nil, err
  66. }
  67. defer fh.Close()
  68. return LoadSpecFromReader(fh)
  69. }
  70. // LoadSpecFromReader reads from an ELF or a raw BTF blob.
  71. //
  72. // Returns ErrNotFound if reading from an ELF which contains no BTF. ExtInfos
  73. // may be nil.
  74. func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
  75. file, err := internal.NewSafeELFFile(rd)
  76. if err != nil {
  77. if bo := guessRawBTFByteOrder(rd); bo != nil {
  78. // Try to parse a naked BTF blob. This will return an error if
  79. // we encounter a Datasec, since we can't fix it up.
  80. spec, err := loadRawSpec(io.NewSectionReader(rd, 0, math.MaxInt64), bo, nil, nil)
  81. return spec, err
  82. }
  83. return nil, err
  84. }
  85. return loadSpecFromELF(file)
  86. }
  87. // LoadSpecAndExtInfosFromReader reads from an ELF.
  88. //
  89. // ExtInfos may be nil if the ELF doesn't contain section metadta.
  90. // Returns ErrNotFound if the ELF contains no BTF.
  91. func LoadSpecAndExtInfosFromReader(rd io.ReaderAt) (*Spec, *ExtInfos, error) {
  92. file, err := internal.NewSafeELFFile(rd)
  93. if err != nil {
  94. return nil, nil, err
  95. }
  96. spec, err := loadSpecFromELF(file)
  97. if err != nil {
  98. return nil, nil, err
  99. }
  100. extInfos, err := loadExtInfosFromELF(file, spec.types, spec.strings)
  101. if err != nil && !errors.Is(err, ErrNotFound) {
  102. return nil, nil, err
  103. }
  104. return spec, extInfos, nil
  105. }
  106. // variableOffsets extracts all symbols offsets from an ELF and indexes them by
  107. // section and variable name.
  108. //
  109. // References to variables in BTF data sections carry unsigned 32-bit offsets.
  110. // Some ELF symbols (e.g. in vmlinux) may point to virtual memory that is well
  111. // beyond this range. Since these symbols cannot be described by BTF info,
  112. // ignore them here.
  113. func variableOffsets(file *internal.SafeELFFile) (map[variable]uint32, error) {
  114. symbols, err := file.Symbols()
  115. if err != nil {
  116. return nil, fmt.Errorf("can't read symbols: %v", err)
  117. }
  118. variableOffsets := make(map[variable]uint32)
  119. for _, symbol := range symbols {
  120. if idx := symbol.Section; idx >= elf.SHN_LORESERVE && idx <= elf.SHN_HIRESERVE {
  121. // Ignore things like SHN_ABS
  122. continue
  123. }
  124. if symbol.Value > math.MaxUint32 {
  125. // VarSecinfo offset is u32, cannot reference symbols in higher regions.
  126. continue
  127. }
  128. if int(symbol.Section) >= len(file.Sections) {
  129. return nil, fmt.Errorf("symbol %s: invalid section %d", symbol.Name, symbol.Section)
  130. }
  131. secName := file.Sections[symbol.Section].Name
  132. variableOffsets[variable{secName, symbol.Name}] = uint32(symbol.Value)
  133. }
  134. return variableOffsets, nil
  135. }
  136. func loadSpecFromELF(file *internal.SafeELFFile) (*Spec, error) {
  137. var (
  138. btfSection *elf.Section
  139. sectionSizes = make(map[string]uint32)
  140. )
  141. for _, sec := range file.Sections {
  142. switch sec.Name {
  143. case ".BTF":
  144. btfSection = sec
  145. default:
  146. if sec.Type != elf.SHT_PROGBITS && sec.Type != elf.SHT_NOBITS {
  147. break
  148. }
  149. if sec.Size > math.MaxUint32 {
  150. return nil, fmt.Errorf("section %s exceeds maximum size", sec.Name)
  151. }
  152. sectionSizes[sec.Name] = uint32(sec.Size)
  153. }
  154. }
  155. if btfSection == nil {
  156. return nil, fmt.Errorf("btf: %w", ErrNotFound)
  157. }
  158. vars, err := variableOffsets(file)
  159. if err != nil {
  160. return nil, err
  161. }
  162. if btfSection.ReaderAt == nil {
  163. return nil, fmt.Errorf("compressed BTF is not supported")
  164. }
  165. rawTypes, rawStrings, err := parseBTF(btfSection.ReaderAt, file.ByteOrder, nil)
  166. if err != nil {
  167. return nil, err
  168. }
  169. err = fixupDatasec(rawTypes, rawStrings, sectionSizes, vars)
  170. if err != nil {
  171. return nil, err
  172. }
  173. return inflateSpec(rawTypes, rawStrings, file.ByteOrder, nil)
  174. }
  175. func loadRawSpec(btf io.ReaderAt, bo binary.ByteOrder,
  176. baseTypes types, baseStrings *stringTable) (*Spec, error) {
  177. rawTypes, rawStrings, err := parseBTF(btf, bo, baseStrings)
  178. if err != nil {
  179. return nil, err
  180. }
  181. return inflateSpec(rawTypes, rawStrings, bo, baseTypes)
  182. }
  183. func inflateSpec(rawTypes []rawType, rawStrings *stringTable, bo binary.ByteOrder,
  184. baseTypes types) (*Spec, error) {
  185. types, err := inflateRawTypes(rawTypes, baseTypes, rawStrings)
  186. if err != nil {
  187. return nil, err
  188. }
  189. typeIDs, typesByName := indexTypes(types, TypeID(len(baseTypes)))
  190. return &Spec{
  191. rawTypes: rawTypes,
  192. namedTypes: typesByName,
  193. typeIDs: typeIDs,
  194. types: types,
  195. strings: rawStrings,
  196. byteOrder: bo,
  197. }, nil
  198. }
  199. func indexTypes(types []Type, typeIDOffset TypeID) (map[Type]TypeID, map[essentialName][]Type) {
  200. namedTypes := 0
  201. for _, typ := range types {
  202. if typ.TypeName() != "" {
  203. // Do a pre-pass to figure out how big types by name has to be.
  204. // Most types have unique names, so it's OK to ignore essentialName
  205. // here.
  206. namedTypes++
  207. }
  208. }
  209. typeIDs := make(map[Type]TypeID, len(types))
  210. typesByName := make(map[essentialName][]Type, namedTypes)
  211. for i, typ := range types {
  212. if name := newEssentialName(typ.TypeName()); name != "" {
  213. typesByName[name] = append(typesByName[name], typ)
  214. }
  215. typeIDs[typ] = TypeID(i) + typeIDOffset
  216. }
  217. return typeIDs, typesByName
  218. }
  219. // LoadKernelSpec returns the current kernel's BTF information.
  220. //
  221. // Defaults to /sys/kernel/btf/vmlinux and falls back to scanning the file system
  222. // for vmlinux ELFs. Returns an error wrapping ErrNotSupported if BTF is not enabled.
  223. func LoadKernelSpec() (*Spec, error) {
  224. fh, err := os.Open("/sys/kernel/btf/vmlinux")
  225. if err == nil {
  226. defer fh.Close()
  227. return loadRawSpec(fh, internal.NativeEndian, nil, nil)
  228. }
  229. file, err := findVMLinux()
  230. if err != nil {
  231. return nil, err
  232. }
  233. defer file.Close()
  234. return loadSpecFromELF(file)
  235. }
  236. // findVMLinux scans multiple well-known paths for vmlinux kernel images.
  237. func findVMLinux() (*internal.SafeELFFile, error) {
  238. release, err := internal.KernelRelease()
  239. if err != nil {
  240. return nil, err
  241. }
  242. // use same list of locations as libbpf
  243. // https://github.com/libbpf/libbpf/blob/9a3a42608dbe3731256a5682a125ac1e23bced8f/src/btf.c#L3114-L3122
  244. locations := []string{
  245. "/boot/vmlinux-%s",
  246. "/lib/modules/%s/vmlinux-%[1]s",
  247. "/lib/modules/%s/build/vmlinux",
  248. "/usr/lib/modules/%s/kernel/vmlinux",
  249. "/usr/lib/debug/boot/vmlinux-%s",
  250. "/usr/lib/debug/boot/vmlinux-%s.debug",
  251. "/usr/lib/debug/lib/modules/%s/vmlinux",
  252. }
  253. for _, loc := range locations {
  254. file, err := internal.OpenSafeELFFile(fmt.Sprintf(loc, release))
  255. if errors.Is(err, os.ErrNotExist) {
  256. continue
  257. }
  258. return file, err
  259. }
  260. return nil, fmt.Errorf("no BTF found for kernel version %s: %w", release, internal.ErrNotSupported)
  261. }
  262. // parseBTFHeader parses the header of the .BTF section.
  263. func parseBTFHeader(r io.Reader, bo binary.ByteOrder) (*btfHeader, error) {
  264. var header btfHeader
  265. if err := binary.Read(r, bo, &header); err != nil {
  266. return nil, fmt.Errorf("can't read header: %v", err)
  267. }
  268. if header.Magic != btfMagic {
  269. return nil, fmt.Errorf("incorrect magic value %v", header.Magic)
  270. }
  271. if header.Version != 1 {
  272. return nil, fmt.Errorf("unexpected version %v", header.Version)
  273. }
  274. if header.Flags != 0 {
  275. return nil, fmt.Errorf("unsupported flags %v", header.Flags)
  276. }
  277. remainder := int64(header.HdrLen) - int64(binary.Size(&header))
  278. if remainder < 0 {
  279. return nil, errors.New("header length shorter than btfHeader size")
  280. }
  281. if _, err := io.CopyN(internal.DiscardZeroes{}, r, remainder); err != nil {
  282. return nil, fmt.Errorf("header padding: %v", err)
  283. }
  284. return &header, nil
  285. }
  286. func guessRawBTFByteOrder(r io.ReaderAt) binary.ByteOrder {
  287. buf := new(bufio.Reader)
  288. for _, bo := range []binary.ByteOrder{
  289. binary.LittleEndian,
  290. binary.BigEndian,
  291. } {
  292. buf.Reset(io.NewSectionReader(r, 0, math.MaxInt64))
  293. if _, err := parseBTFHeader(buf, bo); err == nil {
  294. return bo
  295. }
  296. }
  297. return nil
  298. }
  299. // parseBTF reads a .BTF section into memory and parses it into a list of
  300. // raw types and a string table.
  301. func parseBTF(btf io.ReaderAt, bo binary.ByteOrder, baseStrings *stringTable) ([]rawType, *stringTable, error) {
  302. buf := internal.NewBufferedSectionReader(btf, 0, math.MaxInt64)
  303. header, err := parseBTFHeader(buf, bo)
  304. if err != nil {
  305. return nil, nil, fmt.Errorf("parsing .BTF header: %v", err)
  306. }
  307. rawStrings, err := readStringTable(io.NewSectionReader(btf, header.stringStart(), int64(header.StringLen)),
  308. baseStrings)
  309. if err != nil {
  310. return nil, nil, fmt.Errorf("can't read type names: %w", err)
  311. }
  312. buf.Reset(io.NewSectionReader(btf, header.typeStart(), int64(header.TypeLen)))
  313. rawTypes, err := readTypes(buf, bo, header.TypeLen)
  314. if err != nil {
  315. return nil, nil, fmt.Errorf("can't read types: %w", err)
  316. }
  317. return rawTypes, rawStrings, nil
  318. }
  319. type variable struct {
  320. section string
  321. name string
  322. }
  323. func fixupDatasec(rawTypes []rawType, rawStrings *stringTable, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) error {
  324. for i, rawType := range rawTypes {
  325. if rawType.Kind() != kindDatasec {
  326. continue
  327. }
  328. name, err := rawStrings.Lookup(rawType.NameOff)
  329. if err != nil {
  330. return err
  331. }
  332. if name == ".kconfig" || name == ".ksyms" {
  333. return fmt.Errorf("reference to %s: %w", name, ErrNotSupported)
  334. }
  335. if rawTypes[i].SizeType != 0 {
  336. continue
  337. }
  338. size, ok := sectionSizes[name]
  339. if !ok {
  340. return fmt.Errorf("data section %s: missing size", name)
  341. }
  342. rawTypes[i].SizeType = size
  343. secinfos := rawType.data.([]btfVarSecinfo)
  344. for j, secInfo := range secinfos {
  345. id := int(secInfo.Type - 1)
  346. if id >= len(rawTypes) {
  347. return fmt.Errorf("data section %s: invalid type id %d for variable %d", name, id, j)
  348. }
  349. varName, err := rawStrings.Lookup(rawTypes[id].NameOff)
  350. if err != nil {
  351. return fmt.Errorf("data section %s: can't get name for type %d: %w", name, id, err)
  352. }
  353. offset, ok := variableOffsets[variable{name, varName}]
  354. if !ok {
  355. return fmt.Errorf("data section %s: missing offset for variable %s", name, varName)
  356. }
  357. secinfos[j].Offset = offset
  358. }
  359. }
  360. return nil
  361. }
  362. // Copy creates a copy of Spec.
  363. func (s *Spec) Copy() *Spec {
  364. types := copyTypes(s.types, nil)
  365. typeIDOffset := TypeID(0)
  366. if len(s.types) != 0 {
  367. typeIDOffset = s.typeIDs[s.types[0]]
  368. }
  369. typeIDs, typesByName := indexTypes(types, typeIDOffset)
  370. // NB: Other parts of spec are not copied since they are immutable.
  371. return &Spec{
  372. s.rawTypes,
  373. s.strings,
  374. types,
  375. typeIDs,
  376. typesByName,
  377. s.byteOrder,
  378. }
  379. }
  380. type marshalOpts struct {
  381. ByteOrder binary.ByteOrder
  382. StripFuncLinkage bool
  383. }
  384. func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
  385. var (
  386. buf bytes.Buffer
  387. header = new(btfHeader)
  388. headerLen = binary.Size(header)
  389. )
  390. // Reserve space for the header. We have to write it last since
  391. // we don't know the size of the type section yet.
  392. _, _ = buf.Write(make([]byte, headerLen))
  393. // Write type section, just after the header.
  394. for _, raw := range s.rawTypes {
  395. switch {
  396. case opts.StripFuncLinkage && raw.Kind() == kindFunc:
  397. raw.SetLinkage(StaticFunc)
  398. }
  399. if err := raw.Marshal(&buf, opts.ByteOrder); err != nil {
  400. return nil, fmt.Errorf("can't marshal BTF: %w", err)
  401. }
  402. }
  403. typeLen := uint32(buf.Len() - headerLen)
  404. // Write string section after type section.
  405. stringsLen := s.strings.Length()
  406. buf.Grow(stringsLen)
  407. if err := s.strings.Marshal(&buf); err != nil {
  408. return nil, err
  409. }
  410. // Fill out the header, and write it out.
  411. header = &btfHeader{
  412. Magic: btfMagic,
  413. Version: 1,
  414. Flags: 0,
  415. HdrLen: uint32(headerLen),
  416. TypeOff: 0,
  417. TypeLen: typeLen,
  418. StringOff: typeLen,
  419. StringLen: uint32(stringsLen),
  420. }
  421. raw := buf.Bytes()
  422. err := binary.Write(sliceWriter(raw[:headerLen]), opts.ByteOrder, header)
  423. if err != nil {
  424. return nil, fmt.Errorf("can't write header: %v", err)
  425. }
  426. return raw, nil
  427. }
  428. type sliceWriter []byte
  429. func (sw sliceWriter) Write(p []byte) (int, error) {
  430. if len(p) != len(sw) {
  431. return 0, errors.New("size doesn't match")
  432. }
  433. return copy(sw, p), nil
  434. }
  435. // TypeByID returns the BTF Type with the given type ID.
  436. //
  437. // Returns an error wrapping ErrNotFound if a Type with the given ID
  438. // does not exist in the Spec.
  439. func (s *Spec) TypeByID(id TypeID) (Type, error) {
  440. return s.types.ByID(id)
  441. }
  442. // TypeID returns the ID for a given Type.
  443. //
  444. // Returns an error wrapping ErrNoFound if the type isn't part of the Spec.
  445. func (s *Spec) TypeID(typ Type) (TypeID, error) {
  446. if _, ok := typ.(*Void); ok {
  447. // Equality is weird for void, since it is a zero sized type.
  448. return 0, nil
  449. }
  450. id, ok := s.typeIDs[typ]
  451. if !ok {
  452. return 0, fmt.Errorf("no ID for type %s: %w", typ, ErrNotFound)
  453. }
  454. return id, nil
  455. }
  456. // AnyTypesByName returns a list of BTF Types with the given name.
  457. //
  458. // If the BTF blob describes multiple compilation units like vmlinux, multiple
  459. // Types with the same name and kind can exist, but might not describe the same
  460. // data structure.
  461. //
  462. // Returns an error wrapping ErrNotFound if no matching Type exists in the Spec.
  463. func (s *Spec) AnyTypesByName(name string) ([]Type, error) {
  464. types := s.namedTypes[newEssentialName(name)]
  465. if len(types) == 0 {
  466. return nil, fmt.Errorf("type name %s: %w", name, ErrNotFound)
  467. }
  468. // Return a copy to prevent changes to namedTypes.
  469. result := make([]Type, 0, len(types))
  470. for _, t := range types {
  471. // Match against the full name, not just the essential one
  472. // in case the type being looked up is a struct flavor.
  473. if t.TypeName() == name {
  474. result = append(result, t)
  475. }
  476. }
  477. return result, nil
  478. }
  479. // AnyTypeByName returns a Type with the given name.
  480. //
  481. // Returns an error if multiple types of that name exist.
  482. func (s *Spec) AnyTypeByName(name string) (Type, error) {
  483. types, err := s.AnyTypesByName(name)
  484. if err != nil {
  485. return nil, err
  486. }
  487. if len(types) > 1 {
  488. return nil, fmt.Errorf("found multiple types: %v", types)
  489. }
  490. return types[0], nil
  491. }
  492. // TypeByName searches for a Type with a specific name. Since multiple
  493. // Types with the same name can exist, the parameter typ is taken to
  494. // narrow down the search in case of a clash.
  495. //
  496. // typ must be a non-nil pointer to an implementation of a Type.
  497. // On success, the address of the found Type will be copied to typ.
  498. //
  499. // Returns an error wrapping ErrNotFound if no matching
  500. // Type exists in the Spec. If multiple candidates are found,
  501. // an error is returned.
  502. func (s *Spec) TypeByName(name string, typ interface{}) error {
  503. typValue := reflect.ValueOf(typ)
  504. if typValue.Kind() != reflect.Ptr {
  505. return fmt.Errorf("%T is not a pointer", typ)
  506. }
  507. typPtr := typValue.Elem()
  508. if !typPtr.CanSet() {
  509. return fmt.Errorf("%T cannot be set", typ)
  510. }
  511. wanted := typPtr.Type()
  512. if !wanted.AssignableTo(reflect.TypeOf((*Type)(nil)).Elem()) {
  513. return fmt.Errorf("%T does not satisfy Type interface", typ)
  514. }
  515. types, err := s.AnyTypesByName(name)
  516. if err != nil {
  517. return err
  518. }
  519. var candidate Type
  520. for _, typ := range types {
  521. if reflect.TypeOf(typ) != wanted {
  522. continue
  523. }
  524. if candidate != nil {
  525. return fmt.Errorf("type %s: multiple candidates for %T", name, typ)
  526. }
  527. candidate = typ
  528. }
  529. if candidate == nil {
  530. return fmt.Errorf("type %s: %w", name, ErrNotFound)
  531. }
  532. typPtr.Set(reflect.ValueOf(candidate))
  533. return nil
  534. }
  535. // LoadSplitSpecFromReader loads split BTF from a reader.
  536. //
  537. // Types from base are used to resolve references in the split BTF.
  538. // The returned Spec only contains types from the split BTF, not from the base.
  539. func LoadSplitSpecFromReader(r io.ReaderAt, base *Spec) (*Spec, error) {
  540. return loadRawSpec(r, internal.NativeEndian, base.types, base.strings)
  541. }
  542. // TypesIterator iterates over types of a given spec.
  543. type TypesIterator struct {
  544. spec *Spec
  545. index int
  546. // The last visited type in the spec.
  547. Type Type
  548. }
  549. // Iterate returns the types iterator.
  550. func (s *Spec) Iterate() *TypesIterator {
  551. return &TypesIterator{spec: s, index: 0}
  552. }
  553. // Next returns true as long as there are any remaining types.
  554. func (iter *TypesIterator) Next() bool {
  555. if len(iter.spec.types) <= iter.index {
  556. return false
  557. }
  558. iter.Type = iter.spec.types[iter.index]
  559. iter.index++
  560. return true
  561. }
  562. // Handle is a reference to BTF loaded into the kernel.
  563. type Handle struct {
  564. fd *sys.FD
  565. // Size of the raw BTF in bytes.
  566. size uint32
  567. }
  568. // NewHandle loads BTF into the kernel.
  569. //
  570. // Returns ErrNotSupported if BTF is not supported.
  571. func NewHandle(spec *Spec) (*Handle, error) {
  572. if err := haveBTF(); err != nil {
  573. return nil, err
  574. }
  575. if spec.byteOrder != internal.NativeEndian {
  576. return nil, fmt.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian)
  577. }
  578. btf, err := spec.marshal(marshalOpts{
  579. ByteOrder: internal.NativeEndian,
  580. StripFuncLinkage: haveFuncLinkage() != nil,
  581. })
  582. if err != nil {
  583. return nil, fmt.Errorf("can't marshal BTF: %w", err)
  584. }
  585. if uint64(len(btf)) > math.MaxUint32 {
  586. return nil, errors.New("BTF exceeds the maximum size")
  587. }
  588. attr := &sys.BtfLoadAttr{
  589. Btf: sys.NewSlicePointer(btf),
  590. BtfSize: uint32(len(btf)),
  591. }
  592. fd, err := sys.BtfLoad(attr)
  593. if err != nil {
  594. logBuf := make([]byte, 64*1024)
  595. attr.BtfLogBuf = sys.NewSlicePointer(logBuf)
  596. attr.BtfLogSize = uint32(len(logBuf))
  597. attr.BtfLogLevel = 1
  598. // NB: The syscall will never return ENOSPC as of 5.18-rc4.
  599. _, _ = sys.BtfLoad(attr)
  600. return nil, internal.ErrorWithLog(err, logBuf)
  601. }
  602. return &Handle{fd, attr.BtfSize}, nil
  603. }
  604. // NewHandleFromID returns the BTF handle for a given id.
  605. //
  606. // Prefer calling [ebpf.Program.Handle] or [ebpf.Map.Handle] if possible.
  607. //
  608. // Returns ErrNotExist, if there is no BTF with the given id.
  609. //
  610. // Requires CAP_SYS_ADMIN.
  611. func NewHandleFromID(id ID) (*Handle, error) {
  612. fd, err := sys.BtfGetFdById(&sys.BtfGetFdByIdAttr{
  613. Id: uint32(id),
  614. })
  615. if err != nil {
  616. return nil, fmt.Errorf("get FD for ID %d: %w", id, err)
  617. }
  618. info, err := newHandleInfoFromFD(fd)
  619. if err != nil {
  620. _ = fd.Close()
  621. return nil, err
  622. }
  623. return &Handle{fd, info.size}, nil
  624. }
  625. // Spec parses the kernel BTF into Go types.
  626. //
  627. // base is used to decode split BTF and may be nil.
  628. func (h *Handle) Spec(base *Spec) (*Spec, error) {
  629. var btfInfo sys.BtfInfo
  630. btfBuffer := make([]byte, h.size)
  631. btfInfo.Btf, btfInfo.BtfSize = sys.NewSlicePointerLen(btfBuffer)
  632. if err := sys.ObjInfo(h.fd, &btfInfo); err != nil {
  633. return nil, err
  634. }
  635. var baseTypes types
  636. var baseStrings *stringTable
  637. if base != nil {
  638. baseTypes = base.types
  639. baseStrings = base.strings
  640. }
  641. return loadRawSpec(bytes.NewReader(btfBuffer), internal.NativeEndian, baseTypes, baseStrings)
  642. }
  643. // Close destroys the handle.
  644. //
  645. // Subsequent calls to FD will return an invalid value.
  646. func (h *Handle) Close() error {
  647. if h == nil {
  648. return nil
  649. }
  650. return h.fd.Close()
  651. }
  652. // FD returns the file descriptor for the handle.
  653. func (h *Handle) FD() int {
  654. return h.fd.Int()
  655. }
  656. // Info returns metadata about the handle.
  657. func (h *Handle) Info() (*HandleInfo, error) {
  658. return newHandleInfoFromFD(h.fd)
  659. }
  660. func marshalBTF(types interface{}, strings []byte, bo binary.ByteOrder) []byte {
  661. const minHeaderLength = 24
  662. typesLen := uint32(binary.Size(types))
  663. header := btfHeader{
  664. Magic: btfMagic,
  665. Version: 1,
  666. HdrLen: minHeaderLength,
  667. TypeOff: 0,
  668. TypeLen: typesLen,
  669. StringOff: typesLen,
  670. StringLen: uint32(len(strings)),
  671. }
  672. buf := new(bytes.Buffer)
  673. _ = binary.Write(buf, bo, &header)
  674. _ = binary.Write(buf, bo, types)
  675. buf.Write(strings)
  676. return buf.Bytes()
  677. }
  678. var haveBTF = internal.FeatureTest("BTF", "5.1", func() error {
  679. var (
  680. types struct {
  681. Integer btfType
  682. Var btfType
  683. btfVar struct{ Linkage uint32 }
  684. }
  685. strings = []byte{0, 'a', 0}
  686. )
  687. // We use a BTF_KIND_VAR here, to make sure that
  688. // the kernel understands BTF at least as well as we
  689. // do. BTF_KIND_VAR was introduced ~5.1.
  690. types.Integer.SetKind(kindPointer)
  691. types.Var.NameOff = 1
  692. types.Var.SetKind(kindVar)
  693. types.Var.SizeType = 1
  694. btf := marshalBTF(&types, strings, internal.NativeEndian)
  695. fd, err := sys.BtfLoad(&sys.BtfLoadAttr{
  696. Btf: sys.NewSlicePointer(btf),
  697. BtfSize: uint32(len(btf)),
  698. })
  699. if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) {
  700. // Treat both EINVAL and EPERM as not supported: loading the program
  701. // might still succeed without BTF.
  702. return internal.ErrNotSupported
  703. }
  704. if err != nil {
  705. return err
  706. }
  707. fd.Close()
  708. return nil
  709. })
  710. var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() error {
  711. if err := haveBTF(); err != nil {
  712. return err
  713. }
  714. var (
  715. types struct {
  716. FuncProto btfType
  717. Func btfType
  718. }
  719. strings = []byte{0, 'a', 0}
  720. )
  721. types.FuncProto.SetKind(kindFuncProto)
  722. types.Func.SetKind(kindFunc)
  723. types.Func.SizeType = 1 // aka FuncProto
  724. types.Func.NameOff = 1
  725. types.Func.SetLinkage(GlobalFunc)
  726. btf := marshalBTF(&types, strings, internal.NativeEndian)
  727. fd, err := sys.BtfLoad(&sys.BtfLoadAttr{
  728. Btf: sys.NewSlicePointer(btf),
  729. BtfSize: uint32(len(btf)),
  730. })
  731. if errors.Is(err, unix.EINVAL) {
  732. return internal.ErrNotSupported
  733. }
  734. if err != nil {
  735. return err
  736. }
  737. fd.Close()
  738. return nil
  739. })