summaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--tools/lib/bpf/bpf.c86
-rw-r--r--tools/lib/bpf/bpf.h3
-rw-r--r--tools/lib/bpf/btf.c209
-rw-r--r--tools/lib/bpf/btf.h10
-rw-r--r--tools/lib/bpf/libbpf.c20
5 files changed, 239 insertions, 89 deletions
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 9fbbc0ed5952..3caaa3428774 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -173,11 +173,36 @@ int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name,
173 -1); 173 -1);
174} 174}
175 175
176static void *
177alloc_zero_tailing_info(const void *orecord, __u32 cnt,
178 __u32 actual_rec_size, __u32 expected_rec_size)
179{
180 __u64 info_len = actual_rec_size * cnt;
181 void *info, *nrecord;
182 int i;
183
184 info = malloc(info_len);
185 if (!info)
186 return NULL;
187
188 /* zero out bytes kernel does not understand */
189 nrecord = info;
190 for (i = 0; i < cnt; i++) {
191 memcpy(nrecord, orecord, expected_rec_size);
192 memset(nrecord + expected_rec_size, 0,
193 actual_rec_size - expected_rec_size);
194 orecord += actual_rec_size;
195 nrecord += actual_rec_size;
196 }
197
198 return info;
199}
200
176int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, 201int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
177 char *log_buf, size_t log_buf_sz) 202 char *log_buf, size_t log_buf_sz)
178{ 203{
204 void *finfo = NULL, *linfo = NULL;
179 union bpf_attr attr; 205 union bpf_attr attr;
180 void *finfo = NULL;
181 __u32 name_len; 206 __u32 name_len;
182 int fd; 207 int fd;
183 208
@@ -201,6 +226,9 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
201 attr.func_info_rec_size = load_attr->func_info_rec_size; 226 attr.func_info_rec_size = load_attr->func_info_rec_size;
202 attr.func_info_cnt = load_attr->func_info_cnt; 227 attr.func_info_cnt = load_attr->func_info_cnt;
203 attr.func_info = ptr_to_u64(load_attr->func_info); 228 attr.func_info = ptr_to_u64(load_attr->func_info);
229 attr.line_info_rec_size = load_attr->line_info_rec_size;
230 attr.line_info_cnt = load_attr->line_info_cnt;
231 attr.line_info = ptr_to_u64(load_attr->line_info);
204 memcpy(attr.prog_name, load_attr->name, 232 memcpy(attr.prog_name, load_attr->name,
205 min(name_len, BPF_OBJ_NAME_LEN - 1)); 233 min(name_len, BPF_OBJ_NAME_LEN - 1));
206 234
@@ -212,36 +240,35 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
212 * to give user space a hint how to deal with loading failure. 240 * to give user space a hint how to deal with loading failure.
213 * Check to see whether we can make some changes and load again. 241 * Check to see whether we can make some changes and load again.
214 */ 242 */
215 if (errno == E2BIG && attr.func_info_cnt && 243 while (errno == E2BIG && (!finfo || !linfo)) {
216 attr.func_info_rec_size < load_attr->func_info_rec_size) { 244 if (!finfo && attr.func_info_cnt &&
217 __u32 actual_rec_size = load_attr->func_info_rec_size; 245 attr.func_info_rec_size < load_attr->func_info_rec_size) {
218 __u32 expected_rec_size = attr.func_info_rec_size; 246 /* try with corrected func info records */
219 __u32 finfo_cnt = load_attr->func_info_cnt; 247 finfo = alloc_zero_tailing_info(load_attr->func_info,
220 __u64 finfo_len = actual_rec_size * finfo_cnt; 248 load_attr->func_info_cnt,
221 const void *orecord; 249 load_attr->func_info_rec_size,
222 void *nrecord; 250 attr.func_info_rec_size);
223 int i; 251 if (!finfo)
224 252 goto done;
225 finfo = malloc(finfo_len); 253
226 if (!finfo) 254 attr.func_info = ptr_to_u64(finfo);
227 /* further try with log buffer won't help */ 255 attr.func_info_rec_size = load_attr->func_info_rec_size;
228 return fd; 256 } else if (!linfo && attr.line_info_cnt &&
229 257 attr.line_info_rec_size <
230 /* zero out bytes kernel does not understand */ 258 load_attr->line_info_rec_size) {
231 orecord = load_attr->func_info; 259 linfo = alloc_zero_tailing_info(load_attr->line_info,
232 nrecord = finfo; 260 load_attr->line_info_cnt,
233 for (i = 0; i < load_attr->func_info_cnt; i++) { 261 load_attr->line_info_rec_size,
234 memcpy(nrecord, orecord, expected_rec_size); 262 attr.line_info_rec_size);
235 memset(nrecord + expected_rec_size, 0, 263 if (!linfo)
236 actual_rec_size - expected_rec_size); 264 goto done;
237 orecord += actual_rec_size; 265
238 nrecord += actual_rec_size; 266 attr.line_info = ptr_to_u64(linfo);
267 attr.line_info_rec_size = load_attr->line_info_rec_size;
268 } else {
269 break;
239 } 270 }
240 271
241 /* try with corrected func info records */
242 attr.func_info = ptr_to_u64(finfo);
243 attr.func_info_rec_size = load_attr->func_info_rec_size;
244
245 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); 272 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
246 273
247 if (fd >= 0) 274 if (fd >= 0)
@@ -259,6 +286,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
259 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); 286 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
260done: 287done:
261 free(finfo); 288 free(finfo);
289 free(linfo);
262 return fd; 290 return fd;
263} 291}
264 292
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 098e6f793b76..8f09de482839 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -82,6 +82,9 @@ struct bpf_load_program_attr {
82 __u32 func_info_rec_size; 82 __u32 func_info_rec_size;
83 const void *func_info; 83 const void *func_info;
84 __u32 func_info_cnt; 84 __u32 func_info_cnt;
85 __u32 line_info_rec_size;
86 const void *line_info;
87 __u32 line_info_cnt;
85}; 88};
86 89
87/* Flags to direct loading requirements */ 90/* Flags to direct loading requirements */
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}
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index 936177a538cd..b0610dcdae6b 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -51,6 +51,8 @@ struct btf_ext_header {
51 /* All offsets are in bytes relative to the end of this header */ 51 /* All offsets are in bytes relative to the end of this header */
52 __u32 func_info_off; 52 __u32 func_info_off;
53 __u32 func_info_len; 53 __u32 func_info_len;
54 __u32 line_info_off;
55 __u32 line_info_len;
54}; 56};
55 57
56typedef int (*btf_print_fn_t)(const char *, ...) 58typedef int (*btf_print_fn_t)(const char *, ...)
@@ -70,10 +72,16 @@ LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf);
70 72
71struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log); 73struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
72void btf_ext__free(struct btf_ext *btf_ext); 74void btf_ext__free(struct btf_ext *btf_ext);
73int btf_ext__reloc_func_info(struct btf *btf, struct btf_ext *btf_ext, 75int btf_ext__reloc_func_info(const struct btf *btf,
76 const struct btf_ext *btf_ext,
74 const char *sec_name, __u32 insns_cnt, 77 const char *sec_name, __u32 insns_cnt,
75 void **func_info, __u32 *func_info_len); 78 void **func_info, __u32 *func_info_len);
79int btf_ext__reloc_line_info(const struct btf *btf,
80 const struct btf_ext *btf_ext,
81 const char *sec_name, __u32 insns_cnt,
82 void **line_info, __u32 *cnt);
76__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext); 83__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext);
84__u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext);
77 85
78#ifdef __cplusplus 86#ifdef __cplusplus
79} /* extern "C" */ 87} /* extern "C" */
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4ea3368bf803..e2bc75ee1614 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -170,6 +170,10 @@ struct bpf_program {
170 __u32 func_info_cnt; 170 __u32 func_info_cnt;
171 171
172 struct bpf_capabilities *caps; 172 struct bpf_capabilities *caps;
173
174 void *line_info;
175 __u32 line_info_rec_size;
176 __u32 line_info_cnt;
173}; 177};
174 178
175struct bpf_map { 179struct bpf_map {
@@ -1342,6 +1346,19 @@ bpf_program_reloc_btf_ext(struct bpf_program *prog, struct bpf_object *obj,
1342 prog->func_info_rec_size = btf_ext__func_info_rec_size(obj->btf_ext); 1346 prog->func_info_rec_size = btf_ext__func_info_rec_size(obj->btf_ext);
1343 } 1347 }
1344 1348
1349 if (!insn_offset || prog->line_info) {
1350 err = btf_ext__reloc_line_info(obj->btf, obj->btf_ext,
1351 section_name, insn_offset,
1352 &prog->line_info,
1353 &prog->line_info_cnt);
1354 if (err)
1355 return check_btf_ext_reloc_err(prog, err,
1356 prog->line_info,
1357 "bpf_line_info");
1358
1359 prog->line_info_rec_size = btf_ext__line_info_rec_size(obj->btf_ext);
1360 }
1361
1345 if (!insn_offset) 1362 if (!insn_offset)
1346 prog->btf_fd = btf__fd(obj->btf); 1363 prog->btf_fd = btf__fd(obj->btf);
1347 1364
@@ -1526,6 +1543,9 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
1526 load_attr.func_info = prog->func_info; 1543 load_attr.func_info = prog->func_info;
1527 load_attr.func_info_rec_size = prog->func_info_rec_size; 1544 load_attr.func_info_rec_size = prog->func_info_rec_size;
1528 load_attr.func_info_cnt = prog->func_info_cnt; 1545 load_attr.func_info_cnt = prog->func_info_cnt;
1546 load_attr.line_info = prog->line_info;
1547 load_attr.line_info_rec_size = prog->line_info_rec_size;
1548 load_attr.line_info_cnt = prog->line_info_cnt;
1529 if (!load_attr.insns || !load_attr.insns_cnt) 1549 if (!load_attr.insns || !load_attr.insns_cnt)
1530 return -EINVAL; 1550 return -EINVAL;
1531 1551