diff options
author | Martin KaFai Lau <kafai@fb.com> | 2018-12-07 19:42:31 -0500 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2018-12-09 16:54:38 -0500 |
commit | 3d65014146c69bbc4d2947f60dbd722d352cdc46 (patch) | |
tree | ea591de92250d7ff871083d63bd5823c68b9bee9 | |
parent | f0187f0b17fad7439f510eff4d65606c9ea1190f (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.c | 86 | ||||
-rw-r--r-- | tools/lib/bpf/bpf.h | 3 | ||||
-rw-r--r-- | tools/lib/bpf/btf.c | 209 | ||||
-rw-r--r-- | tools/lib/bpf/btf.h | 10 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.c | 20 |
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 | ||
176 | static void * | ||
177 | alloc_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 | |||
176 | int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, | 201 | int 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)); |
260 | done: | 287 | done: |
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 | ||
40 | struct 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 | |||
40 | struct btf_ext { | 51 | struct 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 | ||
46 | struct btf_sec_func_info { | 56 | struct 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 */ | ||
70 | struct bpf_line_info_min { | ||
71 | __u32 insn_off; | ||
72 | __u32 file_name_off; | ||
73 | __u32 line_off; | ||
74 | __u32 line_col; | ||
75 | }; | ||
76 | |||
59 | static inline __u64 ptr_to_u64(const void *ptr) | 77 | static 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 | ||
489 | static int btf_ext_copy_func_info(struct btf_ext *btf_ext, | 507 | struct 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 | |||
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 | 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 | ||
612 | static 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, ¶m, err_log); | ||
626 | } | ||
627 | |||
628 | static 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, ¶m, err_log); | ||
642 | } | ||
643 | |||
581 | static int btf_ext_parse_hdr(__u8 *data, __u32 data_size, | 644 | static 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 | ||
646 | int btf_ext__reloc_func_info(struct btf *btf, struct btf_ext *btf_ext, | 716 | static 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 | ||
764 | int 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 | |||
772 | int 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 | ||
56 | typedef int (*btf_print_fn_t)(const char *, ...) | 58 | typedef 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 | ||
71 | struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log); | 73 | struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log); |
72 | void btf_ext__free(struct btf_ext *btf_ext); | 74 | void btf_ext__free(struct btf_ext *btf_ext); |
73 | int btf_ext__reloc_func_info(struct btf *btf, struct btf_ext *btf_ext, | 75 | int 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); |
79 | int 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 | ||
175 | struct bpf_map { | 179 | struct 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 | ||