btf.go 19 KB

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