btf.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. package btf
  2. import (
  3. "bytes"
  4. "debug/elf"
  5. "encoding/binary"
  6. "errors"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "math"
  11. "os"
  12. "reflect"
  13. "sync"
  14. "unsafe"
  15. "github.com/cilium/ebpf/internal"
  16. "github.com/cilium/ebpf/internal/unix"
  17. )
  18. const btfMagic = 0xeB9F
  19. // Errors returned by BTF functions.
  20. var (
  21. ErrNotSupported = internal.ErrNotSupported
  22. ErrNotFound = errors.New("not found")
  23. ErrNoExtendedInfo = errors.New("no extended info")
  24. )
  25. // Spec represents decoded BTF.
  26. type Spec struct {
  27. rawTypes []rawType
  28. strings stringTable
  29. types []Type
  30. namedTypes map[string][]namedType
  31. funcInfos map[string]extInfo
  32. lineInfos map[string]extInfo
  33. coreRelos map[string]bpfCoreRelos
  34. byteOrder binary.ByteOrder
  35. }
  36. type btfHeader struct {
  37. Magic uint16
  38. Version uint8
  39. Flags uint8
  40. HdrLen uint32
  41. TypeOff uint32
  42. TypeLen uint32
  43. StringOff uint32
  44. StringLen uint32
  45. }
  46. // LoadSpecFromReader reads BTF sections from an ELF.
  47. //
  48. // Returns a nil Spec and no error if no BTF was present.
  49. func LoadSpecFromReader(rd io.ReaderAt) (*Spec, error) {
  50. file, err := internal.NewSafeELFFile(rd)
  51. if err != nil {
  52. return nil, err
  53. }
  54. defer file.Close()
  55. btfSection, btfExtSection, sectionSizes, err := findBtfSections(file)
  56. if err != nil {
  57. return nil, err
  58. }
  59. if btfSection == nil {
  60. return nil, nil
  61. }
  62. symbols, err := file.Symbols()
  63. if err != nil {
  64. return nil, fmt.Errorf("can't read symbols: %v", err)
  65. }
  66. variableOffsets := make(map[variable]uint32)
  67. for _, symbol := range symbols {
  68. if idx := symbol.Section; idx >= elf.SHN_LORESERVE && idx <= elf.SHN_HIRESERVE {
  69. // Ignore things like SHN_ABS
  70. continue
  71. }
  72. if int(symbol.Section) >= len(file.Sections) {
  73. return nil, fmt.Errorf("symbol %s: invalid section %d", symbol.Name, symbol.Section)
  74. }
  75. secName := file.Sections[symbol.Section].Name
  76. if _, ok := sectionSizes[secName]; !ok {
  77. continue
  78. }
  79. if symbol.Value > math.MaxUint32 {
  80. return nil, fmt.Errorf("section %s: symbol %s: size exceeds maximum", secName, symbol.Name)
  81. }
  82. variableOffsets[variable{secName, symbol.Name}] = uint32(symbol.Value)
  83. }
  84. spec, err := loadNakedSpec(btfSection.Open(), file.ByteOrder, sectionSizes, variableOffsets)
  85. if err != nil {
  86. return nil, err
  87. }
  88. if btfExtSection == nil {
  89. return spec, nil
  90. }
  91. spec.funcInfos, spec.lineInfos, spec.coreRelos, err = parseExtInfos(btfExtSection.Open(), file.ByteOrder, spec.strings)
  92. if err != nil {
  93. return nil, fmt.Errorf("can't read ext info: %w", err)
  94. }
  95. return spec, nil
  96. }
  97. func findBtfSections(file *internal.SafeELFFile) (*elf.Section, *elf.Section, map[string]uint32, error) {
  98. var (
  99. btfSection *elf.Section
  100. btfExtSection *elf.Section
  101. sectionSizes = make(map[string]uint32)
  102. )
  103. for _, sec := range file.Sections {
  104. switch sec.Name {
  105. case ".BTF":
  106. btfSection = sec
  107. case ".BTF.ext":
  108. btfExtSection = sec
  109. default:
  110. if sec.Type != elf.SHT_PROGBITS && sec.Type != elf.SHT_NOBITS {
  111. break
  112. }
  113. if sec.Size > math.MaxUint32 {
  114. return nil, nil, nil, fmt.Errorf("section %s exceeds maximum size", sec.Name)
  115. }
  116. sectionSizes[sec.Name] = uint32(sec.Size)
  117. }
  118. }
  119. return btfSection, btfExtSection, sectionSizes, nil
  120. }
  121. func loadSpecFromVmlinux(rd io.ReaderAt) (*Spec, error) {
  122. file, err := internal.NewSafeELFFile(rd)
  123. if err != nil {
  124. return nil, err
  125. }
  126. defer file.Close()
  127. btfSection, _, _, err := findBtfSections(file)
  128. if err != nil {
  129. return nil, fmt.Errorf(".BTF ELF section: %s", err)
  130. }
  131. if btfSection == nil {
  132. return nil, fmt.Errorf("unable to find .BTF ELF section")
  133. }
  134. return loadNakedSpec(btfSection.Open(), file.ByteOrder, nil, nil)
  135. }
  136. func loadNakedSpec(btf io.ReadSeeker, bo binary.ByteOrder, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) (*Spec, error) {
  137. rawTypes, rawStrings, err := parseBTF(btf, bo)
  138. if err != nil {
  139. return nil, err
  140. }
  141. err = fixupDatasec(rawTypes, rawStrings, sectionSizes, variableOffsets)
  142. if err != nil {
  143. return nil, err
  144. }
  145. types, typesByName, err := inflateRawTypes(rawTypes, rawStrings)
  146. if err != nil {
  147. return nil, err
  148. }
  149. return &Spec{
  150. rawTypes: rawTypes,
  151. namedTypes: typesByName,
  152. types: types,
  153. strings: rawStrings,
  154. byteOrder: bo,
  155. }, nil
  156. }
  157. var kernelBTF struct {
  158. sync.Mutex
  159. *Spec
  160. }
  161. // LoadKernelSpec returns the current kernel's BTF information.
  162. //
  163. // Requires a >= 5.5 kernel with CONFIG_DEBUG_INFO_BTF enabled. Returns
  164. // ErrNotSupported if BTF is not enabled.
  165. func LoadKernelSpec() (*Spec, error) {
  166. kernelBTF.Lock()
  167. defer kernelBTF.Unlock()
  168. if kernelBTF.Spec != nil {
  169. return kernelBTF.Spec, nil
  170. }
  171. var err error
  172. kernelBTF.Spec, err = loadKernelSpec()
  173. return kernelBTF.Spec, err
  174. }
  175. func loadKernelSpec() (*Spec, error) {
  176. release, err := unix.KernelRelease()
  177. if err != nil {
  178. return nil, fmt.Errorf("can't read kernel release number: %w", err)
  179. }
  180. fh, err := os.Open("/sys/kernel/btf/vmlinux")
  181. if err == nil {
  182. defer fh.Close()
  183. return loadNakedSpec(fh, internal.NativeEndian, nil, nil)
  184. }
  185. // use same list of locations as libbpf
  186. // https://github.com/libbpf/libbpf/blob/9a3a42608dbe3731256a5682a125ac1e23bced8f/src/btf.c#L3114-L3122
  187. locations := []string{
  188. "/boot/vmlinux-%s",
  189. "/lib/modules/%s/vmlinux-%[1]s",
  190. "/lib/modules/%s/build/vmlinux",
  191. "/usr/lib/modules/%s/kernel/vmlinux",
  192. "/usr/lib/debug/boot/vmlinux-%s",
  193. "/usr/lib/debug/boot/vmlinux-%s.debug",
  194. "/usr/lib/debug/lib/modules/%s/vmlinux",
  195. }
  196. for _, loc := range locations {
  197. path := fmt.Sprintf(loc, release)
  198. fh, err := os.Open(path)
  199. if err != nil {
  200. continue
  201. }
  202. defer fh.Close()
  203. return loadSpecFromVmlinux(fh)
  204. }
  205. return nil, fmt.Errorf("no BTF for kernel version %s: %w", release, internal.ErrNotSupported)
  206. }
  207. func parseBTF(btf io.ReadSeeker, bo binary.ByteOrder) ([]rawType, stringTable, error) {
  208. rawBTF, err := ioutil.ReadAll(btf)
  209. if err != nil {
  210. return nil, nil, fmt.Errorf("can't read BTF: %v", err)
  211. }
  212. rd := bytes.NewReader(rawBTF)
  213. var header btfHeader
  214. if err := binary.Read(rd, bo, &header); err != nil {
  215. return nil, nil, fmt.Errorf("can't read header: %v", err)
  216. }
  217. if header.Magic != btfMagic {
  218. return nil, nil, fmt.Errorf("incorrect magic value %v", header.Magic)
  219. }
  220. if header.Version != 1 {
  221. return nil, nil, fmt.Errorf("unexpected version %v", header.Version)
  222. }
  223. if header.Flags != 0 {
  224. return nil, nil, fmt.Errorf("unsupported flags %v", header.Flags)
  225. }
  226. remainder := int64(header.HdrLen) - int64(binary.Size(&header))
  227. if remainder < 0 {
  228. return nil, nil, errors.New("header is too short")
  229. }
  230. if _, err := io.CopyN(internal.DiscardZeroes{}, rd, remainder); err != nil {
  231. return nil, nil, fmt.Errorf("header padding: %v", err)
  232. }
  233. if _, err := rd.Seek(int64(header.HdrLen+header.StringOff), io.SeekStart); err != nil {
  234. return nil, nil, fmt.Errorf("can't seek to start of string section: %v", err)
  235. }
  236. rawStrings, err := readStringTable(io.LimitReader(rd, int64(header.StringLen)))
  237. if err != nil {
  238. return nil, nil, fmt.Errorf("can't read type names: %w", err)
  239. }
  240. if _, err := rd.Seek(int64(header.HdrLen+header.TypeOff), io.SeekStart); err != nil {
  241. return nil, nil, fmt.Errorf("can't seek to start of type section: %v", err)
  242. }
  243. rawTypes, err := readTypes(io.LimitReader(rd, int64(header.TypeLen)), bo)
  244. if err != nil {
  245. return nil, nil, fmt.Errorf("can't read types: %w", err)
  246. }
  247. return rawTypes, rawStrings, nil
  248. }
  249. type variable struct {
  250. section string
  251. name string
  252. }
  253. func fixupDatasec(rawTypes []rawType, rawStrings stringTable, sectionSizes map[string]uint32, variableOffsets map[variable]uint32) error {
  254. for i, rawType := range rawTypes {
  255. if rawType.Kind() != kindDatasec {
  256. continue
  257. }
  258. name, err := rawStrings.Lookup(rawType.NameOff)
  259. if err != nil {
  260. return err
  261. }
  262. if name == ".kconfig" || name == ".ksyms" {
  263. return fmt.Errorf("reference to %s: %w", name, ErrNotSupported)
  264. }
  265. if rawTypes[i].SizeType != 0 {
  266. continue
  267. }
  268. size, ok := sectionSizes[name]
  269. if !ok {
  270. return fmt.Errorf("data section %s: missing size", name)
  271. }
  272. rawTypes[i].SizeType = size
  273. secinfos := rawType.data.([]btfVarSecinfo)
  274. for j, secInfo := range secinfos {
  275. id := int(secInfo.Type - 1)
  276. if id >= len(rawTypes) {
  277. return fmt.Errorf("data section %s: invalid type id %d for variable %d", name, id, j)
  278. }
  279. varName, err := rawStrings.Lookup(rawTypes[id].NameOff)
  280. if err != nil {
  281. return fmt.Errorf("data section %s: can't get name for type %d: %w", name, id, err)
  282. }
  283. offset, ok := variableOffsets[variable{name, varName}]
  284. if !ok {
  285. return fmt.Errorf("data section %s: missing offset for variable %s", name, varName)
  286. }
  287. secinfos[j].Offset = offset
  288. }
  289. }
  290. return nil
  291. }
  292. type marshalOpts struct {
  293. ByteOrder binary.ByteOrder
  294. StripFuncLinkage bool
  295. }
  296. func (s *Spec) marshal(opts marshalOpts) ([]byte, error) {
  297. var (
  298. buf bytes.Buffer
  299. header = new(btfHeader)
  300. headerLen = binary.Size(header)
  301. )
  302. // Reserve space for the header. We have to write it last since
  303. // we don't know the size of the type section yet.
  304. _, _ = buf.Write(make([]byte, headerLen))
  305. // Write type section, just after the header.
  306. for _, raw := range s.rawTypes {
  307. switch {
  308. case opts.StripFuncLinkage && raw.Kind() == kindFunc:
  309. raw.SetLinkage(linkageStatic)
  310. }
  311. if err := raw.Marshal(&buf, opts.ByteOrder); err != nil {
  312. return nil, fmt.Errorf("can't marshal BTF: %w", err)
  313. }
  314. }
  315. typeLen := uint32(buf.Len() - headerLen)
  316. // Write string section after type section.
  317. _, _ = buf.Write(s.strings)
  318. // Fill out the header, and write it out.
  319. header = &btfHeader{
  320. Magic: btfMagic,
  321. Version: 1,
  322. Flags: 0,
  323. HdrLen: uint32(headerLen),
  324. TypeOff: 0,
  325. TypeLen: typeLen,
  326. StringOff: typeLen,
  327. StringLen: uint32(len(s.strings)),
  328. }
  329. raw := buf.Bytes()
  330. err := binary.Write(sliceWriter(raw[:headerLen]), opts.ByteOrder, header)
  331. if err != nil {
  332. return nil, fmt.Errorf("can't write header: %v", err)
  333. }
  334. return raw, nil
  335. }
  336. type sliceWriter []byte
  337. func (sw sliceWriter) Write(p []byte) (int, error) {
  338. if len(p) != len(sw) {
  339. return 0, errors.New("size doesn't match")
  340. }
  341. return copy(sw, p), nil
  342. }
  343. // Program finds the BTF for a specific section.
  344. //
  345. // Length is the number of bytes in the raw BPF instruction stream.
  346. //
  347. // Returns an error which may wrap ErrNoExtendedInfo if the Spec doesn't
  348. // contain extended BTF info.
  349. func (s *Spec) Program(name string, length uint64) (*Program, error) {
  350. if length == 0 {
  351. return nil, errors.New("length musn't be zero")
  352. }
  353. if s.funcInfos == nil && s.lineInfos == nil && s.coreRelos == nil {
  354. return nil, fmt.Errorf("BTF for section %s: %w", name, ErrNoExtendedInfo)
  355. }
  356. funcInfos, funcOK := s.funcInfos[name]
  357. lineInfos, lineOK := s.lineInfos[name]
  358. coreRelos, coreOK := s.coreRelos[name]
  359. if !funcOK && !lineOK && !coreOK {
  360. return nil, fmt.Errorf("no extended BTF info for section %s", name)
  361. }
  362. return &Program{s, length, funcInfos, lineInfos, coreRelos}, nil
  363. }
  364. // Datasec returns the BTF required to create maps which represent data sections.
  365. func (s *Spec) Datasec(name string) (*Map, error) {
  366. var datasec Datasec
  367. if err := s.FindType(name, &datasec); err != nil {
  368. return nil, fmt.Errorf("data section %s: can't get BTF: %w", name, err)
  369. }
  370. m := NewMap(s, &Void{}, &datasec)
  371. return &m, nil
  372. }
  373. // FindType searches for a type with a specific name.
  374. //
  375. // hint determines the type of the returned Type.
  376. //
  377. // Returns an error wrapping ErrNotFound if no matching
  378. // type exists in spec.
  379. func (s *Spec) FindType(name string, typ Type) error {
  380. var (
  381. wanted = reflect.TypeOf(typ)
  382. candidate Type
  383. )
  384. for _, typ := range s.namedTypes[essentialName(name)] {
  385. if reflect.TypeOf(typ) != wanted {
  386. continue
  387. }
  388. // Match against the full name, not just the essential one.
  389. if typ.name() != name {
  390. continue
  391. }
  392. if candidate != nil {
  393. return fmt.Errorf("type %s: multiple candidates for %T", name, typ)
  394. }
  395. candidate = typ
  396. }
  397. if candidate == nil {
  398. return fmt.Errorf("type %s: %w", name, ErrNotFound)
  399. }
  400. value := reflect.Indirect(reflect.ValueOf(copyType(candidate)))
  401. reflect.Indirect(reflect.ValueOf(typ)).Set(value)
  402. return nil
  403. }
  404. // Handle is a reference to BTF loaded into the kernel.
  405. type Handle struct {
  406. fd *internal.FD
  407. }
  408. // NewHandle loads BTF into the kernel.
  409. //
  410. // Returns ErrNotSupported if BTF is not supported.
  411. func NewHandle(spec *Spec) (*Handle, error) {
  412. if err := haveBTF(); err != nil {
  413. return nil, err
  414. }
  415. if spec.byteOrder != internal.NativeEndian {
  416. return nil, fmt.Errorf("can't load %s BTF on %s", spec.byteOrder, internal.NativeEndian)
  417. }
  418. btf, err := spec.marshal(marshalOpts{
  419. ByteOrder: internal.NativeEndian,
  420. StripFuncLinkage: haveFuncLinkage() != nil,
  421. })
  422. if err != nil {
  423. return nil, fmt.Errorf("can't marshal BTF: %w", err)
  424. }
  425. if uint64(len(btf)) > math.MaxUint32 {
  426. return nil, errors.New("BTF exceeds the maximum size")
  427. }
  428. attr := &bpfLoadBTFAttr{
  429. btf: internal.NewSlicePointer(btf),
  430. btfSize: uint32(len(btf)),
  431. }
  432. fd, err := bpfLoadBTF(attr)
  433. if err != nil {
  434. logBuf := make([]byte, 64*1024)
  435. attr.logBuf = internal.NewSlicePointer(logBuf)
  436. attr.btfLogSize = uint32(len(logBuf))
  437. attr.btfLogLevel = 1
  438. _, logErr := bpfLoadBTF(attr)
  439. return nil, internal.ErrorWithLog(err, logBuf, logErr)
  440. }
  441. return &Handle{fd}, nil
  442. }
  443. // Close destroys the handle.
  444. //
  445. // Subsequent calls to FD will return an invalid value.
  446. func (h *Handle) Close() error {
  447. return h.fd.Close()
  448. }
  449. // FD returns the file descriptor for the handle.
  450. func (h *Handle) FD() int {
  451. value, err := h.fd.Value()
  452. if err != nil {
  453. return -1
  454. }
  455. return int(value)
  456. }
  457. // Map is the BTF for a map.
  458. type Map struct {
  459. spec *Spec
  460. key, value Type
  461. }
  462. // NewMap returns a new Map containing the given values.
  463. // The key and value arguments are initialized to Void if nil values are given.
  464. func NewMap(spec *Spec, key Type, value Type) Map {
  465. if key == nil {
  466. key = &Void{}
  467. }
  468. if value == nil {
  469. value = &Void{}
  470. }
  471. return Map{
  472. spec: spec,
  473. key: key,
  474. value: value,
  475. }
  476. }
  477. // MapSpec should be a method on Map, but is a free function
  478. // to hide it from users of the ebpf package.
  479. func MapSpec(m *Map) *Spec {
  480. return m.spec
  481. }
  482. // MapKey should be a method on Map, but is a free function
  483. // to hide it from users of the ebpf package.
  484. func MapKey(m *Map) Type {
  485. return m.key
  486. }
  487. // MapValue should be a method on Map, but is a free function
  488. // to hide it from users of the ebpf package.
  489. func MapValue(m *Map) Type {
  490. return m.value
  491. }
  492. // Program is the BTF information for a stream of instructions.
  493. type Program struct {
  494. spec *Spec
  495. length uint64
  496. funcInfos, lineInfos extInfo
  497. coreRelos bpfCoreRelos
  498. }
  499. // ProgramSpec returns the Spec needed for loading function and line infos into the kernel.
  500. //
  501. // This is a free function instead of a method to hide it from users
  502. // of package ebpf.
  503. func ProgramSpec(s *Program) *Spec {
  504. return s.spec
  505. }
  506. // ProgramAppend the information from other to the Program.
  507. //
  508. // This is a free function instead of a method to hide it from users
  509. // of package ebpf.
  510. func ProgramAppend(s, other *Program) error {
  511. funcInfos, err := s.funcInfos.append(other.funcInfos, s.length)
  512. if err != nil {
  513. return fmt.Errorf("func infos: %w", err)
  514. }
  515. lineInfos, err := s.lineInfos.append(other.lineInfos, s.length)
  516. if err != nil {
  517. return fmt.Errorf("line infos: %w", err)
  518. }
  519. s.funcInfos = funcInfos
  520. s.lineInfos = lineInfos
  521. s.coreRelos = s.coreRelos.append(other.coreRelos, s.length)
  522. s.length += other.length
  523. return nil
  524. }
  525. // ProgramFuncInfos returns the binary form of BTF function infos.
  526. //
  527. // This is a free function instead of a method to hide it from users
  528. // of package ebpf.
  529. func ProgramFuncInfos(s *Program) (recordSize uint32, bytes []byte, err error) {
  530. bytes, err = s.funcInfos.MarshalBinary()
  531. if err != nil {
  532. return 0, nil, err
  533. }
  534. return s.funcInfos.recordSize, bytes, nil
  535. }
  536. // ProgramLineInfos returns the binary form of BTF line infos.
  537. //
  538. // This is a free function instead of a method to hide it from users
  539. // of package ebpf.
  540. func ProgramLineInfos(s *Program) (recordSize uint32, bytes []byte, err error) {
  541. bytes, err = s.lineInfos.MarshalBinary()
  542. if err != nil {
  543. return 0, nil, err
  544. }
  545. return s.lineInfos.recordSize, bytes, nil
  546. }
  547. // ProgramRelocations returns the CO-RE relocations required to adjust the
  548. // program to the target.
  549. //
  550. // This is a free function instead of a method to hide it from users
  551. // of package ebpf.
  552. func ProgramRelocations(s *Program, target *Spec) (map[uint64]Relocation, error) {
  553. if len(s.coreRelos) == 0 {
  554. return nil, nil
  555. }
  556. return coreRelocate(s.spec, target, s.coreRelos)
  557. }
  558. type bpfLoadBTFAttr struct {
  559. btf internal.Pointer
  560. logBuf internal.Pointer
  561. btfSize uint32
  562. btfLogSize uint32
  563. btfLogLevel uint32
  564. }
  565. func bpfLoadBTF(attr *bpfLoadBTFAttr) (*internal.FD, error) {
  566. fd, err := internal.BPF(internal.BPF_BTF_LOAD, unsafe.Pointer(attr), unsafe.Sizeof(*attr))
  567. if err != nil {
  568. return nil, err
  569. }
  570. return internal.NewFD(uint32(fd)), nil
  571. }
  572. func marshalBTF(types interface{}, strings []byte, bo binary.ByteOrder) []byte {
  573. const minHeaderLength = 24
  574. typesLen := uint32(binary.Size(types))
  575. header := btfHeader{
  576. Magic: btfMagic,
  577. Version: 1,
  578. HdrLen: minHeaderLength,
  579. TypeOff: 0,
  580. TypeLen: typesLen,
  581. StringOff: typesLen,
  582. StringLen: uint32(len(strings)),
  583. }
  584. buf := new(bytes.Buffer)
  585. _ = binary.Write(buf, bo, &header)
  586. _ = binary.Write(buf, bo, types)
  587. buf.Write(strings)
  588. return buf.Bytes()
  589. }
  590. var haveBTF = internal.FeatureTest("BTF", "5.1", func() error {
  591. var (
  592. types struct {
  593. Integer btfType
  594. Var btfType
  595. btfVar struct{ Linkage uint32 }
  596. }
  597. strings = []byte{0, 'a', 0}
  598. )
  599. // We use a BTF_KIND_VAR here, to make sure that
  600. // the kernel understands BTF at least as well as we
  601. // do. BTF_KIND_VAR was introduced ~5.1.
  602. types.Integer.SetKind(kindPointer)
  603. types.Var.NameOff = 1
  604. types.Var.SetKind(kindVar)
  605. types.Var.SizeType = 1
  606. btf := marshalBTF(&types, strings, internal.NativeEndian)
  607. fd, err := bpfLoadBTF(&bpfLoadBTFAttr{
  608. btf: internal.NewSlicePointer(btf),
  609. btfSize: uint32(len(btf)),
  610. })
  611. if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) {
  612. // Treat both EINVAL and EPERM as not supported: loading the program
  613. // might still succeed without BTF.
  614. return internal.ErrNotSupported
  615. }
  616. if err != nil {
  617. return err
  618. }
  619. fd.Close()
  620. return nil
  621. })
  622. var haveFuncLinkage = internal.FeatureTest("BTF func linkage", "5.6", func() error {
  623. if err := haveBTF(); err != nil {
  624. return err
  625. }
  626. var (
  627. types struct {
  628. FuncProto btfType
  629. Func btfType
  630. }
  631. strings = []byte{0, 'a', 0}
  632. )
  633. types.FuncProto.SetKind(kindFuncProto)
  634. types.Func.SetKind(kindFunc)
  635. types.Func.SizeType = 1 // aka FuncProto
  636. types.Func.NameOff = 1
  637. types.Func.SetLinkage(linkageGlobal)
  638. btf := marshalBTF(&types, strings, internal.NativeEndian)
  639. fd, err := bpfLoadBTF(&bpfLoadBTFAttr{
  640. btf: internal.NewSlicePointer(btf),
  641. btfSize: uint32(len(btf)),
  642. })
  643. if errors.Is(err, unix.EINVAL) {
  644. return internal.ErrNotSupported
  645. }
  646. if err != nil {
  647. return err
  648. }
  649. fd.Close()
  650. return nil
  651. })