Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: libbpf: bpftool: Print bpf_line_info during prog dump

This patch adds print bpf_line_info function in 'prog dump jitted'
and 'prog dump xlated':

[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv
[...]
int test_long_fname_2(struct dummy_tracepoint_args * arg):
bpf_prog_44a040bf25481309_test_long_fname_2:
; static int test_long_fname_2(struct dummy_tracepoint_args *arg)
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x30,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: xor %esi,%esi
; int key = 0;
27: mov %esi,-0x4(%rbp)
; if (!arg->sock)
2a: mov 0x8(%rdi),%rdi
; if (!arg->sock)
2e: cmp $0x0,%rdi
32: je 0x0000000000000070
34: mov %rbp,%rsi
; counts = bpf_map_lookup_elem(&btf_map, &key);
37: add $0xfffffffffffffffc,%rsi
3b: movabs $0xffff8881139d7480,%rdi
45: add $0x110,%rdi
4c: mov 0x0(%rsi),%eax
4f: cmp $0x4,%rax
53: jae 0x000000000000005e
55: shl $0x3,%rax
59: add %rdi,%rax
5c: jmp 0x0000000000000060
5e: xor %eax,%eax
; if (!counts)
60: cmp $0x0,%rax
64: je 0x0000000000000070
; counts->v6++;
66: mov 0x4(%rax),%edi
69: add $0x1,%rdi
6d: mov %edi,0x4(%rax)
70: mov 0x0(%rbp),%rbx
74: mov 0x8(%rbp),%r13
78: mov 0x10(%rbp),%r14
7c: mov 0x18(%rbp),%r15
80: add $0x28,%rbp
84: leaveq
85: retq
[...]

With linum:
[root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv linum
int _dummy_tracepoint(struct dummy_tracepoint_args * arg):
bpf_prog_b07ccb89267cf242__dummy_tracepoint:
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:9]
0: push %rbp
1: mov %rsp,%rbp
4: sub $0x28,%rsp
b: sub $0x28,%rbp
f: mov %rbx,0x0(%rbp)
13: mov %r13,0x8(%rbp)
17: mov %r14,0x10(%rbp)
1b: mov %r15,0x18(%rbp)
1f: xor %eax,%eax
21: mov %rax,0x20(%rbp)
25: callq 0x000000000000851e
; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:2]
2a: xor %eax,%eax
2c: mov 0x0(%rbp),%rbx
30: mov 0x8(%rbp),%r13
34: mov 0x10(%rbp),%r14
38: mov 0x18(%rbp),%r15
3c: add $0x28,%rbp
40: leaveq
41: retq
[...]

Signed-off-by: Martin KaFai Lau <kafai@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Martin KaFai Lau and committed by
Alexei Starovoitov
b053b439 3d650141

+516 -25
+12 -4
tools/bpf/bpftool/Documentation/bpftool-prog.rst
··· 22 22 ============= 23 23 24 24 | **bpftool** **prog { show | list }** [*PROG*] 25 - | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}] 26 - | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] 25 + | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual** | **linum**}] 26 + | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes** | **linum**}] 27 27 | **bpftool** **prog pin** *PROG* *FILE* 28 28 | **bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] 29 29 | **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*] ··· 56 56 Output will start with program ID followed by program type and 57 57 zero or more named attributes (depending on kernel version). 58 58 59 - **bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** }] 59 + **bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** | **linum** }] 60 60 Dump eBPF instructions of the program from the kernel. By 61 61 default, eBPF will be disassembled and printed to standard 62 62 output in human-readable format. In this case, **opcodes** ··· 69 69 built instead, and eBPF instructions will be presented with 70 70 CFG in DOT format, on standard output. 71 71 72 - **bpftool prog dump jited** *PROG* [{ **file** *FILE* | **opcodes** }] 72 + If the prog has line_info available, the source line will 73 + be displayed by default. If **linum** is specified, 74 + the filename, line number and line column will also be 75 + displayed on top of the source line. 76 + **bpftool prog dump jited** *PROG* [{ **file** *FILE* | **opcodes** | **linum** }] 73 77 Dump jited image (host machine code) of the program. 74 78 If *FILE* is specified image will be written to a file, 75 79 otherwise it will be disassembled and printed to stdout. 76 80 77 81 **opcodes** controls if raw opcodes will be printed. 78 82 83 + If the prog has line_info available, the source line will 84 + be displayed by default. If **linum** is specified, 85 + the filename, line number and line column will also be 86 + displayed on top of the source line. 79 87 **bpftool prog pin** *PROG* *FILE* 80 88 Pin program *PROG* as *FILE*. 81 89
+3 -3
tools/bpf/bpftool/bash-completion/bpftool
··· 191 191 192 192 # Deal with simplest keywords 193 193 case $prev in 194 - help|hex|opcodes|visual) 194 + help|hex|opcodes|visual|linum) 195 195 return 0 196 196 ;; 197 197 tag) ··· 278 278 *) 279 279 _bpftool_once_attr 'file' 280 280 if _bpftool_search_list 'xlated'; then 281 - COMPREPLY+=( $( compgen -W 'opcodes visual' -- \ 281 + COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \ 282 282 "$cur" ) ) 283 283 else 284 - COMPREPLY+=( $( compgen -W 'opcodes' -- \ 284 + COMPREPLY+=( $( compgen -W 'opcodes linum' -- \ 285 285 "$cur" ) ) 286 286 fi 287 287 return 0
+64
tools/bpf/bpftool/btf_dumper.c
··· 385 385 if (err < 0) 386 386 func_sig[0] = '\0'; 387 387 } 388 + 389 + static const char *ltrim(const char *s) 390 + { 391 + while (isspace(*s)) 392 + s++; 393 + 394 + return s; 395 + } 396 + 397 + void btf_dump_linfo_plain(const struct btf *btf, 398 + const struct bpf_line_info *linfo, 399 + const char *prefix, bool linum) 400 + { 401 + const char *line = btf__name_by_offset(btf, linfo->line_off); 402 + 403 + if (!line) 404 + return; 405 + line = ltrim(line); 406 + 407 + if (!prefix) 408 + prefix = ""; 409 + 410 + if (linum) { 411 + const char *file = btf__name_by_offset(btf, linfo->file_name_off); 412 + 413 + /* More forgiving on file because linum option is 414 + * expected to provide more info than the already 415 + * available src line. 416 + */ 417 + if (!file) 418 + file = ""; 419 + 420 + printf("%s%s [file:%s line_num:%u line_col:%u]\n", 421 + prefix, line, file, 422 + BPF_LINE_INFO_LINE_NUM(linfo->line_col), 423 + BPF_LINE_INFO_LINE_COL(linfo->line_col)); 424 + } else { 425 + printf("%s%s\n", prefix, line); 426 + } 427 + } 428 + 429 + void btf_dump_linfo_json(const struct btf *btf, 430 + const struct bpf_line_info *linfo, bool linum) 431 + { 432 + const char *line = btf__name_by_offset(btf, linfo->line_off); 433 + 434 + if (line) 435 + jsonw_string_field(json_wtr, "src", ltrim(line)); 436 + 437 + if (linum) { 438 + const char *file = btf__name_by_offset(btf, linfo->file_name_off); 439 + 440 + if (file) 441 + jsonw_string_field(json_wtr, "file", file); 442 + 443 + if (BPF_LINE_INFO_LINE_NUM(linfo->line_col)) 444 + jsonw_int_field(json_wtr, "line_num", 445 + BPF_LINE_INFO_LINE_NUM(linfo->line_col)); 446 + 447 + if (BPF_LINE_INFO_LINE_COL(linfo->line_col)) 448 + jsonw_int_field(json_wtr, "line_col", 449 + BPF_LINE_INFO_LINE_COL(linfo->line_col)); 450 + } 451 + }
+22 -1
tools/bpf/bpftool/jit_disasm.c
··· 21 21 #include <dis-asm.h> 22 22 #include <sys/stat.h> 23 23 #include <limits.h> 24 + #include <libbpf.h> 24 25 25 26 #include "json_writer.h" 26 27 #include "main.h" ··· 69 68 } 70 69 71 70 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 72 - const char *arch, const char *disassembler_options) 71 + const char *arch, const char *disassembler_options, 72 + const struct btf *btf, 73 + const struct bpf_prog_linfo *prog_linfo, 74 + __u64 func_ksym, unsigned int func_idx, 75 + bool linum) 73 76 { 77 + const struct bpf_line_info *linfo = NULL; 74 78 disassembler_ftype disassemble; 75 79 struct disassemble_info info; 80 + unsigned int nr_skip = 0; 76 81 int count, i, pc = 0; 77 82 char tpath[PATH_MAX]; 78 83 bfd *bfdf; ··· 134 127 if (json_output) 135 128 jsonw_start_array(json_wtr); 136 129 do { 130 + if (prog_linfo) { 131 + linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, 132 + func_ksym + pc, 133 + func_idx, 134 + nr_skip); 135 + if (linfo) 136 + nr_skip++; 137 + } 138 + 137 139 if (json_output) { 138 140 jsonw_start_object(json_wtr); 139 141 oper_count = 0; 142 + if (linfo) 143 + btf_dump_linfo_json(btf, linfo, linum); 140 144 jsonw_name(json_wtr, "pc"); 141 145 jsonw_printf(json_wtr, "\"0x%x\"", pc); 142 146 } else { 147 + if (linfo) 148 + btf_dump_linfo_plain(btf, linfo, "; ", 149 + linum); 143 150 printf("%4x:\t", pc); 144 151 } 145 152
+21 -2
tools/bpf/bpftool/main.h
··· 138 138 struct hlist_node hash; 139 139 }; 140 140 141 + struct btf; 142 + struct bpf_line_info; 143 + 141 144 int build_pinned_obj_table(struct pinned_obj_table *table, 142 145 enum bpf_obj_type type); 143 146 void delete_pinned_obj_table(struct pinned_obj_table *tab); ··· 178 175 int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); 179 176 180 177 #ifdef HAVE_LIBBFD_SUPPORT 178 + struct bpf_prog_linfo; 181 179 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 182 - const char *arch, const char *disassembler_options); 180 + const char *arch, const char *disassembler_options, 181 + const struct btf *btf, 182 + const struct bpf_prog_linfo *prog_linfo, 183 + __u64 func_ksym, unsigned int func_idx, 184 + bool linum); 183 185 int disasm_init(void); 184 186 #else 185 187 static inline 186 188 void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, 187 - const char *arch, const char *disassembler_options) 189 + const char *arch, const char *disassembler_options, 190 + const struct btf *btf, 191 + const struct bpf_prog_linfo *prog_linfo, 192 + __u64 func_ksym, unsigned int func_idx, 193 + bool linum) 194 + 188 195 { 189 196 } 190 197 static inline int disasm_init(void) ··· 229 216 const void *data); 230 217 void btf_dumper_type_only(const struct btf *btf, __u32 func_type_id, 231 218 char *func_only, int size); 219 + 220 + void btf_dump_linfo_plain(const struct btf *btf, 221 + const struct bpf_line_info *linfo, 222 + const char *prefix, bool linum); 223 + void btf_dump_linfo_json(const struct btf *btf, 224 + const struct bpf_line_info *linfo, bool linum); 232 225 233 226 struct nlattr; 234 227 struct ifinfomsg;
+90 -10
tools/bpf/bpftool/prog.c
··· 423 423 424 424 static int do_dump(int argc, char **argv) 425 425 { 426 + unsigned int finfo_rec_size, linfo_rec_size, jited_linfo_rec_size; 427 + void *func_info = NULL, *linfo = NULL, *jited_linfo = NULL; 428 + unsigned int finfo_cnt, linfo_cnt = 0, jited_linfo_cnt = 0; 429 + struct bpf_prog_linfo *prog_linfo = NULL; 426 430 unsigned long *func_ksyms = NULL; 427 431 struct bpf_prog_info info = {}; 428 432 unsigned int *func_lens = NULL; 429 433 const char *disasm_opt = NULL; 430 - unsigned int finfo_rec_size; 431 434 unsigned int nr_func_ksyms; 432 435 unsigned int nr_func_lens; 433 436 struct dump_data dd = {}; 434 437 __u32 len = sizeof(info); 435 438 struct btf *btf = NULL; 436 - void *func_info = NULL; 437 - unsigned int finfo_cnt; 438 439 unsigned int buf_size; 439 440 char *filepath = NULL; 440 441 bool opcodes = false; 441 442 bool visual = false; 442 443 char func_sig[1024]; 443 444 unsigned char *buf; 445 + bool linum = false; 444 446 __u32 *member_len; 445 447 __u64 *member_ptr; 446 448 ssize_t n; ··· 485 483 NEXT_ARG(); 486 484 } else if (is_prefix(*argv, "visual")) { 487 485 visual = true; 486 + NEXT_ARG(); 487 + } else if (is_prefix(*argv, "linum")) { 488 + linum = true; 488 489 NEXT_ARG(); 489 490 } 490 491 ··· 548 543 } 549 544 } 550 545 546 + linfo_rec_size = info.line_info_rec_size; 547 + if (info.line_info_cnt && linfo_rec_size && info.btf_id) { 548 + linfo_cnt = info.line_info_cnt; 549 + linfo = malloc(linfo_cnt * linfo_rec_size); 550 + if (!linfo) { 551 + p_err("mem alloc failed"); 552 + close(fd); 553 + goto err_free; 554 + } 555 + } 556 + 557 + jited_linfo_rec_size = info.jited_line_info_rec_size; 558 + if (info.jited_line_info_cnt && 559 + jited_linfo_rec_size && 560 + info.nr_jited_ksyms && 561 + info.nr_jited_func_lens && 562 + info.btf_id) { 563 + jited_linfo_cnt = info.jited_line_info_cnt; 564 + jited_linfo = malloc(jited_linfo_cnt * jited_linfo_rec_size); 565 + if (!jited_linfo) { 566 + p_err("mem alloc failed"); 567 + close(fd); 568 + goto err_free; 569 + } 570 + } 571 + 551 572 memset(&info, 0, sizeof(info)); 552 573 553 574 *member_ptr = ptr_to_u64(buf); ··· 585 554 info.func_info_cnt = finfo_cnt; 586 555 info.func_info_rec_size = finfo_rec_size; 587 556 info.func_info = ptr_to_u64(func_info); 557 + info.line_info_cnt = linfo_cnt; 558 + info.line_info_rec_size = linfo_rec_size; 559 + info.line_info = ptr_to_u64(linfo); 560 + info.jited_line_info_cnt = jited_linfo_cnt; 561 + info.jited_line_info_rec_size = jited_linfo_rec_size; 562 + info.jited_line_info = ptr_to_u64(jited_linfo); 563 + 588 564 589 565 err = bpf_obj_get_info_by_fd(fd, &info, &len); 590 566 close(fd); ··· 634 596 finfo_cnt = 0; 635 597 } 636 598 599 + if (linfo && info.line_info_cnt != linfo_cnt) { 600 + p_err("incorrect line_info_cnt %u vs. expected %u", 601 + info.line_info_cnt, linfo_cnt); 602 + goto err_free; 603 + } 604 + 605 + if (info.line_info_rec_size != linfo_rec_size) { 606 + p_err("incorrect line_info_rec_size %u vs. expected %u", 607 + info.line_info_rec_size, linfo_rec_size); 608 + goto err_free; 609 + } 610 + 611 + if (jited_linfo && info.jited_line_info_cnt != jited_linfo_cnt) { 612 + p_err("incorrect jited_line_info_cnt %u vs. expected %u", 613 + info.jited_line_info_cnt, jited_linfo_cnt); 614 + goto err_free; 615 + } 616 + 617 + if (info.jited_line_info_rec_size != jited_linfo_rec_size) { 618 + p_err("incorrect jited_line_info_rec_size %u vs. expected %u", 619 + info.jited_line_info_rec_size, jited_linfo_rec_size); 620 + goto err_free; 621 + } 622 + 637 623 if ((member_len == &info.jited_prog_len && 638 624 info.jited_prog_insns == 0) || 639 625 (member_len == &info.xlated_prog_len && ··· 669 607 if (info.btf_id && btf__get_from_id(info.btf_id, &btf)) { 670 608 p_err("failed to get btf"); 671 609 goto err_free; 610 + } 611 + 612 + if (linfo_cnt) { 613 + prog_linfo = bpf_prog_linfo__new(&info); 614 + if (!prog_linfo) 615 + p_err("error in processing bpf_line_info. continue without it."); 672 616 } 673 617 674 618 if (filepath) { ··· 758 690 printf("%s:\n", sym_name); 759 691 } 760 692 761 - disasm_print_insn(img, lens[i], opcodes, name, 762 - disasm_opt); 693 + disasm_print_insn(img, lens[i], opcodes, 694 + name, disasm_opt, btf, 695 + prog_linfo, ksyms[i], i, 696 + linum); 697 + 763 698 img += lens[i]; 764 699 765 700 if (json_output) ··· 775 704 jsonw_end_array(json_wtr); 776 705 } else { 777 706 disasm_print_insn(buf, *member_len, opcodes, name, 778 - disasm_opt); 707 + disasm_opt, btf, NULL, 0, 0, false); 779 708 } 780 709 } else if (visual) { 781 710 if (json_output) ··· 789 718 dd.btf = btf; 790 719 dd.func_info = func_info; 791 720 dd.finfo_rec_size = finfo_rec_size; 721 + dd.prog_linfo = prog_linfo; 792 722 793 723 if (json_output) 794 - dump_xlated_json(&dd, buf, *member_len, opcodes); 724 + dump_xlated_json(&dd, buf, *member_len, opcodes, 725 + linum); 795 726 else 796 - dump_xlated_plain(&dd, buf, *member_len, opcodes); 727 + dump_xlated_plain(&dd, buf, *member_len, opcodes, 728 + linum); 797 729 kernel_syms_destroy(&dd); 798 730 } 799 731 ··· 804 730 free(func_ksyms); 805 731 free(func_lens); 806 732 free(func_info); 733 + free(linfo); 734 + free(jited_linfo); 735 + bpf_prog_linfo__free(prog_linfo); 807 736 return 0; 808 737 809 738 err_free: ··· 814 737 free(func_ksyms); 815 738 free(func_lens); 816 739 free(func_info); 740 + free(linfo); 741 + free(jited_linfo); 742 + bpf_prog_linfo__free(prog_linfo); 817 743 return -1; 818 744 } 819 745 ··· 1218 1138 1219 1139 fprintf(stderr, 1220 1140 "Usage: %s %s { show | list } [PROG]\n" 1221 - " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" 1222 - " %s %s dump jited PROG [{ file FILE | opcodes }]\n" 1141 + " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 1142 + " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" 1223 1143 " %s %s pin PROG FILE\n" 1224 1144 " %s %s { load | loadall } OBJ PATH \\\n" 1225 1145 " [type TYPE] [dev NAME] \\\n"
+28 -2
tools/bpf/bpftool/xlated_dumper.c
··· 41 41 #include <stdlib.h> 42 42 #include <string.h> 43 43 #include <sys/types.h> 44 + #include <libbpf.h> 44 45 45 46 #include "disasm.h" 46 47 #include "json_writer.h" ··· 235 234 } 236 235 237 236 void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, 238 - bool opcodes) 237 + bool opcodes, bool linum) 239 238 { 239 + const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; 240 240 const struct bpf_insn_cbs cbs = { 241 241 .cb_print = print_insn_json, 242 242 .cb_call = print_call, ··· 248 246 struct bpf_insn *insn = buf; 249 247 struct btf *btf = dd->btf; 250 248 bool double_insn = false; 249 + unsigned int nr_skip = 0; 251 250 char func_sig[1024]; 252 251 unsigned int i; 253 252 ··· 273 270 jsonw_string(json_wtr, func_sig); 274 271 } 275 272 record = (void *)record + dd->finfo_rec_size; 273 + } 274 + } 275 + 276 + if (prog_linfo) { 277 + const struct bpf_line_info *linfo; 278 + 279 + linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); 280 + if (linfo) { 281 + btf_dump_linfo_json(btf, linfo, linum); 282 + nr_skip++; 276 283 } 277 284 } 278 285 ··· 320 307 } 321 308 322 309 void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, 323 - bool opcodes) 310 + bool opcodes, bool linum) 324 311 { 312 + const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; 325 313 const struct bpf_insn_cbs cbs = { 326 314 .cb_print = print_insn, 327 315 .cb_call = print_call, ··· 332 318 struct bpf_func_info *record; 333 319 struct bpf_insn *insn = buf; 334 320 struct btf *btf = dd->btf; 321 + unsigned int nr_skip = 0; 335 322 bool double_insn = false; 336 323 char func_sig[1024]; 337 324 unsigned int i; ··· 352 337 if (func_sig[0] != '\0') 353 338 printf("%s:\n", func_sig); 354 339 record = (void *)record + dd->finfo_rec_size; 340 + } 341 + } 342 + 343 + if (prog_linfo) { 344 + const struct bpf_line_info *linfo; 345 + 346 + linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); 347 + if (linfo) { 348 + btf_dump_linfo_plain(btf, linfo, "; ", 349 + linum); 350 + nr_skip++; 355 351 } 356 352 } 357 353
+5 -2
tools/bpf/bpftool/xlated_dumper.h
··· 40 40 41 41 #define SYM_MAX_NAME 256 42 42 43 + struct bpf_prog_linfo; 44 + 43 45 struct kernel_sym { 44 46 unsigned long address; 45 47 char name[SYM_MAX_NAME]; ··· 56 54 struct btf *btf; 57 55 void *func_info; 58 56 __u32 finfo_rec_size; 57 + const struct bpf_prog_linfo *prog_linfo; 59 58 char scratch_buff[SYM_MAX_NAME + 8]; 60 59 }; 61 60 ··· 64 61 void kernel_syms_destroy(struct dump_data *dd); 65 62 struct kernel_sym *kernel_syms_search(struct dump_data *dd, unsigned long key); 66 63 void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, 67 - bool opcodes); 64 + bool opcodes, bool linum); 68 65 void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, 69 - bool opcodes); 66 + bool opcodes, bool linum); 70 67 void dump_xlated_for_graph(struct dump_data *dd, void *buf, void *buf_end, 71 68 unsigned int start_index); 72 69
+1 -1
tools/lib/bpf/Build
··· 1 - libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o 1 + libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o bpf_prog_linfo.o
+253
tools/lib/bpf/bpf_prog_linfo.c
··· 1 + // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 2 + /* Copyright (c) 2018 Facebook */ 3 + 4 + #include <string.h> 5 + #include <stdlib.h> 6 + #include <linux/err.h> 7 + #include <linux/bpf.h> 8 + #include "libbpf.h" 9 + 10 + #ifndef min 11 + #define min(x, y) ((x) < (y) ? (x) : (y)) 12 + #endif 13 + 14 + struct bpf_prog_linfo { 15 + void *raw_linfo; 16 + void *raw_jited_linfo; 17 + __u32 *nr_jited_linfo_per_func; 18 + __u32 *jited_linfo_func_idx; 19 + __u32 nr_linfo; 20 + __u32 nr_jited_func; 21 + __u32 rec_size; 22 + __u32 jited_rec_size; 23 + }; 24 + 25 + static int dissect_jited_func(struct bpf_prog_linfo *prog_linfo, 26 + const __u64 *ksym_func, const __u32 *ksym_len) 27 + { 28 + __u32 nr_jited_func, nr_linfo; 29 + const void *raw_jited_linfo; 30 + const __u64 *jited_linfo; 31 + __u64 last_jited_linfo; 32 + /* 33 + * Index to raw_jited_linfo: 34 + * i: Index for searching the next ksym_func 35 + * prev_i: Index to the last found ksym_func 36 + */ 37 + __u32 i, prev_i; 38 + __u32 f; /* Index to ksym_func */ 39 + 40 + raw_jited_linfo = prog_linfo->raw_jited_linfo; 41 + jited_linfo = raw_jited_linfo; 42 + if (ksym_func[0] != *jited_linfo) 43 + goto errout; 44 + 45 + prog_linfo->jited_linfo_func_idx[0] = 0; 46 + nr_jited_func = prog_linfo->nr_jited_func; 47 + nr_linfo = prog_linfo->nr_linfo; 48 + 49 + for (prev_i = 0, i = 1, f = 1; 50 + i < nr_linfo && f < nr_jited_func; 51 + i++) { 52 + raw_jited_linfo += prog_linfo->jited_rec_size; 53 + last_jited_linfo = *jited_linfo; 54 + jited_linfo = raw_jited_linfo; 55 + 56 + if (ksym_func[f] == *jited_linfo) { 57 + prog_linfo->jited_linfo_func_idx[f] = i; 58 + 59 + /* Sanity check */ 60 + if (last_jited_linfo - ksym_func[f - 1] + 1 > 61 + ksym_len[f - 1]) 62 + goto errout; 63 + 64 + prog_linfo->nr_jited_linfo_per_func[f - 1] = 65 + i - prev_i; 66 + prev_i = i; 67 + 68 + /* 69 + * The ksym_func[f] is found in jited_linfo. 70 + * Look for the next one. 71 + */ 72 + f++; 73 + } else if (*jited_linfo <= last_jited_linfo) { 74 + /* Ensure the addr is increasing _within_ a func */ 75 + goto errout; 76 + } 77 + } 78 + 79 + if (f != nr_jited_func) 80 + goto errout; 81 + 82 + prog_linfo->nr_jited_linfo_per_func[nr_jited_func - 1] = 83 + nr_linfo - prev_i; 84 + 85 + return 0; 86 + 87 + errout: 88 + return -EINVAL; 89 + } 90 + 91 + void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo) 92 + { 93 + if (!prog_linfo) 94 + return; 95 + 96 + free(prog_linfo->raw_linfo); 97 + free(prog_linfo->raw_jited_linfo); 98 + free(prog_linfo->nr_jited_linfo_per_func); 99 + free(prog_linfo->jited_linfo_func_idx); 100 + free(prog_linfo); 101 + } 102 + 103 + struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info) 104 + { 105 + struct bpf_prog_linfo *prog_linfo; 106 + __u32 nr_linfo, nr_jited_func; 107 + 108 + nr_linfo = info->line_info_cnt; 109 + 110 + /* 111 + * Test !info->line_info because the kernel may NULL 112 + * the ptr if kernel.kptr_restrict is set. 113 + */ 114 + if (!nr_linfo || !info->line_info) 115 + return NULL; 116 + 117 + /* 118 + * The min size that bpf_prog_linfo has to access for 119 + * searching purpose. 120 + */ 121 + if (info->line_info_rec_size < 122 + offsetof(struct bpf_line_info, file_name_off)) 123 + return NULL; 124 + 125 + prog_linfo = calloc(1, sizeof(*prog_linfo)); 126 + if (!prog_linfo) 127 + return NULL; 128 + 129 + /* Copy xlated line_info */ 130 + prog_linfo->nr_linfo = nr_linfo; 131 + prog_linfo->rec_size = info->line_info_rec_size; 132 + prog_linfo->raw_linfo = malloc(nr_linfo * prog_linfo->rec_size); 133 + if (!prog_linfo->raw_linfo) 134 + goto err_free; 135 + memcpy(prog_linfo->raw_linfo, (void *)(long)info->line_info, 136 + nr_linfo * prog_linfo->rec_size); 137 + 138 + nr_jited_func = info->nr_jited_ksyms; 139 + if (!nr_jited_func || 140 + !info->jited_line_info || 141 + info->jited_line_info_cnt != nr_linfo || 142 + info->jited_line_info_rec_size < sizeof(__u64) || 143 + info->nr_jited_func_lens != nr_jited_func || 144 + !info->jited_ksyms || 145 + !info->jited_func_lens) 146 + /* Not enough info to provide jited_line_info */ 147 + return prog_linfo; 148 + 149 + /* Copy jited_line_info */ 150 + prog_linfo->nr_jited_func = nr_jited_func; 151 + prog_linfo->jited_rec_size = info->jited_line_info_rec_size; 152 + prog_linfo->raw_jited_linfo = malloc(nr_linfo * 153 + prog_linfo->jited_rec_size); 154 + if (!prog_linfo->raw_jited_linfo) 155 + goto err_free; 156 + memcpy(prog_linfo->raw_jited_linfo, 157 + (void *)(long)info->jited_line_info, 158 + nr_linfo * prog_linfo->jited_rec_size); 159 + 160 + /* Number of jited_line_info per jited func */ 161 + prog_linfo->nr_jited_linfo_per_func = malloc(nr_jited_func * 162 + sizeof(__u32)); 163 + if (!prog_linfo->nr_jited_linfo_per_func) 164 + goto err_free; 165 + 166 + /* 167 + * For each jited func, 168 + * the start idx to the "linfo" and "jited_linfo" array, 169 + */ 170 + prog_linfo->jited_linfo_func_idx = malloc(nr_jited_func * 171 + sizeof(__u32)); 172 + if (!prog_linfo->jited_linfo_func_idx) 173 + goto err_free; 174 + 175 + if (dissect_jited_func(prog_linfo, 176 + (__u64 *)(long)info->jited_ksyms, 177 + (__u32 *)(long)info->jited_func_lens)) 178 + goto err_free; 179 + 180 + return prog_linfo; 181 + 182 + err_free: 183 + bpf_prog_linfo__free(prog_linfo); 184 + return NULL; 185 + } 186 + 187 + const struct bpf_line_info * 188 + bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo, 189 + __u64 addr, __u32 func_idx, __u32 nr_skip) 190 + { 191 + __u32 jited_rec_size, rec_size, nr_linfo, start, i; 192 + const void *raw_jited_linfo, *raw_linfo; 193 + const __u64 *jited_linfo; 194 + 195 + if (func_idx >= prog_linfo->nr_jited_func) 196 + return NULL; 197 + 198 + nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx]; 199 + if (nr_skip >= nr_linfo) 200 + return NULL; 201 + 202 + start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip; 203 + jited_rec_size = prog_linfo->jited_rec_size; 204 + raw_jited_linfo = prog_linfo->raw_jited_linfo + 205 + (start * jited_rec_size); 206 + jited_linfo = raw_jited_linfo; 207 + if (addr < *jited_linfo) 208 + return NULL; 209 + 210 + nr_linfo -= nr_skip; 211 + rec_size = prog_linfo->rec_size; 212 + raw_linfo = prog_linfo->raw_linfo + (start * rec_size); 213 + for (i = 0; i < nr_linfo; i++) { 214 + if (addr < *jited_linfo) 215 + break; 216 + 217 + raw_linfo += rec_size; 218 + raw_jited_linfo += jited_rec_size; 219 + jited_linfo = raw_jited_linfo; 220 + } 221 + 222 + return raw_linfo - rec_size; 223 + } 224 + 225 + const struct bpf_line_info * 226 + bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo, 227 + __u32 insn_off, __u32 nr_skip) 228 + { 229 + const struct bpf_line_info *linfo; 230 + __u32 rec_size, nr_linfo, i; 231 + const void *raw_linfo; 232 + 233 + nr_linfo = prog_linfo->nr_linfo; 234 + if (nr_skip >= nr_linfo) 235 + return NULL; 236 + 237 + rec_size = prog_linfo->rec_size; 238 + raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size); 239 + linfo = raw_linfo; 240 + if (insn_off < linfo->insn_off) 241 + return NULL; 242 + 243 + nr_linfo -= nr_skip; 244 + for (i = 0; i < nr_linfo; i++) { 245 + if (insn_off < linfo->insn_off) 246 + break; 247 + 248 + raw_linfo += rec_size; 249 + linfo = raw_linfo; 250 + } 251 + 252 + return raw_linfo - rec_size; 253 + }
+13
tools/lib/bpf/libbpf.h
··· 342 342 int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, 343 343 libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie); 344 344 345 + struct bpf_prog_linfo; 346 + struct bpf_prog_info; 347 + 348 + LIBBPF_API void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo); 349 + LIBBPF_API struct bpf_prog_linfo * 350 + bpf_prog_linfo__new(const struct bpf_prog_info *info); 351 + LIBBPF_API const struct bpf_line_info * 352 + bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo, 353 + __u64 addr, __u32 func_idx, __u32 nr_skip); 354 + LIBBPF_API const struct bpf_line_info * 355 + bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo, 356 + __u32 insn_off, __u32 nr_skip); 357 + 345 358 #ifdef __cplusplus 346 359 } /* extern "C" */ 347 360 #endif
+4
tools/lib/bpf/libbpf.map
··· 99 99 bpf_program__unload; 100 100 bpf_program__unpin; 101 101 bpf_program__unpin_instance; 102 + bpf_prog_linfo__free; 103 + bpf_prog_linfo__new; 104 + bpf_prog_linfo__lfind_addr_func; 105 + bpf_prog_linfo__lfind; 102 106 bpf_raw_tracepoint_open; 103 107 bpf_set_link_xdp_fd; 104 108 bpf_task_fd_query;