aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYonghong Song <yhs@fb.com>2018-11-19 18:29:16 -0500
committerAlexei Starovoitov <ast@kernel.org>2018-11-20 13:54:39 -0500
commit2993e0515bb44e157c17c9ba7309ba46366b6add (patch)
tree15c44288f87b0cb93cbfc6012e0094fc106ecdd7
parent4798c4ba3ba94e4da37b2557dfda04f80a94e8d5 (diff)
tools/bpf: add support to read .BTF.ext sections
The .BTF section is already available to encode types. These types can be used for map pretty print. The whole .BTF will be passed to the kernel as well for which kernel can verify and return to the user space for pretty print etc. The llvm patch at https://reviews.llvm.org/D53736 will generate .BTF section and one more section .BTF.ext. The .BTF.ext section encodes function type information and line information. Note that this patch set only supports function type info. The functionality is implemented in libbpf. The .BTF section can be directly loaded into the kernel, and the .BTF.ext section cannot. The loader may need to do some relocation and merging, similar to merging multiple code sections, before loading into the kernel. Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--tools/lib/bpf/bpf.c46
-rw-r--r--tools/lib/bpf/btf.c274
-rw-r--r--tools/lib/bpf/btf.h50
-rw-r--r--tools/lib/bpf/libbpf.c87
4 files changed, 442 insertions, 15 deletions
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 9b5cf22c4e64..836447bb4f14 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -186,6 +186,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
186 char *log_buf, size_t log_buf_sz) 186 char *log_buf, size_t log_buf_sz)
187{ 187{
188 union bpf_attr attr; 188 union bpf_attr attr;
189 void *finfo = NULL;
189 __u32 name_len; 190 __u32 name_len;
190 int fd; 191 int fd;
191 192
@@ -216,12 +217,55 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
216 if (fd >= 0 || !log_buf || !log_buf_sz) 217 if (fd >= 0 || !log_buf || !log_buf_sz)
217 return fd; 218 return fd;
218 219
220 /* After bpf_prog_load, the kernel may modify certain attributes
221 * to give user space a hint how to deal with loading failure.
222 * Check to see whether we can make some changes and load again.
223 */
224 if (errno == E2BIG && attr.func_info_cnt &&
225 attr.func_info_rec_size < load_attr->func_info_rec_size) {
226 __u32 actual_rec_size = load_attr->func_info_rec_size;
227 __u32 expected_rec_size = attr.func_info_rec_size;
228 __u32 finfo_cnt = load_attr->func_info_cnt;
229 __u64 finfo_len = actual_rec_size * finfo_cnt;
230 const void *orecord;
231 void *nrecord;
232 int i;
233
234 finfo = malloc(finfo_len);
235 if (!finfo)
236 /* further try with log buffer won't help */
237 return fd;
238
239 /* zero out bytes kernel does not understand */
240 orecord = load_attr->func_info;
241 nrecord = finfo;
242 for (i = 0; i < load_attr->func_info_cnt; i++) {
243 memcpy(nrecord, orecord, expected_rec_size);
244 memset(nrecord + expected_rec_size, 0,
245 actual_rec_size - expected_rec_size);
246 orecord += actual_rec_size;
247 nrecord += actual_rec_size;
248 }
249
250 /* try with corrected func info records */
251 attr.func_info = ptr_to_u64(finfo);
252 attr.func_info_rec_size = load_attr->func_info_rec_size;
253
254 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
255
256 if (fd >= 0 || !log_buf || !log_buf_sz)
257 goto done;
258 }
259
219 /* Try again with log */ 260 /* Try again with log */
220 attr.log_buf = ptr_to_u64(log_buf); 261 attr.log_buf = ptr_to_u64(log_buf);
221 attr.log_size = log_buf_sz; 262 attr.log_size = log_buf_sz;
222 attr.log_level = 1; 263 attr.log_level = 1;
223 log_buf[0] = 0; 264 log_buf[0] = 0;
224 return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); 265 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
266done:
267 free(finfo);
268 return fd;
225} 269}
226 270
227int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns, 271int bpf_load_program(enum bpf_prog_type type, const struct bpf_insn *insns,
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index 31225e64766f..fe87cb48a6a9 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -37,6 +37,18 @@ struct btf {
37 int fd; 37 int fd;
38}; 38};
39 39
40struct btf_ext {
41 void *func_info;
42 __u32 func_info_rec_size;
43 __u32 func_info_len;
44};
45
46/* The minimum bpf_func_info checked by the loader */
47struct bpf_func_info_min {
48 __u32 insn_offset;
49 __u32 type_id;
50};
51
40static int btf_add_type(struct btf *btf, struct btf_type *t) 52static int btf_add_type(struct btf *btf, struct btf_type *t)
41{ 53{
42 if (btf->types_size - btf->nr_types < 2) { 54 if (btf->types_size - btf->nr_types < 2) {
@@ -397,3 +409,265 @@ const char *btf__name_by_offset(const struct btf *btf, __u32 offset)
397 else 409 else
398 return NULL; 410 return NULL;
399} 411}
412
413static int btf_ext_validate_func_info(const void *finfo, __u32 size,
414 btf_print_fn_t err_log)
415{
416 int sec_hdrlen = sizeof(struct btf_sec_func_info);
417 __u32 size_left, num_records, record_size;
418 const struct btf_sec_func_info *sinfo;
419 __u64 total_record_size;
420
421 /* At least a func_info record size */
422 if (size < sizeof(__u32)) {
423 elog("BTF.ext func_info record size not found");
424 return -EINVAL;
425 }
426
427 /* The record size needs to meet below minimum standard */
428 record_size = *(__u32 *)finfo;
429 if (record_size < sizeof(struct bpf_func_info_min) ||
430 record_size % sizeof(__u32)) {
431 elog("BTF.ext func_info invalid record size");
432 return -EINVAL;
433 }
434
435 sinfo = finfo + sizeof(__u32);
436 size_left = size - sizeof(__u32);
437
438 /* If no func_info records, return failure now so .BTF.ext
439 * won't be used.
440 */
441 if (!size_left) {
442 elog("BTF.ext no func info records");
443 return -EINVAL;
444 }
445
446 while (size_left) {
447 if (size_left < sec_hdrlen) {
448 elog("BTF.ext func_info header not found");
449 return -EINVAL;
450 }
451
452 num_records = sinfo->num_func_info;
453 if (num_records == 0) {
454 elog("incorrect BTF.ext num_func_info");
455 return -EINVAL;
456 }
457
458 total_record_size = sec_hdrlen +
459 (__u64)num_records * record_size;
460 if (size_left < total_record_size) {
461 elog("incorrect BTF.ext num_func_info");
462 return -EINVAL;
463 }
464
465 size_left -= total_record_size;
466 sinfo = (void *)sinfo + total_record_size;
467 }
468
469 return 0;
470}
471
472static int btf_ext_parse_hdr(__u8 *data, __u32 data_size,
473 btf_print_fn_t err_log)
474{
475 const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
476 __u32 meta_left, last_func_info_pos;
477 void *finfo;
478
479 if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
480 data_size < hdr->hdr_len) {
481 elog("BTF.ext header not found");
482 return -EINVAL;
483 }
484
485 if (hdr->magic != BTF_MAGIC) {
486 elog("Invalid BTF.ext magic:%x\n", hdr->magic);
487 return -EINVAL;
488 }
489
490 if (hdr->version != BTF_VERSION) {
491 elog("Unsupported BTF.ext version:%u\n", hdr->version);
492 return -ENOTSUP;
493 }
494
495 if (hdr->flags) {
496 elog("Unsupported BTF.ext flags:%x\n", hdr->flags);
497 return -ENOTSUP;
498 }
499
500 meta_left = data_size - hdr->hdr_len;
501 if (!meta_left) {
502 elog("BTF.ext has no data\n");
503 return -EINVAL;
504 }
505
506 if (meta_left < hdr->func_info_off) {
507 elog("Invalid BTF.ext func_info section offset:%u\n",
508 hdr->func_info_off);
509 return -EINVAL;
510 }
511
512 if (hdr->func_info_off & 0x03) {
513 elog("BTF.ext func_info section is not aligned to 4 bytes\n");
514 return -EINVAL;
515 }
516
517 last_func_info_pos = hdr->hdr_len + hdr->func_info_off +
518 hdr->func_info_len;
519 if (last_func_info_pos > data_size) {
520 elog("Invalid BTF.ext func_info section size:%u\n",
521 hdr->func_info_len);
522 return -EINVAL;
523 }
524
525 finfo = data + hdr->hdr_len + hdr->func_info_off;
526 return btf_ext_validate_func_info(finfo, hdr->func_info_len,
527 err_log);
528}
529
530void btf_ext__free(struct btf_ext *btf_ext)
531{
532 if (!btf_ext)
533 return;
534
535 free(btf_ext->func_info);
536 free(btf_ext);
537}
538
539struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log)
540{
541 const struct btf_ext_header *hdr;
542 struct btf_ext *btf_ext;
543 void *org_fdata, *fdata;
544 __u32 hdrlen, size_u32;
545 int err;
546
547 err = btf_ext_parse_hdr(data, size, err_log);
548 if (err)
549 return ERR_PTR(err);
550
551 btf_ext = calloc(1, sizeof(struct btf_ext));
552 if (!btf_ext)
553 return ERR_PTR(-ENOMEM);
554
555 hdr = (const struct btf_ext_header *)data;
556 hdrlen = hdr->hdr_len;
557 size_u32 = sizeof(__u32);
558 fdata = malloc(hdr->func_info_len - size_u32);
559 if (!fdata) {
560 free(btf_ext);
561 return ERR_PTR(-ENOMEM);
562 }
563
564 /* remember record size and copy rest of func_info data */
565 org_fdata = data + hdrlen + hdr->func_info_off;
566 btf_ext->func_info_rec_size = *(__u32 *)org_fdata;
567 memcpy(fdata, org_fdata + size_u32, hdr->func_info_len - size_u32);
568 btf_ext->func_info = fdata;
569 btf_ext->func_info_len = hdr->func_info_len - size_u32;
570
571 return btf_ext;
572}
573
574int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
575 const char *sec_name, void **func_info,
576 __u32 *func_info_rec_size, __u32 *func_info_len)
577{
578 __u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
579 __u32 i, record_size, records_len;
580 struct btf_sec_func_info *sinfo;
581 const char *info_sec_name;
582 __s64 remain_len;
583 void *data;
584
585 record_size = btf_ext->func_info_rec_size;
586 sinfo = btf_ext->func_info;
587 remain_len = btf_ext->func_info_len;
588
589 while (remain_len > 0) {
590 records_len = sinfo->num_func_info * record_size;
591 info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
592 if (strcmp(info_sec_name, sec_name)) {
593 remain_len -= sec_hdrlen + records_len;
594 sinfo = (void *)sinfo + sec_hdrlen + records_len;
595 continue;
596 }
597
598 data = malloc(records_len);
599 if (!data)
600 return -ENOMEM;
601
602 memcpy(data, sinfo->data, records_len);
603
604 /* adjust the insn_offset, the data in .BTF.ext is
605 * the actual byte offset, and the kernel expects
606 * the offset in term of bpf_insn.
607 *
608 * adjust the insn offset only, the rest data will
609 * be passed to kernel.
610 */
611 for (i = 0; i < sinfo->num_func_info; i++) {
612 struct bpf_func_info_min *record;
613
614 record = data + i * record_size;
615 record->insn_offset /= sizeof(struct bpf_insn);
616 }
617
618 *func_info = data;
619 *func_info_len = records_len;
620 *func_info_rec_size = record_size;
621 return 0;
622 }
623
624 return -EINVAL;
625}
626
627int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
628 const char *sec_name, __u32 insns_cnt,
629 void **func_info, __u32 *func_info_len)
630{
631 __u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
632 __u32 i, record_size, existing_flen, records_len;
633 struct btf_sec_func_info *sinfo;
634 const char *info_sec_name;
635 __u64 remain_len;
636 void *data;
637
638 record_size = btf_ext->func_info_rec_size;
639 sinfo = btf_ext->func_info;
640 remain_len = btf_ext->func_info_len;
641 while (remain_len > 0) {
642 records_len = sinfo->num_func_info * record_size;
643 info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
644 if (strcmp(info_sec_name, sec_name)) {
645 remain_len -= sec_hdrlen + records_len;
646 sinfo = (void *)sinfo + sec_hdrlen + records_len;
647 continue;
648 }
649
650 existing_flen = *func_info_len;
651 data = realloc(*func_info, existing_flen + records_len);
652 if (!data)
653 return -ENOMEM;
654
655 memcpy(data + existing_flen, sinfo->data, records_len);
656 /* adjust insn_offset only, the rest data will be passed
657 * to the kernel.
658 */
659 for (i = 0; i < sinfo->num_func_info; i++) {
660 struct bpf_func_info_min *record;
661
662 record = data + existing_flen + i * record_size;
663 record->insn_offset =
664 record->insn_offset / sizeof(struct bpf_insn) +
665 insns_cnt;
666 }
667 *func_info = data;
668 *func_info_len = existing_flen + records_len;
669 return 0;
670 }
671
672 return -EINVAL;
673}
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index b77e7080f7e7..578171e8cb26 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -11,10 +11,51 @@
11#endif 11#endif
12 12
13#define BTF_ELF_SEC ".BTF" 13#define BTF_ELF_SEC ".BTF"
14#define BTF_EXT_ELF_SEC ".BTF.ext"
14 15
15struct btf; 16struct btf;
17struct btf_ext;
16struct btf_type; 18struct btf_type;
17 19
20/*
21 * The .BTF.ext ELF section layout defined as
22 * struct btf_ext_header
23 * func_info subsection
24 *
25 * The func_info subsection layout:
26 * record size for struct bpf_func_info in the func_info subsection
27 * struct btf_sec_func_info for section #1
28 * a list of bpf_func_info records for section #1
29 * where struct bpf_func_info mimics one in include/uapi/linux/bpf.h
30 * but may not be identical
31 * struct btf_sec_func_info for section #2
32 * a list of bpf_func_info records for section #2
33 * ......
34 *
35 * Note that the bpf_func_info record size in .BTF.ext may not
36 * be the same as the one defined in include/uapi/linux/bpf.h.
37 * The loader should ensure that record_size meets minimum
38 * requirement and pass the record as is to the kernel. The
39 * kernel will handle the func_info properly based on its contents.
40 */
41struct btf_ext_header {
42 __u16 magic;
43 __u8 version;
44 __u8 flags;
45 __u32 hdr_len;
46
47 /* All offsets are in bytes relative to the end of this header */
48 __u32 func_info_off;
49 __u32 func_info_len;
50};
51
52struct btf_sec_func_info {
53 __u32 sec_name_off;
54 __u32 num_func_info;
55 /* Followed by num_func_info number of bpf func_info records */
56 __u8 data[0];
57};
58
18typedef int (*btf_print_fn_t)(const char *, ...) 59typedef int (*btf_print_fn_t)(const char *, ...)
19 __attribute__((format(printf, 1, 2))); 60 __attribute__((format(printf, 1, 2)));
20 61
@@ -29,4 +70,13 @@ LIBBPF_API int btf__resolve_type(const struct btf *btf, __u32 type_id);
29LIBBPF_API int btf__fd(const struct btf *btf); 70LIBBPF_API int btf__fd(const struct btf *btf);
30LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset); 71LIBBPF_API const char *btf__name_by_offset(const struct btf *btf, __u32 offset);
31 72
73struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
74void btf_ext__free(struct btf_ext *btf_ext);
75int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
76 const char *sec_name, void **func_info,
77 __u32 *func_info_rec_size, __u32 *func_info_len);
78int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
79 const char *sec_name, __u32 insns_cnt, void **func_info,
80 __u32 *func_info_len);
81
32#endif /* __LIBBPF_BTF_H */ 82#endif /* __LIBBPF_BTF_H */
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index a01eb9584e52..cb6565d79603 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -156,6 +156,10 @@ struct bpf_program {
156 bpf_program_clear_priv_t clear_priv; 156 bpf_program_clear_priv_t clear_priv;
157 157
158 enum bpf_attach_type expected_attach_type; 158 enum bpf_attach_type expected_attach_type;
159 int btf_fd;
160 void *func_info;
161 __u32 func_info_rec_size;
162 __u32 func_info_len;
159}; 163};
160 164
161struct bpf_map { 165struct bpf_map {
@@ -212,6 +216,7 @@ struct bpf_object {
212 struct list_head list; 216 struct list_head list;
213 217
214 struct btf *btf; 218 struct btf *btf;
219 struct btf_ext *btf_ext;
215 220
216 void *priv; 221 void *priv;
217 bpf_object_clear_priv_t clear_priv; 222 bpf_object_clear_priv_t clear_priv;
@@ -241,6 +246,9 @@ void bpf_program__unload(struct bpf_program *prog)
241 246
242 prog->instances.nr = -1; 247 prog->instances.nr = -1;
243 zfree(&prog->instances.fds); 248 zfree(&prog->instances.fds);
249
250 zclose(prog->btf_fd);
251 zfree(&prog->func_info);
244} 252}
245 253
246static void bpf_program__exit(struct bpf_program *prog) 254static void bpf_program__exit(struct bpf_program *prog)
@@ -315,6 +323,7 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
315 prog->instances.fds = NULL; 323 prog->instances.fds = NULL;
316 prog->instances.nr = -1; 324 prog->instances.nr = -1;
317 prog->type = BPF_PROG_TYPE_KPROBE; 325 prog->type = BPF_PROG_TYPE_KPROBE;
326 prog->btf_fd = -1;
318 327
319 return 0; 328 return 0;
320errout: 329errout:
@@ -807,6 +816,15 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
807 BTF_ELF_SEC, PTR_ERR(obj->btf)); 816 BTF_ELF_SEC, PTR_ERR(obj->btf));
808 obj->btf = NULL; 817 obj->btf = NULL;
809 } 818 }
819 } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) {
820 obj->btf_ext = btf_ext__new(data->d_buf, data->d_size,
821 __pr_debug);
822 if (IS_ERR(obj->btf_ext)) {
823 pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n",
824 BTF_EXT_ELF_SEC,
825 PTR_ERR(obj->btf_ext));
826 obj->btf_ext = NULL;
827 }
810 } else if (sh.sh_type == SHT_SYMTAB) { 828 } else if (sh.sh_type == SHT_SYMTAB) {
811 if (obj->efile.symbols) { 829 if (obj->efile.symbols) {
812 pr_warning("bpf: multiple SYMTAB in %s\n", 830 pr_warning("bpf: multiple SYMTAB in %s\n",
@@ -1190,6 +1208,7 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
1190 struct bpf_insn *insn, *new_insn; 1208 struct bpf_insn *insn, *new_insn;
1191 struct bpf_program *text; 1209 struct bpf_program *text;
1192 size_t new_cnt; 1210 size_t new_cnt;
1211 int err;
1193 1212
1194 if (relo->type != RELO_CALL) 1213 if (relo->type != RELO_CALL)
1195 return -LIBBPF_ERRNO__RELOC; 1214 return -LIBBPF_ERRNO__RELOC;
@@ -1212,6 +1231,20 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
1212 pr_warning("oom in prog realloc\n"); 1231 pr_warning("oom in prog realloc\n");
1213 return -ENOMEM; 1232 return -ENOMEM;
1214 } 1233 }
1234
1235 if (obj->btf && obj->btf_ext) {
1236 err = btf_ext__reloc(obj->btf, obj->btf_ext,
1237 text->section_name,
1238 prog->insns_cnt,
1239 &prog->func_info,
1240 &prog->func_info_len);
1241 if (err) {
1242 pr_warning("error in btf_ext__reloc for sec %s\n",
1243 text->section_name);
1244 return err;
1245 }
1246 }
1247
1215 memcpy(new_insn + prog->insns_cnt, text->insns, 1248 memcpy(new_insn + prog->insns_cnt, text->insns,
1216 text->insns_cnt * sizeof(*insn)); 1249 text->insns_cnt * sizeof(*insn));
1217 prog->insns = new_insn; 1250 prog->insns = new_insn;
@@ -1231,7 +1264,24 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
1231{ 1264{
1232 int i, err; 1265 int i, err;
1233 1266
1234 if (!prog || !prog->reloc_desc) 1267 if (!prog)
1268 return 0;
1269
1270 if (obj->btf && obj->btf_ext) {
1271 err = btf_ext__reloc_init(obj->btf, obj->btf_ext,
1272 prog->section_name,
1273 &prog->func_info,
1274 &prog->func_info_rec_size,
1275 &prog->func_info_len);
1276 if (err) {
1277 pr_warning("err in btf_ext__reloc_init for sec %s\n",
1278 prog->section_name);
1279 return err;
1280 }
1281 prog->btf_fd = btf__fd(obj->btf);
1282 }
1283
1284 if (!prog->reloc_desc)
1235 return 0; 1285 return 0;
1236 1286
1237 for (i = 0; i < prog->nr_reloc; i++) { 1287 for (i = 0; i < prog->nr_reloc; i++) {
@@ -1319,9 +1369,9 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
1319} 1369}
1320 1370
1321static int 1371static int
1322load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type, 1372load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
1323 const char *name, struct bpf_insn *insns, int insns_cnt, 1373 char *license, __u32 kern_version, int *pfd,
1324 char *license, __u32 kern_version, int *pfd, int prog_ifindex) 1374 __u32 func_info_cnt)
1325{ 1375{
1326 struct bpf_load_program_attr load_attr; 1376 struct bpf_load_program_attr load_attr;
1327 char *cp, errmsg[STRERR_BUFSIZE]; 1377 char *cp, errmsg[STRERR_BUFSIZE];
@@ -1329,14 +1379,18 @@ load_program(enum bpf_prog_type type, enum bpf_attach_type expected_attach_type,
1329 int ret; 1379 int ret;
1330 1380
1331 memset(&load_attr, 0, sizeof(struct bpf_load_program_attr)); 1381 memset(&load_attr, 0, sizeof(struct bpf_load_program_attr));
1332 load_attr.prog_type = type; 1382 load_attr.prog_type = prog->type;
1333 load_attr.expected_attach_type = expected_attach_type; 1383 load_attr.expected_attach_type = prog->expected_attach_type;
1334 load_attr.name = name; 1384 load_attr.name = prog->name;
1335 load_attr.insns = insns; 1385 load_attr.insns = insns;
1336 load_attr.insns_cnt = insns_cnt; 1386 load_attr.insns_cnt = insns_cnt;
1337 load_attr.license = license; 1387 load_attr.license = license;
1338 load_attr.kern_version = kern_version; 1388 load_attr.kern_version = kern_version;
1339 load_attr.prog_ifindex = prog_ifindex; 1389 load_attr.prog_ifindex = prog->prog_ifindex;
1390 load_attr.prog_btf_fd = prog->btf_fd;
1391 load_attr.func_info = prog->func_info;
1392 load_attr.func_info_rec_size = prog->func_info_rec_size;
1393 load_attr.func_info_cnt = func_info_cnt;
1340 1394
1341 if (!load_attr.insns || !load_attr.insns_cnt) 1395 if (!load_attr.insns || !load_attr.insns_cnt)
1342 return -EINVAL; 1396 return -EINVAL;
@@ -1394,8 +1448,14 @@ int
1394bpf_program__load(struct bpf_program *prog, 1448bpf_program__load(struct bpf_program *prog,
1395 char *license, __u32 kern_version) 1449 char *license, __u32 kern_version)
1396{ 1450{
1451 __u32 func_info_cnt;
1397 int err = 0, fd, i; 1452 int err = 0, fd, i;
1398 1453
1454 if (prog->func_info_len == 0)
1455 func_info_cnt = 0;
1456 else
1457 func_info_cnt = prog->func_info_len / prog->func_info_rec_size;
1458
1399 if (prog->instances.nr < 0 || !prog->instances.fds) { 1459 if (prog->instances.nr < 0 || !prog->instances.fds) {
1400 if (prog->preprocessor) { 1460 if (prog->preprocessor) {
1401 pr_warning("Internal error: can't load program '%s'\n", 1461 pr_warning("Internal error: can't load program '%s'\n",
@@ -1417,10 +1477,9 @@ bpf_program__load(struct bpf_program *prog,
1417 pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n", 1477 pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n",
1418 prog->section_name, prog->instances.nr); 1478 prog->section_name, prog->instances.nr);
1419 } 1479 }
1420 err = load_program(prog->type, prog->expected_attach_type, 1480 err = load_program(prog, prog->insns, prog->insns_cnt,
1421 prog->name, prog->insns, prog->insns_cnt,
1422 license, kern_version, &fd, 1481 license, kern_version, &fd,
1423 prog->prog_ifindex); 1482 func_info_cnt);
1424 if (!err) 1483 if (!err)
1425 prog->instances.fds[0] = fd; 1484 prog->instances.fds[0] = fd;
1426 goto out; 1485 goto out;
@@ -1448,11 +1507,10 @@ bpf_program__load(struct bpf_program *prog,
1448 continue; 1507 continue;
1449 } 1508 }
1450 1509
1451 err = load_program(prog->type, prog->expected_attach_type, 1510 err = load_program(prog, result.new_insn_ptr,
1452 prog->name, result.new_insn_ptr,
1453 result.new_insn_cnt, 1511 result.new_insn_cnt,
1454 license, kern_version, &fd, 1512 license, kern_version, &fd,
1455 prog->prog_ifindex); 1513 func_info_cnt);
1456 1514
1457 if (err) { 1515 if (err) {
1458 pr_warning("Loading the %dth instance of program '%s' failed\n", 1516 pr_warning("Loading the %dth instance of program '%s' failed\n",
@@ -2120,6 +2178,7 @@ void bpf_object__close(struct bpf_object *obj)
2120 bpf_object__elf_finish(obj); 2178 bpf_object__elf_finish(obj);
2121 bpf_object__unload(obj); 2179 bpf_object__unload(obj);
2122 btf__free(obj->btf); 2180 btf__free(obj->btf);
2181 btf_ext__free(obj->btf_ext);
2123 2182
2124 for (i = 0; i < obj->nr_maps; i++) { 2183 for (i = 0; i < obj->nr_maps; i++) {
2125 zfree(&obj->maps[i].name); 2184 zfree(&obj->maps[i].name);