Martin Lau says: ==================== This patch series introduces the bpf_line_info. Please see individual patch for details. It will be useful for introspection purpose, like: [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 [...] ====================
Unified · Split
| @@ -1181,6 +1181,8 @@ out_image: · 1180 unmodified lines | |||
| 1181 | } | 1181 | } |
| 1182 | 1182 | ||
| 1183 | if (!image || !prog->is_func || extra_pass) { | 1183 | if (!image || !prog->is_func || extra_pass) { |
| 1184 | if (image) | ||
| 1185 | bpf_prog_fill_jited_linfo(prog, addrs); | ||
| 1184 | out_addrs: | 1186 | out_addrs: |
| 1185 | kfree(addrs); | 1187 | kfree(addrs); |
| 1186 | kfree(jit_data); | 1188 | kfree(jit_data); |
| @@ -319,7 +319,28 @@ struct bpf_prog_aux { · 318 unmodified lines | |||
| 319 | struct bpf_prog_offload *offload; | 319 | struct bpf_prog_offload *offload; |
| 320 | struct btf *btf; | 320 | struct btf *btf; |
| 321 | struct bpf_func_info *func_info; | 321 | struct bpf_func_info *func_info; |
| 322 | /* bpf_line_info loaded from userspace. linfo->insn_off | ||
| 323 | * has the xlated insn offset. | ||
| 324 | * Both the main and sub prog share the same linfo. | ||
| 325 | * The subprog can access its first linfo by | ||
| 326 | * using the linfo_idx. | ||
| 327 | */ | ||
| 328 | struct bpf_line_info *linfo; | ||
| 329 | /* jited_linfo is the jited addr of the linfo. It has a | ||
| 330 | * one to one mapping to linfo: | ||
| 331 | * jited_linfo[i] is the jited addr for the linfo[i]->insn_off. | ||
| 332 | * Both the main and sub prog share the same jited_linfo. | ||
| 333 | * The subprog can access its first jited_linfo by | ||
| 334 | * using the linfo_idx. | ||
| 335 | */ | ||
| 336 | void **jited_linfo; | ||
| 322 | u32 func_info_cnt; | 337 | u32 func_info_cnt; |
| 338 | u32 nr_linfo; | ||
| 339 | /* subprog can use linfo_idx to access its first linfo and | ||
| 340 | * jited_linfo. | ||
| 341 | * main prog always has linfo_idx == 0 | ||
| 342 | */ | ||
| 343 | u32 linfo_idx; | ||
| 323 | union { | 344 | union { |
| 324 | struct work_struct work; | 345 | struct work_struct work; |
| 325 | struct rcu_head rcu; | 346 | struct rcu_head rcu; |
| @@ -203,6 +203,7 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log) · 202 unmodified lines | |||
| 203 | 203 | ||
| 204 | struct bpf_subprog_info { | 204 | struct bpf_subprog_info { |
| 205 | u32 start; /* insn idx of function entry point */ | 205 | u32 start; /* insn idx of function entry point */ |
| 206 | u32 linfo_idx; /* The idx to the main_prog->aux->linfo */ | ||
| 206 | u16 stack_depth; /* max. stack depth used by this function */ | 207 | u16 stack_depth; /* max. stack depth used by this function */ |
| 207 | }; | 208 | }; |
| 208 | 209 | ||
| @@ -46,6 +46,7 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj, · 45 unmodified lines | |||
| 46 | struct seq_file *m); | 46 | struct seq_file *m); |
| 47 | int btf_get_fd_by_id(u32 id); | 47 | int btf_get_fd_by_id(u32 id); |
| 48 | u32 btf_id(const struct btf *btf); | 48 | u32 btf_id(const struct btf *btf); |
| 49 | bool btf_name_offset_valid(const struct btf *btf, u32 offset); | ||
| 49 | 50 | ||
| 50 | #ifdef CONFIG_BPF_SYSCALL | 51 | #ifdef CONFIG_BPF_SYSCALL |
| 51 | const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); | 52 | const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id); |
| @@ -718,6 +718,13 @@ void bpf_prog_free(struct bpf_prog *fp); · 717 unmodified lines | |||
| 718 | 718 | ||
| 719 | bool bpf_opcode_in_insntable(u8 code); | 719 | bool bpf_opcode_in_insntable(u8 code); |
| 720 | 720 | ||
| 721 | void bpf_prog_free_linfo(struct bpf_prog *prog); | ||
| 722 | void bpf_prog_fill_jited_linfo(struct bpf_prog *prog, | ||
| 723 | const u32 *insn_to_jit_off); | ||
| 724 | int bpf_prog_alloc_jited_linfo(struct bpf_prog *prog); | ||
| 725 | void bpf_prog_free_jited_linfo(struct bpf_prog *prog); | ||
| 726 | void bpf_prog_free_unused_jited_linfo(struct bpf_prog *prog); | ||
| 727 | |||
| 721 | struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags); | 728 | struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags); |
| 722 | struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size, | 729 | struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size, |
| 723 | gfp_t gfp_extra_flags); | 730 | gfp_t gfp_extra_flags); |
| @@ -356,6 +356,9 @@ union bpf_attr { · 355 unmodified lines | |||
| 356 | __u32 func_info_rec_size; /* userspace bpf_func_info size */ | 356 | __u32 func_info_rec_size; /* userspace bpf_func_info size */ |
| 357 | __aligned_u64 func_info; /* func info */ | 357 | __aligned_u64 func_info; /* func info */ |
| 358 | __u32 func_info_cnt; /* number of bpf_func_info records */ | 358 | __u32 func_info_cnt; /* number of bpf_func_info records */ |
| 359 | __u32 line_info_rec_size; /* userspace bpf_line_info size */ | ||
| 360 | __aligned_u64 line_info; /* line info */ | ||
| 361 | __u32 line_info_cnt; /* number of bpf_line_info records */ | ||
| 359 | }; | 362 | }; |
| 360 | 363 | ||
| 361 | struct { /* anonymous struct used by BPF_OBJ_* commands */ | 364 | struct { /* anonymous struct used by BPF_OBJ_* commands */ |
| @@ -2679,6 +2682,12 @@ struct bpf_prog_info { · 2317 unmodified lines | |||
| 2679 | __u32 func_info_rec_size; | 2682 | __u32 func_info_rec_size; |
| 2680 | __aligned_u64 func_info; | 2683 | __aligned_u64 func_info; |
| 2681 | __u32 func_info_cnt; | 2684 | __u32 func_info_cnt; |
| 2685 | __u32 line_info_cnt; | ||
| 2686 | __aligned_u64 line_info; | ||
| 2687 | __aligned_u64 jited_line_info; | ||
| 2688 | __u32 jited_line_info_cnt; | ||
| 2689 | __u32 line_info_rec_size; | ||
| 2690 | __u32 jited_line_info_rec_size; | ||
| 2682 | } __attribute__((aligned(8))); | 2691 | } __attribute__((aligned(8))); |
| 2683 | 2692 | ||
| 2684 | struct bpf_map_info { | 2693 | struct bpf_map_info { |
| @@ -2995,4 +3004,14 @@ struct bpf_func_info { · 310 unmodified lines | |||
| 2995 | __u32 type_id; | 3004 | __u32 type_id; |
| 2996 | }; | 3005 | }; |
| 2997 | 3006 | ||
| 3007 | #define BPF_LINE_INFO_LINE_NUM(line_col) ((line_col) >> 10) | ||
| 3008 | #define BPF_LINE_INFO_LINE_COL(line_col) ((line_col) & 0x3ff) | ||
| 3009 | |||
| 3010 | struct bpf_line_info { | ||
| 3011 | __u32 insn_off; | ||
| 3012 | __u32 file_name_off; | ||
| 3013 | __u32 line_off; | ||
| 3014 | __u32 line_col; | ||
| 3015 | }; | ||
| 3016 | |||
| 2998 | #endif /* _UAPI__LINUX_BPF_H__ */ | 3017 | #endif /* _UAPI__LINUX_BPF_H__ */ |
| @@ -444,7 +444,7 @@ static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) · 443 unmodified lines | |||
| 444 | return kind_ops[BTF_INFO_KIND(t->info)]; | 444 | return kind_ops[BTF_INFO_KIND(t->info)]; |
| 445 | } | 445 | } |
| 446 | 446 | ||
| 447 | static bool btf_name_offset_valid(const struct btf *btf, u32 offset) | 447 | bool btf_name_offset_valid(const struct btf *btf, u32 offset) |
| 448 | { | 448 | { |
| 449 | return BTF_STR_OFFSET_VALID(offset) && | 449 | return BTF_STR_OFFSET_VALID(offset) && |
| 450 | offset < btf->hdr.str_len; | 450 | offset < btf->hdr.str_len; |
| @@ -105,6 +105,91 @@ struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags) · 104 unmodified lines | |||
| 105 | } | 105 | } |
| 106 | EXPORT_SYMBOL_GPL(bpf_prog_alloc); | 106 | EXPORT_SYMBOL_GPL(bpf_prog_alloc); |
| 107 | 107 | ||
| 108 | int bpf_prog_alloc_jited_linfo(struct bpf_prog *prog) | ||
| 109 | { | ||
| 110 | if (!prog->aux->nr_linfo || !prog->jit_requested) | ||
| 111 | return 0; | ||
| 112 | |||
| 113 | prog->aux->jited_linfo = kcalloc(prog->aux->nr_linfo, | ||
| 114 | sizeof(*prog->aux->jited_linfo), | ||
| 115 | GFP_KERNEL | __GFP_NOWARN); | ||
| 116 | if (!prog->aux->jited_linfo) | ||
| 117 | return -ENOMEM; | ||
| 118 | |||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | void bpf_prog_free_jited_linfo(struct bpf_prog *prog) | ||
| 123 | { | ||
| 124 | kfree(prog->aux->jited_linfo); | ||
| 125 | prog->aux->jited_linfo = NULL; | ||
| 126 | } | ||
| 127 | |||
| 128 | void bpf_prog_free_unused_jited_linfo(struct bpf_prog *prog) | ||
| 129 | { | ||
| 130 | if (prog->aux->jited_linfo && !prog->aux->jited_linfo[0]) | ||
| 131 | bpf_prog_free_jited_linfo(prog); | ||
| 132 | } | ||
| 133 | |||
| 134 | /* The jit engine is responsible to provide an array | ||
| 135 | * for insn_off to the jited_off mapping (insn_to_jit_off). | ||
| 136 | * | ||
| 137 | * The idx to this array is the insn_off. Hence, the insn_off | ||
| 138 | * here is relative to the prog itself instead of the main prog. | ||
| 139 | * This array has one entry for each xlated bpf insn. | ||
| 140 | * | ||
| 141 | * jited_off is the byte off to the last byte of the jited insn. | ||
| 142 | * | ||
| 143 | * Hence, with | ||
| 144 | * insn_start: | ||
| 145 | * The first bpf insn off of the prog. The insn off | ||
| 146 | * here is relative to the main prog. | ||
| 147 | * e.g. if prog is a subprog, insn_start > 0 | ||
| 148 | * linfo_idx: | ||
| 149 | * The prog's idx to prog->aux->linfo and jited_linfo | ||
| 150 | * | ||
| 151 | * jited_linfo[linfo_idx] = prog->bpf_func | ||
| 152 | * | ||
| 153 | * For i > linfo_idx, | ||
| 154 | * | ||
| 155 | * jited_linfo[i] = prog->bpf_func + | ||
| 156 | * insn_to_jit_off[linfo[i].insn_off - insn_start - 1] | ||
| 157 | */ | ||
| 158 | void bpf_prog_fill_jited_linfo(struct bpf_prog *prog, | ||
| 159 | const u32 *insn_to_jit_off) | ||
| 160 | { | ||
| 161 | u32 linfo_idx, insn_start, insn_end, nr_linfo, i; | ||
| 162 | const struct bpf_line_info *linfo; | ||
| 163 | void **jited_linfo; | ||
| 164 | |||
| 165 | if (!prog->aux->jited_linfo) | ||
| 166 | /* Userspace did not provide linfo */ | ||
| 167 | return; | ||
| 168 | |||
| 169 | linfo_idx = prog->aux->linfo_idx; | ||
| 170 | linfo = &prog->aux->linfo[linfo_idx]; | ||
| 171 | insn_start = linfo[0].insn_off; | ||
| 172 | insn_end = insn_start + prog->len; | ||
| 173 | |||
| 174 | jited_linfo = &prog->aux->jited_linfo[linfo_idx]; | ||
| 175 | jited_linfo[0] = prog->bpf_func; | ||
| 176 | |||
| 177 | nr_linfo = prog->aux->nr_linfo - linfo_idx; | ||
| 178 | |||
| 179 | for (i = 1; i < nr_linfo && linfo[i].insn_off < insn_end; i++) | ||
| 180 | /* The verifier ensures that linfo[i].insn_off is | ||
| 181 | * strictly increasing | ||
| 182 | */ | ||
| 183 | jited_linfo[i] = prog->bpf_func + | ||
| 184 | insn_to_jit_off[linfo[i].insn_off - insn_start - 1]; | ||
| 185 | } | ||
| 186 | |||
| 187 | void bpf_prog_free_linfo(struct bpf_prog *prog) | ||
| 188 | { | ||
| 189 | bpf_prog_free_jited_linfo(prog); | ||
| 190 | kvfree(prog->aux->linfo); | ||
| 191 | } | ||
| 192 | |||
| 108 | struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size, | 193 | struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size, |
| 109 | gfp_t gfp_extra_flags) | 194 | gfp_t gfp_extra_flags) |
| 110 | { | 195 | { |
| @@ -294,6 +379,26 @@ static int bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta, · 183 unmodified lines | |||
| 294 | return ret; | 379 | return ret; |
| 295 | } | 380 | } |
| 296 | 381 | ||
| 382 | static void bpf_adj_linfo(struct bpf_prog *prog, u32 off, u32 delta) | ||
| 383 | { | ||
| 384 | struct bpf_line_info *linfo; | ||
| 385 | u32 i, nr_linfo; | ||
| 386 | |||
| 387 | nr_linfo = prog->aux->nr_linfo; | ||
| 388 | if (!nr_linfo || !delta) | ||
| 389 | return; | ||
| 390 | |||
| 391 | linfo = prog->aux->linfo; | ||
| 392 | |||
| 393 | for (i = 0; i < nr_linfo; i++) | ||
| 394 | if (off < linfo[i].insn_off) | ||
| 395 | break; | ||
| 396 | |||
| 397 | /* Push all off < linfo[i].insn_off by delta */ | ||
| 398 | for (; i < nr_linfo; i++) | ||
| 399 | linfo[i].insn_off += delta; | ||
| 400 | } | ||
| 401 | |||
| 297 | struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off, | 402 | struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off, |
| 298 | const struct bpf_insn *patch, u32 len) | 403 | const struct bpf_insn *patch, u32 len) |
| 299 | { | 404 | { |
| @@ -349,6 +454,8 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off, · 49 unmodified lines | |||
| 349 | */ | 454 | */ |
| 350 | BUG_ON(bpf_adj_branches(prog_adj, off, insn_delta, false)); | 455 | BUG_ON(bpf_adj_branches(prog_adj, off, insn_delta, false)); |
| 351 | 456 | ||
| 457 | bpf_adj_linfo(prog_adj, off, insn_delta); | ||
| 458 | |||
| 352 | return prog_adj; | 459 | return prog_adj; |
| 353 | } | 460 | } |
| 354 | 461 | ||
| @@ -1591,13 +1698,20 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err) · 1236 unmodified lines | |||
| 1591 | * be JITed, but falls back to the interpreter. | 1698 | * be JITed, but falls back to the interpreter. |
| 1592 | */ | 1699 | */ |
| 1593 | if (!bpf_prog_is_dev_bound(fp->aux)) { | 1700 | if (!bpf_prog_is_dev_bound(fp->aux)) { |
| 1701 | *err = bpf_prog_alloc_jited_linfo(fp); | ||
| 1702 | if (*err) | ||
| 1703 | return fp; | ||
| 1704 | |||
| 1594 | fp = bpf_int_jit_compile(fp); | 1705 | fp = bpf_int_jit_compile(fp); |
| 1595 | #ifdef CONFIG_BPF_JIT_ALWAYS_ON | ||
| 1596 | if (!fp->jited) { | 1706 | if (!fp->jited) { |
| 1707 | bpf_prog_free_jited_linfo(fp); | ||
| 1708 | #ifdef CONFIG_BPF_JIT_ALWAYS_ON | ||
| 1597 | *err = -ENOTSUPP; | 1709 | *err = -ENOTSUPP; |
| 1598 | return fp; | 1710 | return fp; |
| 1599 | } | ||
| 1600 | #endif | 1711 | #endif |
| 1712 | } else { | ||
| 1713 | bpf_prog_free_unused_jited_linfo(fp); | ||
| 1714 | } | ||
| 1601 | } else { | 1715 | } else { |
| 1602 | *err = bpf_prog_offload_compile(fp); | 1716 | *err = bpf_prog_offload_compile(fp); |
| 1603 | if (*err) | 1717 | if (*err) |
| @@ -1215,6 +1215,7 @@ static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) · 1214 unmodified lines | |||
| 1215 | bpf_prog_kallsyms_del_all(prog); | 1215 | bpf_prog_kallsyms_del_all(prog); |
| 1216 | btf_put(prog->aux->btf); | 1216 | btf_put(prog->aux->btf); |
| 1217 | kvfree(prog->aux->func_info); | 1217 | kvfree(prog->aux->func_info); |
| 1218 | bpf_prog_free_linfo(prog); | ||
| 1218 | 1219 | ||
| 1219 | call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); | 1220 | call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu); |
| 1220 | } | 1221 | } |
| @@ -1439,7 +1440,7 @@ bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type, · 218 unmodified lines | |||
| 1439 | } | 1440 | } |
| 1440 | 1441 | ||
| 1441 | /* last field in 'union bpf_attr' used by this command */ | 1442 | /* last field in 'union bpf_attr' used by this command */ |
| 1442 | #define BPF_PROG_LOAD_LAST_FIELD func_info_cnt | 1443 | #define BPF_PROG_LOAD_LAST_FIELD line_info_cnt |
| 1443 | 1444 | ||
| 1444 | static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) | 1445 | static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) |
| 1445 | { | 1446 | { |
| @@ -1560,6 +1561,7 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) · 114 unmodified lines | |||
| 1560 | return err; | 1561 | return err; |
| 1561 | 1562 | ||
| 1562 | free_used_maps: | 1563 | free_used_maps: |
| 1564 | bpf_prog_free_linfo(prog); | ||
| 1563 | kvfree(prog->aux->func_info); | 1565 | kvfree(prog->aux->func_info); |
| 1564 | btf_put(prog->aux->btf); | 1566 | btf_put(prog->aux->btf); |
| 1565 | bpf_prog_kallsyms_del_subprogs(prog); | 1567 | bpf_prog_kallsyms_del_subprogs(prog); |
| @@ -2041,6 +2043,37 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog) · 475 unmodified lines | |||
| 2041 | return insns; | 2043 | return insns; |
| 2042 | } | 2044 | } |
| 2043 | 2045 | ||
| 2046 | static int set_info_rec_size(struct bpf_prog_info *info) | ||
| 2047 | { | ||
| 2048 | /* | ||
| 2049 | * Ensure info.*_rec_size is the same as kernel expected size | ||
| 2050 | * | ||
| 2051 | * or | ||
| 2052 | * | ||
| 2053 | * Only allow zero *_rec_size if both _rec_size and _cnt are | ||
| 2054 | * zero. In this case, the kernel will set the expected | ||
| 2055 | * _rec_size back to the info. | ||
| 2056 | */ | ||
| 2057 | |||
| 2058 | if ((info->func_info_cnt || info->func_info_rec_size) && | ||
| 2059 | info->func_info_rec_size != sizeof(struct bpf_func_info)) | ||
| 2060 | return -EINVAL; | ||
| 2061 | |||
| 2062 | if ((info->line_info_cnt || info->line_info_rec_size) && | ||
| 2063 | info->line_info_rec_size != sizeof(struct bpf_line_info)) | ||
| 2064 | return -EINVAL; | ||
| 2065 | |||
| 2066 | if ((info->jited_line_info_cnt || info->jited_line_info_rec_size) && | ||
| 2067 | info->jited_line_info_rec_size != sizeof(__u64)) | ||
| 2068 | return -EINVAL; | ||
| 2069 | |||
| 2070 | info->func_info_rec_size = sizeof(struct bpf_func_info); | ||
| 2071 | info->line_info_rec_size = sizeof(struct bpf_line_info); | ||
| 2072 | info->jited_line_info_rec_size = sizeof(__u64); | ||
| 2073 | |||
| 2074 | return 0; | ||
| 2075 | } | ||
| 2076 | |||
| 2044 | static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, | 2077 | static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, |
| 2045 | const union bpf_attr *attr, | 2078 | const union bpf_attr *attr, |
| 2046 | union bpf_attr __user *uattr) | 2079 | union bpf_attr __user *uattr) |
| @@ -2083,11 +2116,9 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, · 36 unmodified lines | |||
| 2083 | return -EFAULT; | 2116 | return -EFAULT; |
| 2084 | } | 2117 | } |
| 2085 | 2118 | ||
| 2086 | if ((info.func_info_cnt || info.func_info_rec_size) && | 2119 | err = set_info_rec_size(&info); |
| 2087 | info.func_info_rec_size != sizeof(struct bpf_func_info)) | 2120 | if (err) |
| 2088 | return -EINVAL; | 2121 | return err; |
| 2089 | |||
| 2090 | info.func_info_rec_size = sizeof(struct bpf_func_info); | ||
| 2091 | 2122 | ||
| 2092 | if (!capable(CAP_SYS_ADMIN)) { | 2123 | if (!capable(CAP_SYS_ADMIN)) { |
| 2093 | info.jited_prog_len = 0; | 2124 | info.jited_prog_len = 0; |
| @@ -2095,6 +2126,8 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, · 1 unmodified line | |||
| 2095 | info.nr_jited_ksyms = 0; | 2126 | info.nr_jited_ksyms = 0; |
| 2096 | info.nr_jited_func_lens = 0; | 2127 | info.nr_jited_func_lens = 0; |
| 2097 | info.func_info_cnt = 0; | 2128 | info.func_info_cnt = 0; |
| 2129 | info.line_info_cnt = 0; | ||
| 2130 | info.jited_line_info_cnt = 0; | ||
| 2098 | goto done; | 2131 | goto done; |
| 2099 | } | 2132 | } |
| 2100 | 2133 | ||
| @@ -2251,6 +2284,44 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, · 150 unmodified lines | |||
| 2251 | } | 2284 | } |
| 2252 | } | 2285 | } |
| 2253 | 2286 | ||
| 2287 | ulen = info.line_info_cnt; | ||
| 2288 | info.line_info_cnt = prog->aux->nr_linfo; | ||
| 2289 | if (info.line_info_cnt && ulen) { | ||
| 2290 | if (bpf_dump_raw_ok()) { | ||
| 2291 | __u8 __user *user_linfo; | ||
| 2292 | |||
| 2293 | user_linfo = u64_to_user_ptr(info.line_info); | ||
| 2294 | ulen = min_t(u32, info.line_info_cnt, ulen); | ||
| 2295 | if (copy_to_user(user_linfo, prog->aux->linfo, | ||
| 2296 | info.line_info_rec_size * ulen)) | ||
| 2297 | return -EFAULT; | ||
| 2298 | } else { | ||
| 2299 | info.line_info = 0; | ||
| 2300 | } | ||
| 2301 | } | ||
| 2302 | |||
| 2303 | ulen = info.jited_line_info_cnt; | ||
| 2304 | if (prog->aux->jited_linfo) | ||
| 2305 | info.jited_line_info_cnt = prog->aux->nr_linfo; | ||
| 2306 | else | ||
| 2307 | info.jited_line_info_cnt = 0; | ||
| 2308 | if (info.jited_line_info_cnt && ulen) { | ||
| 2309 | if (bpf_dump_raw_ok()) { | ||
| 2310 | __u64 __user *user_linfo; | ||
| 2311 | u32 i; | ||
| 2312 | |||
| 2313 | user_linfo = u64_to_user_ptr(info.jited_line_info); | ||
| 2314 | ulen = min_t(u32, info.jited_line_info_cnt, ulen); | ||
| 2315 | for (i = 0; i < ulen; i++) { | ||
| 2316 | if (put_user((__u64)(long)prog->aux->jited_linfo[i], | ||
| 2317 | &user_linfo[i])) | ||
| 2318 | return -EFAULT; | ||
| 2319 | } | ||
| 2320 | } else { | ||
| 2321 | info.jited_line_info = 0; | ||
| 2322 | } | ||
| 2323 | } | ||
| 2324 | |||
| 2254 | done: | 2325 | done: |
| 2255 | if (copy_to_user(uinfo, &info, info_len) || | 2326 | if (copy_to_user(uinfo, &info, info_len) || |
| 2256 | put_user(info_len, &uattr->info.info_len)) | 2327 | put_user(info_len, &uattr->info.info_len)) |
| @@ -4640,15 +4640,17 @@ err_free: · 4639 unmodified lines | |||
| 4640 | #define MIN_BPF_FUNCINFO_SIZE 8 | 4640 | #define MIN_BPF_FUNCINFO_SIZE 8 |
| 4641 | #define MAX_FUNCINFO_REC_SIZE 252 | 4641 | #define MAX_FUNCINFO_REC_SIZE 252 |
| 4642 | 4642 | ||
| 4643 | static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env, | 4643 | static int check_btf_func(struct bpf_verifier_env *env, |
| 4644 | union bpf_attr *attr, union bpf_attr __user *uattr) | 4644 | const union bpf_attr *attr, |
| 4645 | union bpf_attr __user *uattr) | ||
| 4645 | { | 4646 | { |
| 4646 | u32 i, nfuncs, urec_size, min_size, prev_offset; | 4647 | u32 i, nfuncs, urec_size, min_size, prev_offset; |
| 4647 | u32 krec_size = sizeof(struct bpf_func_info); | 4648 | u32 krec_size = sizeof(struct bpf_func_info); |
| 4648 | struct bpf_func_info *krecord = NULL; | 4649 | struct bpf_func_info *krecord; |
| 4649 | const struct btf_type *type; | 4650 | const struct btf_type *type; |
| 4651 | struct bpf_prog *prog; | ||
| 4652 | const struct btf *btf; | ||
| 4650 | void __user *urecord; | 4653 | void __user *urecord; |
| 4651 | struct btf *btf; | ||
| 4652 | int ret = 0; | 4654 | int ret = 0; |
| 4653 | 4655 | ||
| 4654 | nfuncs = attr->func_info_cnt; | 4656 | nfuncs = attr->func_info_cnt; |
| @@ -4668,20 +4670,15 @@ static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env, · 13 unmodified lines | |||
| 4668 | return -EINVAL; | 4670 | return -EINVAL; |
| 4669 | } | 4671 | } |
| 4670 | 4672 | ||
| 4671 | btf = btf_get_by_fd(attr->prog_btf_fd); | 4673 | prog = env->prog; |
| 4672 | if (IS_ERR(btf)) { | 4674 | btf = prog->aux->btf; |
| 4673 | verbose(env, "unable to get btf from fd\n"); | ||
| 4674 | return PTR_ERR(btf); | ||
| 4675 | } | ||
| 4676 | 4675 | ||
| 4677 | urecord = u64_to_user_ptr(attr->func_info); | 4676 | urecord = u64_to_user_ptr(attr->func_info); |
| 4678 | min_size = min_t(u32, krec_size, urec_size); | 4677 | min_size = min_t(u32, krec_size, urec_size); |
| 4679 | 4678 | ||
| 4680 | krecord = kvcalloc(nfuncs, krec_size, GFP_KERNEL | __GFP_NOWARN); | 4679 | krecord = kvcalloc(nfuncs, krec_size, GFP_KERNEL | __GFP_NOWARN); |
| 4681 | if (!krecord) { | 4680 | if (!krecord) |
| 4682 | ret = -ENOMEM; | 4681 | return -ENOMEM; |
| 4683 | goto free_btf; | ||
| 4684 | } | ||
| 4685 | 4682 | ||
| 4686 | for (i = 0; i < nfuncs; i++) { | 4683 | for (i = 0; i < nfuncs; i++) { |
| 4687 | ret = bpf_check_uarg_tail_zero(urecord, krec_size, urec_size); | 4684 | ret = bpf_check_uarg_tail_zero(urecord, krec_size, urec_size); |
| @@ -4694,12 +4691,12 @@ static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env, · 6 unmodified lines | |||
| 4694 | if (put_user(min_size, &uattr->func_info_rec_size)) | 4691 | if (put_user(min_size, &uattr->func_info_rec_size)) |
| 4695 | ret = -EFAULT; | 4692 | ret = -EFAULT; |
| 4696 | } | 4693 | } |
| 4697 | goto free_btf; | 4694 | goto err_free; |
| 4698 | } | 4695 | } |
| 4699 | 4696 | ||
| 4700 | if (copy_from_user(&krecord[i], urecord, min_size)) { | 4697 | if (copy_from_user(&krecord[i], urecord, min_size)) { |
| 4701 | ret = -EFAULT; | 4698 | ret = -EFAULT; |
| 4702 | goto free_btf; | 4699 | goto err_free; |
| 4703 | } | 4700 | } |
| 4704 | 4701 | ||
| 4705 | /* check insn_off */ | 4702 | /* check insn_off */ |
| @@ -4709,20 +4706,20 @@ static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env, · 3 unmodified lines | |||
| 4709 | "nonzero insn_off %u for the first func info record", | 4706 | "nonzero insn_off %u for the first func info record", |
| 4710 | krecord[i].insn_off); | 4707 | krecord[i].insn_off); |
| 4711 | ret = -EINVAL; | 4708 | ret = -EINVAL; |
| 4712 | goto free_btf; | 4709 | goto err_free; |
| 4713 | } | 4710 | } |
| 4714 | } else if (krecord[i].insn_off <= prev_offset) { | 4711 | } else if (krecord[i].insn_off <= prev_offset) { |
| 4715 | verbose(env, | 4712 | verbose(env, |
| 4716 | "same or smaller insn offset (%u) than previous func info record (%u)", | 4713 | "same or smaller insn offset (%u) than previous func info record (%u)", |
| 4717 | krecord[i].insn_off, prev_offset); | 4714 | krecord[i].insn_off, prev_offset); |
| 4718 | ret = -EINVAL; | 4715 | ret = -EINVAL; |
| 4719 | goto free_btf; | 4716 | goto err_free; |
| 4720 | } | 4717 | } |
| 4721 | 4718 | ||
| 4722 | if (env->subprog_info[i].start != krecord[i].insn_off) { | 4719 | if (env->subprog_info[i].start != krecord[i].insn_off) { |
| 4723 | verbose(env, "func_info BTF section doesn't match subprog layout in BPF program\n"); | 4720 | verbose(env, "func_info BTF section doesn't match subprog layout in BPF program\n"); |
| 4724 | ret = -EINVAL; | 4721 | ret = -EINVAL; |
| 4725 | goto free_btf; | 4722 | goto err_free; |
| 4726 | } | 4723 | } |
| 4727 | 4724 | ||
| 4728 | /* check type_id */ | 4725 | /* check type_id */ |
| @@ -4731,20 +4728,18 @@ static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env, · 2 unmodified lines | |||
| 4731 | verbose(env, "invalid type id %d in func info", | 4728 | verbose(env, "invalid type id %d in func info", |
| 4732 | krecord[i].type_id); | 4729 | krecord[i].type_id); |
| 4733 | ret = -EINVAL; | 4730 | ret = -EINVAL; |
| 4734 | goto free_btf; | 4731 | goto err_free; |
| 4735 | } | 4732 | } |
| 4736 | 4733 | ||
| 4737 | prev_offset = krecord[i].insn_off; | 4734 | prev_offset = krecord[i].insn_off; |
| 4738 | urecord += urec_size; | 4735 | urecord += urec_size; |
| 4739 | } | 4736 | } |
| 4740 | 4737 | ||
| 4741 | prog->aux->btf = btf; | ||
| 4742 | prog->aux->func_info = krecord; | 4738 | prog->aux->func_info = krecord; |
| 4743 | prog->aux->func_info_cnt = nfuncs; | 4739 | prog->aux->func_info_cnt = nfuncs; |
| 4744 | return 0; | 4740 | return 0; |
| 4745 | 4741 | ||
| 4746 | free_btf: | 4742 | err_free: |
| 4747 | btf_put(btf); | ||
| 4748 | kvfree(krecord); | 4743 | kvfree(krecord); |
| 4749 | return ret; | 4744 | return ret; |
| 4750 | } | 4745 | } |
| @@ -4760,6 +4755,150 @@ static void adjust_btf_func(struct bpf_verifier_env *env) · 9 unmodified lines | |||
| 4760 | env->prog->aux->func_info[i].insn_off = env->subprog_info[i].start; | 4755 | env->prog->aux->func_info[i].insn_off = env->subprog_info[i].start; |
| 4761 | } | 4756 | } |
| 4762 | 4757 | ||
| 4758 | #define MIN_BPF_LINEINFO_SIZE (offsetof(struct bpf_line_info, line_col) + \ | ||
| 4759 | sizeof(((struct bpf_line_info *)(0))->line_col)) | ||
| 4760 | #define MAX_LINEINFO_REC_SIZE MAX_FUNCINFO_REC_SIZE | ||
| 4761 | |||
| 4762 | static int check_btf_line(struct bpf_verifier_env *env, | ||
| 4763 | const union bpf_attr *attr, | ||
| 4764 | union bpf_attr __user *uattr) | ||
| 4765 | { | ||
| 4766 | u32 i, s, nr_linfo, ncopy, expected_size, rec_size, prev_offset = 0; | ||
| 4767 | struct bpf_subprog_info *sub; | ||
| 4768 | struct bpf_line_info *linfo; | ||
| 4769 | struct bpf_prog *prog; | ||
| 4770 | const struct btf *btf; | ||
| 4771 | void __user *ulinfo; | ||
| 4772 | int err; | ||
| 4773 | |||
| 4774 | nr_linfo = attr->line_info_cnt; | ||
| 4775 | if (!nr_linfo) | ||
| 4776 | return 0; | ||
| 4777 | |||
| 4778 | rec_size = attr->line_info_rec_size; | ||
| 4779 | if (rec_size < MIN_BPF_LINEINFO_SIZE || | ||
| 4780 | rec_size > MAX_LINEINFO_REC_SIZE || | ||
| 4781 | rec_size & (sizeof(u32) - 1)) | ||
| 4782 | return -EINVAL; | ||
| 4783 | |||
| 4784 | /* Need to zero it in case the userspace may | ||
| 4785 | * pass in a smaller bpf_line_info object. | ||
| 4786 | */ | ||
| 4787 | linfo = kvcalloc(nr_linfo, sizeof(struct bpf_line_info), | ||
| 4788 | GFP_KERNEL | __GFP_NOWARN); | ||
| 4789 | if (!linfo) | ||
| 4790 | return -ENOMEM; | ||
| 4791 | |||
| 4792 | prog = env->prog; | ||
| 4793 | btf = prog->aux->btf; | ||
| 4794 | |||
| 4795 | s = 0; | ||
| 4796 | sub = env->subprog_info; | ||
| 4797 | ulinfo = u64_to_user_ptr(attr->line_info); | ||
| 4798 | expected_size = sizeof(struct bpf_line_info); | ||
| 4799 | ncopy = min_t(u32, expected_size, rec_size); | ||
| 4800 | for (i = 0; i < nr_linfo; i++) { | ||
| 4801 | err = bpf_check_uarg_tail_zero(ulinfo, expected_size, rec_size); | ||
| 4802 | if (err) { | ||
| 4803 | if (err == -E2BIG) { | ||
| 4804 | verbose(env, "nonzero tailing record in line_info"); | ||
| 4805 | if (put_user(expected_size, | ||
| 4806 | &uattr->line_info_rec_size)) | ||
| 4807 | err = -EFAULT; | ||
| 4808 | } | ||
| 4809 | goto err_free; | ||
| 4810 | } | ||
| 4811 | |||
| 4812 | if (copy_from_user(&linfo[i], ulinfo, ncopy)) { | ||
| 4813 | err = -EFAULT; | ||
| 4814 | goto err_free; | ||
| 4815 | } | ||
| 4816 | |||
| 4817 | /* | ||
| 4818 | * Check insn_off to ensure | ||
| 4819 | * 1) strictly increasing AND | ||
| 4820 | * 2) bounded by prog->len | ||
| 4821 | * | ||
| 4822 | * The linfo[0].insn_off == 0 check logically falls into | ||
| 4823 | * the later "missing bpf_line_info for func..." case | ||
| 4824 | * because the first linfo[0].insn_off must be the | ||
| 4825 | * first sub also and the first sub must have | ||
| 4826 | * subprog_info[0].start == 0. | ||
| 4827 | */ | ||
| 4828 | if ((i && linfo[i].insn_off <= prev_offset) || | ||
| 4829 | linfo[i].insn_off >= prog->len) { | ||
| 4830 | verbose(env, "Invalid line_info[%u].insn_off:%u (prev_offset:%u prog->len:%u)\n", | ||
| 4831 | i, linfo[i].insn_off, prev_offset, | ||
| 4832 | prog->len); | ||
| 4833 | err = -EINVAL; | ||
| 4834 | goto err_free; | ||
| 4835 | } | ||
| 4836 | |||
| 4837 | if (!btf_name_offset_valid(btf, linfo[i].line_off) || | ||
| 4838 | !btf_name_offset_valid(btf, linfo[i].file_name_off)) { | ||
| 4839 | verbose(env, "Invalid line_info[%u].line_off or .file_name_off\n", i); | ||
| 4840 | err = -EINVAL; | ||
| 4841 | goto err_free; | ||
| 4842 | } | ||
| 4843 | |||
| 4844 | if (s != env->subprog_cnt) { | ||
| 4845 | if (linfo[i].insn_off == sub[s].start) { | ||
| 4846 | sub[s].linfo_idx = i; | ||
| 4847 | s++; | ||
| 4848 | } else if (sub[s].start < linfo[i].insn_off) { | ||
| 4849 | verbose(env, "missing bpf_line_info for func#%u\n", s); | ||
| 4850 | err = -EINVAL; | ||
| 4851 | goto err_free; | ||
| 4852 | } | ||
| 4853 | } | ||
| 4854 | |||
| 4855 | prev_offset = linfo[i].insn_off; | ||
| 4856 | ulinfo += rec_size; | ||
| 4857 | } | ||
| 4858 | |||
| 4859 | if (s != env->subprog_cnt) { | ||
| 4860 | verbose(env, "missing bpf_line_info for %u funcs starting from func#%u\n", | ||
| 4861 | env->subprog_cnt - s, s); | ||
| 4862 | err = -EINVAL; | ||
| 4863 | goto err_free; | ||
| 4864 | } | ||
| 4865 | |||
| 4866 | prog->aux->linfo = linfo; | ||
| 4867 | prog->aux->nr_linfo = nr_linfo; | ||
| 4868 | |||
| 4869 | return 0; | ||
| 4870 | |||
| 4871 | err_free: | ||
| 4872 | kvfree(linfo); | ||
| 4873 | return err; | ||
| 4874 | } | ||
| 4875 | |||
| 4876 | static int check_btf_info(struct bpf_verifier_env *env, | ||
| 4877 | const union bpf_attr *attr, | ||
| 4878 | union bpf_attr __user *uattr) | ||
| 4879 | { | ||
| 4880 | struct btf *btf; | ||
| 4881 | int err; | ||
| 4882 | |||
| 4883 | if (!attr->func_info_cnt && !attr->line_info_cnt) | ||
| 4884 | return 0; | ||
| 4885 | |||
| 4886 | btf = btf_get_by_fd(attr->prog_btf_fd); | ||
| 4887 | if (IS_ERR(btf)) | ||
| 4888 | return PTR_ERR(btf); | ||
| 4889 | env->prog->aux->btf = btf; | ||
| 4890 | |||
| 4891 | err = check_btf_func(env, attr, uattr); | ||
| 4892 | if (err) | ||
| 4893 | return err; | ||
| 4894 | |||
| 4895 | err = check_btf_line(env, attr, uattr); | ||
| 4896 | if (err) | ||
| 4897 | return err; | ||
| 4898 | |||
| 4899 | return 0; | ||
| 4900 | } | ||
| 4901 | |||
| 4763 | /* check %cur's range satisfies %old's */ | 4902 | /* check %cur's range satisfies %old's */ |
| 4764 | static bool range_within(struct bpf_reg_state *old, | 4903 | static bool range_within(struct bpf_reg_state *old, |
| 4765 | struct bpf_reg_state *cur) | 4904 | struct bpf_reg_state *cur) |
| @@ -6004,7 +6143,7 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 1238 unmodified lines | |||
| 6004 | int i, j, subprog_start, subprog_end = 0, len, subprog; | 6143 | int i, j, subprog_start, subprog_end = 0, len, subprog; |
| 6005 | struct bpf_insn *insn; | 6144 | struct bpf_insn *insn; |
| 6006 | void *old_bpf_func; | 6145 | void *old_bpf_func; |
| 6007 | int err = -ENOMEM; | 6146 | int err; |
| 6008 | 6147 | ||
| 6009 | if (env->subprog_cnt <= 1) | 6148 | if (env->subprog_cnt <= 1) |
| 6010 | return 0; | 6149 | return 0; |
| @@ -6035,6 +6174,11 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 24 unmodified lines | |||
| 6035 | insn->imm = 1; | 6174 | insn->imm = 1; |
| 6036 | } | 6175 | } |
| 6037 | 6176 | ||
| 6177 | err = bpf_prog_alloc_jited_linfo(prog); | ||
| 6178 | if (err) | ||
| 6179 | goto out_undo_insn; | ||
| 6180 | |||
| 6181 | err = -ENOMEM; | ||
| 6038 | func = kcalloc(env->subprog_cnt, sizeof(prog), GFP_KERNEL); | 6182 | func = kcalloc(env->subprog_cnt, sizeof(prog), GFP_KERNEL); |
| 6039 | if (!func) | 6183 | if (!func) |
| 6040 | goto out_undo_insn; | 6184 | goto out_undo_insn; |
| @@ -6065,6 +6209,10 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 24 unmodified lines | |||
| 6065 | func[i]->aux->name[0] = 'F'; | 6209 | func[i]->aux->name[0] = 'F'; |
| 6066 | func[i]->aux->stack_depth = env->subprog_info[i].stack_depth; | 6210 | func[i]->aux->stack_depth = env->subprog_info[i].stack_depth; |
| 6067 | func[i]->jit_requested = 1; | 6211 | func[i]->jit_requested = 1; |
| 6212 | func[i]->aux->linfo = prog->aux->linfo; | ||
| 6213 | func[i]->aux->nr_linfo = prog->aux->nr_linfo; | ||
| 6214 | func[i]->aux->jited_linfo = prog->aux->jited_linfo; | ||
| 6215 | func[i]->aux->linfo_idx = env->subprog_info[i].linfo_idx; | ||
| 6068 | func[i] = bpf_int_jit_compile(func[i]); | 6216 | func[i] = bpf_int_jit_compile(func[i]); |
| 6069 | if (!func[i]->jited) { | 6217 | if (!func[i]->jited) { |
| 6070 | err = -ENOTSUPP; | 6218 | err = -ENOTSUPP; |
| @@ -6138,6 +6286,7 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 67 unmodified lines | |||
| 6138 | prog->bpf_func = func[0]->bpf_func; | 6286 | prog->bpf_func = func[0]->bpf_func; |
| 6139 | prog->aux->func = func; | 6287 | prog->aux->func = func; |
| 6140 | prog->aux->func_cnt = env->subprog_cnt; | 6288 | prog->aux->func_cnt = env->subprog_cnt; |
| 6289 | bpf_prog_free_unused_jited_linfo(prog); | ||
| 6141 | return 0; | 6290 | return 0; |
| 6142 | out_free: | 6291 | out_free: |
| 6143 | for (i = 0; i < env->subprog_cnt; i++) | 6292 | for (i = 0; i < env->subprog_cnt; i++) |
| @@ -6154,6 +6303,7 @@ out_undo_insn: · 10 unmodified lines | |||
| 6154 | insn->off = 0; | 6303 | insn->off = 0; |
| 6155 | insn->imm = env->insn_aux_data[i].call_imm; | 6304 | insn->imm = env->insn_aux_data[i].call_imm; |
| 6156 | } | 6305 | } |
| 6306 | bpf_prog_free_jited_linfo(prog); | ||
| 6157 | return err; | 6307 | return err; |
| 6158 | } | 6308 | } |
| 6159 | 6309 | ||
| @@ -6526,7 +6676,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, · 366 unmodified lines | |||
| 6526 | if (ret < 0) | 6676 | if (ret < 0) |
| 6527 | goto skip_full_check; | 6677 | goto skip_full_check; |
| 6528 | 6678 | ||
| 6529 | ret = check_btf_func(env->prog, env, attr, uattr); | 6679 | ret = check_btf_info(env, attr, uattr); |
| 6530 | if (ret < 0) | 6680 | if (ret < 0) |
| 6531 | goto skip_full_check; | 6681 | goto skip_full_check; |
| 6532 | 6682 | ||
| @@ -22,8 +22,8 @@ MAP COMMANDS · 21 unmodified lines | |||
| 22 | ============= | 22 | ============= |
| 23 | 23 | ||
| 24 | | **bpftool** **prog { show | list }** [*PROG*] | 24 | | **bpftool** **prog { show | list }** [*PROG*] |
| 25 | | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}] | 25 | | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual** | **linum**}] |
| 26 | | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] | 26 | | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes** | **linum**}] |
| 27 | | **bpftool** **prog pin** *PROG* *FILE* | 27 | | **bpftool** **prog pin** *PROG* *FILE* |
| 28 | | **bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] | 28 | | **bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*] |
| 29 | | **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*] | 29 | | **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*] |
| @@ -56,7 +56,7 @@ DESCRIPTION · 26 unmodified lines | |||
| 56 | Output will start with program ID followed by program type and | 56 | Output will start with program ID followed by program type and |
| 57 | zero or more named attributes (depending on kernel version). | 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 | Dump eBPF instructions of the program from the kernel. By | 60 | Dump eBPF instructions of the program from the kernel. By |
| 61 | default, eBPF will be disassembled and printed to standard | 61 | default, eBPF will be disassembled and printed to standard |
| 62 | output in human-readable format. In this case, **opcodes** | 62 | output in human-readable format. In this case, **opcodes** |
| @@ -69,13 +69,21 @@ DESCRIPTION · 6 unmodified lines | |||
| 69 | built instead, and eBPF instructions will be presented with | 69 | built instead, and eBPF instructions will be presented with |
| 70 | CFG in DOT format, on standard output. | 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 | Dump jited image (host machine code) of the program. | 77 | Dump jited image (host machine code) of the program. |
| 74 | If *FILE* is specified image will be written to a file, | 78 | If *FILE* is specified image will be written to a file, |
| 75 | otherwise it will be disassembled and printed to stdout. | 79 | otherwise it will be disassembled and printed to stdout. |
| 76 | 80 | ||
| 77 | **opcodes** controls if raw opcodes will be printed. | 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 | **bpftool prog pin** *PROG* *FILE* | 87 | **bpftool prog pin** *PROG* *FILE* |
| 80 | Pin program *PROG* as *FILE*. | 88 | Pin program *PROG* as *FILE*. |
| 81 | 89 | ||
| @@ -191,7 +191,7 @@ _bpftool() · 190 unmodified lines | |||
| 191 | 191 | ||
| 192 | # Deal with simplest keywords | 192 | # Deal with simplest keywords |
| 193 | case $prev in | 193 | case $prev in |
| 194 | help|hex|opcodes|visual) | 194 | help|hex|opcodes|visual|linum) |
| 195 | return 0 | 195 | return 0 |
| 196 | ;; | 196 | ;; |
| 197 | tag) | 197 | tag) |
| @@ -278,10 +278,10 @@ _bpftool() · 80 unmodified lines | |||
| 278 | *) | 278 | *) |
| 279 | _bpftool_once_attr 'file' | 279 | _bpftool_once_attr 'file' |
| 280 | if _bpftool_search_list 'xlated'; then | 280 | if _bpftool_search_list 'xlated'; then |
| 281 | COMPREPLY+=( $( compgen -W 'opcodes visual' -- \ | 281 | COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \ |
| 282 | "$cur" ) ) | 282 | "$cur" ) ) |
| 283 | else | 283 | else |
| 284 | COMPREPLY+=( $( compgen -W 'opcodes' -- \ | 284 | COMPREPLY+=( $( compgen -W 'opcodes linum' -- \ |
| 285 | "$cur" ) ) | 285 | "$cur" ) ) |
| 286 | fi | 286 | fi |
| 287 | return 0 | 287 | return 0 |
| @@ -385,3 +385,67 @@ void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig, · 384 unmodified lines | |||
| 385 | if (err < 0) | 385 | if (err < 0) |
| 386 | func_sig[0] = '\0'; | 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 | } | ||
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include <dis-asm.h> | 21 | #include <dis-asm.h> |
| 22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
| 23 | #include <limits.h> | 23 | #include <limits.h> |
| 24 | #include <libbpf.h> | ||
| 24 | 25 | ||
| 25 | #include "json_writer.h" | 26 | #include "json_writer.h" |
| 26 | #include "main.h" | 27 | #include "main.h" |
| @@ -68,10 +69,16 @@ static int fprintf_json(void *out, const char *fmt, ...) · 41 unmodified lines | |||
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, | 71 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, |
| 71 | const char *arch, const char *disassembler_options) | 72 | const char *arch, const char *disassembler_options, |
| 73 | const struct btf *btf, | ||
| 74 | const struct bpf_prog_linfo *prog_linfo, | ||
| 75 | __u64 func_ksym, unsigned int func_idx, | ||
| 76 | bool linum) | ||
| 72 | { | 77 | { |
| 78 | const struct bpf_line_info *linfo = NULL; | ||
| 73 | disassembler_ftype disassemble; | 79 | disassembler_ftype disassemble; |
| 74 | struct disassemble_info info; | 80 | struct disassemble_info info; |
| 81 | unsigned int nr_skip = 0; | ||
| 75 | int count, i, pc = 0; | 82 | int count, i, pc = 0; |
| 76 | char tpath[PATH_MAX]; | 83 | char tpath[PATH_MAX]; |
| 77 | bfd *bfdf; | 84 | bfd *bfdf; |
| @@ -127,12 +134,26 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, · 49 unmodified lines | |||
| 127 | if (json_output) | 134 | if (json_output) |
| 128 | jsonw_start_array(json_wtr); | 135 | jsonw_start_array(json_wtr); |
| 129 | do { | 136 | do { |
| 137 | if (prog_linfo) { | ||
| 138 | linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, | ||
| 139 | func_ksym + pc, | ||
| 140 | func_idx, | ||
| 141 | nr_skip); | ||
| 142 | if (linfo) | ||
| 143 | nr_skip++; | ||
| 144 | } | ||
| 145 | |||
| 130 | if (json_output) { | 146 | if (json_output) { |
| 131 | jsonw_start_object(json_wtr); | 147 | jsonw_start_object(json_wtr); |
| 132 | oper_count = 0; | 148 | oper_count = 0; |
| 149 | if (linfo) | ||
| 150 | btf_dump_linfo_json(btf, linfo, linum); | ||
| 133 | jsonw_name(json_wtr, "pc"); | 151 | jsonw_name(json_wtr, "pc"); |
| 134 | jsonw_printf(json_wtr, "\"0x%x\"", pc); | 152 | jsonw_printf(json_wtr, "\"0x%x\"", pc); |
| 135 | } else { | 153 | } else { |
| 154 | if (linfo) | ||
| 155 | btf_dump_linfo_plain(btf, linfo, "; ", | ||
| 156 | linum); | ||
| 136 | printf("%4x:\t", pc); | 157 | printf("%4x:\t", pc); |
| 137 | } | 158 | } |
| 138 | 159 | ||
| @@ -138,6 +138,9 @@ struct pinned_obj { · 137 unmodified lines | |||
| 138 | struct hlist_node hash; | 138 | struct hlist_node hash; |
| 139 | }; | 139 | }; |
| 140 | 140 | ||
| 141 | struct btf; | ||
| 142 | struct bpf_line_info; | ||
| 143 | |||
| 141 | int build_pinned_obj_table(struct pinned_obj_table *table, | 144 | int build_pinned_obj_table(struct pinned_obj_table *table, |
| 142 | enum bpf_obj_type type); | 145 | enum bpf_obj_type type); |
| 143 | void delete_pinned_obj_table(struct pinned_obj_table *tab); | 146 | void delete_pinned_obj_table(struct pinned_obj_table *tab); |
| @@ -175,13 +178,23 @@ int map_parse_fd(int *argc, char ***argv); · 31 unmodified lines | |||
| 175 | int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); | 178 | int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len); |
| 176 | 179 | ||
| 177 | #ifdef HAVE_LIBBFD_SUPPORT | 180 | #ifdef HAVE_LIBBFD_SUPPORT |
| 181 | struct bpf_prog_linfo; | ||
| 178 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, | 182 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, |
| 179 | const char *arch, const char *disassembler_options); | 183 | const char *arch, const char *disassembler_options, |
| 184 | const struct btf *btf, | ||
| 185 | const struct bpf_prog_linfo *prog_linfo, | ||
| 186 | __u64 func_ksym, unsigned int func_idx, | ||
| 187 | bool linum); | ||
| 180 | int disasm_init(void); | 188 | int disasm_init(void); |
| 181 | #else | 189 | #else |
| 182 | static inline | 190 | static inline |
| 183 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, | 191 | void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, |
| 184 | const char *arch, const char *disassembler_options) | 192 | const char *arch, const char *disassembler_options, |
| 193 | const struct btf *btf, | ||
| 194 | const struct bpf_prog_linfo *prog_linfo, | ||
| 195 | __u64 func_ksym, unsigned int func_idx, | ||
| 196 | bool linum) | ||
| 197 | |||
| 185 | { | 198 | { |
| 186 | } | 199 | } |
| 187 | static inline int disasm_init(void) | 200 | static inline int disasm_init(void) |
| @@ -217,6 +230,12 @@ int btf_dumper_type(const struct btf_dumper *d, __u32 type_id, · 29 unmodified lines | |||
| 217 | void btf_dumper_type_only(const struct btf *btf, __u32 func_type_id, | 230 | void btf_dumper_type_only(const struct btf *btf, __u32 func_type_id, |
| 218 | char *func_only, int size); | 231 | char *func_only, int size); |
| 219 | 232 | ||
| 233 | void btf_dump_linfo_plain(const struct btf *btf, | ||
| 234 | const struct bpf_line_info *linfo, | ||
| 235 | const char *prefix, bool linum); | ||
| 236 | void btf_dump_linfo_json(const struct btf *btf, | ||
| 237 | const struct bpf_line_info *linfo, bool linum); | ||
| 238 | |||
| 220 | struct nlattr; | 239 | struct nlattr; |
| 221 | struct ifinfomsg; | 240 | struct ifinfomsg; |
| 222 | struct tcmsg; | 241 | struct tcmsg; |
| @@ -423,24 +423,26 @@ static int do_show(int argc, char **argv) · 422 unmodified lines | |||
| 423 | 423 | ||
| 424 | static int do_dump(int argc, char **argv) | 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 | unsigned long *func_ksyms = NULL; | 430 | unsigned long *func_ksyms = NULL; |
| 427 | struct bpf_prog_info info = {}; | 431 | struct bpf_prog_info info = {}; |
| 428 | unsigned int *func_lens = NULL; | 432 | unsigned int *func_lens = NULL; |
| 429 | const char *disasm_opt = NULL; | 433 | const char *disasm_opt = NULL; |
| 430 | unsigned int finfo_rec_size; | ||
| 431 | unsigned int nr_func_ksyms; | 434 | unsigned int nr_func_ksyms; |
| 432 | unsigned int nr_func_lens; | 435 | unsigned int nr_func_lens; |
| 433 | struct dump_data dd = {}; | 436 | struct dump_data dd = {}; |
| 434 | __u32 len = sizeof(info); | 437 | __u32 len = sizeof(info); |
| 435 | struct btf *btf = NULL; | 438 | struct btf *btf = NULL; |
| 436 | void *func_info = NULL; | ||
| 437 | unsigned int finfo_cnt; | ||
| 438 | unsigned int buf_size; | 439 | unsigned int buf_size; |
| 439 | char *filepath = NULL; | 440 | char *filepath = NULL; |
| 440 | bool opcodes = false; | 441 | bool opcodes = false; |
| 441 | bool visual = false; | 442 | bool visual = false; |
| 442 | char func_sig[1024]; | 443 | char func_sig[1024]; |
| 443 | unsigned char *buf; | 444 | unsigned char *buf; |
| 445 | bool linum = false; | ||
| 444 | __u32 *member_len; | 446 | __u32 *member_len; |
| 445 | __u64 *member_ptr; | 447 | __u64 *member_ptr; |
| 446 | ssize_t n; | 448 | ssize_t n; |
| @@ -484,6 +486,9 @@ static int do_dump(int argc, char **argv) · 37 unmodified lines | |||
| 484 | } else if (is_prefix(*argv, "visual")) { | 486 | } else if (is_prefix(*argv, "visual")) { |
| 485 | visual = true; | 487 | visual = true; |
| 486 | NEXT_ARG(); | 488 | NEXT_ARG(); |
| 489 | } else if (is_prefix(*argv, "linum")) { | ||
| 490 | linum = true; | ||
| 491 | NEXT_ARG(); | ||
| 487 | } | 492 | } |
| 488 | 493 | ||
| 489 | if (argc) { | 494 | if (argc) { |
| @@ -543,6 +548,32 @@ static int do_dump(int argc, char **argv) · 53 unmodified lines | |||
| 543 | } | 548 | } |
| 544 | } | 549 | } |
| 545 | 550 | ||
| 551 | linfo_rec_size = info.line_info_rec_size; | ||
| 552 | if (info.line_info_cnt && linfo_rec_size && info.btf_id) { | ||
| 553 | linfo_cnt = info.line_info_cnt; | ||
| 554 | linfo = malloc(linfo_cnt * linfo_rec_size); | ||
| 555 | if (!linfo) { | ||
| 556 | p_err("mem alloc failed"); | ||
| 557 | close(fd); | ||
| 558 | goto err_free; | ||
| 559 | } | ||
| 560 | } | ||
| 561 | |||
| 562 | jited_linfo_rec_size = info.jited_line_info_rec_size; | ||
| 563 | if (info.jited_line_info_cnt && | ||
| 564 | jited_linfo_rec_size && | ||
| 565 | info.nr_jited_ksyms && | ||
| 566 | info.nr_jited_func_lens && | ||
| 567 | info.btf_id) { | ||
| 568 | jited_linfo_cnt = info.jited_line_info_cnt; | ||
| 569 | jited_linfo = malloc(jited_linfo_cnt * jited_linfo_rec_size); | ||
| 570 | if (!jited_linfo) { | ||
| 571 | p_err("mem alloc failed"); | ||
| 572 | close(fd); | ||
| 573 | goto err_free; | ||
| 574 | } | ||
| 575 | } | ||
| 576 | |||
| 546 | memset(&info, 0, sizeof(info)); | 577 | memset(&info, 0, sizeof(info)); |
| 547 | 578 | ||
| 548 | *member_ptr = ptr_to_u64(buf); | 579 | *member_ptr = ptr_to_u64(buf); |
| @@ -554,6 +585,13 @@ static int do_dump(int argc, char **argv) · 5 unmodified lines | |||
| 554 | info.func_info_cnt = finfo_cnt; | 585 | info.func_info_cnt = finfo_cnt; |
| 555 | info.func_info_rec_size = finfo_rec_size; | 586 | info.func_info_rec_size = finfo_rec_size; |
| 556 | info.func_info = ptr_to_u64(func_info); | 587 | info.func_info = ptr_to_u64(func_info); |
| 588 | info.line_info_cnt = linfo_cnt; | ||
| 589 | info.line_info_rec_size = linfo_rec_size; | ||
| 590 | info.line_info = ptr_to_u64(linfo); | ||
| 591 | info.jited_line_info_cnt = jited_linfo_cnt; | ||
| 592 | info.jited_line_info_rec_size = jited_linfo_rec_size; | ||
| 593 | info.jited_line_info = ptr_to_u64(jited_linfo); | ||
| 594 | |||
| 557 | 595 | ||
| 558 | err = bpf_obj_get_info_by_fd(fd, &info, &len); | 596 | err = bpf_obj_get_info_by_fd(fd, &info, &len); |
| 559 | close(fd); | 597 | close(fd); |
| @@ -596,6 +634,30 @@ static int do_dump(int argc, char **argv) · 36 unmodified lines | |||
| 596 | finfo_cnt = 0; | 634 | finfo_cnt = 0; |
| 597 | } | 635 | } |
| 598 | 636 | ||
| 637 | if (linfo && info.line_info_cnt != linfo_cnt) { | ||
| 638 | p_err("incorrect line_info_cnt %u vs. expected %u", | ||
| 639 | info.line_info_cnt, linfo_cnt); | ||
| 640 | goto err_free; | ||
| 641 | } | ||
| 642 | |||
| 643 | if (info.line_info_rec_size != linfo_rec_size) { | ||
| 644 | p_err("incorrect line_info_rec_size %u vs. expected %u", | ||
| 645 | info.line_info_rec_size, linfo_rec_size); | ||
| 646 | goto err_free; | ||
| 647 | } | ||
| 648 | |||
| 649 | if (jited_linfo && info.jited_line_info_cnt != jited_linfo_cnt) { | ||
| 650 | p_err("incorrect jited_line_info_cnt %u vs. expected %u", | ||
| 651 | info.jited_line_info_cnt, jited_linfo_cnt); | ||
| 652 | goto err_free; | ||
| 653 | } | ||
| 654 | |||
| 655 | if (info.jited_line_info_rec_size != jited_linfo_rec_size) { | ||
| 656 | p_err("incorrect jited_line_info_rec_size %u vs. expected %u", | ||
| 657 | info.jited_line_info_rec_size, jited_linfo_rec_size); | ||
| 658 | goto err_free; | ||
| 659 | } | ||
| 660 | |||
| 599 | if ((member_len == &info.jited_prog_len && | 661 | if ((member_len == &info.jited_prog_len && |
| 600 | info.jited_prog_insns == 0) || | 662 | info.jited_prog_insns == 0) || |
| 601 | (member_len == &info.xlated_prog_len && | 663 | (member_len == &info.xlated_prog_len && |
| @@ -609,6 +671,12 @@ static int do_dump(int argc, char **argv) · 7 unmodified lines | |||
| 609 | goto err_free; | 671 | goto err_free; |
| 610 | } | 672 | } |
| 611 | 673 | ||
| 674 | if (linfo_cnt) { | ||
| 675 | prog_linfo = bpf_prog_linfo__new(&info); | ||
| 676 | if (!prog_linfo) | ||
| 677 | p_err("error in processing bpf_line_info. continue without it."); | ||
| 678 | } | ||
| 679 | |||
| 612 | if (filepath) { | 680 | if (filepath) { |
| 613 | fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); | 681 | fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); |
| 614 | if (fd < 0) { | 682 | if (fd < 0) { |
| @@ -690,8 +758,11 @@ static int do_dump(int argc, char **argv) · 75 unmodified lines | |||
| 690 | printf("%s:\n", sym_name); | 758 | printf("%s:\n", sym_name); |
| 691 | } | 759 | } |
| 692 | 760 | ||
| 693 | disasm_print_insn(img, lens[i], opcodes, name, | 761 | disasm_print_insn(img, lens[i], opcodes, |
| 694 | disasm_opt); | 762 | name, disasm_opt, btf, |
| 763 | prog_linfo, ksyms[i], i, | ||
| 764 | linum); | ||
| 765 | |||
| 695 | img += lens[i]; | 766 | img += lens[i]; |
| 696 | 767 | ||
| 697 | if (json_output) | 768 | if (json_output) |
| @@ -704,7 +775,7 @@ static int do_dump(int argc, char **argv) · 6 unmodified lines | |||
| 704 | jsonw_end_array(json_wtr); | 775 | jsonw_end_array(json_wtr); |
| 705 | } else { | 776 | } else { |
| 706 | disasm_print_insn(buf, *member_len, opcodes, name, | 777 | disasm_print_insn(buf, *member_len, opcodes, name, |
| 707 | disasm_opt); | 778 | disasm_opt, btf, NULL, 0, 0, false); |
| 708 | } | 779 | } |
| 709 | } else if (visual) { | 780 | } else if (visual) { |
| 710 | if (json_output) | 781 | if (json_output) |
| @@ -718,11 +789,14 @@ static int do_dump(int argc, char **argv) · 7 unmodified lines | |||
| 718 | dd.btf = btf; | 789 | dd.btf = btf; |
| 719 | dd.func_info = func_info; | 790 | dd.func_info = func_info; |
| 720 | dd.finfo_rec_size = finfo_rec_size; | 791 | dd.finfo_rec_size = finfo_rec_size; |
| 792 | dd.prog_linfo = prog_linfo; | ||
| 721 | 793 | ||
| 722 | if (json_output) | 794 | if (json_output) |
| 723 | dump_xlated_json(&dd, buf, *member_len, opcodes); | 795 | dump_xlated_json(&dd, buf, *member_len, opcodes, |
| 796 | linum); | ||
| 724 | else | 797 | else |
| 725 | dump_xlated_plain(&dd, buf, *member_len, opcodes); | 798 | dump_xlated_plain(&dd, buf, *member_len, opcodes, |
| 799 | linum); | ||
| 726 | kernel_syms_destroy(&dd); | 800 | kernel_syms_destroy(&dd); |
| 727 | } | 801 | } |
| 728 | 802 | ||
| @@ -730,6 +804,9 @@ static int do_dump(int argc, char **argv) · 1 unmodified line | |||
| 730 | free(func_ksyms); | 804 | free(func_ksyms); |
| 731 | free(func_lens); | 805 | free(func_lens); |
| 732 | free(func_info); | 806 | free(func_info); |
| 807 | free(linfo); | ||
| 808 | free(jited_linfo); | ||
| 809 | bpf_prog_linfo__free(prog_linfo); | ||
| 733 | return 0; | 810 | return 0; |
| 734 | 811 | ||
| 735 | err_free: | 812 | err_free: |
| @@ -737,6 +814,9 @@ err_free: · 1 unmodified line | |||
| 737 | free(func_ksyms); | 814 | free(func_ksyms); |
| 738 | free(func_lens); | 815 | free(func_lens); |
| 739 | free(func_info); | 816 | free(func_info); |
| 817 | free(linfo); | ||
| 818 | free(jited_linfo); | ||
| 819 | bpf_prog_linfo__free(prog_linfo); | ||
| 740 | return -1; | 820 | return -1; |
| 741 | } | 821 | } |
| 742 | 822 | ||
| @@ -1138,8 +1218,8 @@ static int do_help(int argc, char **argv) · 395 unmodified lines | |||
| 1138 | 1218 | ||
| 1139 | fprintf(stderr, | 1219 | fprintf(stderr, |
| 1140 | "Usage: %s %s { show | list } [PROG]\n" | 1220 | "Usage: %s %s { show | list } [PROG]\n" |
| 1141 | " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n" | 1221 | " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" |
| 1142 | " %s %s dump jited PROG [{ file FILE | opcodes }]\n" | 1222 | " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n" |
| 1143 | " %s %s pin PROG FILE\n" | 1223 | " %s %s pin PROG FILE\n" |
| 1144 | " %s %s { load | loadall } OBJ PATH \\\n" | 1224 | " %s %s { load | loadall } OBJ PATH \\\n" |
| 1145 | " [type TYPE] [dev NAME] \\\n" | 1225 | " [type TYPE] [dev NAME] \\\n" |
| @@ -41,6 +41,7 @@ · 40 unmodified lines | |||
| 41 | #include <stdlib.h> | 41 | #include <stdlib.h> |
| 42 | #include <string.h> | 42 | #include <string.h> |
| 43 | #include <sys/types.h> | 43 | #include <sys/types.h> |
| 44 | #include <libbpf.h> | ||
| 44 | 45 | ||
| 45 | #include "disasm.h" | 46 | #include "disasm.h" |
| 46 | #include "json_writer.h" | 47 | #include "json_writer.h" |
| @@ -234,8 +235,9 @@ static const char *print_imm(void *private_data, · 187 unmodified lines | |||
| 234 | } | 235 | } |
| 235 | 236 | ||
| 236 | void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, | 237 | void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, |
| 237 | bool opcodes) | 238 | bool opcodes, bool linum) |
| 238 | { | 239 | { |
| 240 | const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; | ||
| 239 | const struct bpf_insn_cbs cbs = { | 241 | const struct bpf_insn_cbs cbs = { |
| 240 | .cb_print = print_insn_json, | 242 | .cb_print = print_insn_json, |
| 241 | .cb_call = print_call, | 243 | .cb_call = print_call, |
| @@ -246,6 +248,7 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, · 4 unmodified lines | |||
| 246 | struct bpf_insn *insn = buf; | 248 | struct bpf_insn *insn = buf; |
| 247 | struct btf *btf = dd->btf; | 249 | struct btf *btf = dd->btf; |
| 248 | bool double_insn = false; | 250 | bool double_insn = false; |
| 251 | unsigned int nr_skip = 0; | ||
| 249 | char func_sig[1024]; | 252 | char func_sig[1024]; |
| 250 | unsigned int i; | 253 | unsigned int i; |
| 251 | 254 | ||
| @@ -273,6 +276,16 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, · 21 unmodified lines | |||
| 273 | } | 276 | } |
| 274 | } | 277 | } |
| 275 | 278 | ||
| 279 | if (prog_linfo) { | ||
| 280 | const struct bpf_line_info *linfo; | ||
| 281 | |||
| 282 | linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); | ||
| 283 | if (linfo) { | ||
| 284 | btf_dump_linfo_json(btf, linfo, linum); | ||
| 285 | nr_skip++; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 276 | jsonw_name(json_wtr, "disasm"); | 289 | jsonw_name(json_wtr, "disasm"); |
| 277 | print_bpf_insn(&cbs, insn + i, true); | 290 | print_bpf_insn(&cbs, insn + i, true); |
| 278 | 291 | ||
| @@ -307,8 +320,9 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, · 28 unmodified lines | |||
| 307 | } | 320 | } |
| 308 | 321 | ||
| 309 | void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, | 322 | void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, |
| 310 | bool opcodes) | 323 | bool opcodes, bool linum) |
| 311 | { | 324 | { |
| 325 | const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo; | ||
| 312 | const struct bpf_insn_cbs cbs = { | 326 | const struct bpf_insn_cbs cbs = { |
| 313 | .cb_print = print_insn, | 327 | .cb_print = print_insn, |
| 314 | .cb_call = print_call, | 328 | .cb_call = print_call, |
| @@ -318,6 +332,7 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, · 3 unmodified lines | |||
| 318 | struct bpf_func_info *record; | 332 | struct bpf_func_info *record; |
| 319 | struct bpf_insn *insn = buf; | 333 | struct bpf_insn *insn = buf; |
| 320 | struct btf *btf = dd->btf; | 334 | struct btf *btf = dd->btf; |
| 335 | unsigned int nr_skip = 0; | ||
| 321 | bool double_insn = false; | 336 | bool double_insn = false; |
| 322 | char func_sig[1024]; | 337 | char func_sig[1024]; |
| 323 | unsigned int i; | 338 | unsigned int i; |
| @@ -340,6 +355,17 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, · 16 unmodified lines | |||
| 340 | } | 355 | } |
| 341 | } | 356 | } |
| 342 | 357 | ||
| 358 | if (prog_linfo) { | ||
| 359 | const struct bpf_line_info *linfo; | ||
| 360 | |||
| 361 | linfo = bpf_prog_linfo__lfind(prog_linfo, i, nr_skip); | ||
| 362 | if (linfo) { | ||
| 363 | btf_dump_linfo_plain(btf, linfo, "; ", | ||
| 364 | linum); | ||
| 365 | nr_skip++; | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 343 | double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); | 369 | double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); |
| 344 | 370 | ||
| 345 | printf("% 4d: ", i); | 371 | printf("% 4d: ", i); |
| @@ -40,6 +40,8 @@ · 39 unmodified lines | |||
| 40 | 40 | ||
| 41 | #define SYM_MAX_NAME 256 | 41 | #define SYM_MAX_NAME 256 |
| 42 | 42 | ||
| 43 | struct bpf_prog_linfo; | ||
| 44 | |||
| 43 | struct kernel_sym { | 45 | struct kernel_sym { |
| 44 | unsigned long address; | 46 | unsigned long address; |
| 45 | char name[SYM_MAX_NAME]; | 47 | char name[SYM_MAX_NAME]; |
| @@ -54,6 +56,7 @@ struct dump_data { · 8 unmodified lines | |||
| 54 | struct btf *btf; | 56 | struct btf *btf; |
| 55 | void *func_info; | 57 | void *func_info; |
| 56 | __u32 finfo_rec_size; | 58 | __u32 finfo_rec_size; |
| 59 | const struct bpf_prog_linfo *prog_linfo; | ||
| 57 | char scratch_buff[SYM_MAX_NAME + 8]; | 60 | char scratch_buff[SYM_MAX_NAME + 8]; |
| 58 | }; | 61 | }; |
| 59 | 62 | ||
| @@ -61,9 +64,9 @@ void kernel_syms_load(struct dump_data *dd); · 1 unmodified line | |||
| 61 | void kernel_syms_destroy(struct dump_data *dd); | 64 | void kernel_syms_destroy(struct dump_data *dd); |
| 62 | struct kernel_sym *kernel_syms_search(struct dump_data *dd, unsigned long key); | 65 | struct kernel_sym *kernel_syms_search(struct dump_data *dd, unsigned long key); |
| 63 | void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, | 66 | void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, |
| 64 | bool opcodes); | 67 | bool opcodes, bool linum); |
| 65 | void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, | 68 | void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, |
| 66 | bool opcodes); | 69 | bool opcodes, bool linum); |
| 67 | void dump_xlated_for_graph(struct dump_data *dd, void *buf, void *buf_end, | 70 | void dump_xlated_for_graph(struct dump_data *dd, void *buf, void *buf_end, |
| 68 | unsigned int start_index); | 71 | unsigned int start_index); |
| 69 | 72 | ||
| @@ -356,6 +356,9 @@ union bpf_attr { · 355 unmodified lines | |||
| 356 | __u32 func_info_rec_size; /* userspace bpf_func_info size */ | 356 | __u32 func_info_rec_size; /* userspace bpf_func_info size */ |
| 357 | __aligned_u64 func_info; /* func info */ | 357 | __aligned_u64 func_info; /* func info */ |
| 358 | __u32 func_info_cnt; /* number of bpf_func_info records */ | 358 | __u32 func_info_cnt; /* number of bpf_func_info records */ |
| 359 | __u32 line_info_rec_size; /* userspace bpf_line_info size */ | ||
| 360 | __aligned_u64 line_info; /* line info */ | ||
| 361 | __u32 line_info_cnt; /* number of bpf_line_info records */ | ||
| 359 | }; | 362 | }; |
| 360 | 363 | ||
| 361 | struct { /* anonymous struct used by BPF_OBJ_* commands */ | 364 | struct { /* anonymous struct used by BPF_OBJ_* commands */ |
| @@ -2679,6 +2682,12 @@ struct bpf_prog_info { · 2317 unmodified lines | |||
| 2679 | __u32 func_info_rec_size; | 2682 | __u32 func_info_rec_size; |
| 2680 | __aligned_u64 func_info; | 2683 | __aligned_u64 func_info; |
| 2681 | __u32 func_info_cnt; | 2684 | __u32 func_info_cnt; |
| 2685 | __u32 line_info_cnt; | ||
| 2686 | __aligned_u64 line_info; | ||
| 2687 | __aligned_u64 jited_line_info; | ||
| 2688 | __u32 jited_line_info_cnt; | ||
| 2689 | __u32 line_info_rec_size; | ||
| 2690 | __u32 jited_line_info_rec_size; | ||
| 2682 | } __attribute__((aligned(8))); | 2691 | } __attribute__((aligned(8))); |
| 2683 | 2692 | ||
| 2684 | struct bpf_map_info { | 2693 | struct bpf_map_info { |
| @@ -2995,4 +3004,14 @@ struct bpf_func_info { · 310 unmodified lines | |||
| 2995 | __u32 type_id; | 3004 | __u32 type_id; |
| 2996 | }; | 3005 | }; |
| 2997 | 3006 | ||
| 3007 | #define BPF_LINE_INFO_LINE_NUM(line_col) ((line_col) >> 10) | ||
| 3008 | #define BPF_LINE_INFO_LINE_COL(line_col) ((line_col) & 0x3ff) | ||
| 3009 | |||
| 3010 | struct bpf_line_info { | ||
| 3011 | __u32 insn_off; | ||
| 3012 | __u32 file_name_off; | ||
| 3013 | __u32 line_off; | ||
| 3014 | __u32 line_col; | ||
| 3015 | }; | ||
| 3016 | |||
| 2998 | #endif /* _UAPI__LINUX_BPF_H__ */ | 3017 | #endif /* _UAPI__LINUX_BPF_H__ */ |
| @@ -1 +1 @@ | |||
| 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 |
| @@ -173,11 +173,36 @@ int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name, · 172 unmodified lines | |||
| 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,53 +226,58 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, · 17 unmodified lines | |||
| 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 | ||
| 207 | fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); | 235 | fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); |
| 208 | if (fd >= 0 || !log_buf || !log_buf_sz) | 236 | if (fd >= 0) |
| 209 | return fd; | 237 | return fd; |
| 210 | 238 | ||
| 211 | /* After bpf_prog_load, the kernel may modify certain attributes | 239 | /* After bpf_prog_load, the kernel may modify certain attributes |
| 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 || !log_buf || !log_buf_sz) | 274 | if (fd >= 0) |
| 248 | goto done; | 275 | goto done; |
| 249 | } | 276 | } |
| 250 | 277 | ||
| 278 | if (!log_buf || !log_buf_sz) | ||
| 279 | goto done; | ||
| 280 | |||
| 251 | /* Try again with log */ | 281 | /* Try again with log */ |
| 252 | attr.log_buf = ptr_to_u64(log_buf); | 282 | attr.log_buf = ptr_to_u64(log_buf); |
| 253 | attr.log_size = log_buf_sz; | 283 | attr.log_size = log_buf_sz; |
| @@ -256,6 +286,7 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, · 2 unmodified lines | |||
| 256 | fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); | 286 | fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); |
| 257 | done: | 287 | done: |
| 258 | free(finfo); | 288 | free(finfo); |
| 289 | free(linfo); | ||
| 259 | return fd; | 290 | return fd; |
| 260 | } | 291 | } |
| 261 | 292 | ||
| @@ -82,6 +82,9 @@ struct bpf_load_program_attr { · 81 unmodified lines | |||
| 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 */ |
| @@ -0,0 +1,253 @@ | |||
| 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 | } | ||
| @@ -37,10 +37,27 @@ struct btf { · 36 unmodified lines | |||
| 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; | 54 | }; |
| 55 | |||
| 56 | struct btf_ext_info_sec { | ||
| 57 | __u32 sec_name_off; | ||
| 58 | __u32 num_info; | ||
| 59 | /* Followed by num_info * record_size number of bytes */ | ||
| 60 | __u8 data[0]; | ||
| 44 | }; | 61 | }; |
| 45 | 62 | ||
| 46 | /* The minimum bpf_func_info checked by the loader */ | 63 | /* The minimum bpf_func_info checked by the loader */ |
| @@ -49,6 +66,14 @@ struct bpf_func_info_min { · 2 unmodified lines | |||
| 49 | __u32 type_id; | 66 | __u32 type_id; |
| 50 | }; | 67 | }; |
| 51 | 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 | |||
| 52 | static inline __u64 ptr_to_u64(const void *ptr) | 77 | static inline __u64 ptr_to_u64(const void *ptr) |
| 53 | { | 78 | { |
| 54 | return (__u64) (unsigned long) ptr; | 79 | return (__u64) (unsigned long) ptr; |
| @@ -479,71 +504,147 @@ exit_free: · 424 unmodified lines | |||
| 479 | return err; | 504 | return err; |
| 480 | } | 505 | } |
| 481 | 506 | ||
| 482 | static int btf_ext_validate_func_info(const void *finfo, __u32 size, | 507 | struct btf_ext_sec_copy_param { |
| 483 | btf_print_fn_t err_log) | 508 | __u32 off; |
| 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) | ||
| 484 | { | 519 | { |
| 485 | int sec_hdrlen = sizeof(struct btf_sec_func_info); | 520 | const struct btf_ext_header *hdr = (struct btf_ext_header *)data; |
| 486 | __u32 size_left, num_records, record_size; | 521 | const struct btf_ext_info_sec *sinfo; |
| 487 | const struct btf_sec_func_info *sinfo; | 522 | struct btf_ext_info *ext_info; |
| 488 | __u64 total_record_size; | 523 | __u32 info_left, record_size; |
| 489 | 524 | /* The start of the info sec (including the __u32 record_size). */ | |
| 490 | /* At least a func_info record size */ | 525 | const void *info; |
| 491 | if (size < sizeof(__u32)) { | 526 | |
| 492 | elog("BTF.ext func_info record size not found"); | 527 | /* data and data_size do not include btf_ext_header from now on */ |
| 528 | data = data + hdr->hdr_len; | ||
| 529 | data_size -= hdr->hdr_len; | ||
| 530 | |||
| 531 | if (ext_sec->off & 0x03) { | ||
| 532 | elog(".BTF.ext %s section is not aligned to 4 bytes\n", | ||
| 533 | ext_sec->desc); | ||
| 493 | return -EINVAL; | 534 | return -EINVAL; |
| 494 | } | 535 | } |
| 495 | 536 | ||
| 496 | /* The record size needs to meet below minimum standard */ | 537 | if (data_size < ext_sec->off || |
| 497 | record_size = *(__u32 *)finfo; | 538 | ext_sec->len > data_size - ext_sec->off) { |
| 498 | if (record_size < sizeof(struct bpf_func_info_min) || | 539 | elog("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n", |
| 499 | record_size % sizeof(__u32)) { | 540 | ext_sec->desc, ext_sec->off, ext_sec->len); |
| 500 | elog("BTF.ext func_info invalid record size"); | ||
| 501 | return -EINVAL; | 541 | return -EINVAL; |
| 502 | } | 542 | } |
| 503 | 543 | ||
| 504 | sinfo = finfo + sizeof(__u32); | 544 | info = data + ext_sec->off; |
| 505 | size_left = size - sizeof(__u32); | 545 | info_left = ext_sec->len; |
| 506 | 546 | ||
| 507 | /* If no func_info records, return failure now so .BTF.ext | 547 | /* At least a record size */ |
| 508 | * won't be used. | 548 | if (info_left < sizeof(__u32)) { |
| 509 | */ | 549 | elog(".BTF.ext %s record size not found\n", ext_sec->desc); |
| 510 | if (!size_left) { | 550 | return -EINVAL; |
| 511 | elog("BTF.ext no func info records"); | 551 | } |
| 552 | |||
| 553 | /* The record size needs to meet the minimum standard */ | ||
| 554 | record_size = *(__u32 *)info; | ||
| 555 | if (record_size < ext_sec->min_rec_size || | ||
| 556 | record_size & 0x03) { | ||
| 557 | elog("%s section in .BTF.ext has invalid record size %u\n", | ||
| 558 | ext_sec->desc, record_size); | ||
| 512 | return -EINVAL; | 559 | return -EINVAL; |
| 513 | } | 560 | } |
| 514 | 561 | ||
| 515 | while (size_left) { | 562 | sinfo = info + sizeof(__u32); |
| 516 | if (size_left < sec_hdrlen) { | 563 | info_left -= sizeof(__u32); |
| 517 | elog("BTF.ext func_info header not found"); | 564 | |
| 565 | /* If no records, return failure now so .BTF.ext won't be used. */ | ||
| 566 | if (!info_left) { | ||
| 567 | elog("%s section in .BTF.ext has no records", ext_sec->desc); | ||
| 568 | return -EINVAL; | ||
| 569 | } | ||
| 570 | |||
| 571 | while (info_left) { | ||
| 572 | unsigned int sec_hdrlen = sizeof(struct btf_ext_info_sec); | ||
| 573 | __u64 total_record_size; | ||
| 574 | __u32 num_records; | ||
| 575 | |||
| 576 | if (info_left < sec_hdrlen) { | ||
| 577 | elog("%s section header is not found in .BTF.ext\n", | ||
| 578 | ext_sec->desc); | ||
| 518 | return -EINVAL; | 579 | return -EINVAL; |
| 519 | } | 580 | } |
| 520 | 581 | ||
| 521 | num_records = sinfo->num_func_info; | 582 | num_records = sinfo->num_info; |
| 522 | if (num_records == 0) { | 583 | if (num_records == 0) { |
| 523 | elog("incorrect BTF.ext num_func_info"); | 584 | elog("%s section has incorrect num_records in .BTF.ext\n", |
| 585 | ext_sec->desc); | ||
| 524 | return -EINVAL; | 586 | return -EINVAL; |
| 525 | } | 587 | } |
| 526 | 588 | ||
| 527 | total_record_size = sec_hdrlen + | 589 | total_record_size = sec_hdrlen + |
| 528 | (__u64)num_records * record_size; | 590 | (__u64)num_records * record_size; |
| 529 | if (size_left < total_record_size) { | 591 | if (info_left < total_record_size) { |
| 530 | elog("incorrect BTF.ext num_func_info"); | 592 | elog("%s section has incorrect num_records in .BTF.ext\n", |
| 593 | ext_sec->desc); | ||
| 531 | return -EINVAL; | 594 | return -EINVAL; |
| 532 | } | 595 | } |
| 533 | 596 | ||
| 534 | size_left -= total_record_size; | 597 | info_left -= total_record_size; |
| 535 | sinfo = (void *)sinfo + total_record_size; | 598 | sinfo = (void *)sinfo + total_record_size; |
| 536 | } | 599 | } |
| 537 | 600 | ||
| 601 | ext_info = ext_sec->ext_info; | ||
| 602 | ext_info->len = ext_sec->len - sizeof(__u32); | ||
| 603 | ext_info->rec_size = record_size; | ||
| 604 | ext_info->info = malloc(ext_info->len); | ||
| 605 | if (!ext_info->info) | ||
| 606 | return -ENOMEM; | ||
| 607 | memcpy(ext_info->info, info + sizeof(__u32), ext_info->len); | ||
| 608 | |||
| 538 | return 0; | 609 | return 0; |
| 539 | } | 610 | } |
| 540 | 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 | |||
| 541 | static int btf_ext_parse_hdr(__u8 *data, __u32 data_size, | 644 | static int btf_ext_parse_hdr(__u8 *data, __u32 data_size, |
| 542 | btf_print_fn_t err_log) | 645 | btf_print_fn_t err_log) |
| 543 | { | 646 | { |
| 544 | const struct btf_ext_header *hdr = (struct btf_ext_header *)data; | 647 | const struct btf_ext_header *hdr = (struct btf_ext_header *)data; |
| 545 | __u32 meta_left, last_func_info_pos; | ||
| 546 | void *finfo; | ||
| 547 | 648 | ||
| 548 | if (data_size < offsetof(struct btf_ext_header, func_info_off) || | 649 | if (data_size < offsetof(struct btf_ext_header, func_info_off) || |
| 549 | data_size < hdr->hdr_len) { | 650 | data_size < hdr->hdr_len) { |
| @@ -566,34 +667,12 @@ static int btf_ext_parse_hdr(__u8 *data, __u32 data_size, · 16 unmodified lines | |||
| 566 | return -ENOTSUP; | 667 | return -ENOTSUP; |
| 567 | } | 668 | } |
| 568 | 669 | ||
| 569 | meta_left = data_size - hdr->hdr_len; | 670 | if (data_size == hdr->hdr_len) { |
| 570 | if (!meta_left) { | ||
| 571 | elog("BTF.ext has no data\n"); | 671 | elog("BTF.ext has no data\n"); |
| 572 | return -EINVAL; | 672 | return -EINVAL; |
| 573 | } | 673 | } |
| 574 | 674 | ||
| 575 | if (meta_left < hdr->func_info_off) { | 675 | return 0; |
| 576 | elog("Invalid BTF.ext func_info section offset:%u\n", | ||
| 577 | hdr->func_info_off); | ||
| 578 | return -EINVAL; | ||
| 579 | } | ||
| 580 | |||
| 581 | if (hdr->func_info_off & 0x03) { | ||
| 582 | elog("BTF.ext func_info section is not aligned to 4 bytes\n"); | ||
| 583 | return -EINVAL; | ||
| 584 | } | ||
| 585 | |||
| 586 | last_func_info_pos = hdr->hdr_len + hdr->func_info_off + | ||
| 587 | hdr->func_info_len; | ||
| 588 | if (last_func_info_pos > data_size) { | ||
| 589 | elog("Invalid BTF.ext func_info section size:%u\n", | ||
| 590 | hdr->func_info_len); | ||
| 591 | return -EINVAL; | ||
| 592 | } | ||
| 593 | |||
| 594 | finfo = data + hdr->hdr_len + hdr->func_info_off; | ||
| 595 | return btf_ext_validate_func_info(finfo, hdr->func_info_len, | ||
| 596 | err_log); | ||
| 597 | } | 676 | } |
| 598 | 677 | ||
| 599 | void btf_ext__free(struct btf_ext *btf_ext) | 678 | void btf_ext__free(struct btf_ext *btf_ext) |
| @@ -601,16 +680,14 @@ void btf_ext__free(struct btf_ext *btf_ext) · 1 unmodified line | |||
| 601 | if (!btf_ext) | 680 | if (!btf_ext) |
| 602 | return; | 681 | return; |
| 603 | 682 | ||
| 604 | free(btf_ext->func_info); | 683 | free(btf_ext->func_info.info); |
| 684 | free(btf_ext->line_info.info); | ||
| 605 | free(btf_ext); | 685 | free(btf_ext); |
| 606 | } | 686 | } |
| 607 | 687 | ||
| 608 | struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log) | 688 | struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log) |
| 609 | { | 689 | { |
| 610 | const struct btf_ext_header *hdr; | ||
| 611 | struct btf_ext *btf_ext; | 690 | struct btf_ext *btf_ext; |
| 612 | void *org_fdata, *fdata; | ||
| 613 | __u32 hdrlen, size_u32; | ||
| 614 | int err; | 691 | int err; |
| 615 | 692 | ||
| 616 | err = btf_ext_parse_hdr(data, size, err_log); | 693 | err = btf_ext_parse_hdr(data, size, err_log); |
| @@ -621,42 +698,38 @@ struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log) · 4 unmodified lines | |||
| 621 | if (!btf_ext) | 698 | if (!btf_ext) |
| 622 | return ERR_PTR(-ENOMEM); | 699 | return ERR_PTR(-ENOMEM); |
| 623 | 700 | ||
| 624 | hdr = (const struct btf_ext_header *)data; | 701 | err = btf_ext_copy_func_info(btf_ext, data, size, err_log); |
| 625 | hdrlen = hdr->hdr_len; | 702 | if (err) { |
| 626 | size_u32 = sizeof(__u32); | 703 | btf_ext__free(btf_ext); |
| 627 | fdata = malloc(hdr->func_info_len - size_u32); | 704 | return ERR_PTR(err); |
| 628 | if (!fdata) { | ||
| 629 | free(btf_ext); | ||
| 630 | return ERR_PTR(-ENOMEM); | ||
| 631 | } | 705 | } |
| 632 | 706 | ||
| 633 | /* remember record size and copy rest of func_info data */ | 707 | err = btf_ext_copy_line_info(btf_ext, data, size, err_log); |
| 634 | org_fdata = data + hdrlen + hdr->func_info_off; | 708 | if (err) { |
| 635 | btf_ext->func_info_rec_size = *(__u32 *)org_fdata; | 709 | btf_ext__free(btf_ext); |
| 636 | memcpy(fdata, org_fdata + size_u32, hdr->func_info_len - size_u32); | 710 | return ERR_PTR(err); |
| 637 | btf_ext->func_info = fdata; | 711 | } |
| 638 | btf_ext->func_info_len = hdr->func_info_len - size_u32; | ||
| 639 | 712 | ||
| 640 | return btf_ext; | 713 | return btf_ext; |
| 641 | } | 714 | } |
| 642 | 715 | ||
| 643 | int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext, | 716 | static int btf_ext_reloc_info(const struct btf *btf, |
| 644 | const char *sec_name, void **func_info, | 717 | const struct btf_ext_info *ext_info, |
| 645 | __u32 *func_info_rec_size, __u32 *func_info_len) | 718 | const char *sec_name, __u32 insns_cnt, |
| 719 | void **info, __u32 *cnt) | ||
| 646 | { | 720 | { |
| 647 | __u32 sec_hdrlen = sizeof(struct btf_sec_func_info); | 721 | __u32 sec_hdrlen = sizeof(struct btf_ext_info_sec); |
| 648 | __u32 i, record_size, records_len; | 722 | __u32 i, record_size, existing_len, records_len; |
| 649 | struct btf_sec_func_info *sinfo; | 723 | struct btf_ext_info_sec *sinfo; |
| 650 | const char *info_sec_name; | 724 | const char *info_sec_name; |
| 651 | __s64 remain_len; | 725 | __u64 remain_len; |
| 652 | void *data; | 726 | void *data; |
| 653 | 727 | ||
| 654 | record_size = btf_ext->func_info_rec_size; | 728 | record_size = ext_info->rec_size; |
| 655 | sinfo = btf_ext->func_info; | 729 | sinfo = ext_info->info; |
| 656 | remain_len = btf_ext->func_info_len; | 730 | remain_len = ext_info->len; |
| 657 | |||
| 658 | while (remain_len > 0) { | 731 | while (remain_len > 0) { |
| 659 | records_len = sinfo->num_func_info * record_size; | 732 | records_len = sinfo->num_info * record_size; |
| 660 | 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); |
| 661 | if (strcmp(info_sec_name, sec_name)) { | 734 | if (strcmp(info_sec_name, sec_name)) { |
| 662 | remain_len -= sec_hdrlen + records_len; | 735 | remain_len -= sec_hdrlen + records_len; |
| @@ -664,79 +737,52 @@ int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext, · 1 unmodified line | |||
| 664 | continue; | 737 | continue; |
| 665 | } | 738 | } |
| 666 | 739 | ||
| 667 | data = malloc(records_len); | 740 | existing_len = (*cnt) * record_size; |
| 741 | data = realloc(*info, existing_len + records_len); | ||
| 668 | if (!data) | 742 | if (!data) |
| 669 | return -ENOMEM; | 743 | return -ENOMEM; |
| 670 | 744 | ||
| 671 | memcpy(data, sinfo->data, records_len); | 745 | memcpy(data + existing_len, sinfo->data, records_len); |
| 672 | 746 | /* adjust insn_off only, the rest data will be passed | |
| 673 | /* adjust the insn_off, the data in .BTF.ext is | 747 | * to the kernel. |
| 674 | * the actual byte offset, and the kernel expects | ||
| 675 | * the offset in term of bpf_insn. | ||
| 676 | * | ||
| 677 | * adjust the insn offset only, the rest data will | ||
| 678 | * be passed to kernel. | ||
| 679 | */ | 748 | */ |
| 680 | for (i = 0; i < sinfo->num_func_info; i++) { | 749 | for (i = 0; i < sinfo->num_info; i++) { |
| 681 | struct bpf_func_info_min *record; | 750 | __u32 *insn_off; |
| 682 | 751 | ||
| 683 | record = data + i * record_size; | 752 | insn_off = data + existing_len + (i * record_size); |
| 684 | record->insn_off /= sizeof(struct bpf_insn); | 753 | *insn_off = *insn_off / sizeof(struct bpf_insn) + |
| 754 | insns_cnt; | ||
| 685 | } | 755 | } |
| 686 | 756 | *info = data; | |
| 687 | *func_info = data; | 757 | *cnt += sinfo->num_info; |
| 688 | *func_info_len = records_len; | ||
| 689 | *func_info_rec_size = record_size; | ||
| 690 | return 0; | 758 | return 0; |
| 691 | } | 759 | } |
| 692 | 760 | ||
| 693 | return -EINVAL; | 761 | return -ENOENT; |
| 694 | } | 762 | } |
| 695 | 763 | ||
| 696 | int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext, | 764 | int btf_ext__reloc_func_info(const struct btf *btf, const struct btf_ext *btf_ext, |
| 697 | const char *sec_name, __u32 insns_cnt, | 765 | const char *sec_name, __u32 insns_cnt, |
| 698 | void **func_info, __u32 *func_info_len) | 766 | void **func_info, __u32 *cnt) |
| 699 | { | 767 | { |
| 700 | __u32 sec_hdrlen = sizeof(struct btf_sec_func_info); | 768 | return btf_ext_reloc_info(btf, &btf_ext->func_info, sec_name, |
| 701 | __u32 i, record_size, existing_flen, records_len; | 769 | insns_cnt, func_info, cnt); |
| 702 | struct btf_sec_func_info *sinfo; | 770 | } |
| 703 | const char *info_sec_name; | ||
| 704 | __u64 remain_len; | ||
| 705 | void *data; | ||
| 706 | |||
| 707 | record_size = btf_ext->func_info_rec_size; | ||
| 708 | sinfo = btf_ext->func_info; | ||
| 709 | remain_len = btf_ext->func_info_len; | ||
| 710 | while (remain_len > 0) { | ||
| 711 | records_len = sinfo->num_func_info * record_size; | ||
| 712 | info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off); | ||
| 713 | if (strcmp(info_sec_name, sec_name)) { | ||
| 714 | remain_len -= sec_hdrlen + records_len; | ||
| 715 | sinfo = (void *)sinfo + sec_hdrlen + records_len; | ||
| 716 | continue; | ||
| 717 | } | ||
| 718 | |||
| 719 | existing_flen = *func_info_len; | ||
| 720 | data = realloc(*func_info, existing_flen + records_len); | ||
| 721 | if (!data) | ||
| 722 | return -ENOMEM; | ||
| 723 | 771 | ||
| 724 | memcpy(data + existing_flen, sinfo->data, records_len); | 772 | int btf_ext__reloc_line_info(const struct btf *btf, const struct btf_ext *btf_ext, |
| 725 | /* adjust insn_off only, the rest data will be passed | 773 | const char *sec_name, __u32 insns_cnt, |
| 726 | * to the kernel. | 774 | void **line_info, __u32 *cnt) |
| 727 | */ | 775 | { |
| 728 | for (i = 0; i < sinfo->num_func_info; i++) { | 776 | return btf_ext_reloc_info(btf, &btf_ext->line_info, sec_name, |
| 729 | struct bpf_func_info_min *record; | 777 | insns_cnt, line_info, cnt); |
| 778 | } | ||
| 730 | 779 | ||
| 731 | record = data + existing_flen + i * record_size; | 780 | __u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext) |
| 732 | record->insn_off = | 781 | { |
| 733 | record->insn_off / sizeof(struct bpf_insn) + | 782 | return btf_ext->func_info.rec_size; |
| 734 | insns_cnt; | 783 | } |
| 735 | } | ||
| 736 | *func_info = data; | ||
| 737 | *func_info_len = existing_flen + records_len; | ||
| 738 | return 0; | ||
| 739 | } | ||
| 740 | 784 | ||
| 741 | return -EINVAL; | 785 | __u32 btf_ext__line_info_rec_size(const struct btf_ext *btf_ext) |
| 786 | { | ||
| 787 | return btf_ext->line_info.rec_size; | ||
| 742 | } | 788 | } |
| @@ -51,13 +51,8 @@ struct btf_ext_header { · 50 unmodified lines | |||
| 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 | }; | 54 | __u32 line_info_off; |
| 55 | 55 | __u32 line_info_len; | |
| 56 | struct btf_sec_func_info { | ||
| 57 | __u32 sec_name_off; | ||
| 58 | __u32 num_func_info; | ||
| 59 | /* Followed by num_func_info number of bpf func_info records */ | ||
| 60 | __u8 data[0]; | ||
| 61 | }; | 56 | }; |
| 62 | 57 | ||
| 63 | typedef int (*btf_print_fn_t)(const char *, ...) | 58 | typedef int (*btf_print_fn_t)(const char *, ...) |
| @@ -77,12 +72,16 @@ LIBBPF_API int btf__get_from_id(__u32 id, struct btf **btf); · 13 unmodified lines | |||
| 77 | 72 | ||
| 78 | 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); |
| 79 | void btf_ext__free(struct btf_ext *btf_ext); | 74 | void btf_ext__free(struct btf_ext *btf_ext); |
| 80 | int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext, | 75 | int btf_ext__reloc_func_info(const struct btf *btf, |
| 81 | const char *sec_name, void **func_info, | 76 | const struct btf_ext *btf_ext, |
| 82 | __u32 *func_info_rec_size, __u32 *func_info_len); | 77 | const char *sec_name, __u32 insns_cnt, |
| 83 | int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext, | 78 | void **func_info, __u32 *func_info_len); |
| 84 | const char *sec_name, __u32 insns_cnt, void **func_info, | 79 | int btf_ext__reloc_line_info(const struct btf *btf, |
| 85 | __u32 *func_info_len); | 80 | const struct btf_ext *btf_ext, |
| 81 | const char *sec_name, __u32 insns_cnt, | ||
| 82 | void **line_info, __u32 *cnt); | ||
| 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); | ||
| 86 | 85 | ||
| 87 | #ifdef __cplusplus | 86 | #ifdef __cplusplus |
| 88 | } /* extern "C" */ | 87 | } /* extern "C" */ |
| @@ -167,9 +167,13 @@ struct bpf_program { · 166 unmodified lines | |||
| 167 | int btf_fd; | 167 | int btf_fd; |
| 168 | void *func_info; | 168 | void *func_info; |
| 169 | __u32 func_info_rec_size; | 169 | __u32 func_info_rec_size; |
| 170 | __u32 func_info_len; | 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 { |
| @@ -779,6 +783,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) · 603 unmodified lines | |||
| 779 | { | 783 | { |
| 780 | Elf *elf = obj->efile.elf; | 784 | Elf *elf = obj->efile.elf; |
| 781 | GElf_Ehdr *ep = &obj->efile.ehdr; | 785 | GElf_Ehdr *ep = &obj->efile.ehdr; |
| 786 | Elf_Data *btf_ext_data = NULL; | ||
| 782 | Elf_Scn *scn = NULL; | 787 | Elf_Scn *scn = NULL; |
| 783 | int idx = 0, err = 0; | 788 | int idx = 0, err = 0; |
| 784 | 789 | ||
| @@ -841,14 +846,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) · 56 unmodified lines | |||
| 841 | obj->btf = NULL; | 846 | obj->btf = NULL; |
| 842 | } | 847 | } |
| 843 | } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) { | 848 | } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) { |
| 844 | obj->btf_ext = btf_ext__new(data->d_buf, data->d_size, | 849 | btf_ext_data = data; |
| 845 | __pr_debug); | ||
| 846 | if (IS_ERR(obj->btf_ext)) { | ||
| 847 | pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n", | ||
| 848 | BTF_EXT_ELF_SEC, | ||
| 849 | PTR_ERR(obj->btf_ext)); | ||
| 850 | obj->btf_ext = NULL; | ||
| 851 | } | ||
| 852 | } else if (sh.sh_type == SHT_SYMTAB) { | 850 | } else if (sh.sh_type == SHT_SYMTAB) { |
| 853 | if (obj->efile.symbols) { | 851 | if (obj->efile.symbols) { |
| 854 | pr_warning("bpf: multiple SYMTAB in %s\n", | 852 | pr_warning("bpf: multiple SYMTAB in %s\n", |
| @@ -910,6 +908,22 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) · 55 unmodified lines | |||
| 910 | pr_warning("Corrupted ELF file: index of strtab invalid\n"); | 908 | pr_warning("Corrupted ELF file: index of strtab invalid\n"); |
| 911 | return LIBBPF_ERRNO__FORMAT; | 909 | return LIBBPF_ERRNO__FORMAT; |
| 912 | } | 910 | } |
| 911 | if (btf_ext_data) { | ||
| 912 | if (!obj->btf) { | ||
| 913 | pr_debug("Ignore ELF section %s because its depending ELF section %s is not found.\n", | ||
| 914 | BTF_EXT_ELF_SEC, BTF_ELF_SEC); | ||
| 915 | } else { | ||
| 916 | obj->btf_ext = btf_ext__new(btf_ext_data->d_buf, | ||
| 917 | btf_ext_data->d_size, | ||
| 918 | __pr_debug); | ||
| 919 | if (IS_ERR(obj->btf_ext)) { | ||
| 920 | pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n", | ||
| 921 | BTF_EXT_ELF_SEC, | ||
| 922 | PTR_ERR(obj->btf_ext)); | ||
| 923 | obj->btf_ext = NULL; | ||
| 924 | } | ||
| 925 | } | ||
| 926 | } | ||
| 913 | if (obj->efile.maps_shndx >= 0) { | 927 | if (obj->efile.maps_shndx >= 0) { |
| 914 | err = bpf_object__init_maps(obj, flags); | 928 | err = bpf_object__init_maps(obj, flags); |
| 915 | if (err) | 929 | if (err) |
| @@ -1275,6 +1289,82 @@ bpf_object__create_maps(struct bpf_object *obj) · 359 unmodified lines | |||
| 1275 | return 0; | 1289 | return 0; |
| 1276 | } | 1290 | } |
| 1277 | 1291 | ||
| 1292 | static int | ||
| 1293 | check_btf_ext_reloc_err(struct bpf_program *prog, int err, | ||
| 1294 | void *btf_prog_info, const char *info_name) | ||
| 1295 | { | ||
| 1296 | if (err != -ENOENT) { | ||
| 1297 | pr_warning("Error in loading %s for sec %s.\n", | ||
| 1298 | info_name, prog->section_name); | ||
| 1299 | return err; | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | /* err == -ENOENT (i.e. prog->section_name not found in btf_ext) */ | ||
| 1303 | |||
| 1304 | if (btf_prog_info) { | ||
| 1305 | /* | ||
| 1306 | * Some info has already been found but has problem | ||
| 1307 | * in the last btf_ext reloc. Must have to error | ||
| 1308 | * out. | ||
| 1309 | */ | ||
| 1310 | pr_warning("Error in relocating %s for sec %s.\n", | ||
| 1311 | info_name, prog->section_name); | ||
| 1312 | return err; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | /* | ||
| 1316 | * Have problem loading the very first info. Ignore | ||
| 1317 | * the rest. | ||
| 1318 | */ | ||
| 1319 | pr_warning("Cannot find %s for main program sec %s. Ignore all %s.\n", | ||
| 1320 | info_name, prog->section_name, info_name); | ||
| 1321 | return 0; | ||
| 1322 | } | ||
| 1323 | |||
| 1324 | static int | ||
| 1325 | bpf_program_reloc_btf_ext(struct bpf_program *prog, struct bpf_object *obj, | ||
| 1326 | const char *section_name, __u32 insn_offset) | ||
| 1327 | { | ||
| 1328 | int err; | ||
| 1329 | |||
| 1330 | if (!insn_offset || prog->func_info) { | ||
| 1331 | /* | ||
| 1332 | * !insn_offset => main program | ||
| 1333 | * | ||
| 1334 | * For sub prog, the main program's func_info has to | ||
| 1335 | * be loaded first (i.e. prog->func_info != NULL) | ||
| 1336 | */ | ||
| 1337 | err = btf_ext__reloc_func_info(obj->btf, obj->btf_ext, | ||
| 1338 | section_name, insn_offset, | ||
| 1339 | &prog->func_info, | ||
| 1340 | &prog->func_info_cnt); | ||
| 1341 | if (err) | ||
| 1342 | return check_btf_ext_reloc_err(prog, err, | ||
| 1343 | prog->func_info, | ||
| 1344 | "bpf_func_info"); | ||
| 1345 | |||
| 1346 | prog->func_info_rec_size = btf_ext__func_info_rec_size(obj->btf_ext); | ||
| 1347 | } | ||
| 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 | |||
| 1362 | if (!insn_offset) | ||
| 1363 | prog->btf_fd = btf__fd(obj->btf); | ||
| 1364 | |||
| 1365 | return 0; | ||
| 1366 | } | ||
| 1367 | |||
| 1278 | static int | 1368 | static int |
| 1279 | bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, | 1369 | bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, |
| 1280 | struct reloc_desc *relo) | 1370 | struct reloc_desc *relo) |
| @@ -1306,17 +1396,12 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, · 25 unmodified lines | |||
| 1306 | return -ENOMEM; | 1396 | return -ENOMEM; |
| 1307 | } | 1397 | } |
| 1308 | 1398 | ||
| 1309 | if (obj->btf && obj->btf_ext) { | 1399 | if (obj->btf_ext) { |
| 1310 | err = btf_ext__reloc(obj->btf, obj->btf_ext, | 1400 | err = bpf_program_reloc_btf_ext(prog, obj, |
| 1311 | text->section_name, | 1401 | text->section_name, |
| 1312 | prog->insns_cnt, | 1402 | prog->insns_cnt); |
| 1313 | &prog->func_info, | 1403 | if (err) |
| 1314 | &prog->func_info_len); | ||
| 1315 | if (err) { | ||
| 1316 | pr_warning("error in btf_ext__reloc for sec %s\n", | ||
| 1317 | text->section_name); | ||
| 1318 | return err; | 1404 | return err; |
| 1319 | } | ||
| 1320 | } | 1405 | } |
| 1321 | 1406 | ||
| 1322 | memcpy(new_insn + prog->insns_cnt, text->insns, | 1407 | memcpy(new_insn + prog->insns_cnt, text->insns, |
| @@ -1341,18 +1426,11 @@ bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj) · 18 unmodified lines | |||
| 1341 | if (!prog) | 1426 | if (!prog) |
| 1342 | return 0; | 1427 | return 0; |
| 1343 | 1428 | ||
| 1344 | if (obj->btf && obj->btf_ext) { | 1429 | if (obj->btf_ext) { |
| 1345 | err = btf_ext__reloc_init(obj->btf, obj->btf_ext, | 1430 | err = bpf_program_reloc_btf_ext(prog, obj, |
| 1346 | prog->section_name, | 1431 | prog->section_name, 0); |
| 1347 | &prog->func_info, | 1432 | if (err) |
| 1348 | &prog->func_info_rec_size, | ||
| 1349 | &prog->func_info_len); | ||
| 1350 | if (err) { | ||
| 1351 | pr_warning("err in btf_ext__reloc_init for sec %s\n", | ||
| 1352 | prog->section_name); | ||
| 1353 | return err; | 1433 | return err; |
| 1354 | } | ||
| 1355 | prog->btf_fd = btf__fd(obj->btf); | ||
| 1356 | } | 1434 | } |
| 1357 | 1435 | ||
| 1358 | if (!prog->reloc_desc) | 1436 | if (!prog->reloc_desc) |
| @@ -1444,8 +1522,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) · 85 unmodified lines | |||
| 1444 | 1522 | ||
| 1445 | static int | 1523 | static int |
| 1446 | load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt, | 1524 | load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt, |
| 1447 | char *license, __u32 kern_version, int *pfd, | 1525 | char *license, __u32 kern_version, int *pfd) |
| 1448 | __u32 func_info_cnt) | ||
| 1449 | { | 1526 | { |
| 1450 | struct bpf_load_program_attr load_attr; | 1527 | struct bpf_load_program_attr load_attr; |
| 1451 | char *cp, errmsg[STRERR_BUFSIZE]; | 1528 | char *cp, errmsg[STRERR_BUFSIZE]; |
| @@ -1465,8 +1542,10 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt, · 13 unmodified lines | |||
| 1465 | load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0; | 1542 | load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0; |
| 1466 | load_attr.func_info = prog->func_info; | 1543 | load_attr.func_info = prog->func_info; |
| 1467 | load_attr.func_info_rec_size = prog->func_info_rec_size; | 1544 | load_attr.func_info_rec_size = prog->func_info_rec_size; |
| 1468 | load_attr.func_info_cnt = func_info_cnt; | 1545 | load_attr.func_info_cnt = prog->func_info_cnt; |
| 1469 | 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; | ||
| 1470 | if (!load_attr.insns || !load_attr.insns_cnt) | 1549 | if (!load_attr.insns || !load_attr.insns_cnt) |
| 1471 | return -EINVAL; | 1550 | return -EINVAL; |
| 1472 | 1551 | ||
| @@ -1523,14 +1602,8 @@ int · 50 unmodified lines | |||
| 1523 | bpf_program__load(struct bpf_program *prog, | 1602 | bpf_program__load(struct bpf_program *prog, |
| 1524 | char *license, __u32 kern_version) | 1603 | char *license, __u32 kern_version) |
| 1525 | { | 1604 | { |
| 1526 | __u32 func_info_cnt; | ||
| 1527 | int err = 0, fd, i; | 1605 | int err = 0, fd, i; |
| 1528 | 1606 | ||
| 1529 | if (prog->func_info_len == 0) | ||
| 1530 | func_info_cnt = 0; | ||
| 1531 | else | ||
| 1532 | func_info_cnt = prog->func_info_len / prog->func_info_rec_size; | ||
| 1533 | |||
| 1534 | if (prog->instances.nr < 0 || !prog->instances.fds) { | 1607 | if (prog->instances.nr < 0 || !prog->instances.fds) { |
| 1535 | if (prog->preprocessor) { | 1608 | if (prog->preprocessor) { |
| 1536 | pr_warning("Internal error: can't load program '%s'\n", | 1609 | pr_warning("Internal error: can't load program '%s'\n", |
| @@ -1553,8 +1626,7 @@ bpf_program__load(struct bpf_program *prog, · 16 unmodified lines | |||
| 1553 | prog->section_name, prog->instances.nr); | 1626 | prog->section_name, prog->instances.nr); |
| 1554 | } | 1627 | } |
| 1555 | err = load_program(prog, prog->insns, prog->insns_cnt, | 1628 | err = load_program(prog, prog->insns, prog->insns_cnt, |
| 1556 | license, kern_version, &fd, | 1629 | license, kern_version, &fd); |
| 1557 | func_info_cnt); | ||
| 1558 | if (!err) | 1630 | if (!err) |
| 1559 | prog->instances.fds[0] = fd; | 1631 | prog->instances.fds[0] = fd; |
| 1560 | goto out; | 1632 | goto out; |
| @@ -1584,8 +1656,7 @@ bpf_program__load(struct bpf_program *prog, · 23 unmodified lines | |||
| 1584 | 1656 | ||
| 1585 | err = load_program(prog, result.new_insn_ptr, | 1657 | err = load_program(prog, result.new_insn_ptr, |
| 1586 | result.new_insn_cnt, | 1658 | result.new_insn_cnt, |
| 1587 | license, kern_version, &fd, | 1659 | license, kern_version, &fd); |
| 1588 | func_info_cnt); | ||
| 1589 | 1660 | ||
| 1590 | if (err) { | 1661 | if (err) { |
| 1591 | pr_warning("Loading the %dth instance of program '%s' failed\n", | 1662 | pr_warning("Loading the %dth instance of program '%s' failed\n", |
| @@ -342,6 +342,19 @@ int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, · 341 unmodified lines | |||
| 342 | int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, | 342 | int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle, |
| 343 | libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie); | 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 | #ifdef __cplusplus | 358 | #ifdef __cplusplus |
| 346 | } /* extern "C" */ | 359 | } /* extern "C" */ |
| 347 | #endif | 360 | #endif |
| @@ -99,6 +99,10 @@ LIBBPF_0.0.1 { · 98 unmodified lines | |||
| 99 | bpf_program__unload; | 99 | bpf_program__unload; |
| 100 | bpf_program__unpin; | 100 | bpf_program__unpin; |
| 101 | bpf_program__unpin_instance; | 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 | bpf_raw_tracepoint_open; | 106 | bpf_raw_tracepoint_open; |
| 103 | bpf_set_link_xdp_fd; | 107 | bpf_set_link_xdp_fd; |
| 104 | bpf_task_fd_query; | 108 | bpf_task_fd_query; |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | #include <linux/err.h> | 6 | #include <linux/err.h> |
| 7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| 8 | #include <linux/filter.h> | 8 | #include <linux/filter.h> |
| 9 | #include <linux/unistd.h> | ||
| 9 | #include <bpf/bpf.h> | 10 | #include <bpf/bpf.h> |
| 10 | #include <sys/resource.h> | 11 | #include <sys/resource.h> |
| 11 | #include <libelf.h> | 12 | #include <libelf.h> |
| @@ -107,19 +108,20 @@ static int __base_pr(const char *format, ...) · 95 unmodified lines | |||
| 107 | #define BTF_END_RAW 0xdeadbeef | 108 | #define BTF_END_RAW 0xdeadbeef |
| 108 | #define NAME_TBD 0xdeadb33f | 109 | #define NAME_TBD 0xdeadb33f |
| 109 | 110 | ||
| 110 | #define MAX_NR_RAW_TYPES 1024 | 111 | #define MAX_NR_RAW_U32 1024 |
| 111 | #define BTF_LOG_BUF_SIZE 65535 | 112 | #define BTF_LOG_BUF_SIZE 65535 |
| 112 | 113 | ||
| 113 | static struct args { | 114 | static struct args { |
| 114 | unsigned int raw_test_num; | 115 | unsigned int raw_test_num; |
| 115 | unsigned int file_test_num; | 116 | unsigned int file_test_num; |
| 116 | unsigned int get_info_test_num; | 117 | unsigned int get_info_test_num; |
| 118 | unsigned int info_raw_test_num; | ||
| 117 | bool raw_test; | 119 | bool raw_test; |
| 118 | bool file_test; | 120 | bool file_test; |
| 119 | bool get_info_test; | 121 | bool get_info_test; |
| 120 | bool pprint_test; | 122 | bool pprint_test; |
| 121 | bool always_log; | 123 | bool always_log; |
| 122 | bool func_type_test; | 124 | bool info_raw_test; |
| 123 | } args; | 125 | } args; |
| 124 | 126 | ||
| 125 | static char btf_log_buf[BTF_LOG_BUF_SIZE]; | 127 | static char btf_log_buf[BTF_LOG_BUF_SIZE]; |
| @@ -135,7 +137,7 @@ struct btf_raw_test { · 9 unmodified lines | |||
| 135 | const char *str_sec; | 137 | const char *str_sec; |
| 136 | const char *map_name; | 138 | const char *map_name; |
| 137 | const char *err_str; | 139 | const char *err_str; |
| 138 | __u32 raw_types[MAX_NR_RAW_TYPES]; | 140 | __u32 raw_types[MAX_NR_RAW_U32]; |
| 139 | __u32 str_sec_size; | 141 | __u32 str_sec_size; |
| 140 | enum bpf_map_type map_type; | 142 | enum bpf_map_type map_type; |
| 141 | __u32 key_size; | 143 | __u32 key_size; |
| @@ -154,6 +156,9 @@ struct btf_raw_test { · 12 unmodified lines | |||
| 154 | int str_len_delta; | 156 | int str_len_delta; |
| 155 | }; | 157 | }; |
| 156 | 158 | ||
| 159 | #define BTF_STR_SEC(str) \ | ||
| 160 | .str_sec = str, .str_sec_size = sizeof(str) | ||
| 161 | |||
| 157 | static struct btf_raw_test raw_tests[] = { | 162 | static struct btf_raw_test raw_tests[] = { |
| 158 | /* enum E { | 163 | /* enum E { |
| 159 | * E0, | 164 | * E0, |
| @@ -1856,11 +1861,11 @@ static const char *get_next_str(const char *start, const char *end) · 1696 unmodified lines | |||
| 1856 | return start < end - 1 ? start + 1 : NULL; | 1861 | return start < end - 1 ? start + 1 : NULL; |
| 1857 | } | 1862 | } |
| 1858 | 1863 | ||
| 1859 | static int get_type_sec_size(const __u32 *raw_types) | 1864 | static int get_raw_sec_size(const __u32 *raw_types) |
| 1860 | { | 1865 | { |
| 1861 | int i; | 1866 | int i; |
| 1862 | 1867 | ||
| 1863 | for (i = MAX_NR_RAW_TYPES - 1; | 1868 | for (i = MAX_NR_RAW_U32 - 1; |
| 1864 | i >= 0 && raw_types[i] != BTF_END_RAW; | 1869 | i >= 0 && raw_types[i] != BTF_END_RAW; |
| 1865 | i--) | 1870 | i--) |
| 1866 | ; | 1871 | ; |
| @@ -1872,7 +1877,8 @@ static void *btf_raw_create(const struct btf_header *hdr, · 5 unmodified lines | |||
| 1872 | const __u32 *raw_types, | 1877 | const __u32 *raw_types, |
| 1873 | const char *str, | 1878 | const char *str, |
| 1874 | unsigned int str_sec_size, | 1879 | unsigned int str_sec_size, |
| 1875 | unsigned int *btf_size) | 1880 | unsigned int *btf_size, |
| 1881 | const char **ret_next_str) | ||
| 1876 | { | 1882 | { |
| 1877 | const char *next_str = str, *end_str = str + str_sec_size; | 1883 | const char *next_str = str, *end_str = str + str_sec_size; |
| 1878 | unsigned int size_needed, offset; | 1884 | unsigned int size_needed, offset; |
| @@ -1881,7 +1887,7 @@ static void *btf_raw_create(const struct btf_header *hdr, · 2 unmodified lines | |||
| 1881 | uint32_t *ret_types; | 1887 | uint32_t *ret_types; |
| 1882 | void *raw_btf; | 1888 | void *raw_btf; |
| 1883 | 1889 | ||
| 1884 | type_sec_size = get_type_sec_size(raw_types); | 1890 | type_sec_size = get_raw_sec_size(raw_types); |
| 1885 | if (CHECK(type_sec_size < 0, "Cannot get nr_raw_types")) | 1891 | if (CHECK(type_sec_size < 0, "Cannot get nr_raw_types")) |
| 1886 | return NULL; | 1892 | return NULL; |
| 1887 | 1893 | ||
| @@ -1920,6 +1926,8 @@ static void *btf_raw_create(const struct btf_header *hdr, · 32 unmodified lines | |||
| 1920 | ret_hdr->str_len = str_sec_size; | 1926 | ret_hdr->str_len = str_sec_size; |
| 1921 | 1927 | ||
| 1922 | *btf_size = size_needed; | 1928 | *btf_size = size_needed; |
| 1929 | if (ret_next_str) | ||
| 1930 | *ret_next_str = next_str; | ||
| 1923 | 1931 | ||
| 1924 | return raw_btf; | 1932 | return raw_btf; |
| 1925 | } | 1933 | } |
| @@ -1939,7 +1947,7 @@ static int do_test_raw(unsigned int test_num) · 13 unmodified lines | |||
| 1939 | test->raw_types, | 1947 | test->raw_types, |
| 1940 | test->str_sec, | 1948 | test->str_sec, |
| 1941 | test->str_sec_size, | 1949 | test->str_sec_size, |
| 1942 | &raw_btf_size); | 1950 | &raw_btf_size, NULL); |
| 1943 | 1951 | ||
| 1944 | if (!raw_btf) | 1952 | if (!raw_btf) |
| 1945 | return -1; | 1953 | return -1; |
| @@ -2016,7 +2024,7 @@ static int test_raw(void) · 70 unmodified lines | |||
| 2016 | struct btf_get_info_test { | 2024 | struct btf_get_info_test { |
| 2017 | const char *descr; | 2025 | const char *descr; |
| 2018 | const char *str_sec; | 2026 | const char *str_sec; |
| 2019 | __u32 raw_types[MAX_NR_RAW_TYPES]; | 2027 | __u32 raw_types[MAX_NR_RAW_U32]; |
| 2020 | __u32 str_sec_size; | 2028 | __u32 str_sec_size; |
| 2021 | int btf_size_delta; | 2029 | int btf_size_delta; |
| 2022 | int (*special_test)(unsigned int test_num); | 2030 | int (*special_test)(unsigned int test_num); |
| @@ -2096,7 +2104,7 @@ static int test_big_btf_info(unsigned int test_num) · 73 unmodified lines | |||
| 2096 | test->raw_types, | 2104 | test->raw_types, |
| 2097 | test->str_sec, | 2105 | test->str_sec, |
| 2098 | test->str_sec_size, | 2106 | test->str_sec_size, |
| 2099 | &raw_btf_size); | 2107 | &raw_btf_size, NULL); |
| 2100 | 2108 | ||
| 2101 | if (!raw_btf) | 2109 | if (!raw_btf) |
| 2102 | return -1; | 2110 | return -1; |
| @@ -2180,7 +2188,7 @@ static int test_btf_id(unsigned int test_num) · 77 unmodified lines | |||
| 2180 | test->raw_types, | 2188 | test->raw_types, |
| 2181 | test->str_sec, | 2189 | test->str_sec, |
| 2182 | test->str_sec_size, | 2190 | test->str_sec_size, |
| 2183 | &raw_btf_size); | 2191 | &raw_btf_size, NULL); |
| 2184 | 2192 | ||
| 2185 | if (!raw_btf) | 2193 | if (!raw_btf) |
| 2186 | return -1; | 2194 | return -1; |
| @@ -2318,7 +2326,7 @@ static int do_test_get_info(unsigned int test_num) · 131 unmodified lines | |||
| 2318 | test->raw_types, | 2326 | test->raw_types, |
| 2319 | test->str_sec, | 2327 | test->str_sec, |
| 2320 | test->str_sec_size, | 2328 | test->str_sec_size, |
| 2321 | &raw_btf_size); | 2329 | &raw_btf_size, NULL); |
| 2322 | 2330 | ||
| 2323 | if (!raw_btf) | 2331 | if (!raw_btf) |
| 2324 | return -1; | 2332 | return -1; |
| @@ -2847,7 +2855,7 @@ static int do_test_pprint(void) · 522 unmodified lines | |||
| 2847 | fprintf(stderr, "%s......", test->descr); | 2855 | fprintf(stderr, "%s......", test->descr); |
| 2848 | raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, | 2856 | raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, |
| 2849 | test->str_sec, test->str_sec_size, | 2857 | test->str_sec, test->str_sec_size, |
| 2850 | &raw_btf_size); | 2858 | &raw_btf_size, NULL); |
| 2851 | 2859 | ||
| 2852 | if (!raw_btf) | 2860 | if (!raw_btf) |
| 2853 | return -1; | 2861 | return -1; |
| @@ -3051,18 +3059,25 @@ static int test_pprint(void) · 197 unmodified lines | |||
| 3051 | return err; | 3059 | return err; |
| 3052 | } | 3060 | } |
| 3053 | 3061 | ||
| 3054 | static struct btf_func_type_test { | 3062 | #define BPF_LINE_INFO_ENC(insn_off, file_off, line_off, line_num, line_col) \ |
| 3063 | (insn_off), (file_off), (line_off), ((line_num) << 10 | ((line_col) & 0x3ff)) | ||
| 3064 | |||
| 3065 | static struct prog_info_raw_test { | ||
| 3055 | const char *descr; | 3066 | const char *descr; |
| 3056 | const char *str_sec; | 3067 | const char *str_sec; |
| 3057 | __u32 raw_types[MAX_NR_RAW_TYPES]; | 3068 | const char *err_str; |
| 3069 | __u32 raw_types[MAX_NR_RAW_U32]; | ||
| 3058 | __u32 str_sec_size; | 3070 | __u32 str_sec_size; |
| 3059 | struct bpf_insn insns[MAX_INSNS]; | 3071 | struct bpf_insn insns[MAX_INSNS]; |
| 3060 | __u32 prog_type; | 3072 | __u32 prog_type; |
| 3061 | __u32 func_info[MAX_SUBPROGS][2]; | 3073 | __u32 func_info[MAX_SUBPROGS][2]; |
| 3062 | __u32 func_info_rec_size; | 3074 | __u32 func_info_rec_size; |
| 3063 | __u32 func_info_cnt; | 3075 | __u32 func_info_cnt; |
| 3076 | __u32 line_info[MAX_NR_RAW_U32]; | ||
| 3077 | __u32 line_info_rec_size; | ||
| 3078 | __u32 nr_jited_ksyms; | ||
| 3064 | bool expected_prog_load_failure; | 3079 | bool expected_prog_load_failure; |
| 3065 | } func_type_test[] = { | 3080 | } info_raw_tests[] = { |
| 3066 | { | 3081 | { |
| 3067 | .descr = "func_type (main func + one sub)", | 3082 | .descr = "func_type (main func + one sub)", |
| 3068 | .raw_types = { | 3083 | .raw_types = { |
| @@ -3091,6 +3106,7 @@ static struct btf_func_type_test { · 22 unmodified lines | |||
| 3091 | .func_info = { {0, 5}, {3, 6} }, | 3106 | .func_info = { {0, 5}, {3, 6} }, |
| 3092 | .func_info_rec_size = 8, | 3107 | .func_info_rec_size = 8, |
| 3093 | .func_info_cnt = 2, | 3108 | .func_info_cnt = 2, |
| 3109 | .line_info = { BTF_END_RAW }, | ||
| 3094 | }, | 3110 | }, |
| 3095 | 3111 | ||
| 3096 | { | 3112 | { |
| @@ -3121,6 +3137,7 @@ static struct btf_func_type_test { · 24 unmodified lines | |||
| 3121 | .func_info = { {0, 5}, {3, 6} }, | 3137 | .func_info = { {0, 5}, {3, 6} }, |
| 3122 | .func_info_rec_size = 4, | 3138 | .func_info_rec_size = 4, |
| 3123 | .func_info_cnt = 2, | 3139 | .func_info_cnt = 2, |
| 3140 | .line_info = { BTF_END_RAW }, | ||
| 3124 | .expected_prog_load_failure = true, | 3141 | .expected_prog_load_failure = true, |
| 3125 | }, | 3142 | }, |
| 3126 | 3143 | ||
| @@ -3152,6 +3169,7 @@ static struct btf_func_type_test { · 25 unmodified lines | |||
| 3152 | .func_info = { {0, 5}, {3, 6} }, | 3169 | .func_info = { {0, 5}, {3, 6} }, |
| 3153 | .func_info_rec_size = 8, | 3170 | .func_info_rec_size = 8, |
| 3154 | .func_info_cnt = 1, | 3171 | .func_info_cnt = 1, |
| 3172 | .line_info = { BTF_END_RAW }, | ||
| 3155 | .expected_prog_load_failure = true, | 3173 | .expected_prog_load_failure = true, |
| 3156 | }, | 3174 | }, |
| 3157 | 3175 | ||
| @@ -3183,6 +3201,278 @@ static struct btf_func_type_test { · 25 unmodified lines | |||
| 3183 | .func_info = { {0, 5}, {2, 6} }, | 3201 | .func_info = { {0, 5}, {2, 6} }, |
| 3184 | .func_info_rec_size = 8, | 3202 | .func_info_rec_size = 8, |
| 3185 | .func_info_cnt = 2, | 3203 | .func_info_cnt = 2, |
| 3204 | .line_info = { BTF_END_RAW }, | ||
| 3205 | .expected_prog_load_failure = true, | ||
| 3206 | }, | ||
| 3207 | |||
| 3208 | { | ||
| 3209 | .descr = "line_info (No subprog)", | ||
| 3210 | .raw_types = { | ||
| 3211 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
| 3212 | BTF_END_RAW, | ||
| 3213 | }, | ||
| 3214 | BTF_STR_SEC("\0int\0int a=1;\0int b=2;\0return a + b;\0return a + b;"), | ||
| 3215 | .insns = { | ||
| 3216 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
| 3217 | BPF_MOV64_IMM(BPF_REG_1, 2), | ||
| 3218 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
| 3219 | BPF_EXIT_INSN(), | ||
| 3220 | }, | ||
| 3221 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 3222 | .func_info_cnt = 0, | ||
| 3223 | .line_info = { | ||
| 3224 | BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10), | ||
| 3225 | BPF_LINE_INFO_ENC(1, 0, NAME_TBD, 2, 9), | ||
| 3226 | BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 3, 8), | ||
| 3227 | BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 4, 7), | ||
| 3228 | BTF_END_RAW, | ||
| 3229 | }, | ||
| 3230 | .line_info_rec_size = sizeof(struct bpf_line_info), | ||
| 3231 | .nr_jited_ksyms = 1, | ||
| 3232 | }, | ||
| 3233 | |||
| 3234 | { | ||
| 3235 | .descr = "line_info (No subprog. insn_off >= prog->len)", | ||
| 3236 | .raw_types = { | ||
| 3237 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
| 3238 | BTF_END_RAW, | ||
| 3239 | }, | ||
| 3240 | BTF_STR_SEC("\0int\0int a=1;\0int b=2;\0return a + b;\0return a + b;"), | ||
| 3241 | .insns = { | ||
| 3242 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
| 3243 | BPF_MOV64_IMM(BPF_REG_1, 2), | ||
| 3244 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
| 3245 | BPF_EXIT_INSN(), | ||
| 3246 | }, | ||
| 3247 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 3248 | .func_info_cnt = 0, | ||
| 3249 | .line_info = { | ||
| 3250 | BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10), | ||
| 3251 | BPF_LINE_INFO_ENC(1, 0, NAME_TBD, 2, 9), | ||
| 3252 | BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 3, 8), | ||
| 3253 | BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 4, 7), | ||
| 3254 | BPF_LINE_INFO_ENC(4, 0, 0, 5, 6), | ||
| 3255 | BTF_END_RAW, | ||
| 3256 | }, | ||
| 3257 | .line_info_rec_size = sizeof(struct bpf_line_info), | ||
| 3258 | .nr_jited_ksyms = 1, | ||
| 3259 | .err_str = "line_info[4].insn_off", | ||
| 3260 | .expected_prog_load_failure = true, | ||
| 3261 | }, | ||
| 3262 | |||
| 3263 | { | ||
| 3264 | .descr = "line_info (No subprog. zero tailing line_info", | ||
| 3265 | .raw_types = { | ||
| 3266 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
| 3267 | BTF_END_RAW, | ||
| 3268 | }, | ||
| 3269 | BTF_STR_SEC("\0int\0int a=1;\0int b=2;\0return a + b;\0return a + b;"), | ||
| 3270 | .insns = { | ||
| 3271 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
| 3272 | BPF_MOV64_IMM(BPF_REG_1, 2), | ||
| 3273 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
| 3274 | BPF_EXIT_INSN(), | ||
| 3275 | }, | ||
| 3276 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 3277 | .func_info_cnt = 0, | ||
| 3278 | .line_info = { | ||
| 3279 | BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10), 0, | ||
| 3280 | BPF_LINE_INFO_ENC(1, 0, NAME_TBD, 2, 9), 0, | ||
| 3281 | BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 3, 8), 0, | ||
| 3282 | BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 4, 7), 0, | ||
| 3283 | BTF_END_RAW, | ||
| 3284 | }, | ||
| 3285 | .line_info_rec_size = sizeof(struct bpf_line_info) + sizeof(__u32), | ||
| 3286 | .nr_jited_ksyms = 1, | ||
| 3287 | }, | ||
| 3288 | |||
| 3289 | { | ||
| 3290 | .descr = "line_info (No subprog. nonzero tailing line_info)", | ||
| 3291 | .raw_types = { | ||
| 3292 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
| 3293 | BTF_END_RAW, | ||
| 3294 | }, | ||
| 3295 | BTF_STR_SEC("\0int\0int a=1;\0int b=2;\0return a + b;\0return a + b;"), | ||
| 3296 | .insns = { | ||
| 3297 | BPF_MOV64_IMM(BPF_REG_0, 1), | ||
| 3298 | BPF_MOV64_IMM(BPF_REG_1, 2), | ||
| 3299 | BPF_ALU64_REG(BPF_ADD, BPF_REG_0, BPF_REG_1), | ||
| 3300 | BPF_EXIT_INSN(), | ||
| 3301 | }, | ||
| 3302 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 3303 | .func_info_cnt = 0, | ||
| 3304 | .line_info = { | ||
| 3305 | BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10), 0, | ||
| 3306 | BPF_LINE_INFO_ENC(1, 0, NAME_TBD, 2, 9), 0, | ||
| 3307 | BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 3, 8), 0, | ||
| 3308 | BPF_LINE_INFO_ENC(3, 0, NAME_TBD, 4, 7), 1, | ||
| 3309 | BTF_END_RAW, | ||
| 3310 | }, | ||
| 3311 | .line_info_rec_size = sizeof(struct bpf_line_info) + sizeof(__u32), | ||
| 3312 | .nr_jited_ksyms = 1, | ||
| 3313 | .err_str = "nonzero tailing record in line_info", | ||
| 3314 | .expected_prog_load_failure = true, | ||
| 3315 | }, | ||
| 3316 | |||
| 3317 | { | ||
| 3318 | .descr = "line_info (subprog)", | ||
| 3319 | .raw_types = { | ||
| 3320 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
| 3321 | BTF_END_RAW, | ||
| 3322 | }, | ||
| 3323 | BTF_STR_SEC("\0int\0int a=1+1;\0return func(a);\0b+=1;\0return b;"), | ||
| 3324 | .insns = { | ||
| 3325 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
| 3326 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1), | ||
| 3327 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
| 3328 | BPF_CALL_REL(1), | ||
| 3329 | BPF_EXIT_INSN(), | ||
| 3330 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
| 3331 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 3332 | BPF_EXIT_INSN(), | ||
| 3333 | }, | ||
| 3334 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 3335 | .func_info_cnt = 0, | ||
| 3336 | .line_info = { | ||
| 3337 | BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10), | ||
| 3338 | BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 2, 9), | ||
| 3339 | BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 3, 8), | ||
| 3340 | BPF_LINE_INFO_ENC(7, 0, NAME_TBD, 4, 7), | ||
| 3341 | BTF_END_RAW, | ||
| 3342 | }, | ||
| 3343 | .line_info_rec_size = sizeof(struct bpf_line_info), | ||
| 3344 | .nr_jited_ksyms = 2, | ||
| 3345 | }, | ||
| 3346 | |||
| 3347 | { | ||
| 3348 | .descr = "line_info (subprog + func_info)", | ||
| 3349 | .raw_types = { | ||
| 3350 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
| 3351 | BTF_FUNC_PROTO_ENC(1, 1), /* [2] */ | ||
| 3352 | BTF_FUNC_PROTO_ARG_ENC(NAME_TBD, 1), | ||
| 3353 | BTF_FUNC_ENC(NAME_TBD, 2), /* [3] */ | ||
| 3354 | BTF_FUNC_ENC(NAME_TBD, 2), /* [4] */ | ||
| 3355 | BTF_END_RAW, | ||
| 3356 | }, | ||
| 3357 | BTF_STR_SEC("\0int\0x\0sub\0main\0int a=1+1;\0return func(a);\0b+=1;\0return b;"), | ||
| 3358 | .insns = { | ||
| 3359 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
| 3360 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1), | ||
| 3361 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
| 3362 | BPF_CALL_REL(1), | ||
| 3363 | BPF_EXIT_INSN(), | ||
| 3364 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
| 3365 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 3366 | BPF_EXIT_INSN(), | ||
| 3367 | }, | ||
| 3368 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 3369 | .func_info_cnt = 2, | ||
| 3370 | .func_info_rec_size = 8, | ||
| 3371 | .func_info = { {0, 4}, {5, 3} }, | ||
| 3372 | .line_info = { | ||
| 3373 | BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10), | ||
| 3374 | BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 2, 9), | ||
| 3375 | BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 3, 8), | ||
| 3376 | BPF_LINE_INFO_ENC(7, 0, NAME_TBD, 4, 7), | ||
| 3377 | BTF_END_RAW, | ||
| 3378 | }, | ||
| 3379 | .line_info_rec_size = sizeof(struct bpf_line_info), | ||
| 3380 | .nr_jited_ksyms = 2, | ||
| 3381 | }, | ||
| 3382 | |||
| 3383 | { | ||
| 3384 | .descr = "line_info (subprog. missing 1st func line info)", | ||
| 3385 | .raw_types = { | ||
| 3386 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
| 3387 | BTF_END_RAW, | ||
| 3388 | }, | ||
| 3389 | BTF_STR_SEC("\0int\0int a=1+1;\0return func(a);\0b+=1;\0return b;"), | ||
| 3390 | .insns = { | ||
| 3391 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
| 3392 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1), | ||
| 3393 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
| 3394 | BPF_CALL_REL(1), | ||
| 3395 | BPF_EXIT_INSN(), | ||
| 3396 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
| 3397 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 3398 | BPF_EXIT_INSN(), | ||
| 3399 | }, | ||
| 3400 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 3401 | .func_info_cnt = 0, | ||
| 3402 | .line_info = { | ||
| 3403 | BPF_LINE_INFO_ENC(1, 0, NAME_TBD, 1, 10), | ||
| 3404 | BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 2, 9), | ||
| 3405 | BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 3, 8), | ||
| 3406 | BPF_LINE_INFO_ENC(7, 0, NAME_TBD, 4, 7), | ||
| 3407 | BTF_END_RAW, | ||
| 3408 | }, | ||
| 3409 | .line_info_rec_size = sizeof(struct bpf_line_info), | ||
| 3410 | .nr_jited_ksyms = 2, | ||
| 3411 | .err_str = "missing bpf_line_info for func#0", | ||
| 3412 | .expected_prog_load_failure = true, | ||
| 3413 | }, | ||
| 3414 | |||
| 3415 | { | ||
| 3416 | .descr = "line_info (subprog. missing 2nd func line info)", | ||
| 3417 | .raw_types = { | ||
| 3418 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
| 3419 | BTF_END_RAW, | ||
| 3420 | }, | ||
| 3421 | BTF_STR_SEC("\0int\0int a=1+1;\0return func(a);\0b+=1;\0return b;"), | ||
| 3422 | .insns = { | ||
| 3423 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
| 3424 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1), | ||
| 3425 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
| 3426 | BPF_CALL_REL(1), | ||
| 3427 | BPF_EXIT_INSN(), | ||
| 3428 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
| 3429 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 3430 | BPF_EXIT_INSN(), | ||
| 3431 | }, | ||
| 3432 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 3433 | .func_info_cnt = 0, | ||
| 3434 | .line_info = { | ||
| 3435 | BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10), | ||
| 3436 | BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 2, 9), | ||
| 3437 | BPF_LINE_INFO_ENC(6, 0, NAME_TBD, 3, 8), | ||
| 3438 | BPF_LINE_INFO_ENC(7, 0, NAME_TBD, 4, 7), | ||
| 3439 | BTF_END_RAW, | ||
| 3440 | }, | ||
| 3441 | .line_info_rec_size = sizeof(struct bpf_line_info), | ||
| 3442 | .nr_jited_ksyms = 2, | ||
| 3443 | .err_str = "missing bpf_line_info for func#1", | ||
| 3444 | .expected_prog_load_failure = true, | ||
| 3445 | }, | ||
| 3446 | |||
| 3447 | { | ||
| 3448 | .descr = "line_info (subprog. unordered insn offset)", | ||
| 3449 | .raw_types = { | ||
| 3450 | BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ | ||
| 3451 | BTF_END_RAW, | ||
| 3452 | }, | ||
| 3453 | BTF_STR_SEC("\0int\0int a=1+1;\0return func(a);\0b+=1;\0return b;"), | ||
| 3454 | .insns = { | ||
| 3455 | BPF_MOV64_IMM(BPF_REG_2, 1), | ||
| 3456 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, 1), | ||
| 3457 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), | ||
| 3458 | BPF_CALL_REL(1), | ||
| 3459 | BPF_EXIT_INSN(), | ||
| 3460 | BPF_MOV64_REG(BPF_REG_0, BPF_REG_1), | ||
| 3461 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 1), | ||
| 3462 | BPF_EXIT_INSN(), | ||
| 3463 | }, | ||
| 3464 | .prog_type = BPF_PROG_TYPE_TRACEPOINT, | ||
| 3465 | .func_info_cnt = 0, | ||
| 3466 | .line_info = { | ||
| 3467 | BPF_LINE_INFO_ENC(0, 0, NAME_TBD, 1, 10), | ||
| 3468 | BPF_LINE_INFO_ENC(5, 0, NAME_TBD, 2, 9), | ||
| 3469 | BPF_LINE_INFO_ENC(2, 0, NAME_TBD, 3, 8), | ||
| 3470 | BPF_LINE_INFO_ENC(7, 0, NAME_TBD, 4, 7), | ||
| 3471 | BTF_END_RAW, | ||
| 3472 | }, | ||
| 3473 | .line_info_rec_size = sizeof(struct bpf_line_info), | ||
| 3474 | .nr_jited_ksyms = 2, | ||
| 3475 | .err_str = "Invalid line_info[2].insn_off", | ||
| 3186 | .expected_prog_load_failure = true, | 3476 | .expected_prog_load_failure = true, |
| 3187 | }, | 3477 | }, |
| 3188 | 3478 | ||
| @@ -3198,90 +3488,84 @@ static size_t probe_prog_length(const struct bpf_insn *fp) · 9 unmodified lines | |||
| 3198 | return len + 1; | 3488 | return len + 1; |
| 3199 | } | 3489 | } |
| 3200 | 3490 | ||
| 3201 | static int do_test_func_type(int test_num) | 3491 | static __u32 *patch_name_tbd(const __u32 *raw_u32, |
| 3492 | const char *str, __u32 str_off, | ||
| 3493 | unsigned int str_sec_size, | ||
| 3494 | unsigned int *ret_size) | ||
| 3202 | { | 3495 | { |
| 3203 | const struct btf_func_type_test *test = &func_type_test[test_num]; | 3496 | int i, raw_u32_size = get_raw_sec_size(raw_u32); |
| 3204 | unsigned int raw_btf_size, info_len, rec_size; | 3497 | const char *end_str = str + str_sec_size; |
| 3205 | int i, btf_fd = -1, prog_fd = -1, err = 0; | 3498 | const char *next_str = str + str_off; |
| 3206 | struct bpf_load_program_attr attr = {}; | 3499 | __u32 *new_u32 = NULL; |
| 3207 | void *raw_btf, *func_info = NULL; | ||
| 3208 | struct bpf_prog_info info = {}; | ||
| 3209 | struct bpf_func_info *finfo; | ||
| 3210 | 3500 | ||
| 3211 | fprintf(stderr, "%s......", test->descr); | 3501 | if (raw_u32_size == -1) |
| 3212 | raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, | 3502 | return ERR_PTR(-EINVAL); |
| 3213 | test->str_sec, test->str_sec_size, | ||
| 3214 | &raw_btf_size); | ||
| 3215 | 3503 | ||
| 3216 | if (!raw_btf) | 3504 | if (!raw_u32_size) { |
| 3217 | return -1; | 3505 | *ret_size = 0; |
| 3506 | return NULL; | ||
| 3507 | } | ||
| 3218 | 3508 | ||
| 3219 | *btf_log_buf = '\0'; | 3509 | new_u32 = malloc(raw_u32_size); |
| 3220 | btf_fd = bpf_load_btf(raw_btf, raw_btf_size, | 3510 | if (!new_u32) |
| 3221 | btf_log_buf, BTF_LOG_BUF_SIZE, | 3511 | return ERR_PTR(-ENOMEM); |
| 3222 | args.always_log); | ||
| 3223 | free(raw_btf); | ||
| 3224 | 3512 | ||
| 3225 | if (CHECK(btf_fd == -1, "invalid btf_fd errno:%d", errno)) { | 3513 | for (i = 0; i < raw_u32_size / sizeof(raw_u32[0]); i++) { |
| 3226 | err = -1; | 3514 | if (raw_u32[i] == NAME_TBD) { |
| 3227 | goto done; | 3515 | next_str = get_next_str(next_str, end_str); |
| 3516 | if (CHECK(!next_str, "Error in getting next_str\n")) { | ||
| 3517 | free(new_u32); | ||
| 3518 | return ERR_PTR(-EINVAL); | ||
| 3519 | } | ||
| 3520 | new_u32[i] = next_str - str; | ||
| 3521 | next_str += strlen(next_str); | ||
| 3522 | } else { | ||
| 3523 | new_u32[i] = raw_u32[i]; | ||
| 3524 | } | ||
| 3228 | } | 3525 | } |
| 3229 | 3526 | ||
| 3230 | if (*btf_log_buf && args.always_log) | 3527 | *ret_size = raw_u32_size; |
| 3231 | fprintf(stderr, "\n%s", btf_log_buf); | 3528 | return new_u32; |
| 3232 | 3529 | } | |
| 3233 | attr.prog_type = test->prog_type; | ||
| 3234 | attr.insns = test->insns; | ||
| 3235 | attr.insns_cnt = probe_prog_length(attr.insns); | ||
| 3236 | attr.license = "GPL"; | ||
| 3237 | attr.prog_btf_fd = btf_fd; | ||
| 3238 | attr.func_info_rec_size = test->func_info_rec_size; | ||
| 3239 | attr.func_info_cnt = test->func_info_cnt; | ||
| 3240 | attr.func_info = test->func_info; | ||
| 3241 | 3530 | ||
| 3242 | *btf_log_buf = '\0'; | 3531 | static int test_get_finfo(const struct prog_info_raw_test *test, |
| 3243 | prog_fd = bpf_load_program_xattr(&attr, btf_log_buf, | 3532 | int prog_fd) |
| 3244 | BTF_LOG_BUF_SIZE); | 3533 | { |
| 3245 | if (test->expected_prog_load_failure && prog_fd == -1) { | 3534 | struct bpf_prog_info info = {}; |
| 3246 | err = 0; | 3535 | struct bpf_func_info *finfo; |
| 3247 | goto done; | 3536 | __u32 info_len, rec_size, i; |
| 3248 | } | 3537 | void *func_info = NULL; |
| 3249 | if (CHECK(prog_fd == -1, "invalid prog_id errno:%d", errno)) { | 3538 | int err; |
| 3250 | fprintf(stderr, "%s\n", btf_log_buf); | ||
| 3251 | err = -1; | ||
| 3252 | goto done; | ||
| 3253 | } | ||
| 3254 | 3539 | ||
| 3255 | /* get necessary lens */ | 3540 | /* get necessary lens */ |
| 3256 | info_len = sizeof(struct bpf_prog_info); | 3541 | info_len = sizeof(struct bpf_prog_info); |
| 3257 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); | 3542 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); |
| 3258 | if (CHECK(err == -1, "invalid get info (1st) errno:%d", errno)) { | 3543 | if (CHECK(err == -1, "invalid get info (1st) errno:%d", errno)) { |
| 3259 | fprintf(stderr, "%s\n", btf_log_buf); | 3544 | fprintf(stderr, "%s\n", btf_log_buf); |
| 3260 | err = -1; | 3545 | return -1; |
| 3261 | goto done; | ||
| 3262 | } | 3546 | } |
| 3263 | if (CHECK(info.func_info_cnt != 2, | 3547 | if (CHECK(info.func_info_cnt != test->func_info_cnt, |
| 3264 | "incorrect info.func_info_cnt (1st) %d\n", | 3548 | "incorrect info.func_info_cnt (1st) %d", |
| 3265 | info.func_info_cnt)) { | 3549 | info.func_info_cnt)) { |
| 3266 | err = -1; | 3550 | return -1; |
| 3267 | goto done; | ||
| 3268 | } | 3551 | } |
| 3552 | |||
| 3269 | rec_size = info.func_info_rec_size; | 3553 | rec_size = info.func_info_rec_size; |
| 3270 | if (CHECK(rec_size < 4, | 3554 | if (CHECK(rec_size < 8, |
| 3271 | "incorrect info.func_info_rec_size (1st) %d\n", rec_size)) { | 3555 | "incorrect info.func_info_rec_size (1st) %d", rec_size)) { |
| 3272 | err = -1; | 3556 | return -1; |
| 3273 | goto done; | ||
| 3274 | } | 3557 | } |
| 3275 | 3558 | ||
| 3559 | if (!info.func_info_cnt) | ||
| 3560 | return 0; | ||
| 3561 | |||
| 3276 | func_info = malloc(info.func_info_cnt * rec_size); | 3562 | func_info = malloc(info.func_info_cnt * rec_size); |
| 3277 | if (CHECK(!func_info, "out of memory")) { | 3563 | if (CHECK(!func_info, "out of memory")) |
| 3278 | err = -1; | 3564 | return -1; |
| 3279 | goto done; | ||
| 3280 | } | ||
| 3281 | 3565 | ||
| 3282 | /* reset info to only retrieve func_info related data */ | 3566 | /* reset info to only retrieve func_info related data */ |
| 3283 | memset(&info, 0, sizeof(info)); | 3567 | memset(&info, 0, sizeof(info)); |
| 3284 | info.func_info_cnt = 2; | 3568 | info.func_info_cnt = test->func_info_cnt; |
| 3285 | info.func_info_rec_size = rec_size; | 3569 | info.func_info_rec_size = rec_size; |
| 3286 | info.func_info = ptr_to_u64(func_info); | 3570 | info.func_info = ptr_to_u64(func_info); |
| 3287 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); | 3571 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); |
| @@ -3290,14 +3574,14 @@ static int do_test_func_type(int test_num) · 2 unmodified lines | |||
| 3290 | err = -1; | 3574 | err = -1; |
| 3291 | goto done; | 3575 | goto done; |
| 3292 | } | 3576 | } |
| 3293 | if (CHECK(info.func_info_cnt != 2, | 3577 | if (CHECK(info.func_info_cnt != test->func_info_cnt, |
| 3294 | "incorrect info.func_info_cnt (2nd) %d\n", | 3578 | "incorrect info.func_info_cnt (2nd) %d", |
| 3295 | info.func_info_cnt)) { | 3579 | info.func_info_cnt)) { |
| 3296 | err = -1; | 3580 | err = -1; |
| 3297 | goto done; | 3581 | goto done; |
| 3298 | } | 3582 | } |
| 3299 | if (CHECK(info.func_info_rec_size != rec_size, | 3583 | if (CHECK(info.func_info_rec_size < 8, |
| 3300 | "incorrect info.func_info_rec_size (2nd) %d\n", | 3584 | "incorrect info.func_info_rec_size (2nd) %d", |
| 3301 | info.func_info_rec_size)) { | 3585 | info.func_info_rec_size)) { |
| 3302 | err = -1; | 3586 | err = -1; |
| 3303 | goto done; | 3587 | goto done; |
| @@ -3310,7 +3594,7 @@ static int do_test_func_type(int test_num) · 6 unmodified lines | |||
| 3310 | } | 3594 | } |
| 3311 | 3595 | ||
| 3312 | finfo = func_info; | 3596 | finfo = func_info; |
| 3313 | for (i = 0; i < 2; i++) { | 3597 | for (i = 0; i < test->func_info_cnt; i++) { |
| 3314 | if (CHECK(finfo->type_id != test->func_info[i][1], | 3598 | if (CHECK(finfo->type_id != test->func_info[i][1], |
| 3315 | "incorrect func_type %u expected %u", | 3599 | "incorrect func_type %u expected %u", |
| 3316 | finfo->type_id, test->func_info[i][1])) { | 3600 | finfo->type_id, test->func_info[i][1])) { |
| @@ -3320,7 +3604,307 @@ static int do_test_func_type(int test_num) · 3 unmodified lines | |||
| 3320 | finfo = (void *)finfo + rec_size; | 3604 | finfo = (void *)finfo + rec_size; |
| 3321 | } | 3605 | } |
| 3322 | 3606 | ||
| 3607 | err = 0; | ||
| 3608 | |||
| 3609 | done: | ||
| 3610 | free(func_info); | ||
| 3611 | return err; | ||
| 3612 | } | ||
| 3613 | |||
| 3614 | static int test_get_linfo(const struct prog_info_raw_test *test, | ||
| 3615 | const void *patched_linfo, | ||
| 3616 | __u32 cnt, int prog_fd) | ||
| 3617 | { | ||
| 3618 | __u32 i, info_len, nr_jited_ksyms, nr_jited_func_lens; | ||
| 3619 | __u64 *jited_linfo = NULL, *jited_ksyms = NULL; | ||
| 3620 | __u32 rec_size, jited_rec_size, jited_cnt; | ||
| 3621 | struct bpf_line_info *linfo = NULL; | ||
| 3622 | __u32 cur_func_len, ksyms_found; | ||
| 3623 | struct bpf_prog_info info = {}; | ||
| 3624 | __u32 *jited_func_lens = NULL; | ||
| 3625 | __u64 cur_func_ksyms; | ||
| 3626 | int err; | ||
| 3627 | |||
| 3628 | jited_cnt = cnt; | ||
| 3629 | rec_size = sizeof(*linfo); | ||
| 3630 | jited_rec_size = sizeof(*jited_linfo); | ||
| 3631 | if (test->nr_jited_ksyms) | ||
| 3632 | nr_jited_ksyms = test->nr_jited_ksyms; | ||
| 3633 | else | ||
| 3634 | nr_jited_ksyms = test->func_info_cnt; | ||
| 3635 | nr_jited_func_lens = nr_jited_ksyms; | ||
| 3636 | |||
| 3637 | info_len = sizeof(struct bpf_prog_info); | ||
| 3638 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); | ||
| 3639 | if (CHECK(err == -1, "err:%d errno:%d", err, errno)) { | ||
| 3640 | err = -1; | ||
| 3641 | goto done; | ||
| 3642 | } | ||
| 3643 | |||
| 3644 | if (!info.jited_prog_len) { | ||
| 3645 | /* prog is not jited */ | ||
| 3646 | jited_cnt = 0; | ||
| 3647 | nr_jited_ksyms = 1; | ||
| 3648 | nr_jited_func_lens = 1; | ||
| 3649 | } | ||
| 3650 | |||
| 3651 | if (CHECK(info.line_info_cnt != cnt || | ||
| 3652 | info.jited_line_info_cnt != jited_cnt || | ||
| 3653 | info.nr_jited_ksyms != nr_jited_ksyms || | ||
| 3654 | info.nr_jited_func_lens != nr_jited_func_lens || | ||
| 3655 | (!info.line_info_cnt && info.jited_line_info_cnt), | ||
| 3656 | "info: line_info_cnt:%u(expected:%u) jited_line_info_cnt:%u(expected:%u) nr_jited_ksyms:%u(expected:%u) nr_jited_func_lens:%u(expected:%u)", | ||
| 3657 | info.line_info_cnt, cnt, | ||
| 3658 | info.jited_line_info_cnt, jited_cnt, | ||
| 3659 | info.nr_jited_ksyms, nr_jited_ksyms, | ||
| 3660 | info.nr_jited_func_lens, nr_jited_func_lens)) { | ||
| 3661 | err = -1; | ||
| 3662 | goto done; | ||
| 3663 | } | ||
| 3664 | |||
| 3665 | if (CHECK(info.line_info_rec_size < 16 || | ||
| 3666 | info.jited_line_info_rec_size < 8, | ||
| 3667 | "info: line_info_rec_size:%u(userspace expected:%u) jited_line_info_rec_size:%u(userspace expected:%u)", | ||
| 3668 | info.line_info_rec_size, rec_size, | ||
| 3669 | info.jited_line_info_rec_size, jited_rec_size)) { | ||
| 3670 | err = -1; | ||
| 3671 | goto done; | ||
| 3672 | } | ||
| 3673 | |||
| 3674 | if (!cnt) | ||
| 3675 | return 0; | ||
| 3676 | |||
| 3677 | rec_size = info.line_info_rec_size; | ||
| 3678 | jited_rec_size = info.jited_line_info_rec_size; | ||
| 3679 | |||
| 3680 | memset(&info, 0, sizeof(info)); | ||
| 3681 | |||
| 3682 | linfo = calloc(cnt, rec_size); | ||
| 3683 | if (CHECK(!linfo, "!linfo")) { | ||
| 3684 | err = -1; | ||
| 3685 | goto done; | ||
| 3686 | } | ||
| 3687 | info.line_info_cnt = cnt; | ||
| 3688 | info.line_info_rec_size = rec_size; | ||
| 3689 | info.line_info = ptr_to_u64(linfo); | ||
| 3690 | |||
| 3691 | if (jited_cnt) { | ||
| 3692 | jited_linfo = calloc(jited_cnt, jited_rec_size); | ||
| 3693 | jited_ksyms = calloc(nr_jited_ksyms, sizeof(*jited_ksyms)); | ||
| 3694 | jited_func_lens = calloc(nr_jited_func_lens, | ||
| 3695 | sizeof(*jited_func_lens)); | ||
| 3696 | if (CHECK(!jited_linfo || !jited_ksyms || !jited_func_lens, | ||
| 3697 | "jited_linfo:%p jited_ksyms:%p jited_func_lens:%p", | ||
| 3698 | jited_linfo, jited_ksyms, jited_func_lens)) { | ||
| 3699 | err = -1; | ||
| 3700 | goto done; | ||
| 3701 | } | ||
| 3702 | |||
| 3703 | info.jited_line_info_cnt = jited_cnt; | ||
| 3704 | info.jited_line_info_rec_size = jited_rec_size; | ||
| 3705 | info.jited_line_info = ptr_to_u64(jited_linfo); | ||
| 3706 | info.nr_jited_ksyms = nr_jited_ksyms; | ||
| 3707 | info.jited_ksyms = ptr_to_u64(jited_ksyms); | ||
| 3708 | info.nr_jited_func_lens = nr_jited_func_lens; | ||
| 3709 | info.jited_func_lens = ptr_to_u64(jited_func_lens); | ||
| 3710 | } | ||
| 3711 | |||
| 3712 | err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len); | ||
| 3713 | |||
| 3714 | /* | ||
| 3715 | * Only recheck the info.*line_info* fields. | ||
| 3716 | * Other fields are not the concern of this test. | ||
| 3717 | */ | ||
| 3718 | if (CHECK(err == -1 || | ||
| 3719 | !info.line_info || | ||
| 3720 | info.line_info_cnt != cnt || | ||
| 3721 | (jited_cnt && !info.jited_line_info) || | ||
| 3722 | info.jited_line_info_cnt != jited_cnt || | ||
| 3723 | info.line_info_rec_size != rec_size || | ||
| 3724 | info.jited_line_info_rec_size != jited_rec_size, | ||
| 3725 | "err:%d errno:%d info: line_info_cnt:%u(expected:%u) jited_line_info_cnt:%u(expected:%u) line_info_rec_size:%u(expected:%u) jited_linfo_rec_size:%u(expected:%u) line_info:%p jited_line_info:%p", | ||
| 3726 | err, errno, | ||
| 3727 | info.line_info_cnt, cnt, | ||
| 3728 | info.jited_line_info_cnt, jited_cnt, | ||
| 3729 | info.line_info_rec_size, rec_size, | ||
| 3730 | info.jited_line_info_rec_size, jited_rec_size, | ||
| 3731 | (void *)(long)info.line_info, | ||
| 3732 | (void *)(long)info.jited_line_info)) { | ||
| 3733 | err = -1; | ||
| 3734 | goto done; | ||
| 3735 | } | ||
| 3736 | |||
| 3737 | CHECK(linfo[0].insn_off, "linfo[0].insn_off:%u", | ||
| 3738 | linfo[0].insn_off); | ||
| 3739 | for (i = 1; i < cnt; i++) { | ||
| 3740 | const struct bpf_line_info *expected_linfo; | ||
| 3741 | |||
| 3742 | expected_linfo = patched_linfo + (i * test->line_info_rec_size); | ||
| 3743 | if (CHECK(linfo[i].insn_off <= linfo[i - 1].insn_off, | ||
| 3744 | "linfo[%u].insn_off:%u <= linfo[%u].insn_off:%u", | ||
| 3745 | i, linfo[i].insn_off, | ||
| 3746 | i - 1, linfo[i - 1].insn_off)) { | ||
| 3747 | err = -1; | ||
| 3748 | goto done; | ||
| 3749 | } | ||
| 3750 | if (CHECK(linfo[i].file_name_off != expected_linfo->file_name_off || | ||
| 3751 | linfo[i].line_off != expected_linfo->line_off || | ||
| 3752 | linfo[i].line_col != expected_linfo->line_col, | ||
| 3753 | "linfo[%u] (%u, %u, %u) != (%u, %u, %u)", i, | ||
| 3754 | linfo[i].file_name_off, | ||
| 3755 | linfo[i].line_off, | ||
| 3756 | linfo[i].line_col, | ||
| 3757 | expected_linfo->file_name_off, | ||
| 3758 | expected_linfo->line_off, | ||
| 3759 | expected_linfo->line_col)) { | ||
| 3760 | err = -1; | ||
| 3761 | goto done; | ||
| 3762 | } | ||
| 3763 | } | ||
| 3764 | |||
| 3765 | if (!jited_cnt) { | ||
| 3766 | fprintf(stderr, "not jited. skipping jited_line_info check. "); | ||
| 3767 | err = 0; | ||
| 3768 | goto done; | ||
| 3769 | } | ||
| 3770 | |||
| 3771 | if (CHECK(jited_linfo[0] != jited_ksyms[0], | ||
| 3772 | "jited_linfo[0]:%lx != jited_ksyms[0]:%lx", | ||
| 3773 | (long)(jited_linfo[0]), (long)(jited_ksyms[0]))) { | ||
| 3774 | err = -1; | ||
| 3775 | goto done; | ||
| 3776 | } | ||
| 3777 | |||
| 3778 | ksyms_found = 1; | ||
| 3779 | cur_func_len = jited_func_lens[0]; | ||
| 3780 | cur_func_ksyms = jited_ksyms[0]; | ||
| 3781 | for (i = 1; i < jited_cnt; i++) { | ||
| 3782 | if (ksyms_found < nr_jited_ksyms && | ||
| 3783 | jited_linfo[i] == jited_ksyms[ksyms_found]) { | ||
| 3784 | cur_func_ksyms = jited_ksyms[ksyms_found]; | ||
| 3785 | cur_func_len = jited_ksyms[ksyms_found]; | ||
| 3786 | ksyms_found++; | ||
| 3787 | continue; | ||
| 3788 | } | ||
| 3789 | |||
| 3790 | if (CHECK(jited_linfo[i] <= jited_linfo[i - 1], | ||
| 3791 | "jited_linfo[%u]:%lx <= jited_linfo[%u]:%lx", | ||
| 3792 | i, (long)jited_linfo[i], | ||
| 3793 | i - 1, (long)(jited_linfo[i - 1]))) { | ||
| 3794 | err = -1; | ||
| 3795 | goto done; | ||
| 3796 | } | ||
| 3797 | |||
| 3798 | if (CHECK(jited_linfo[i] - cur_func_ksyms > cur_func_len, | ||
| 3799 | "jited_linfo[%u]:%lx - %lx > %u", | ||
| 3800 | i, (long)jited_linfo[i], (long)cur_func_ksyms, | ||
| 3801 | cur_func_len)) { | ||
| 3802 | err = -1; | ||
| 3803 | goto done; | ||
| 3804 | } | ||
| 3805 | } | ||
| 3806 | |||
| 3807 | if (CHECK(ksyms_found != nr_jited_ksyms, | ||
| 3808 | "ksyms_found:%u != nr_jited_ksyms:%u", | ||
| 3809 | ksyms_found, nr_jited_ksyms)) { | ||
| 3810 | err = -1; | ||
| 3811 | goto done; | ||
| 3812 | } | ||
| 3813 | |||
| 3814 | err = 0; | ||
| 3815 | |||
| 3323 | done: | 3816 | done: |
| 3817 | free(linfo); | ||
| 3818 | free(jited_linfo); | ||
| 3819 | free(jited_ksyms); | ||
| 3820 | free(jited_func_lens); | ||
| 3821 | return err; | ||
| 3822 | } | ||
| 3823 | |||
| 3824 | static int do_test_info_raw(unsigned int test_num) | ||
| 3825 | { | ||
| 3826 | const struct prog_info_raw_test *test = &info_raw_tests[test_num - 1]; | ||
| 3827 | unsigned int raw_btf_size, linfo_str_off, linfo_size; | ||
| 3828 | int btf_fd = -1, prog_fd = -1, err = 0; | ||
| 3829 | void *raw_btf, *patched_linfo = NULL; | ||
| 3830 | const char *ret_next_str; | ||
| 3831 | union bpf_attr attr = {}; | ||
| 3832 | |||
| 3833 | fprintf(stderr, "BTF prog info raw test[%u] (%s): ", test_num, test->descr); | ||
| 3834 | raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types, | ||
| 3835 | test->str_sec, test->str_sec_size, | ||
| 3836 | &raw_btf_size, &ret_next_str); | ||
| 3837 | |||
| 3838 | if (!raw_btf) | ||
| 3839 | return -1; | ||
| 3840 | |||
| 3841 | *btf_log_buf = '\0'; | ||
| 3842 | btf_fd = bpf_load_btf(raw_btf, raw_btf_size, | ||
| 3843 | btf_log_buf, BTF_LOG_BUF_SIZE, | ||
| 3844 | args.always_log); | ||
| 3845 | free(raw_btf); | ||
| 3846 | |||
| 3847 | if (CHECK(btf_fd == -1, "invalid btf_fd errno:%d", errno)) { | ||
| 3848 | err = -1; | ||
| 3849 | goto done; | ||
| 3850 | } | ||
| 3851 | |||
| 3852 | if (*btf_log_buf && args.always_log) | ||
| 3853 | fprintf(stderr, "\n%s", btf_log_buf); | ||
| 3854 | *btf_log_buf = '\0'; | ||
| 3855 | |||
| 3856 | linfo_str_off = ret_next_str - test->str_sec; | ||
| 3857 | patched_linfo = patch_name_tbd(test->line_info, | ||
| 3858 | test->str_sec, linfo_str_off, | ||
| 3859 | test->str_sec_size, &linfo_size); | ||
| 3860 | if (IS_ERR(patched_linfo)) { | ||
| 3861 | fprintf(stderr, "error in creating raw bpf_line_info"); | ||
| 3862 | err = -1; | ||
| 3863 | goto done; | ||
| 3864 | } | ||
| 3865 | |||
| 3866 | attr.prog_type = test->prog_type; | ||
| 3867 | attr.insns = ptr_to_u64(test->insns); | ||
| 3868 | attr.insn_cnt = probe_prog_length(test->insns); | ||
| 3869 | attr.license = ptr_to_u64("GPL"); | ||
| 3870 | attr.prog_btf_fd = btf_fd; | ||
| 3871 | attr.func_info_rec_size = test->func_info_rec_size; | ||
| 3872 | attr.func_info_cnt = test->func_info_cnt; | ||
| 3873 | attr.func_info = ptr_to_u64(test->func_info); | ||
| 3874 | attr.log_buf = ptr_to_u64(btf_log_buf); | ||
| 3875 | attr.log_size = BTF_LOG_BUF_SIZE; | ||
| 3876 | attr.log_level = 1; | ||
| 3877 | if (linfo_size) { | ||
| 3878 | attr.line_info_rec_size = test->line_info_rec_size; | ||
| 3879 | attr.line_info = ptr_to_u64(patched_linfo); | ||
| 3880 | attr.line_info_cnt = linfo_size / attr.line_info_rec_size; | ||
| 3881 | } | ||
| 3882 | |||
| 3883 | prog_fd = syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); | ||
| 3884 | err = ((prog_fd == -1) != test->expected_prog_load_failure); | ||
| 3885 | if (CHECK(err, "prog_fd:%d expected_prog_load_failure:%u errno:%d", | ||
| 3886 | prog_fd, test->expected_prog_load_failure, errno) || | ||
| 3887 | CHECK(test->err_str && !strstr(btf_log_buf, test->err_str), | ||
| 3888 | "expected err_str:%s", test->err_str)) { | ||
| 3889 | err = -1; | ||
| 3890 | goto done; | ||
| 3891 | } | ||
| 3892 | |||
| 3893 | if (prog_fd == -1) | ||
| 3894 | goto done; | ||
| 3895 | |||
| 3896 | err = test_get_finfo(test, prog_fd); | ||
| 3897 | if (err) | ||
| 3898 | goto done; | ||
| 3899 | |||
| 3900 | err = test_get_linfo(test, patched_linfo, attr.line_info_cnt, prog_fd); | ||
| 3901 | if (err) | ||
| 3902 | goto done; | ||
| 3903 | |||
| 3904 | done: | ||
| 3905 | if (!err) | ||
| 3906 | fprintf(stderr, "OK"); | ||
| 3907 | |||
| 3324 | if (*btf_log_buf && (err || args.always_log)) | 3908 | if (*btf_log_buf && (err || args.always_log)) |
| 3325 | fprintf(stderr, "\n%s", btf_log_buf); | 3909 | fprintf(stderr, "\n%s", btf_log_buf); |
| 3326 | 3910 | ||
| @@ -3328,33 +3912,41 @@ done: · 1 unmodified line | |||
| 3328 | close(btf_fd); | 3912 | close(btf_fd); |
| 3329 | if (prog_fd != -1) | 3913 | if (prog_fd != -1) |
| 3330 | close(prog_fd); | 3914 | close(prog_fd); |
| 3331 | free(func_info); | 3915 | |
| 3916 | if (!IS_ERR(patched_linfo)) | ||
| 3917 | free(patched_linfo); | ||
| 3918 | |||
| 3332 | return err; | 3919 | return err; |
| 3333 | } | 3920 | } |
| 3334 | 3921 | ||
| 3335 | static int test_func_type(void) | 3922 | static int test_info_raw(void) |
| 3336 | { | 3923 | { |
| 3337 | unsigned int i; | 3924 | unsigned int i; |
| 3338 | int err = 0; | 3925 | int err = 0; |
| 3339 | 3926 | ||
| 3340 | for (i = 0; i < ARRAY_SIZE(func_type_test); i++) | 3927 | if (args.info_raw_test_num) |
| 3341 | err |= count_result(do_test_func_type(i)); | 3928 | return count_result(do_test_info_raw(args.info_raw_test_num)); |
| 3929 | |||
| 3930 | for (i = 1; i <= ARRAY_SIZE(info_raw_tests); i++) | ||
| 3931 | err |= count_result(do_test_info_raw(i)); | ||
| 3342 | 3932 | ||
| 3343 | return err; | 3933 | return err; |
| 3344 | } | 3934 | } |
| 3345 | 3935 | ||
| 3346 | static void usage(const char *cmd) | 3936 | static void usage(const char *cmd) |
| 3347 | { | 3937 | { |
| 3348 | fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] |" | 3938 | fprintf(stderr, "Usage: %s [-l] [[-r btf_raw_test_num (1 - %zu)] |\n" |
| 3349 | " [-g test_num (1 - %zu)] |" | 3939 | "\t[-g btf_get_info_test_num (1 - %zu)] |\n" |
| 3350 | " [-f test_num (1 - %zu)] | [-p] | [-k] ]\n", | 3940 | "\t[-f btf_file_test_num (1 - %zu)] |\n" |
| 3941 | "\t[-k btf_prog_info_raw_test_num (1 - %zu)] |\n" | ||
| 3942 | "\t[-p (pretty print test)]]\n", | ||
| 3351 | cmd, ARRAY_SIZE(raw_tests), ARRAY_SIZE(get_info_tests), | 3943 | cmd, ARRAY_SIZE(raw_tests), ARRAY_SIZE(get_info_tests), |
| 3352 | ARRAY_SIZE(file_tests)); | 3944 | ARRAY_SIZE(file_tests), ARRAY_SIZE(info_raw_tests)); |
| 3353 | } | 3945 | } |
| 3354 | 3946 | ||
| 3355 | static int parse_args(int argc, char **argv) | 3947 | static int parse_args(int argc, char **argv) |
| 3356 | { | 3948 | { |
| 3357 | const char *optstr = "lpkf:r:g:"; | 3949 | const char *optstr = "lpk:f:r:g:"; |
| 3358 | int opt; | 3950 | int opt; |
| 3359 | 3951 | ||
| 3360 | while ((opt = getopt(argc, argv, optstr)) != -1) { | 3952 | while ((opt = getopt(argc, argv, optstr)) != -1) { |
| @@ -3378,7 +3970,8 @@ static int parse_args(int argc, char **argv) · 17 unmodified lines | |||
| 3378 | args.pprint_test = true; | 3970 | args.pprint_test = true; |
| 3379 | break; | 3971 | break; |
| 3380 | case 'k': | 3972 | case 'k': |
| 3381 | args.func_type_test = true; | 3973 | args.info_raw_test_num = atoi(optarg); |
| 3974 | args.info_raw_test = true; | ||
| 3382 | break; | 3975 | break; |
| 3383 | case 'h': | 3976 | case 'h': |
| 3384 | usage(argv[0]); | 3977 | usage(argv[0]); |
| @@ -3413,6 +4006,14 @@ static int parse_args(int argc, char **argv) · 28 unmodified lines | |||
| 3413 | return -1; | 4006 | return -1; |
| 3414 | } | 4007 | } |
| 3415 | 4008 | ||
| 4009 | if (args.info_raw_test_num && | ||
| 4010 | (args.info_raw_test_num < 1 || | ||
| 4011 | args.info_raw_test_num > ARRAY_SIZE(info_raw_tests))) { | ||
| 4012 | fprintf(stderr, "BTF prog info raw test number must be [1 - %zu]\n", | ||
| 4013 | ARRAY_SIZE(info_raw_tests)); | ||
| 4014 | return -1; | ||
| 4015 | } | ||
| 4016 | |||
| 3416 | return 0; | 4017 | return 0; |
| 3417 | } | 4018 | } |
| 3418 | 4019 | ||
| @@ -3445,16 +4046,17 @@ int main(int argc, char **argv) · 26 unmodified lines | |||
| 3445 | if (args.pprint_test) | 4046 | if (args.pprint_test) |
| 3446 | err |= test_pprint(); | 4047 | err |= test_pprint(); |
| 3447 | 4048 | ||
| 3448 | if (args.func_type_test) | 4049 | if (args.info_raw_test) |
| 3449 | err |= test_func_type(); | 4050 | err |= test_info_raw(); |
| 3450 | 4051 | ||
| 3451 | if (args.raw_test || args.get_info_test || args.file_test || | 4052 | if (args.raw_test || args.get_info_test || args.file_test || |
| 3452 | args.pprint_test || args.func_type_test) | 4053 | args.pprint_test || args.info_raw_test) |
| 3453 | goto done; | 4054 | goto done; |
| 3454 | 4055 | ||
| 3455 | err |= test_raw(); | 4056 | err |= test_raw(); |
| 3456 | err |= test_get_info(); | 4057 | err |= test_get_info(); |
| 3457 | err |= test_file(); | 4058 | err |= test_file(); |
| 4059 | err |= test_info_raw(); | ||
| 3458 | 4060 | ||
| 3459 | done: | 4061 | done: |
| 3460 | print_summary(); | 4062 | print_summary(); |