aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/btf.c
diff options
context:
space:
mode:
authorMartin KaFai Lau <kafai@fb.com>2018-12-07 19:42:31 -0500
committerAlexei Starovoitov <ast@kernel.org>2018-12-09 16:54:38 -0500
commit3d65014146c69bbc4d2947f60dbd722d352cdc46 (patch)
treeea591de92250d7ff871083d63bd5823c68b9bee9 /tools/lib/bpf/btf.c
parentf0187f0b17fad7439f510eff4d65606c9ea1190f (diff)
bpf: libbpf: Add btf_line_info support to libbpf
This patch adds bpf_line_info support to libbpf: 1) Parsing the line_info sec from ".BTF.ext" 2) Relocating the line_info. If the main prog *_info relocation fails, it will ignore the remaining subprog line_info and continue. If the subprog *_info relocation fails, it will bail out. 3) BPF_PROG_LOAD a prog with line_info Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Yonghong Song <yhs@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/lib/bpf/btf.c')
-rw-r--r--tools/lib/bpf/btf.c209
1 files changed, 150 insertions, 59 deletions
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index aa4fa02b13fc..d682d3b8f7b9 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -37,16 +37,26 @@ struct btf {
37 int fd; 37 int fd;
38}; 38};
39 39
40struct btf_ext_info {
41 /*
42 * info points to a deep copy of the individual info section
43 * (e.g. func_info and line_info) from the .BTF.ext.
44 * It does not include the __u32 rec_size.
45 */
46 void *info;
47 __u32 rec_size;
48 __u32 len;
49};
50
40struct btf_ext { 51struct btf_ext {
41 void *func_info; 52 struct btf_ext_info func_info;
42 __u32 func_info_rec_size; 53 struct btf_ext_info line_info;
43 __u32 func_info_len;
44}; 54};
45 55
46struct btf_sec_func_info { 56struct btf_ext_info_sec {
47 __u32 sec_name_off; 57 __u32 sec_name_off;
48 __u32 num_func_info; 58 __u32 num_info;
49 /* Followed by num_func_info number of bpf func_info records */ 59 /* Followed by num_info * record_size number of bytes */
50 __u8 data[0]; 60 __u8 data[0];
51}; 61};
52 62
@@ -56,6 +66,14 @@ struct bpf_func_info_min {
56 __u32 type_id; 66 __u32 type_id;
57}; 67};
58 68
69/* The minimum bpf_line_info checked by the loader */
70struct bpf_line_info_min {
71 __u32 insn_off;
72 __u32 file_name_off;
73 __u32 line_off;
74 __u32 line_col;
75};
76
59static inline __u64 ptr_to_u64(const void *ptr) 77static inline __u64 ptr_to_u64(const void *ptr)
60{ 78{
61 return (__u64) (unsigned long) ptr; 79 return (__u64) (unsigned long) ptr;
@@ -486,12 +504,22 @@ exit_free:
486 return err; 504 return err;
487} 505}
488 506
489static int btf_ext_copy_func_info(struct btf_ext *btf_ext, 507struct btf_ext_sec_copy_param {
490 __u8 *data, __u32 data_size, 508 __u32 off;
491 btf_print_fn_t err_log) 509 __u32 len;
510 __u32 min_rec_size;
511 struct btf_ext_info *ext_info;
512 const char *desc;
513};
514
515static 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 btf_print_fn_t err_log)
492{ 519{
493 const struct btf_ext_header *hdr = (struct btf_ext_header *)data; 520 const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
494 const struct btf_sec_func_info *sinfo; 521 const struct btf_ext_info_sec *sinfo;
522 struct btf_ext_info *ext_info;
495 __u32 info_left, record_size; 523 __u32 info_left, record_size;
496 /* The start of the info sec (including the __u32 record_size). */ 524 /* The start of the info sec (including the __u32 record_size). */
497 const void *info; 525 const void *info;
@@ -500,66 +528,69 @@ static int btf_ext_copy_func_info(struct btf_ext *btf_ext,
500 data = data + hdr->hdr_len; 528 data = data + hdr->hdr_len;
501 data_size -= hdr->hdr_len; 529 data_size -= hdr->hdr_len;
502 530
503 if (hdr->func_info_off & 0x03) { 531 if (ext_sec->off & 0x03) {
504 elog("BTF.ext func_info section is not aligned to 4 bytes\n"); 532 elog(".BTF.ext %s section is not aligned to 4 bytes\n",
533 ext_sec->desc);
505 return -EINVAL; 534 return -EINVAL;
506 } 535 }
507 536
508 if (data_size < hdr->func_info_off || 537 if (data_size < ext_sec->off ||
509 hdr->func_info_len > data_size - hdr->func_info_off) { 538 ext_sec->len > data_size - ext_sec->off) {
510 elog("func_info section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n", 539 elog("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
511 hdr->func_info_off, hdr->func_info_len); 540 ext_sec->desc, ext_sec->off, ext_sec->len);
512 return -EINVAL; 541 return -EINVAL;
513 } 542 }
514 543
515 info = data + hdr->func_info_off; 544 info = data + ext_sec->off;
516 info_left = hdr->func_info_len; 545 info_left = ext_sec->len;
517 546
518 /* At least a func_info record size */ 547 /* At least a record size */
519 if (info_left < sizeof(__u32)) { 548 if (info_left < sizeof(__u32)) {
520 elog("BTF.ext func_info record size not found"); 549 elog(".BTF.ext %s record size not found\n", ext_sec->desc);
521 return -EINVAL; 550 return -EINVAL;
522 } 551 }
523 552
524 /* The record size needs to meet the minimum standard */ 553 /* The record size needs to meet the minimum standard */
525 record_size = *(__u32 *)info; 554 record_size = *(__u32 *)info;
526 if (record_size < sizeof(struct bpf_func_info_min) || 555 if (record_size < ext_sec->min_rec_size ||
527 record_size & 0x03) { 556 record_size & 0x03) {
528 elog("BTF.ext func_info invalid record size"); 557 elog("%s section in .BTF.ext has invalid record size %u\n",
558 ext_sec->desc, record_size);
529 return -EINVAL; 559 return -EINVAL;
530 } 560 }
531 561
532 sinfo = info + sizeof(__u32); 562 sinfo = info + sizeof(__u32);
533 info_left -= sizeof(__u32); 563 info_left -= sizeof(__u32);
534 564
535 /* If no func_info records, return failure now so .BTF.ext 565 /* If no records, return failure now so .BTF.ext won't be used. */
536 * won't be used.
537 */
538 if (!info_left) { 566 if (!info_left) {
539 elog("BTF.ext no func info records"); 567 elog("%s section in .BTF.ext has no records", ext_sec->desc);
540 return -EINVAL; 568 return -EINVAL;
541 } 569 }
542 570
543 while (info_left) { 571 while (info_left) {
544 unsigned int sec_hdrlen = sizeof(struct btf_sec_func_info); 572 unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec);
545 __u64 total_record_size; 573 __u64 total_record_size;
546 __u32 num_records; 574 __u32 num_records;
547 575
548 if (info_left < sec_hdrlen) { 576 if (info_left < sec_hdrlen) {
549 elog("BTF.ext func_info header not found"); 577 elog("%s section header is not found in .BTF.ext\n",
578 ext_sec->desc);
550 return -EINVAL; 579 return -EINVAL;
551 } 580 }
552 581
553 num_records = sinfo->num_func_info; 582 num_records = sinfo->num_info;
554 if (num_records == 0) { 583 if (num_records == 0) {
555 elog("incorrect BTF.ext num_func_info"); 584 elog("%s section has incorrect num_records in .BTF.ext\n",
585 ext_sec->desc);
556 return -EINVAL; 586 return -EINVAL;
557 } 587 }
558 588
559 total_record_size = sec_hdrlen + 589 total_record_size = sec_hdrlen +
560 (__u64)num_records * record_size; 590 (__u64)num_records * record_size;
561 if (info_left < total_record_size) { 591 if (info_left < total_record_size) {
562 elog("incorrect BTF.ext num_func_info"); 592 elog("%s section has incorrect num_records in .BTF.ext\n",
593 ext_sec->desc);
563 return -EINVAL; 594 return -EINVAL;
564 } 595 }
565 596
@@ -567,17 +598,49 @@ static int btf_ext_copy_func_info(struct btf_ext *btf_ext,
567 sinfo = (void *)sinfo + total_record_size; 598 sinfo = (void *)sinfo + total_record_size;
568 } 599 }
569 600
570 btf_ext->func_info_len = hdr->func_info_len - sizeof(__u32); 601 ext_info = ext_sec->ext_info;
571 btf_ext->func_info_rec_size = record_size; 602 ext_info->len = ext_sec->len - sizeof(__u32);
572 btf_ext->func_info = malloc(btf_ext->func_info_len); 603 ext_info->rec_size = record_size;
573 if (!btf_ext->func_info) 604 ext_info->info = malloc(ext_info->len);
605 if (!ext_info->info)
574 return -ENOMEM; 606 return -ENOMEM;
575 memcpy(btf_ext->func_info, info + sizeof(__u32), 607 memcpy(ext_info->info, info + sizeof(__u32), ext_info->len);
576 btf_ext->func_info_len);
577 608
578 return 0; 609 return 0;
579} 610}
580 611
612static int btf_ext_copy_func_info(struct btf_ext *btf_ext,
613 __u8 *data, __u32 data_size,
614 btf_print_fn_t err_log)
615{
616 const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
617 struct btf_ext_sec_copy_param param = {
618 .off = hdr->func_info_off,
619 .len = hdr->func_info_len,
620 .min_rec_size = sizeof(struct bpf_func_info_min),
621 .ext_info = &btf_ext->func_info,
622 .desc = "func_info"
623 };
624
625 return btf_ext_copy_info(btf_ext, data, data_size, &param, err_log);
626}
627
628static int btf_ext_copy_line_info(struct btf_ext *btf_ext,
629 __u8 *data, __u32 data_size,
630 btf_print_fn_t err_log)
631{
632 const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
633 struct btf_ext_sec_copy_param param = {
634 .off = hdr->line_info_off,
635 .len = hdr->line_info_len,
636 .min_rec_size = sizeof(struct bpf_line_info_min),
637 .ext_info = &btf_ext->line_info,
638 .desc = "line_info",
639 };
640
641 return btf_ext_copy_info(btf_ext, data, data_size, &param, err_log);
642}
643
581static int btf_ext_parse_hdr(__u8 *data, __u32 data_size, 644static int btf_ext_parse_hdr(__u8 *data, __u32 data_size,
582 btf_print_fn_t err_log) 645 btf_print_fn_t err_log)
583{ 646{
@@ -617,7 +680,8 @@ void btf_ext__free(struct btf_ext *btf_ext)
617 if (!btf_ext) 680 if (!btf_ext)
618 return; 681 return;
619 682
620 free(btf_ext->func_info); 683 free(btf_ext->func_info.info);
684 free(btf_ext->line_info.info);
621 free(btf_ext); 685 free(btf_ext);
622} 686}
623 687
@@ -640,25 +704,32 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log)
640 return ERR_PTR(err); 704 return ERR_PTR(err);
641 } 705 }
642 706
707 err = btf_ext_copy_line_info(btf_ext, data, size, err_log);
708 if (err) {
709 btf_ext__free(btf_ext);
710 return ERR_PTR(err);
711 }
712
643 return btf_ext; 713 return btf_ext;
644} 714}
645 715
646int btf_ext__reloc_func_info(struct btf *btf, struct btf_ext *btf_ext, 716static int btf_ext_reloc_info(const struct btf *btf,
647 const char *sec_name, __u32 insns_cnt, 717 const struct btf_ext_info *ext_info,
648 void **func_info, __u32 *cnt) 718 const char *sec_name, __u32 insns_cnt,
719 void **info, __u32 *cnt)
649{ 720{
650 __u32 sec_hdrlen = sizeof(struct btf_sec_func_info); 721 __u32 sec_hdrlen = sizeof(struct btf_ext_info_sec);
651 __u32 i, record_size, existing_flen, records_len; 722 __u32 i, record_size, existing_len, records_len;
652 struct btf_sec_func_info *sinfo; 723 struct btf_ext_info_sec *sinfo;
653 const char *info_sec_name; 724 const char *info_sec_name;
654 __u64 remain_len; 725 __u64 remain_len;
655 void *data; 726 void *data;
656 727
657 record_size = btf_ext->func_info_rec_size; 728 record_size = ext_info->rec_size;
658 sinfo = btf_ext->func_info; 729 sinfo = ext_info->info;
659 remain_len = btf_ext->func_info_len; 730 remain_len = ext_info->len;
660 while (remain_len > 0) { 731 while (remain_len > 0) {
661 records_len = sinfo->num_func_info * record_size; 732 records_len = sinfo->num_info * record_size;
662 info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off); 733 info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
663 if (strcmp(info_sec_name, sec_name)) { 734 if (strcmp(info_sec_name, sec_name)) {
664 remain_len -= sec_hdrlen + records_len; 735 remain_len -= sec_hdrlen + records_len;
@@ -666,32 +737,52 @@ int btf_ext__reloc_func_info(struct btf *btf, struct btf_ext *btf_ext,
666 continue; 737 continue;
667 } 738 }
668 739
669 existing_flen = (*cnt) * record_size; 740 existing_len = (*cnt) * record_size;
670 data = realloc(*func_info, existing_flen + records_len); 741 data = realloc(*info, existing_len + records_len);
671 if (!data) 742 if (!data)
672 return -ENOMEM; 743 return -ENOMEM;
673 744
674 memcpy(data + existing_flen, sinfo->data, records_len); 745 memcpy(data + existing_len, sinfo->data, records_len);
675 /* adjust insn_off only, the rest data will be passed 746 /* adjust insn_off only, the rest data will be passed
676 * to the kernel. 747 * to the kernel.
677 */ 748 */
678 for (i = 0; i < sinfo->num_func_info; i++) { 749 for (i = 0; i < sinfo->num_info; i++) {
679 struct bpf_func_info_min *record; 750 __u32 *insn_off;
680 751
681 record = data + existing_flen + i * record_size; 752 insn_off = data + existing_len + (i * record_size);
682 record->insn_off = 753 *insn_off = *insn_off / sizeof(struct bpf_insn) +
683 record->insn_off / sizeof(struct bpf_insn) +
684 insns_cnt; 754 insns_cnt;
685 } 755 }
686 *func_info = data; 756 *info = data;
687 *cnt += sinfo->num_func_info; 757 *cnt += sinfo->num_info;
688 return 0; 758 return 0;
689 } 759 }
690 760
691 return -ENOENT; 761 return -ENOENT;
692} 762}
693 763
764int btf_ext__reloc_func_info(const struct btf *btf, const struct btf_ext *btf_ext,
765 const char *sec_name, __u32 insns_cnt,
766 void **func_info, __u32 *cnt)
767{
768 return btf_ext_reloc_info(btf, &btf_ext->func_info, sec_name,
769 insns_cnt, func_info, cnt);
770}
771
772int btf_ext__reloc_line_info(const struct btf *btf, const struct btf_ext *btf_ext,
773 const char *sec_name, __u32 insns_cnt,
774 void **line_info, __u32 *cnt)
775{
776 return btf_ext_reloc_info(btf, &btf_ext->line_info, sec_name,
777 insns_cnt, line_info, cnt);
778}
779
694__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext) 780__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext)
695{ 781{
696 return btf_ext->func_info_rec_size; 782 return btf_ext->func_info.rec_size;
783}
784
785__u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext)
786{
787 return btf_ext->line_info.rec_size;
697} 788}