51a0db05bf80300453f9770fa76a1ebf964efe0b
[platform/kernel/linux-starfive.git] / tools / lib / bpf / btf.c
1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 /* Copyright (c) 2018 Facebook */
3
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <linux/err.h>
9 #include <linux/btf.h>
10 #include "btf.h"
11 #include "bpf.h"
12 #include "libbpf.h"
13 #include "libbpf_util.h"
14
15 #define max(a, b) ((a) > (b) ? (a) : (b))
16 #define min(a, b) ((a) < (b) ? (a) : (b))
17
18 #define BTF_MAX_NR_TYPES 65535
19
20 #define IS_MODIFIER(k) (((k) == BTF_KIND_TYPEDEF) || \
21                 ((k) == BTF_KIND_VOLATILE) || \
22                 ((k) == BTF_KIND_CONST) || \
23                 ((k) == BTF_KIND_RESTRICT))
24
25 static struct btf_type btf_void;
26
27 struct btf {
28         union {
29                 struct btf_header *hdr;
30                 void *data;
31         };
32         struct btf_type **types;
33         const char *strings;
34         void *nohdr_data;
35         __u32 nr_types;
36         __u32 types_size;
37         __u32 data_size;
38         int fd;
39 };
40
41 struct btf_ext_info {
42         /*
43          * info points to a deep copy of the individual info section
44          * (e.g. func_info and line_info) from the .BTF.ext.
45          * It does not include the __u32 rec_size.
46          */
47         void *info;
48         __u32 rec_size;
49         __u32 len;
50 };
51
52 struct btf_ext {
53         struct btf_ext_info func_info;
54         struct btf_ext_info line_info;
55 };
56
57 struct btf_ext_info_sec {
58         __u32   sec_name_off;
59         __u32   num_info;
60         /* Followed by num_info * record_size number of bytes */
61         __u8    data[0];
62 };
63
64 /* The minimum bpf_func_info checked by the loader */
65 struct bpf_func_info_min {
66         __u32   insn_off;
67         __u32   type_id;
68 };
69
70 /* The minimum bpf_line_info checked by the loader */
71 struct bpf_line_info_min {
72         __u32   insn_off;
73         __u32   file_name_off;
74         __u32   line_off;
75         __u32   line_col;
76 };
77
78 static inline __u64 ptr_to_u64(const void *ptr)
79 {
80         return (__u64) (unsigned long) ptr;
81 }
82
83 static int btf_add_type(struct btf *btf, struct btf_type *t)
84 {
85         if (btf->types_size - btf->nr_types < 2) {
86                 struct btf_type **new_types;
87                 __u32 expand_by, new_size;
88
89                 if (btf->types_size == BTF_MAX_NR_TYPES)
90                         return -E2BIG;
91
92                 expand_by = max(btf->types_size >> 2, 16);
93                 new_size = min(BTF_MAX_NR_TYPES, btf->types_size + expand_by);
94
95                 new_types = realloc(btf->types, sizeof(*new_types) * new_size);
96                 if (!new_types)
97                         return -ENOMEM;
98
99                 if (btf->nr_types == 0)
100                         new_types[0] = &btf_void;
101
102                 btf->types = new_types;
103                 btf->types_size = new_size;
104         }
105
106         btf->types[++(btf->nr_types)] = t;
107
108         return 0;
109 }
110
111 static int btf_parse_hdr(struct btf *btf)
112 {
113         const struct btf_header *hdr = btf->hdr;
114         __u32 meta_left;
115
116         if (btf->data_size < sizeof(struct btf_header)) {
117                 pr_debug("BTF header not found\n");
118                 return -EINVAL;
119         }
120
121         if (hdr->magic != BTF_MAGIC) {
122                 pr_debug("Invalid BTF magic:%x\n", hdr->magic);
123                 return -EINVAL;
124         }
125
126         if (hdr->version != BTF_VERSION) {
127                 pr_debug("Unsupported BTF version:%u\n", hdr->version);
128                 return -ENOTSUP;
129         }
130
131         if (hdr->flags) {
132                 pr_debug("Unsupported BTF flags:%x\n", hdr->flags);
133                 return -ENOTSUP;
134         }
135
136         meta_left = btf->data_size - sizeof(*hdr);
137         if (!meta_left) {
138                 pr_debug("BTF has no data\n");
139                 return -EINVAL;
140         }
141
142         if (meta_left < hdr->type_off) {
143                 pr_debug("Invalid BTF type section offset:%u\n", hdr->type_off);
144                 return -EINVAL;
145         }
146
147         if (meta_left < hdr->str_off) {
148                 pr_debug("Invalid BTF string section offset:%u\n", hdr->str_off);
149                 return -EINVAL;
150         }
151
152         if (hdr->type_off >= hdr->str_off) {
153                 pr_debug("BTF type section offset >= string section offset. No type?\n");
154                 return -EINVAL;
155         }
156
157         if (hdr->type_off & 0x02) {
158                 pr_debug("BTF type section is not aligned to 4 bytes\n");
159                 return -EINVAL;
160         }
161
162         btf->nohdr_data = btf->hdr + 1;
163
164         return 0;
165 }
166
167 static int btf_parse_str_sec(struct btf *btf)
168 {
169         const struct btf_header *hdr = btf->hdr;
170         const char *start = btf->nohdr_data + hdr->str_off;
171         const char *end = start + btf->hdr->str_len;
172
173         if (!hdr->str_len || hdr->str_len - 1 > BTF_MAX_NAME_OFFSET ||
174             start[0] || end[-1]) {
175                 pr_debug("Invalid BTF string section\n");
176                 return -EINVAL;
177         }
178
179         btf->strings = start;
180
181         return 0;
182 }
183
184 static int btf_parse_type_sec(struct btf *btf)
185 {
186         struct btf_header *hdr = btf->hdr;
187         void *nohdr_data = btf->nohdr_data;
188         void *next_type = nohdr_data + hdr->type_off;
189         void *end_type = nohdr_data + hdr->str_off;
190
191         while (next_type < end_type) {
192                 struct btf_type *t = next_type;
193                 __u16 vlen = BTF_INFO_VLEN(t->info);
194                 int err;
195
196                 next_type += sizeof(*t);
197                 switch (BTF_INFO_KIND(t->info)) {
198                 case BTF_KIND_INT:
199                         next_type += sizeof(int);
200                         break;
201                 case BTF_KIND_ARRAY:
202                         next_type += sizeof(struct btf_array);
203                         break;
204                 case BTF_KIND_STRUCT:
205                 case BTF_KIND_UNION:
206                         next_type += vlen * sizeof(struct btf_member);
207                         break;
208                 case BTF_KIND_ENUM:
209                         next_type += vlen * sizeof(struct btf_enum);
210                         break;
211                 case BTF_KIND_FUNC_PROTO:
212                         next_type += vlen * sizeof(struct btf_param);
213                         break;
214                 case BTF_KIND_FUNC:
215                 case BTF_KIND_TYPEDEF:
216                 case BTF_KIND_PTR:
217                 case BTF_KIND_FWD:
218                 case BTF_KIND_VOLATILE:
219                 case BTF_KIND_CONST:
220                 case BTF_KIND_RESTRICT:
221                         break;
222                 default:
223                         pr_debug("Unsupported BTF_KIND:%u\n",
224                              BTF_INFO_KIND(t->info));
225                         return -EINVAL;
226                 }
227
228                 err = btf_add_type(btf, t);
229                 if (err)
230                         return err;
231         }
232
233         return 0;
234 }
235
236 const struct btf_type *btf__type_by_id(const struct btf *btf, __u32 type_id)
237 {
238         if (type_id > btf->nr_types)
239                 return NULL;
240
241         return btf->types[type_id];
242 }
243
244 static bool btf_type_is_void(const struct btf_type *t)
245 {
246         return t == &btf_void || BTF_INFO_KIND(t->info) == BTF_KIND_FWD;
247 }
248
249 static bool btf_type_is_void_or_null(const struct btf_type *t)
250 {
251         return !t || btf_type_is_void(t);
252 }
253
254 static __s64 btf_type_size(const struct btf_type *t)
255 {
256         switch (BTF_INFO_KIND(t->info)) {
257         case BTF_KIND_INT:
258         case BTF_KIND_STRUCT:
259         case BTF_KIND_UNION:
260         case BTF_KIND_ENUM:
261                 return t->size;
262         case BTF_KIND_PTR:
263                 return sizeof(void *);
264         default:
265                 return -EINVAL;
266         }
267 }
268
269 #define MAX_RESOLVE_DEPTH 32
270
271 __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
272 {
273         const struct btf_array *array;
274         const struct btf_type *t;
275         __u32 nelems = 1;
276         __s64 size = -1;
277         int i;
278
279         t = btf__type_by_id(btf, type_id);
280         for (i = 0; i < MAX_RESOLVE_DEPTH && !btf_type_is_void_or_null(t);
281              i++) {
282                 size = btf_type_size(t);
283                 if (size >= 0)
284                         break;
285
286                 switch (BTF_INFO_KIND(t->info)) {
287                 case BTF_KIND_TYPEDEF:
288                 case BTF_KIND_VOLATILE:
289                 case BTF_KIND_CONST:
290                 case BTF_KIND_RESTRICT:
291                         type_id = t->type;
292                         break;
293                 case BTF_KIND_ARRAY:
294                         array = (const struct btf_array *)(t + 1);
295                         if (nelems && array->nelems > UINT32_MAX / nelems)
296                                 return -E2BIG;
297                         nelems *= array->nelems;
298                         type_id = array->type;
299                         break;
300                 default:
301                         return -EINVAL;
302                 }
303
304                 t = btf__type_by_id(btf, type_id);
305         }
306
307         if (size < 0)
308                 return -EINVAL;
309
310         if (nelems && size > UINT32_MAX / nelems)
311                 return -E2BIG;
312
313         return nelems * size;
314 }
315
316 int btf__resolve_type(const struct btf *btf, __u32 type_id)
317 {
318         const struct btf_type *t;
319         int depth = 0;
320
321         t = btf__type_by_id(btf, type_id);
322         while (depth < MAX_RESOLVE_DEPTH &&
323                !btf_type_is_void_or_null(t) &&
324                IS_MODIFIER(BTF_INFO_KIND(t->info))) {
325                 type_id = t->type;
326                 t = btf__type_by_id(btf, type_id);
327                 depth++;
328         }
329
330         if (depth == MAX_RESOLVE_DEPTH || btf_type_is_void_or_null(t))
331                 return -EINVAL;
332
333         return type_id;
334 }
335
336 __s32 btf__find_by_name(const struct btf *btf, const char *type_name)
337 {
338         __u32 i;
339
340         if (!strcmp(type_name, "void"))
341                 return 0;
342
343         for (i = 1; i <= btf->nr_types; i++) {
344                 const struct btf_type *t = btf->types[i];
345                 const char *name = btf__name_by_offset(btf, t->name_off);
346
347                 if (name && !strcmp(type_name, name))
348                         return i;
349         }
350
351         return -ENOENT;
352 }
353
354 void btf__free(struct btf *btf)
355 {
356         if (!btf)
357                 return;
358
359         if (btf->fd != -1)
360                 close(btf->fd);
361
362         free(btf->data);
363         free(btf->types);
364         free(btf);
365 }
366
367 struct btf *btf__new(__u8 *data, __u32 size)
368 {
369         __u32 log_buf_size = 0;
370         char *log_buf = NULL;
371         struct btf *btf;
372         int err;
373
374         btf = calloc(1, sizeof(struct btf));
375         if (!btf)
376                 return ERR_PTR(-ENOMEM);
377
378         btf->fd = -1;
379
380         log_buf = malloc(BPF_LOG_BUF_SIZE);
381         if (!log_buf) {
382                 err = -ENOMEM;
383                 goto done;
384         }
385
386         *log_buf = 0;
387         log_buf_size = BPF_LOG_BUF_SIZE;
388
389         btf->data = malloc(size);
390         if (!btf->data) {
391                 err = -ENOMEM;
392                 goto done;
393         }
394
395         memcpy(btf->data, data, size);
396         btf->data_size = size;
397
398         btf->fd = bpf_load_btf(btf->data, btf->data_size,
399                                log_buf, log_buf_size, false);
400
401         if (btf->fd == -1) {
402                 err = -errno;
403                 pr_warning("Error loading BTF: %s(%d)\n", strerror(errno), errno);
404                 if (log_buf && *log_buf)
405                         pr_warning("%s\n", log_buf);
406                 goto done;
407         }
408
409         err = btf_parse_hdr(btf);
410         if (err)
411                 goto done;
412
413         err = btf_parse_str_sec(btf);
414         if (err)
415                 goto done;
416
417         err = btf_parse_type_sec(btf);
418
419 done:
420         free(log_buf);
421
422         if (err) {
423                 btf__free(btf);
424                 return ERR_PTR(err);
425         }
426
427         return btf;
428 }
429
430 int btf__fd(const struct btf *btf)
431 {
432         return btf->fd;
433 }
434
435 const char *btf__name_by_offset(const struct btf *btf, __u32 offset)
436 {
437         if (offset < btf->hdr->str_len)
438                 return &btf->strings[offset];
439         else
440                 return NULL;
441 }
442
443 int btf__get_from_id(__u32 id, struct btf **btf)
444 {
445         struct bpf_btf_info btf_info = { 0 };
446         __u32 len = sizeof(btf_info);
447         __u32 last_size;
448         int btf_fd;
449         void *ptr;
450         int err;
451
452         err = 0;
453         *btf = NULL;
454         btf_fd = bpf_btf_get_fd_by_id(id);
455         if (btf_fd < 0)
456                 return 0;
457
458         /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so
459          * let's start with a sane default - 4KiB here - and resize it only if
460          * bpf_obj_get_info_by_fd() needs a bigger buffer.
461          */
462         btf_info.btf_size = 4096;
463         last_size = btf_info.btf_size;
464         ptr = malloc(last_size);
465         if (!ptr) {
466                 err = -ENOMEM;
467                 goto exit_free;
468         }
469
470         bzero(ptr, last_size);
471         btf_info.btf = ptr_to_u64(ptr);
472         err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
473
474         if (!err && btf_info.btf_size > last_size) {
475                 void *temp_ptr;
476
477                 last_size = btf_info.btf_size;
478                 temp_ptr = realloc(ptr, last_size);
479                 if (!temp_ptr) {
480                         err = -ENOMEM;
481                         goto exit_free;
482                 }
483                 ptr = temp_ptr;
484                 bzero(ptr, last_size);
485                 btf_info.btf = ptr_to_u64(ptr);
486                 err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len);
487         }
488
489         if (err || btf_info.btf_size > last_size) {
490                 err = errno;
491                 goto exit_free;
492         }
493
494         *btf = btf__new((__u8 *)(long)btf_info.btf, btf_info.btf_size);
495         if (IS_ERR(*btf)) {
496                 err = PTR_ERR(*btf);
497                 *btf = NULL;
498         }
499
500 exit_free:
501         close(btf_fd);
502         free(ptr);
503
504         return err;
505 }
506
507 struct btf_ext_sec_copy_param {
508         __u32 off;
509         __u32 len;
510         __u32 min_rec_size;
511         struct btf_ext_info *ext_info;
512         const char *desc;
513 };
514
515 static int btf_ext_copy_info(struct btf_ext *btf_ext,
516                              __u8 *data, __u32 data_size,
517                              struct btf_ext_sec_copy_param *ext_sec)
518 {
519         const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
520         const struct btf_ext_info_sec *sinfo;
521         struct btf_ext_info *ext_info;
522         __u32 info_left, record_size;
523         /* The start of the info sec (including the __u32 record_size). */
524         const void *info;
525
526         /* data and data_size do not include btf_ext_header from now on */
527         data = data + hdr->hdr_len;
528         data_size -= hdr->hdr_len;
529
530         if (ext_sec->off & 0x03) {
531                 pr_debug(".BTF.ext %s section is not aligned to 4 bytes\n",
532                      ext_sec->desc);
533                 return -EINVAL;
534         }
535
536         if (data_size < ext_sec->off ||
537             ext_sec->len > data_size - ext_sec->off) {
538                 pr_debug("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
539                      ext_sec->desc, ext_sec->off, ext_sec->len);
540                 return -EINVAL;
541         }
542
543         info = data + ext_sec->off;
544         info_left = ext_sec->len;
545
546         /* At least a record size */
547         if (info_left < sizeof(__u32)) {
548                 pr_debug(".BTF.ext %s record size not found\n", ext_sec->desc);
549                 return -EINVAL;
550         }
551
552         /* The record size needs to meet the minimum standard */
553         record_size = *(__u32 *)info;
554         if (record_size < ext_sec->min_rec_size ||
555             record_size & 0x03) {
556                 pr_debug("%s section in .BTF.ext has invalid record size %u\n",
557                      ext_sec->desc, record_size);
558                 return -EINVAL;
559         }
560
561         sinfo = info + sizeof(__u32);
562         info_left -= sizeof(__u32);
563
564         /* If no records, return failure now so .BTF.ext won't be used. */
565         if (!info_left) {
566                 pr_debug("%s section in .BTF.ext has no records", ext_sec->desc);
567                 return -EINVAL;
568         }
569
570         while (info_left) {
571                 unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec);
572                 __u64 total_record_size;
573                 __u32 num_records;
574
575                 if (info_left < sec_hdrlen) {
576                         pr_debug("%s section header is not found in .BTF.ext\n",
577                              ext_sec->desc);
578                         return -EINVAL;
579                 }
580
581                 num_records = sinfo->num_info;
582                 if (num_records == 0) {
583                         pr_debug("%s section has incorrect num_records in .BTF.ext\n",
584                              ext_sec->desc);
585                         return -EINVAL;
586                 }
587
588                 total_record_size = sec_hdrlen +
589                                     (__u64)num_records * record_size;
590                 if (info_left < total_record_size) {
591                         pr_debug("%s section has incorrect num_records in .BTF.ext\n",
592                              ext_sec->desc);
593                         return -EINVAL;
594                 }
595
596                 info_left -= total_record_size;
597                 sinfo = (void *)sinfo + total_record_size;
598         }
599
600         ext_info = ext_sec->ext_info;
601         ext_info->len = ext_sec->len - sizeof(__u32);
602         ext_info->rec_size = record_size;
603         ext_info->info = malloc(ext_info->len);
604         if (!ext_info->info)
605                 return -ENOMEM;
606         memcpy(ext_info->info, info + sizeof(__u32), ext_info->len);
607
608         return 0;
609 }
610
611 static int btf_ext_copy_func_info(struct btf_ext *btf_ext,
612                                   __u8 *data, __u32 data_size)
613 {
614         const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
615         struct btf_ext_sec_copy_param param = {
616                 .off = hdr->func_info_off,
617                 .len = hdr->func_info_len,
618                 .min_rec_size = sizeof(struct bpf_func_info_min),
619                 .ext_info = &btf_ext->func_info,
620                 .desc = "func_info"
621         };
622
623         return btf_ext_copy_info(btf_ext, data, data_size, &param);
624 }
625
626 static int btf_ext_copy_line_info(struct btf_ext *btf_ext,
627                                   __u8 *data, __u32 data_size)
628 {
629         const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
630         struct btf_ext_sec_copy_param param = {
631                 .off = hdr->line_info_off,
632                 .len = hdr->line_info_len,
633                 .min_rec_size = sizeof(struct bpf_line_info_min),
634                 .ext_info = &btf_ext->line_info,
635                 .desc = "line_info",
636         };
637
638         return btf_ext_copy_info(btf_ext, data, data_size, &param);
639 }
640
641 static int btf_ext_parse_hdr(__u8 *data, __u32 data_size)
642 {
643         const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
644
645         if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
646             data_size < hdr->hdr_len) {
647                 pr_debug("BTF.ext header not found");
648                 return -EINVAL;
649         }
650
651         if (hdr->magic != BTF_MAGIC) {
652                 pr_debug("Invalid BTF.ext magic:%x\n", hdr->magic);
653                 return -EINVAL;
654         }
655
656         if (hdr->version != BTF_VERSION) {
657                 pr_debug("Unsupported BTF.ext version:%u\n", hdr->version);
658                 return -ENOTSUP;
659         }
660
661         if (hdr->flags) {
662                 pr_debug("Unsupported BTF.ext flags:%x\n", hdr->flags);
663                 return -ENOTSUP;
664         }
665
666         if (data_size == hdr->hdr_len) {
667                 pr_debug("BTF.ext has no data\n");
668                 return -EINVAL;
669         }
670
671         return 0;
672 }
673
674 void btf_ext__free(struct btf_ext *btf_ext)
675 {
676         if (!btf_ext)
677                 return;
678
679         free(btf_ext->func_info.info);
680         free(btf_ext->line_info.info);
681         free(btf_ext);
682 }
683
684 struct btf_ext *btf_ext__new(__u8 *data, __u32 size)
685 {
686         struct btf_ext *btf_ext;
687         int err;
688
689         err = btf_ext_parse_hdr(data, size);
690         if (err)
691                 return ERR_PTR(err);
692
693         btf_ext = calloc(1, sizeof(struct btf_ext));
694         if (!btf_ext)
695                 return ERR_PTR(-ENOMEM);
696
697         err = btf_ext_copy_func_info(btf_ext, data, size);
698         if (err) {
699                 btf_ext__free(btf_ext);
700                 return ERR_PTR(err);
701         }
702
703         err = btf_ext_copy_line_info(btf_ext, data, size);
704         if (err) {
705                 btf_ext__free(btf_ext);
706                 return ERR_PTR(err);
707         }
708
709         return btf_ext;
710 }
711
712 static int btf_ext_reloc_info(const struct btf *btf,
713                               const struct btf_ext_info *ext_info,
714                               const char *sec_name, __u32 insns_cnt,
715                               void **info, __u32 *cnt)
716 {
717         __u32 sec_hdrlen = sizeof(struct btf_ext_info_sec);
718         __u32 i, record_size, existing_len, records_len;
719         struct btf_ext_info_sec *sinfo;
720         const char *info_sec_name;
721         __u64 remain_len;
722         void *data;
723
724         record_size = ext_info->rec_size;
725         sinfo = ext_info->info;
726         remain_len = ext_info->len;
727         while (remain_len > 0) {
728                 records_len = sinfo->num_info * record_size;
729                 info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
730                 if (strcmp(info_sec_name, sec_name)) {
731                         remain_len -= sec_hdrlen + records_len;
732                         sinfo = (void *)sinfo + sec_hdrlen + records_len;
733                         continue;
734                 }
735
736                 existing_len = (*cnt) * record_size;
737                 data = realloc(*info, existing_len + records_len);
738                 if (!data)
739                         return -ENOMEM;
740
741                 memcpy(data + existing_len, sinfo->data, records_len);
742                 /* adjust insn_off only, the rest data will be passed
743                  * to the kernel.
744                  */
745                 for (i = 0; i < sinfo->num_info; i++) {
746                         __u32 *insn_off;
747
748                         insn_off = data + existing_len + (i * record_size);
749                         *insn_off = *insn_off / sizeof(struct bpf_insn) +
750                                 insns_cnt;
751                 }
752                 *info = data;
753                 *cnt += sinfo->num_info;
754                 return 0;
755         }
756
757         return -ENOENT;
758 }
759
760 int btf_ext__reloc_func_info(const struct btf *btf, const struct btf_ext *btf_ext,
761                              const char *sec_name, __u32 insns_cnt,
762                              void **func_info, __u32 *cnt)
763 {
764         return btf_ext_reloc_info(btf, &btf_ext->func_info, sec_name,
765                                   insns_cnt, func_info, cnt);
766 }
767
768 int btf_ext__reloc_line_info(const struct btf *btf, const struct btf_ext *btf_ext,
769                              const char *sec_name, __u32 insns_cnt,
770                              void **line_info, __u32 *cnt)
771 {
772         return btf_ext_reloc_info(btf, &btf_ext->line_info, sec_name,
773                                   insns_cnt, line_info, cnt);
774 }
775
776 __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext)
777 {
778         return btf_ext->func_info.rec_size;
779 }
780
781 __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext)
782 {
783         return btf_ext->line_info.rec_size;
784 }