History

Merge branch 'bpf_line_info'

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 [...] ====================

Alexei Starovoitov committed 7 years ago

Commit ca5d1a72 parents 6baefa1 b053b4329 files · +2036 −388Browse files

Unified · Split

29 files
  1. arch/x86/net/bpf_jit_comp.c +2 −0
  2. include/linux/bpf.h +21 −0
  3. include/linux/bpf_verifier.h +1 −0
  4. include/linux/btf.h +1 −0
  5. include/linux/filter.h +7 −0
  6. include/uapi/linux/bpf.h +19 −0
  7. kernel/bpf/btf.c +1 −1
  8. kernel/bpf/core.c +116 −2
  9. kernel/bpf/syscall.c +77 −6
  10. kernel/bpf/verifier.c +174 −24
  11. tools/bpf/bpftool/Documentation/bpftool-prog.rst +12 −4
  12. tools/bpf/bpftool/bash-completion/bpftool +3 −3
  13. tools/bpf/bpftool/btf_dumper.c +64 −0
  14. tools/bpf/bpftool/jit_disasm.c +22 −1
  15. tools/bpf/bpftool/main.h +21 −2
  16. tools/bpf/bpftool/prog.c +90 −10
  17. tools/bpf/bpftool/xlated_dumper.c +28 −2
  18. tools/bpf/bpftool/xlated_dumper.h +5 −2
  19. tools/include/uapi/linux/bpf.h +19 −0
  20. tools/lib/bpf/Build +1 −1
  21. tools/lib/bpf/bpf.c +62 −31
  22. tools/lib/bpf/bpf.h +3 −0
  23. tools/lib/bpf/bpf_prog_linfo.c +253 −0
  24. tools/lib/bpf/btf.c +194 −148
  25. tools/lib/bpf/btf.h +12 −13
  26. tools/lib/bpf/libbpf.c +115 −44
  27. tools/lib/bpf/libbpf.h +13 −0
  28. tools/lib/bpf/libbpf.map +4 −0
  29. tools/testing/selftests/bpf/test_btf.c +696 −94
arch/x86/net/bpf_jit_comp.c+2−0
@@ -1181,6 +1181,8 @@ out_image: · 1180 unmodified lines
11811181 }
11821182
11831183 if (!image || !prog->is_func || extra_pass) {
1184+ if (image)
1185+ bpf_prog_fill_jited_linfo(prog, addrs);
11841186 out_addrs:
11851187 kfree(addrs);
11861188 kfree(jit_data);
include/linux/bpf.h+21−0
@@ -319,7 +319,28 @@ struct bpf_prog_aux { · 318 unmodified lines
319319 struct bpf_prog_offload *offload;
320320 struct btf *btf;
321321 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;
322337 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;
323344 union {
324345 struct work_struct work;
325346 struct rcu_head rcu;
include/linux/bpf_verifier.h+1−0
@@ -203,6 +203,7 @@ static inline bool bpf_verifier_log_needed(const struct bpf_verifier_log *log) · 202 unmodified lines
203203
204204 struct bpf_subprog_info {
205205 u32 start; /* insn idx of function entry point */
206+ u32 linfo_idx; /* The idx to the main_prog->aux->linfo */
206207 u16 stack_depth; /* max. stack depth used by this function */
207208 };
208209
include/linux/btf.h+1−0
@@ -46,6 +46,7 @@ void btf_type_seq_show(const struct btf *btf, u32 type_id, void *obj, · 45 unmodified lines
4646 struct seq_file *m);
4747 int btf_get_fd_by_id(u32 id);
4848 u32 btf_id(const struct btf *btf);
49+bool btf_name_offset_valid(const struct btf *btf, u32 offset);
4950
5051 #ifdef CONFIG_BPF_SYSCALL
5152 const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id);
include/linux/filter.h+7−0
@@ -718,6 +718,13 @@ void bpf_prog_free(struct bpf_prog *fp); · 717 unmodified lines
718718
719719 bool bpf_opcode_in_insntable(u8 code);
720720
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+
721728 struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags);
722729 struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
723730 gfp_t gfp_extra_flags);
include/uapi/linux/bpf.h+19−0
@@ -356,6 +356,9 @@ union bpf_attr { · 355 unmodified lines
356356 __u32 func_info_rec_size; /* userspace bpf_func_info size */
357357 __aligned_u64 func_info; /* func info */
358358 __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 */
359362 };
360363
361364 struct { /* anonymous struct used by BPF_OBJ_* commands */
@@ -2679,6 +2682,12 @@ struct bpf_prog_info { · 2317 unmodified lines
26792682 __u32 func_info_rec_size;
26802683 __aligned_u64 func_info;
26812684 __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;
26822691 } __attribute__((aligned(8)));
26832692
26842693 struct bpf_map_info {
@@ -2995,4 +3004,14 @@ struct bpf_func_info { · 310 unmodified lines
29953004 __u32 type_id;
29963005 };
29973006
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+
29983017 #endif /* _UAPI__LINUX_BPF_H__ */
kernel/bpf/btf.c+1−1
@@ -444,7 +444,7 @@ static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) · 443 unmodified lines
444444 return kind_ops[BTF_INFO_KIND(t->info)];
445445 }
446446
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)
448448 {
449449 return BTF_STR_OFFSET_VALID(offset) &&
450450 offset < btf->hdr.str_len;
kernel/bpf/core.c+116−2
@@ -105,6 +105,91 @@ struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags) · 104 unmodified lines
105105 }
106106 EXPORT_SYMBOL_GPL(bpf_prog_alloc);
107107
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+
108193 struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size,
109194 gfp_t gfp_extra_flags)
110195 {
@@ -294,6 +379,26 @@ static int bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta, · 183 unmodified lines
294379 return ret;
295380 }
296381
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+
297402 struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
298403 const struct bpf_insn *patch, u32 len)
299404 {
@@ -349,6 +454,8 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off, · 49 unmodified lines
349454 */
350455 BUG_ON(bpf_adj_branches(prog_adj, off, insn_delta, false));
351456
457+ bpf_adj_linfo(prog_adj, off, insn_delta);
458+
352459 return prog_adj;
353460 }
354461
@@ -1591,13 +1698,20 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err) · 1236 unmodified lines
15911698 * be JITed, but falls back to the interpreter.
15921699 */
15931700 if (!bpf_prog_is_dev_bound(fp->aux)) {
1701+ *err = bpf_prog_alloc_jited_linfo(fp);
1702+ if (*err)
1703+ return fp;
1704+
15941705 fp = bpf_int_jit_compile(fp);
1595−#ifdef CONFIG_BPF_JIT_ALWAYS_ON
15961706 if (!fp->jited) {
1707+ bpf_prog_free_jited_linfo(fp);
1708+#ifdef CONFIG_BPF_JIT_ALWAYS_ON
15971709 *err = -ENOTSUPP;
15981710 return fp;
1599− }
16001711 #endif
1712+ } else {
1713+ bpf_prog_free_unused_jited_linfo(fp);
1714+ }
16011715 } else {
16021716 *err = bpf_prog_offload_compile(fp);
16031717 if (*err)
kernel/bpf/syscall.c+77−6
@@ -1215,6 +1215,7 @@ static void __bpf_prog_put(struct bpf_prog *prog, bool do_idr_lock) · 1214 unmodified lines
12151215 bpf_prog_kallsyms_del_all(prog);
12161216 btf_put(prog->aux->btf);
12171217 kvfree(prog->aux->func_info);
1218+ bpf_prog_free_linfo(prog);
12181219
12191220 call_rcu(&prog->aux->rcu, __bpf_prog_put_rcu);
12201221 }
@@ -1439,7 +1440,7 @@ bpf_prog_load_check_attach_type(enum bpf_prog_type prog_type, · 218 unmodified lines
14391440 }
14401441
14411442 /* 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
14431444
14441445 static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr)
14451446 {
@@ -1560,6 +1561,7 @@ static int bpf_prog_load(union bpf_attr *attr, union bpf_attr __user *uattr) · 114 unmodified lines
15601561 return err;
15611562
15621563 free_used_maps:
1564+ bpf_prog_free_linfo(prog);
15631565 kvfree(prog->aux->func_info);
15641566 btf_put(prog->aux->btf);
15651567 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
20412043 return insns;
20422044 }
20432045
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+
20442077 static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
20452078 const union bpf_attr *attr,
20462079 union bpf_attr __user *uattr)
@@ -2083,11 +2116,9 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, · 36 unmodified lines
20832116 return -EFAULT;
20842117 }
20852118
2086− if ((info.func_info_cnt || info.func_info_rec_size) &&
2087− info.func_info_rec_size != sizeof(struct bpf_func_info))
2088− return -EINVAL;
2089−
2090− info.func_info_rec_size = sizeof(struct bpf_func_info);
2119+ err = set_info_rec_size(&info);
2120+ if (err)
2121+ return err;
20912122
20922123 if (!capable(CAP_SYS_ADMIN)) {
20932124 info.jited_prog_len = 0;
@@ -2095,6 +2126,8 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, · 1 unmodified line
20952126 info.nr_jited_ksyms = 0;
20962127 info.nr_jited_func_lens = 0;
20972128 info.func_info_cnt = 0;
2129+ info.line_info_cnt = 0;
2130+ info.jited_line_info_cnt = 0;
20982131 goto done;
20992132 }
21002133
@@ -2251,6 +2284,44 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog, · 150 unmodified lines
22512284 }
22522285 }
22532286
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+
22542325 done:
22552326 if (copy_to_user(uinfo, &info, info_len) ||
22562327 put_user(info_len, &uattr->info.info_len))
kernel/bpf/verifier.c+174−24
@@ -4640,15 +4640,17 @@ err_free: · 4639 unmodified lines
46404640 #define MIN_BPF_FUNCINFO_SIZE 8
46414641 #define MAX_FUNCINFO_REC_SIZE 252
46424642
4643−static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env,
4644− union bpf_attr *attr, union bpf_attr __user *uattr)
4643+static int check_btf_func(struct bpf_verifier_env *env,
4644+ const union bpf_attr *attr,
4645+ union bpf_attr __user *uattr)
46454646 {
46464647 u32 i, nfuncs, urec_size, min_size, prev_offset;
46474648 u32 krec_size = sizeof(struct bpf_func_info);
4648− struct bpf_func_info *krecord = NULL;
4649+ struct bpf_func_info *krecord;
46494650 const struct btf_type *type;
4651+ struct bpf_prog *prog;
4652+ const struct btf *btf;
46504653 void __user *urecord;
4651− struct btf *btf;
46524654 int ret = 0;
46534655
46544656 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
46684670 return -EINVAL;
46694671 }
46704672
4671− btf = btf_get_by_fd(attr->prog_btf_fd);
4672− if (IS_ERR(btf)) {
4673− verbose(env, "unable to get btf from fd\n");
4674− return PTR_ERR(btf);
4675− }
4673+ prog = env->prog;
4674+ btf = prog->aux->btf;
46764675
46774676 urecord = u64_to_user_ptr(attr->func_info);
46784677 min_size = min_t(u32, krec_size, urec_size);
46794678
46804679 krecord = kvcalloc(nfuncs, krec_size, GFP_KERNEL | __GFP_NOWARN);
4681− if (!krecord) {
4682− ret = -ENOMEM;
4683− goto free_btf;
4684− }
4680+ if (!krecord)
4681+ return -ENOMEM;
46854682
46864683 for (i = 0; i < nfuncs; i++) {
46874684 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
46944691 if (put_user(min_size, &uattr->func_info_rec_size))
46954692 ret = -EFAULT;
46964693 }
4697− goto free_btf;
4694+ goto err_free;
46984695 }
46994696
47004697 if (copy_from_user(&krecord[i], urecord, min_size)) {
47014698 ret = -EFAULT;
4702− goto free_btf;
4699+ goto err_free;
47034700 }
47044701
47054702 /* check insn_off */
@@ -4709,20 +4706,20 @@ static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env, · 3 unmodified lines
47094706 "nonzero insn_off %u for the first func info record",
47104707 krecord[i].insn_off);
47114708 ret = -EINVAL;
4712− goto free_btf;
4709+ goto err_free;
47134710 }
47144711 } else if (krecord[i].insn_off <= prev_offset) {
47154712 verbose(env,
47164713 "same or smaller insn offset (%u) than previous func info record (%u)",
47174714 krecord[i].insn_off, prev_offset);
47184715 ret = -EINVAL;
4719− goto free_btf;
4716+ goto err_free;
47204717 }
47214718
47224719 if (env->subprog_info[i].start != krecord[i].insn_off) {
47234720 verbose(env, "func_info BTF section doesn't match subprog layout in BPF program\n");
47244721 ret = -EINVAL;
4725− goto free_btf;
4722+ goto err_free;
47264723 }
47274724
47284725 /* check type_id */
@@ -4731,20 +4728,18 @@ static int check_btf_func(struct bpf_prog *prog, struct bpf_verifier_env *env, · 2 unmodified lines
47314728 verbose(env, "invalid type id %d in func info",
47324729 krecord[i].type_id);
47334730 ret = -EINVAL;
4734− goto free_btf;
4731+ goto err_free;
47354732 }
47364733
47374734 prev_offset = krecord[i].insn_off;
47384735 urecord += urec_size;
47394736 }
47404737
4741− prog->aux->btf = btf;
47424738 prog->aux->func_info = krecord;
47434739 prog->aux->func_info_cnt = nfuncs;
47444740 return 0;
47454741
4746−free_btf:
4747− btf_put(btf);
4742+err_free:
47484743 kvfree(krecord);
47494744 return ret;
47504745 }
@@ -4760,6 +4755,150 @@ static void adjust_btf_func(struct bpf_verifier_env *env) · 9 unmodified lines
47604755 env->prog->aux->func_info[i].insn_off = env->subprog_info[i].start;
47614756 }
47624757
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+
47634902 /* check %cur's range satisfies %old's */
47644903 static bool range_within(struct bpf_reg_state *old,
47654904 struct bpf_reg_state *cur)
@@ -6004,7 +6143,7 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 1238 unmodified lines
60046143 int i, j, subprog_start, subprog_end = 0, len, subprog;
60056144 struct bpf_insn *insn;
60066145 void *old_bpf_func;
6007− int err = -ENOMEM;
6146+ int err;
60086147
60096148 if (env->subprog_cnt <= 1)
60106149 return 0;
@@ -6035,6 +6174,11 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 24 unmodified lines
60356174 insn->imm = 1;
60366175 }
60376176
6177+ err = bpf_prog_alloc_jited_linfo(prog);
6178+ if (err)
6179+ goto out_undo_insn;
6180+
6181+ err = -ENOMEM;
60386182 func = kcalloc(env->subprog_cnt, sizeof(prog), GFP_KERNEL);
60396183 if (!func)
60406184 goto out_undo_insn;
@@ -6065,6 +6209,10 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 24 unmodified lines
60656209 func[i]->aux->name[0] = 'F';
60666210 func[i]->aux->stack_depth = env->subprog_info[i].stack_depth;
60676211 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;
60686216 func[i] = bpf_int_jit_compile(func[i]);
60696217 if (!func[i]->jited) {
60706218 err = -ENOTSUPP;
@@ -6138,6 +6286,7 @@ static int jit_subprogs(struct bpf_verifier_env *env) · 67 unmodified lines
61386286 prog->bpf_func = func[0]->bpf_func;
61396287 prog->aux->func = func;
61406288 prog->aux->func_cnt = env->subprog_cnt;
6289+ bpf_prog_free_unused_jited_linfo(prog);
61416290 return 0;
61426291 out_free:
61436292 for (i = 0; i < env->subprog_cnt; i++)
@@ -6154,6 +6303,7 @@ out_undo_insn: · 10 unmodified lines
61546303 insn->off = 0;
61556304 insn->imm = env->insn_aux_data[i].call_imm;
61566305 }
6306+ bpf_prog_free_jited_linfo(prog);
61576307 return err;
61586308 }
61596309
@@ -6526,7 +6676,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, · 366 unmodified lines
65266676 if (ret < 0)
65276677 goto skip_full_check;
65286678
6529− ret = check_btf_func(env->prog, env, attr, uattr);
6679+ ret = check_btf_info(env, attr, uattr);
65306680 if (ret < 0)
65316681 goto skip_full_check;
65326682
tools/bpf/bpftool/Documentation/bpftool-prog.rst+12−4
@@ -22,8 +22,8 @@ MAP COMMANDS · 21 unmodified lines
2222 =============
2323
2424 | **bpftool** **prog { show | list }** [*PROG*]
25−| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
26−| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
25+| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual** | **linum**}]
26+| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes** | **linum**}]
2727 | **bpftool** **prog pin** *PROG* *FILE*
2828 | **bpftool** **prog { load | loadall }** *OBJ* *PATH* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
2929 | **bpftool** **prog attach** *PROG* *ATTACH_TYPE* [*MAP*]
@@ -56,7 +56,7 @@ DESCRIPTION · 26 unmodified lines
5656 Output will start with program ID followed by program type and
5757 zero or more named attributes (depending on kernel version).
5858
59− **bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** }]
59+ **bpftool prog dump xlated** *PROG* [{ **file** *FILE* | **opcodes** | **visual** | **linum** }]
6060 Dump eBPF instructions of the program from the kernel. By
6161 default, eBPF will be disassembled and printed to standard
6262 output in human-readable format. In this case, **opcodes**
@@ -69,13 +69,21 @@ DESCRIPTION · 6 unmodified lines
6969 built instead, and eBPF instructions will be presented with
7070 CFG in DOT format, on standard output.
7171
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** }]
7377 Dump jited image (host machine code) of the program.
7478 If *FILE* is specified image will be written to a file,
7579 otherwise it will be disassembled and printed to stdout.
7680
7781 **opcodes** controls if raw opcodes will be printed.
7882
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.
7987 **bpftool prog pin** *PROG* *FILE*
8088 Pin program *PROG* as *FILE*.
8189
tools/bpf/bpftool/bash-completion/bpftool+3−3
@@ -191,7 +191,7 @@ _bpftool() · 190 unmodified lines
191191
192192 # Deal with simplest keywords
193193 case $prev in
194− help|hex|opcodes|visual)
194+ help|hex|opcodes|visual|linum)
195195 return 0
196196 ;;
197197 tag)
@@ -278,10 +278,10 @@ _bpftool() · 80 unmodified lines
278278 *)
279279 _bpftool_once_attr 'file'
280280 if _bpftool_search_list 'xlated'; then
281− COMPREPLY+=( $( compgen -W 'opcodes visual' -- \
281+ COMPREPLY+=( $( compgen -W 'opcodes visual linum' -- \
282282 "$cur" ) )
283283 else
284− COMPREPLY+=( $( compgen -W 'opcodes' -- \
284+ COMPREPLY+=( $( compgen -W 'opcodes linum' -- \
285285 "$cur" ) )
286286 fi
287287 return 0
tools/bpf/bpftool/btf_dumper.c+64−0
@@ -385,3 +385,67 @@ void btf_dumper_type_only(const struct btf *btf, __u32 type_id, char *func_sig, · 384 unmodified lines
385385 if (err < 0)
386386 func_sig[0] = '\0';
387387 }
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+}
tools/bpf/bpftool/jit_disasm.c+22−1
@@ -21,6 +21,7 @@ · 20 unmodified lines
2121 #include <dis-asm.h>
2222 #include <sys/stat.h>
2323 #include <limits.h>
24+#include <libbpf.h>
2425
2526 #include "json_writer.h"
2627 #include "main.h"
@@ -68,10 +69,16 @@ static int fprintf_json(void *out, const char *fmt, ...) · 41 unmodified lines
6869 }
6970
7071 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)
7277 {
78+ const struct bpf_line_info *linfo = NULL;
7379 disassembler_ftype disassemble;
7480 struct disassemble_info info;
81+ unsigned int nr_skip = 0;
7582 int count, i, pc = 0;
7683 char tpath[PATH_MAX];
7784 bfd *bfdf;
@@ -127,12 +134,26 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes, · 49 unmodified lines
127134 if (json_output)
128135 jsonw_start_array(json_wtr);
129136 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+
130146 if (json_output) {
131147 jsonw_start_object(json_wtr);
132148 oper_count = 0;
149+ if (linfo)
150+ btf_dump_linfo_json(btf, linfo, linum);
133151 jsonw_name(json_wtr, "pc");
134152 jsonw_printf(json_wtr, "\"0x%x\"", pc);
135153 } else {
154+ if (linfo)
155+ btf_dump_linfo_plain(btf, linfo, "; ",
156+ linum);
136157 printf("%4x:\t", pc);
137158 }
138159
tools/bpf/bpftool/main.h+21−2
@@ -138,6 +138,9 @@ struct pinned_obj { · 137 unmodified lines
138138 struct hlist_node hash;
139139 };
140140
141+struct btf;
142+struct bpf_line_info;
143+
141144 int build_pinned_obj_table(struct pinned_obj_table *table,
142145 enum bpf_obj_type type);
143146 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
175178 int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
176179
177180 #ifdef HAVE_LIBBFD_SUPPORT
181+struct bpf_prog_linfo;
178182 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);
180188 int disasm_init(void);
181189 #else
182190 static inline
183191 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+
185198 {
186199 }
187200 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
217230 void btf_dumper_type_only(const struct btf *btf, __u32 func_type_id,
218231 char *func_only, int size);
219232
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+
220239 struct nlattr;
221240 struct ifinfomsg;
222241 struct tcmsg;
tools/bpf/bpftool/prog.c+90−10
@@ -423,24 +423,26 @@ static int do_show(int argc, char **argv) · 422 unmodified lines
423423
424424 static int do_dump(int argc, char **argv)
425425 {
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;
426430 unsigned long *func_ksyms = NULL;
427431 struct bpf_prog_info info = {};
428432 unsigned int *func_lens = NULL;
429433 const char *disasm_opt = NULL;
430− unsigned int finfo_rec_size;
431434 unsigned int nr_func_ksyms;
432435 unsigned int nr_func_lens;
433436 struct dump_data dd = {};
434437 __u32 len = sizeof(info);
435438 struct btf *btf = NULL;
436− void *func_info = NULL;
437− unsigned int finfo_cnt;
438439 unsigned int buf_size;
439440 char *filepath = NULL;
440441 bool opcodes = false;
441442 bool visual = false;
442443 char func_sig[1024];
443444 unsigned char *buf;
445+ bool linum = false;
444446 __u32 *member_len;
445447 __u64 *member_ptr;
446448 ssize_t n;
@@ -484,6 +486,9 @@ static int do_dump(int argc, char **argv) · 37 unmodified lines
484486 } else if (is_prefix(*argv, "visual")) {
485487 visual = true;
486488 NEXT_ARG();
489+ } else if (is_prefix(*argv, "linum")) {
490+ linum = true;
491+ NEXT_ARG();
487492 }
488493
489494 if (argc) {
@@ -543,6 +548,32 @@ static int do_dump(int argc, char **argv) · 53 unmodified lines
543548 }
544549 }
545550
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+
546577 memset(&info, 0, sizeof(info));
547578
548579 *member_ptr = ptr_to_u64(buf);
@@ -554,6 +585,13 @@ static int do_dump(int argc, char **argv) · 5 unmodified lines
554585 info.func_info_cnt = finfo_cnt;
555586 info.func_info_rec_size = finfo_rec_size;
556587 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+
557595
558596 err = bpf_obj_get_info_by_fd(fd, &info, &len);
559597 close(fd);
@@ -596,6 +634,30 @@ static int do_dump(int argc, char **argv) · 36 unmodified lines
596634 finfo_cnt = 0;
597635 }
598636
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+
599661 if ((member_len == &info.jited_prog_len &&
600662 info.jited_prog_insns == 0) ||
601663 (member_len == &info.xlated_prog_len &&
@@ -609,6 +671,12 @@ static int do_dump(int argc, char **argv) · 7 unmodified lines
609671 goto err_free;
610672 }
611673
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+
612680 if (filepath) {
613681 fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600);
614682 if (fd < 0) {
@@ -690,8 +758,11 @@ static int do_dump(int argc, char **argv) · 75 unmodified lines
690758 printf("%s:\n", sym_name);
691759 }
692760
693− disasm_print_insn(img, lens[i], opcodes, name,
694− disasm_opt);
761+ disasm_print_insn(img, lens[i], opcodes,
762+ name, disasm_opt, btf,
763+ prog_linfo, ksyms[i], i,
764+ linum);
765+
695766 img += lens[i];
696767
697768 if (json_output)
@@ -704,7 +775,7 @@ static int do_dump(int argc, char **argv) · 6 unmodified lines
704775 jsonw_end_array(json_wtr);
705776 } else {
706777 disasm_print_insn(buf, *member_len, opcodes, name,
707− disasm_opt);
778+ disasm_opt, btf, NULL, 0, 0, false);
708779 }
709780 } else if (visual) {
710781 if (json_output)
@@ -718,11 +789,14 @@ static int do_dump(int argc, char **argv) · 7 unmodified lines
718789 dd.btf = btf;
719790 dd.func_info = func_info;
720791 dd.finfo_rec_size = finfo_rec_size;
792+ dd.prog_linfo = prog_linfo;
721793
722794 if (json_output)
723− dump_xlated_json(&dd, buf, *member_len, opcodes);
795+ dump_xlated_json(&dd, buf, *member_len, opcodes,
796+ linum);
724797 else
725− dump_xlated_plain(&dd, buf, *member_len, opcodes);
798+ dump_xlated_plain(&dd, buf, *member_len, opcodes,
799+ linum);
726800 kernel_syms_destroy(&dd);
727801 }
728802
@@ -730,6 +804,9 @@ static int do_dump(int argc, char **argv) · 1 unmodified line
730804 free(func_ksyms);
731805 free(func_lens);
732806 free(func_info);
807+ free(linfo);
808+ free(jited_linfo);
809+ bpf_prog_linfo__free(prog_linfo);
733810 return 0;
734811
735812 err_free:
@@ -737,6 +814,9 @@ err_free: · 1 unmodified line
737814 free(func_ksyms);
738815 free(func_lens);
739816 free(func_info);
817+ free(linfo);
818+ free(jited_linfo);
819+ bpf_prog_linfo__free(prog_linfo);
740820 return -1;
741821 }
742822
@@ -1138,8 +1218,8 @@ static int do_help(int argc, char **argv) · 395 unmodified lines
11381218
11391219 fprintf(stderr,
11401220 "Usage: %s %s { show | list } [PROG]\n"
1141− " %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
1142− " %s %s dump jited PROG [{ file FILE | opcodes }]\n"
1221+ " %s %s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n"
1222+ " %s %s dump jited PROG [{ file FILE | opcodes | linum }]\n"
11431223 " %s %s pin PROG FILE\n"
11441224 " %s %s { load | loadall } OBJ PATH \\\n"
11451225 " [type TYPE] [dev NAME] \\\n"
tools/bpf/bpftool/xlated_dumper.c+28−2
@@ -41,6 +41,7 @@ · 40 unmodified lines
4141 #include <stdlib.h>
4242 #include <string.h>
4343 #include <sys/types.h>
44+#include <libbpf.h>
4445
4546 #include "disasm.h"
4647 #include "json_writer.h"
@@ -234,8 +235,9 @@ static const char *print_imm(void *private_data, · 187 unmodified lines
234235 }
235236
236237 void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
237− bool opcodes)
238+ bool opcodes, bool linum)
238239 {
240+ const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo;
239241 const struct bpf_insn_cbs cbs = {
240242 .cb_print = print_insn_json,
241243 .cb_call = print_call,
@@ -246,6 +248,7 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, · 4 unmodified lines
246248 struct bpf_insn *insn = buf;
247249 struct btf *btf = dd->btf;
248250 bool double_insn = false;
251+ unsigned int nr_skip = 0;
249252 char func_sig[1024];
250253 unsigned int i;
251254
@@ -273,6 +276,16 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, · 21 unmodified lines
273276 }
274277 }
275278
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+
276289 jsonw_name(json_wtr, "disasm");
277290 print_bpf_insn(&cbs, insn + i, true);
278291
@@ -307,8 +320,9 @@ void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len, · 28 unmodified lines
307320 }
308321
309322 void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
310− bool opcodes)
323+ bool opcodes, bool linum)
311324 {
325+ const struct bpf_prog_linfo *prog_linfo = dd->prog_linfo;
312326 const struct bpf_insn_cbs cbs = {
313327 .cb_print = print_insn,
314328 .cb_call = print_call,
@@ -318,6 +332,7 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, · 3 unmodified lines
318332 struct bpf_func_info *record;
319333 struct bpf_insn *insn = buf;
320334 struct btf *btf = dd->btf;
335+ unsigned int nr_skip = 0;
321336 bool double_insn = false;
322337 char func_sig[1024];
323338 unsigned int i;
@@ -340,6 +355,17 @@ void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len, · 16 unmodified lines
340355 }
341356 }
342357
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+
343369 double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
344370
345371 printf("% 4d: ", i);
tools/bpf/bpftool/xlated_dumper.h+5−2
@@ -40,6 +40,8 @@ · 39 unmodified lines
4040
4141 #define SYM_MAX_NAME 256
4242
43+struct bpf_prog_linfo;
44+
4345 struct kernel_sym {
4446 unsigned long address;
4547 char name[SYM_MAX_NAME];
@@ -54,6 +56,7 @@ struct dump_data { · 8 unmodified lines
5456 struct btf *btf;
5557 void *func_info;
5658 __u32 finfo_rec_size;
59+ const struct bpf_prog_linfo *prog_linfo;
5760 char scratch_buff[SYM_MAX_NAME + 8];
5861 };
5962
@@ -61,9 +64,9 @@ void kernel_syms_load(struct dump_data *dd); · 1 unmodified line
6164 void kernel_syms_destroy(struct dump_data *dd);
6265 struct kernel_sym *kernel_syms_search(struct dump_data *dd, unsigned long key);
6366 void dump_xlated_json(struct dump_data *dd, void *buf, unsigned int len,
64− bool opcodes);
67+ bool opcodes, bool linum);
6568 void dump_xlated_plain(struct dump_data *dd, void *buf, unsigned int len,
66− bool opcodes);
69+ bool opcodes, bool linum);
6770 void dump_xlated_for_graph(struct dump_data *dd, void *buf, void *buf_end,
6871 unsigned int start_index);
6972
tools/include/uapi/linux/bpf.h+19−0
@@ -356,6 +356,9 @@ union bpf_attr { · 355 unmodified lines
356356 __u32 func_info_rec_size; /* userspace bpf_func_info size */
357357 __aligned_u64 func_info; /* func info */
358358 __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 */
359362 };
360363
361364 struct { /* anonymous struct used by BPF_OBJ_* commands */
@@ -2679,6 +2682,12 @@ struct bpf_prog_info { · 2317 unmodified lines
26792682 __u32 func_info_rec_size;
26802683 __aligned_u64 func_info;
26812684 __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;
26822691 } __attribute__((aligned(8)));
26832692
26842693 struct bpf_map_info {
@@ -2995,4 +3004,14 @@ struct bpf_func_info { · 310 unmodified lines
29953004 __u32 type_id;
29963005 };
29973006
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+
29983017 #endif /* _UAPI__LINUX_BPF_H__ */
tools/lib/bpf/Build+1−1
@@ -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
tools/lib/bpf/bpf.c+62−31
@@ -173,11 +173,36 @@ int bpf_create_map_in_map(enum bpf_map_type map_type, const char *name, · 172 unmodified lines
173173 -1);
174174 }
175175
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+
176201 int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
177202 char *log_buf, size_t log_buf_sz)
178203 {
204+ void *finfo = NULL, *linfo = NULL;
179205 union bpf_attr attr;
180− void *finfo = NULL;
181206 __u32 name_len;
182207 int fd;
183208
@@ -201,53 +226,58 @@ int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr, · 17 unmodified lines
201226 attr.func_info_rec_size = load_attr->func_info_rec_size;
202227 attr.func_info_cnt = load_attr->func_info_cnt;
203228 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);
204232 memcpy(attr.prog_name, load_attr->name,
205233 min(name_len, BPF_OBJ_NAME_LEN - 1));
206234
207235 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
208− if (fd >= 0 || !log_buf || !log_buf_sz)
236+ if (fd >= 0)
209237 return fd;
210238
211239 /* After bpf_prog_load, the kernel may modify certain attributes
212240 * to give user space a hint how to deal with loading failure.
213241 * Check to see whether we can make some changes and load again.
214242 */
215− if (errno == E2BIG && attr.func_info_cnt &&
216− attr.func_info_rec_size < load_attr->func_info_rec_size) {
217− __u32 actual_rec_size = load_attr->func_info_rec_size;
218− __u32 expected_rec_size = attr.func_info_rec_size;
219− __u32 finfo_cnt = load_attr->func_info_cnt;
220− __u64 finfo_len = actual_rec_size * finfo_cnt;
221− const void *orecord;
222− void *nrecord;
223− int i;
224−
225− finfo = malloc(finfo_len);
226− if (!finfo)
227− /* further try with log buffer won't help */
228− return fd;
229−
230− /* zero out bytes kernel does not understand */
231− orecord = load_attr->func_info;
232− nrecord = finfo;
233− for (i = 0; i < load_attr->func_info_cnt; i++) {
234− memcpy(nrecord, orecord, expected_rec_size);
235− memset(nrecord + expected_rec_size, 0,
236− actual_rec_size - expected_rec_size);
237− orecord += actual_rec_size;
238− nrecord += actual_rec_size;
243+ while (errno == E2BIG && (!finfo || !linfo)) {
244+ if (!finfo && attr.func_info_cnt &&
245+ attr.func_info_rec_size < load_attr->func_info_rec_size) {
246+ /* try with corrected func info records */
247+ finfo = alloc_zero_tailing_info(load_attr->func_info,
248+ load_attr->func_info_cnt,
249+ load_attr->func_info_rec_size,
250+ attr.func_info_rec_size);
251+ if (!finfo)
252+ goto done;
253+
254+ attr.func_info = ptr_to_u64(finfo);
255+ attr.func_info_rec_size = load_attr->func_info_rec_size;
256+ } else if (!linfo && attr.line_info_cnt &&
257+ attr.line_info_rec_size <
258+ load_attr->line_info_rec_size) {
259+ linfo = alloc_zero_tailing_info(load_attr->line_info,
260+ load_attr->line_info_cnt,
261+ load_attr->line_info_rec_size,
262+ attr.line_info_rec_size);
263+ if (!linfo)
264+ goto done;
265+
266+ attr.line_info = ptr_to_u64(linfo);
267+ attr.line_info_rec_size = load_attr->line_info_rec_size;
268+ } else {
269+ break;
239270 }
240271
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−
245272 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
246273
247− if (fd >= 0 || !log_buf || !log_buf_sz)
274+ if (fd >= 0)
248275 goto done;
249276 }
250277
278+ if (!log_buf || !log_buf_sz)
279+ goto done;
280+
251281 /* Try again with log */
252282 attr.log_buf = ptr_to_u64(log_buf);
253283 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
256286 fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
257287 done:
258288 free(finfo);
289+ free(linfo);
259290 return fd;
260291 }
261292
tools/lib/bpf/bpf.h+3−0
@@ -82,6 +82,9 @@ struct bpf_load_program_attr { · 81 unmodified lines
8282 __u32 func_info_rec_size;
8383 const void *func_info;
8484 __u32 func_info_cnt;
85+ __u32 line_info_rec_size;
86+ const void *line_info;
87+ __u32 line_info_cnt;
8588 };
8689
8790 /* Flags to direct loading requirements */
tools/lib/bpf/bpf_prog_linfo.c+253−0
@@ -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+}
tools/lib/bpf/btf.c+194−148
@@ -37,10 +37,27 @@ struct btf { · 36 unmodified lines
3737 int fd;
3838 };
3939
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+
4051 struct btf_ext {
41− void *func_info;
42− __u32 func_info_rec_size;
43− __u32 func_info_len;
52+ struct btf_ext_info func_info;
53+ struct btf_ext_info line_info;
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];
4461 };
4562
4663 /* The minimum bpf_func_info checked by the loader */
@@ -49,6 +66,14 @@ struct bpf_func_info_min { · 2 unmodified lines
4966 __u32 type_id;
5067 };
5168
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+
5277 static inline __u64 ptr_to_u64(const void *ptr)
5378 {
5479 return (__u64) (unsigned long) ptr;
@@ -479,71 +504,147 @@ exit_free: · 424 unmodified lines
479504 return err;
480505 }
481506
482−static int btf_ext_validate_func_info(const void *finfo, __u32 size,
483− btf_print_fn_t err_log)
507+struct btf_ext_sec_copy_param {
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)
484519 {
485− int sec_hdrlen = sizeof(struct btf_sec_func_info);
486− __u32 size_left, num_records, record_size;
487− const struct btf_sec_func_info *sinfo;
488− __u64 total_record_size;
489−
490− /* At least a func_info record size */
491− if (size < sizeof(__u32)) {
492− elog("BTF.ext func_info record size not found");
520+ const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
521+ const struct btf_ext_info_sec *sinfo;
522+ struct btf_ext_info *ext_info;
523+ __u32 info_left, record_size;
524+ /* The start of the info sec (including the __u32 record_size). */
525+ const void *info;
526+
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);
493534 return -EINVAL;
494535 }
495536
496− /* The record size needs to meet below minimum standard */
497− record_size = *(__u32 *)finfo;
498− if (record_size < sizeof(struct bpf_func_info_min) ||
499− record_size % sizeof(__u32)) {
500− elog("BTF.ext func_info invalid record size");
537+ if (data_size < ext_sec->off ||
538+ ext_sec->len > data_size - ext_sec->off) {
539+ elog("%s section (off:%u len:%u) is beyond the end of the ELF section .BTF.ext\n",
540+ ext_sec->desc, ext_sec->off, ext_sec->len);
501541 return -EINVAL;
502542 }
503543
504− sinfo = finfo + sizeof(__u32);
505− size_left = size - sizeof(__u32);
544+ info = data + ext_sec->off;
545+ info_left = ext_sec->len;
506546
507− /* If no func_info records, return failure now so .BTF.ext
508− * won't be used.
509− */
510− if (!size_left) {
511− elog("BTF.ext no func info records");
547+ /* At least a record size */
548+ if (info_left < sizeof(__u32)) {
549+ elog(".BTF.ext %s record size not found\n", ext_sec->desc);
550+ return -EINVAL;
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);
512559 return -EINVAL;
513560 }
514561
515− while (size_left) {
516− if (size_left < sec_hdrlen) {
517− elog("BTF.ext func_info header not found");
562+ sinfo = info + sizeof(__u32);
563+ info_left -= sizeof(__u32);
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);
518579 return -EINVAL;
519580 }
520581
521− num_records = sinfo->num_func_info;
582+ num_records = sinfo->num_info;
522583 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);
524586 return -EINVAL;
525587 }
526588
527589 total_record_size = sec_hdrlen +
528590 (__u64)num_records * record_size;
529− if (size_left < total_record_size) {
530− elog("incorrect BTF.ext num_func_info");
591+ if (info_left < total_record_size) {
592+ elog("%s section has incorrect num_records in .BTF.ext\n",
593+ ext_sec->desc);
531594 return -EINVAL;
532595 }
533596
534− size_left -= total_record_size;
597+ info_left -= total_record_size;
535598 sinfo = (void *)sinfo + total_record_size;
536599 }
537600
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+
538609 return 0;
539610 }
540611
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, &param, 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, &param, err_log);
642+}
643+
541644 static int btf_ext_parse_hdr(__u8 *data, __u32 data_size,
542645 btf_print_fn_t err_log)
543646 {
544647 const struct btf_ext_header *hdr = (struct btf_ext_header *)data;
545− __u32 meta_left, last_func_info_pos;
546− void *finfo;
547648
548649 if (data_size < offsetof(struct btf_ext_header, func_info_off) ||
549650 data_size < hdr->hdr_len) {
@@ -566,34 +667,12 @@ static int btf_ext_parse_hdr(__u8 *data, __u32 data_size, · 16 unmodified lines
566667 return -ENOTSUP;
567668 }
568669
569− meta_left = data_size - hdr->hdr_len;
570− if (!meta_left) {
670+ if (data_size == hdr->hdr_len) {
571671 elog("BTF.ext has no data\n");
572672 return -EINVAL;
573673 }
574674
575− if (meta_left < hdr->func_info_off) {
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);
675+ return 0;
597676 }
598677
599678 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
601680 if (!btf_ext)
602681 return;
603682
604− free(btf_ext->func_info);
683+ free(btf_ext->func_info.info);
684+ free(btf_ext->line_info.info);
605685 free(btf_ext);
606686 }
607687
608688 struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log)
609689 {
610− const struct btf_ext_header *hdr;
611690 struct btf_ext *btf_ext;
612− void *org_fdata, *fdata;
613− __u32 hdrlen, size_u32;
614691 int err;
615692
616693 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
621698 if (!btf_ext)
622699 return ERR_PTR(-ENOMEM);
623700
624− hdr = (const struct btf_ext_header *)data;
625− hdrlen = hdr->hdr_len;
626− size_u32 = sizeof(__u32);
627− fdata = malloc(hdr->func_info_len - size_u32);
628− if (!fdata) {
629− free(btf_ext);
630− return ERR_PTR(-ENOMEM);
701+ err = btf_ext_copy_func_info(btf_ext, data, size, err_log);
702+ if (err) {
703+ btf_ext__free(btf_ext);
704+ return ERR_PTR(err);
631705 }
632706
633− /* remember record size and copy rest of func_info data */
634− org_fdata = data + hdrlen + hdr->func_info_off;
635− btf_ext->func_info_rec_size = *(__u32 *)org_fdata;
636− memcpy(fdata, org_fdata + size_u32, hdr->func_info_len - size_u32);
637− btf_ext->func_info = fdata;
638− btf_ext->func_info_len = hdr->func_info_len - size_u32;
707+ err = btf_ext_copy_line_info(btf_ext, data, size, err_log);
708+ if (err) {
709+ btf_ext__free(btf_ext);
710+ return ERR_PTR(err);
711+ }
639712
640713 return btf_ext;
641714 }
642715
643−int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
644− const char *sec_name, void **func_info,
645− __u32 *func_info_rec_size, __u32 *func_info_len)
716+static int btf_ext_reloc_info(const struct btf *btf,
717+ const struct btf_ext_info *ext_info,
718+ const char *sec_name, __u32 insns_cnt,
719+ void **info, __u32 *cnt)
646720 {
647− __u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
648− __u32 i, record_size, records_len;
649− struct btf_sec_func_info *sinfo;
721+ __u32 sec_hdrlen = sizeof(struct btf_ext_info_sec);
722+ __u32 i, record_size, existing_len, records_len;
723+ struct btf_ext_info_sec *sinfo;
650724 const char *info_sec_name;
651− __s64 remain_len;
725+ __u64 remain_len;
652726 void *data;
653727
654− record_size = btf_ext->func_info_rec_size;
655− sinfo = btf_ext->func_info;
656− remain_len = btf_ext->func_info_len;
657−
728+ record_size = ext_info->rec_size;
729+ sinfo = ext_info->info;
730+ remain_len = ext_info->len;
658731 while (remain_len > 0) {
659− records_len = sinfo->num_func_info * record_size;
732+ records_len = sinfo->num_info * record_size;
660733 info_sec_name = btf__name_by_offset(btf, sinfo->sec_name_off);
661734 if (strcmp(info_sec_name, sec_name)) {
662735 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
664737 continue;
665738 }
666739
667− data = malloc(records_len);
740+ existing_len = (*cnt) * record_size;
741+ data = realloc(*info, existing_len + records_len);
668742 if (!data)
669743 return -ENOMEM;
670744
671− memcpy(data, sinfo->data, records_len);
672−
673− /* adjust the insn_off, the data in .BTF.ext is
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.
745+ memcpy(data + existing_len, sinfo->data, records_len);
746+ /* adjust insn_off only, the rest data will be passed
747+ * to the kernel.
679748 */
680− for (i = 0; i < sinfo->num_func_info; i++) {
681− struct bpf_func_info_min *record;
749+ for (i = 0; i < sinfo->num_info; i++) {
750+ __u32 *insn_off;
682751
683− record = data + i * record_size;
684− record->insn_off /= sizeof(struct bpf_insn);
752+ insn_off = data + existing_len + (i * record_size);
753+ *insn_off = *insn_off / sizeof(struct bpf_insn) +
754+ insns_cnt;
685755 }
686−
687− *func_info = data;
688− *func_info_len = records_len;
689− *func_info_rec_size = record_size;
756+ *info = data;
757+ *cnt += sinfo->num_info;
690758 return 0;
691759 }
692760
693− return -EINVAL;
761+ return -ENOENT;
694762 }
695763
696−int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
697− const char *sec_name, __u32 insns_cnt,
698− void **func_info, __u32 *func_info_len)
764+int btf_ext__reloc_func_info(const struct btf *btf, const struct btf_ext *btf_ext,
765+ const char *sec_name, __u32 insns_cnt,
766+ void **func_info, __u32 *cnt)
699767 {
700− __u32 sec_hdrlen = sizeof(struct btf_sec_func_info);
701− __u32 i, record_size, existing_flen, records_len;
702− struct btf_sec_func_info *sinfo;
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;
768+ return btf_ext_reloc_info(btf, &btf_ext->func_info, sec_name,
769+ insns_cnt, func_info, cnt);
770+}
723771
724− memcpy(data + existing_flen, sinfo->data, records_len);
725− /* adjust insn_off only, the rest data will be passed
726− * to the kernel.
727− */
728− for (i = 0; i < sinfo->num_func_info; i++) {
729− struct bpf_func_info_min *record;
772+int btf_ext__reloc_line_info(const struct btf *btf, const struct btf_ext *btf_ext,
773+ const char *sec_name, __u32 insns_cnt,
774+ void **line_info, __u32 *cnt)
775+{
776+ return btf_ext_reloc_info(btf, &btf_ext->line_info, sec_name,
777+ insns_cnt, line_info, cnt);
778+}
730779
731− record = data + existing_flen + i * record_size;
732− record->insn_off =
733− record->insn_off / sizeof(struct bpf_insn) +
734− insns_cnt;
735− }
736− *func_info = data;
737− *func_info_len = existing_flen + records_len;
738− return 0;
739− }
780+__u32 btf_ext__func_info_rec_size(const struct btf_ext *btf_ext)
781+{
782+ return btf_ext->func_info.rec_size;
783+}
740784
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;
742788 }
tools/lib/bpf/btf.h+12−13
@@ -51,13 +51,8 @@ struct btf_ext_header { · 50 unmodified lines
5151 /* All offsets are in bytes relative to the end of this header */
5252 __u32 func_info_off;
5353 __u32 func_info_len;
54−};
55−
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];
54+ __u32 line_info_off;
55+ __u32 line_info_len;
6156 };
6257
6358 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
7772
7873 struct btf_ext *btf_ext__new(__u8 *data, __u32 size, btf_print_fn_t err_log);
7974 void btf_ext__free(struct btf_ext *btf_ext);
80−int btf_ext__reloc_init(struct btf *btf, struct btf_ext *btf_ext,
81− const char *sec_name, void **func_info,
82− __u32 *func_info_rec_size, __u32 *func_info_len);
83−int btf_ext__reloc(struct btf *btf, struct btf_ext *btf_ext,
84− const char *sec_name, __u32 insns_cnt, void **func_info,
85− __u32 *func_info_len);
75+int btf_ext__reloc_func_info(const struct btf *btf,
76+ const struct btf_ext *btf_ext,
77+ const char *sec_name, __u32 insns_cnt,
78+ void **func_info, __u32 *func_info_len);
79+int btf_ext__reloc_line_info(const struct btf *btf,
80+ const struct btf_ext *btf_ext,
81+ const char *sec_name, __u32 insns_cnt,
82+ void **line_info, __u32 *cnt);
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);
8685
8786 #ifdef __cplusplus
8887 } /* extern "C" */
tools/lib/bpf/libbpf.c+115−44
@@ -167,9 +167,13 @@ struct bpf_program { · 166 unmodified lines
167167 int btf_fd;
168168 void *func_info;
169169 __u32 func_info_rec_size;
170− __u32 func_info_len;
170+ __u32 func_info_cnt;
171171
172172 struct bpf_capabilities *caps;
173+
174+ void *line_info;
175+ __u32 line_info_rec_size;
176+ __u32 line_info_cnt;
173177 };
174178
175179 struct bpf_map {
@@ -779,6 +783,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) · 603 unmodified lines
779783 {
780784 Elf *elf = obj->efile.elf;
781785 GElf_Ehdr *ep = &obj->efile.ehdr;
786+ Elf_Data *btf_ext_data = NULL;
782787 Elf_Scn *scn = NULL;
783788 int idx = 0, err = 0;
784789
@@ -841,14 +846,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags) · 56 unmodified lines
841846 obj->btf = NULL;
842847 }
843848 } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) {
844− obj->btf_ext = btf_ext__new(data->d_buf, data->d_size,
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− }
849+ btf_ext_data = data;
852850 } else if (sh.sh_type == SHT_SYMTAB) {
853851 if (obj->efile.symbols) {
854852 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
910908 pr_warning("Corrupted ELF file: index of strtab invalid\n");
911909 return LIBBPF_ERRNO__FORMAT;
912910 }
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+ }
913927 if (obj->efile.maps_shndx >= 0) {
914928 err = bpf_object__init_maps(obj, flags);
915929 if (err)
@@ -1275,6 +1289,82 @@ bpf_object__create_maps(struct bpf_object *obj) · 359 unmodified lines
12751289 return 0;
12761290 }
12771291
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+
12781368 static int
12791369 bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
12801370 struct reloc_desc *relo)
@@ -1306,17 +1396,12 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj, · 25 unmodified lines
13061396 return -ENOMEM;
13071397 }
13081398
1309− if (obj->btf && obj->btf_ext) {
1310− err = btf_ext__reloc(obj->btf, obj->btf_ext,
1311− text->section_name,
1312− prog->insns_cnt,
1313− &prog->func_info,
1314− &prog->func_info_len);
1315− if (err) {
1316− pr_warning("error in btf_ext__reloc for sec %s\n",
1317− text->section_name);
1399+ if (obj->btf_ext) {
1400+ err = bpf_program_reloc_btf_ext(prog, obj,
1401+ text->section_name,
1402+ prog->insns_cnt);
1403+ if (err)
13181404 return err;
1319− }
13201405 }
13211406
13221407 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
13411426 if (!prog)
13421427 return 0;
13431428
1344− if (obj->btf && obj->btf_ext) {
1345− err = btf_ext__reloc_init(obj->btf, obj->btf_ext,
1346− prog->section_name,
1347− &prog->func_info,
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);
1429+ if (obj->btf_ext) {
1430+ err = bpf_program_reloc_btf_ext(prog, obj,
1431+ prog->section_name, 0);
1432+ if (err)
13531433 return err;
1354− }
1355− prog->btf_fd = btf__fd(obj->btf);
13561434 }
13571435
13581436 if (!prog->reloc_desc)
@@ -1444,8 +1522,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj) · 85 unmodified lines
14441522
14451523 static int
14461524 load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt,
1447− char *license, __u32 kern_version, int *pfd,
1448− __u32 func_info_cnt)
1525+ char *license, __u32 kern_version, int *pfd)
14491526 {
14501527 struct bpf_load_program_attr load_attr;
14511528 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
14651542 load_attr.prog_btf_fd = prog->btf_fd >= 0 ? prog->btf_fd : 0;
14661543 load_attr.func_info = prog->func_info;
14671544 load_attr.func_info_rec_size = prog->func_info_rec_size;
1468− load_attr.func_info_cnt = func_info_cnt;
1469−
1545+ load_attr.func_info_cnt = prog->func_info_cnt;
1546+ load_attr.line_info = prog->line_info;
1547+ load_attr.line_info_rec_size = prog->line_info_rec_size;
1548+ load_attr.line_info_cnt = prog->line_info_cnt;
14701549 if (!load_attr.insns || !load_attr.insns_cnt)
14711550 return -EINVAL;
14721551
@@ -1523,14 +1602,8 @@ int · 50 unmodified lines
15231602 bpf_program__load(struct bpf_program *prog,
15241603 char *license, __u32 kern_version)
15251604 {
1526− __u32 func_info_cnt;
15271605 int err = 0, fd, i;
15281606
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−
15341607 if (prog->instances.nr < 0 || !prog->instances.fds) {
15351608 if (prog->preprocessor) {
15361609 pr_warning("Internal error: can't load program '%s'\n",
@@ -1553,8 +1626,7 @@ bpf_program__load(struct bpf_program *prog, · 16 unmodified lines
15531626 prog->section_name, prog->instances.nr);
15541627 }
15551628 err = load_program(prog, prog->insns, prog->insns_cnt,
1556− license, kern_version, &fd,
1557− func_info_cnt);
1629+ license, kern_version, &fd);
15581630 if (!err)
15591631 prog->instances.fds[0] = fd;
15601632 goto out;
@@ -1584,8 +1656,7 @@ bpf_program__load(struct bpf_program *prog, · 23 unmodified lines
15841656
15851657 err = load_program(prog, result.new_insn_ptr,
15861658 result.new_insn_cnt,
1587− license, kern_version, &fd,
1588− func_info_cnt);
1659+ license, kern_version, &fd);
15891660
15901661 if (err) {
15911662 pr_warning("Loading the %dth instance of program '%s' failed\n",
tools/lib/bpf/libbpf.h+13−0
@@ -342,6 +342,19 @@ int libbpf_nl_get_qdisc(int sock, unsigned int nl_pid, int ifindex, · 341 unmodified lines
342342 int libbpf_nl_get_filter(int sock, unsigned int nl_pid, int ifindex, int handle,
343343 libbpf_dump_nlmsg_t dump_filter_nlmsg, void *cookie);
344344
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+
345358 #ifdef __cplusplus
346359 } /* extern "C" */
347360 #endif
tools/lib/bpf/libbpf.map+4−0
@@ -99,6 +99,10 @@ LIBBPF_0.0.1 { · 98 unmodified lines
9999 bpf_program__unload;
100100 bpf_program__unpin;
101101 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;
102106 bpf_raw_tracepoint_open;
103107 bpf_set_link_xdp_fd;
104108 bpf_task_fd_query;
tools/testing/selftests/bpf/test_btf.c+696−94
@@ -6,6 +6,7 @@ · 5 unmodified lines
66 #include <linux/err.h>
77 #include <linux/kernel.h>
88 #include <linux/filter.h>
9+#include <linux/unistd.h>
910 #include <bpf/bpf.h>
1011 #include <sys/resource.h>
1112 #include <libelf.h>
@@ -107,19 +108,20 @@ static int __base_pr(const char *format, ...) · 95 unmodified lines
107108 #define BTF_END_RAW 0xdeadbeef
108109 #define NAME_TBD 0xdeadb33f
109110
110−#define MAX_NR_RAW_TYPES 1024
111+#define MAX_NR_RAW_U32 1024
111112 #define BTF_LOG_BUF_SIZE 65535
112113
113114 static struct args {
114115 unsigned int raw_test_num;
115116 unsigned int file_test_num;
116117 unsigned int get_info_test_num;
118+ unsigned int info_raw_test_num;
117119 bool raw_test;
118120 bool file_test;
119121 bool get_info_test;
120122 bool pprint_test;
121123 bool always_log;
122− bool func_type_test;
124+ bool info_raw_test;
123125 } args;
124126
125127 static char btf_log_buf[BTF_LOG_BUF_SIZE];
@@ -135,7 +137,7 @@ struct btf_raw_test { · 9 unmodified lines
135137 const char *str_sec;
136138 const char *map_name;
137139 const char *err_str;
138− __u32 raw_types[MAX_NR_RAW_TYPES];
140+ __u32 raw_types[MAX_NR_RAW_U32];
139141 __u32 str_sec_size;
140142 enum bpf_map_type map_type;
141143 __u32 key_size;
@@ -154,6 +156,9 @@ struct btf_raw_test { · 12 unmodified lines
154156 int str_len_delta;
155157 };
156158
159+#define BTF_STR_SEC(str) \
160+ .str_sec = str, .str_sec_size = sizeof(str)
161+
157162 static struct btf_raw_test raw_tests[] = {
158163 /* enum E {
159164 * E0,
@@ -1856,11 +1861,11 @@ static const char *get_next_str(const char *start, const char *end) · 1696 unmodified lines
18561861 return start < end - 1 ? start + 1 : NULL;
18571862 }
18581863
1859−static int get_type_sec_size(const __u32 *raw_types)
1864+static int get_raw_sec_size(const __u32 *raw_types)
18601865 {
18611866 int i;
18621867
1863− for (i = MAX_NR_RAW_TYPES - 1;
1868+ for (i = MAX_NR_RAW_U32 - 1;
18641869 i >= 0 && raw_types[i] != BTF_END_RAW;
18651870 i--)
18661871 ;
@@ -1872,7 +1877,8 @@ static void *btf_raw_create(const struct btf_header *hdr, · 5 unmodified lines
18721877 const __u32 *raw_types,
18731878 const char *str,
18741879 unsigned int str_sec_size,
1875− unsigned int *btf_size)
1880+ unsigned int *btf_size,
1881+ const char **ret_next_str)
18761882 {
18771883 const char *next_str = str, *end_str = str + str_sec_size;
18781884 unsigned int size_needed, offset;
@@ -1881,7 +1887,7 @@ static void *btf_raw_create(const struct btf_header *hdr, · 2 unmodified lines
18811887 uint32_t *ret_types;
18821888 void *raw_btf;
18831889
1884− type_sec_size = get_type_sec_size(raw_types);
1890+ type_sec_size = get_raw_sec_size(raw_types);
18851891 if (CHECK(type_sec_size < 0, "Cannot get nr_raw_types"))
18861892 return NULL;
18871893
@@ -1920,6 +1926,8 @@ static void *btf_raw_create(const struct btf_header *hdr, · 32 unmodified lines
19201926 ret_hdr->str_len = str_sec_size;
19211927
19221928 *btf_size = size_needed;
1929+ if (ret_next_str)
1930+ *ret_next_str = next_str;
19231931
19241932 return raw_btf;
19251933 }
@@ -1939,7 +1947,7 @@ static int do_test_raw(unsigned int test_num) · 13 unmodified lines
19391947 test->raw_types,
19401948 test->str_sec,
19411949 test->str_sec_size,
1942− &raw_btf_size);
1950+ &raw_btf_size, NULL);
19431951
19441952 if (!raw_btf)
19451953 return -1;
@@ -2016,7 +2024,7 @@ static int test_raw(void) · 70 unmodified lines
20162024 struct btf_get_info_test {
20172025 const char *descr;
20182026 const char *str_sec;
2019− __u32 raw_types[MAX_NR_RAW_TYPES];
2027+ __u32 raw_types[MAX_NR_RAW_U32];
20202028 __u32 str_sec_size;
20212029 int btf_size_delta;
20222030 int (*special_test)(unsigned int test_num);
@@ -2096,7 +2104,7 @@ static int test_big_btf_info(unsigned int test_num) · 73 unmodified lines
20962104 test->raw_types,
20972105 test->str_sec,
20982106 test->str_sec_size,
2099− &raw_btf_size);
2107+ &raw_btf_size, NULL);
21002108
21012109 if (!raw_btf)
21022110 return -1;
@@ -2180,7 +2188,7 @@ static int test_btf_id(unsigned int test_num) · 77 unmodified lines
21802188 test->raw_types,
21812189 test->str_sec,
21822190 test->str_sec_size,
2183− &raw_btf_size);
2191+ &raw_btf_size, NULL);
21842192
21852193 if (!raw_btf)
21862194 return -1;
@@ -2318,7 +2326,7 @@ static int do_test_get_info(unsigned int test_num) · 131 unmodified lines
23182326 test->raw_types,
23192327 test->str_sec,
23202328 test->str_sec_size,
2321− &raw_btf_size);
2329+ &raw_btf_size, NULL);
23222330
23232331 if (!raw_btf)
23242332 return -1;
@@ -2847,7 +2855,7 @@ static int do_test_pprint(void) · 522 unmodified lines
28472855 fprintf(stderr, "%s......", test->descr);
28482856 raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
28492857 test->str_sec, test->str_sec_size,
2850− &raw_btf_size);
2858+ &raw_btf_size, NULL);
28512859
28522860 if (!raw_btf)
28532861 return -1;
@@ -3051,18 +3059,25 @@ static int test_pprint(void) · 197 unmodified lines
30513059 return err;
30523060 }
30533061
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 {
30553066 const char *descr;
30563067 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];
30583070 __u32 str_sec_size;
30593071 struct bpf_insn insns[MAX_INSNS];
30603072 __u32 prog_type;
30613073 __u32 func_info[MAX_SUBPROGS][2];
30623074 __u32 func_info_rec_size;
30633075 __u32 func_info_cnt;
3076+ __u32 line_info[MAX_NR_RAW_U32];
3077+ __u32 line_info_rec_size;
3078+ __u32 nr_jited_ksyms;
30643079 bool expected_prog_load_failure;
3065−} func_type_test[] = {
3080+} info_raw_tests[] = {
30663081 {
30673082 .descr = "func_type (main func + one sub)",
30683083 .raw_types = {
@@ -3091,6 +3106,7 @@ static struct btf_func_type_test { · 22 unmodified lines
30913106 .func_info = { {0, 5}, {3, 6} },
30923107 .func_info_rec_size = 8,
30933108 .func_info_cnt = 2,
3109+ .line_info = { BTF_END_RAW },
30943110 },
30953111
30963112 {
@@ -3121,6 +3137,7 @@ static struct btf_func_type_test { · 24 unmodified lines
31213137 .func_info = { {0, 5}, {3, 6} },
31223138 .func_info_rec_size = 4,
31233139 .func_info_cnt = 2,
3140+ .line_info = { BTF_END_RAW },
31243141 .expected_prog_load_failure = true,
31253142 },
31263143
@@ -3152,6 +3169,7 @@ static struct btf_func_type_test { · 25 unmodified lines
31523169 .func_info = { {0, 5}, {3, 6} },
31533170 .func_info_rec_size = 8,
31543171 .func_info_cnt = 1,
3172+ .line_info = { BTF_END_RAW },
31553173 .expected_prog_load_failure = true,
31563174 },
31573175
@@ -3183,6 +3201,278 @@ static struct btf_func_type_test { · 25 unmodified lines
31833201 .func_info = { {0, 5}, {2, 6} },
31843202 .func_info_rec_size = 8,
31853203 .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",
31863476 .expected_prog_load_failure = true,
31873477 },
31883478
@@ -3198,90 +3488,84 @@ static size_t probe_prog_length(const struct bpf_insn *fp) · 9 unmodified lines
31983488 return len + 1;
31993489 }
32003490
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)
32023495 {
3203− const struct btf_func_type_test *test = &func_type_test[test_num];
3204− unsigned int raw_btf_size, info_len, rec_size;
3205− int i, btf_fd = -1, prog_fd = -1, err = 0;
3206− struct bpf_load_program_attr attr = {};
3207− void *raw_btf, *func_info = NULL;
3208− struct bpf_prog_info info = {};
3209− struct bpf_func_info *finfo;
3496+ int i, raw_u32_size = get_raw_sec_size(raw_u32);
3497+ const char *end_str = str + str_sec_size;
3498+ const char *next_str = str + str_off;
3499+ __u32 *new_u32 = NULL;
32103500
3211− fprintf(stderr, "%s......", test->descr);
3212− raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
3213− test->str_sec, test->str_sec_size,
3214− &raw_btf_size);
3501+ if (raw_u32_size == -1)
3502+ return ERR_PTR(-EINVAL);
32153503
3216− if (!raw_btf)
3217− return -1;
3504+ if (!raw_u32_size) {
3505+ *ret_size = 0;
3506+ return NULL;
3507+ }
32183508
3219− *btf_log_buf = '\0';
3220− btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
3221− btf_log_buf, BTF_LOG_BUF_SIZE,
3222− args.always_log);
3223− free(raw_btf);
3509+ new_u32 = malloc(raw_u32_size);
3510+ if (!new_u32)
3511+ return ERR_PTR(-ENOMEM);
32243512
3225− if (CHECK(btf_fd == -1, "invalid btf_fd errno:%d", errno)) {
3226− err = -1;
3227− goto done;
3513+ for (i = 0; i < raw_u32_size / sizeof(raw_u32[0]); i++) {
3514+ if (raw_u32[i] == NAME_TBD) {
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+ }
32283525 }
32293526
3230− if (*btf_log_buf && args.always_log)
3231− fprintf(stderr, "\n%s", btf_log_buf);
3232−
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;
3527+ *ret_size = raw_u32_size;
3528+ return new_u32;
3529+}
32413530
3242− *btf_log_buf = '\0';
3243− prog_fd = bpf_load_program_xattr(&attr, btf_log_buf,
3244− BTF_LOG_BUF_SIZE);
3245− if (test->expected_prog_load_failure && prog_fd == -1) {
3246− err = 0;
3247− goto done;
3248− }
3249− if (CHECK(prog_fd == -1, "invalid prog_id errno:%d", errno)) {
3250− fprintf(stderr, "%s\n", btf_log_buf);
3251− err = -1;
3252− goto done;
3253− }
3531+static int test_get_finfo(const struct prog_info_raw_test *test,
3532+ int prog_fd)
3533+{
3534+ struct bpf_prog_info info = {};
3535+ struct bpf_func_info *finfo;
3536+ __u32 info_len, rec_size, i;
3537+ void *func_info = NULL;
3538+ int err;
32543539
32553540 /* get necessary lens */
32563541 info_len = sizeof(struct bpf_prog_info);
32573542 err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
32583543 if (CHECK(err == -1, "invalid get info (1st) errno:%d", errno)) {
32593544 fprintf(stderr, "%s\n", btf_log_buf);
3260− err = -1;
3261− goto done;
3545+ return -1;
32623546 }
3263− if (CHECK(info.func_info_cnt != 2,
3264− "incorrect info.func_info_cnt (1st) %d\n",
3547+ if (CHECK(info.func_info_cnt != test->func_info_cnt,
3548+ "incorrect info.func_info_cnt (1st) %d",
32653549 info.func_info_cnt)) {
3266− err = -1;
3267− goto done;
3550+ return -1;
32683551 }
3552+
32693553 rec_size = info.func_info_rec_size;
3270− if (CHECK(rec_size < 4,
3271− "incorrect info.func_info_rec_size (1st) %d\n", rec_size)) {
3272− err = -1;
3273− goto done;
3554+ if (CHECK(rec_size < 8,
3555+ "incorrect info.func_info_rec_size (1st) %d", rec_size)) {
3556+ return -1;
32743557 }
32753558
3559+ if (!info.func_info_cnt)
3560+ return 0;
3561+
32763562 func_info = malloc(info.func_info_cnt * rec_size);
3277− if (CHECK(!func_info, "out of memory")) {
3278− err = -1;
3279− goto done;
3280− }
3563+ if (CHECK(!func_info, "out of memory"))
3564+ return -1;
32813565
32823566 /* reset info to only retrieve func_info related data */
32833567 memset(&info, 0, sizeof(info));
3284− info.func_info_cnt = 2;
3568+ info.func_info_cnt = test->func_info_cnt;
32853569 info.func_info_rec_size = rec_size;
32863570 info.func_info = ptr_to_u64(func_info);
32873571 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
32903574 err = -1;
32913575 goto done;
32923576 }
3293− if (CHECK(info.func_info_cnt != 2,
3294− "incorrect info.func_info_cnt (2nd) %d\n",
3577+ if (CHECK(info.func_info_cnt != test->func_info_cnt,
3578+ "incorrect info.func_info_cnt (2nd) %d",
32953579 info.func_info_cnt)) {
32963580 err = -1;
32973581 goto done;
32983582 }
3299− if (CHECK(info.func_info_rec_size != rec_size,
3300− "incorrect info.func_info_rec_size (2nd) %d\n",
3583+ if (CHECK(info.func_info_rec_size < 8,
3584+ "incorrect info.func_info_rec_size (2nd) %d",
33013585 info.func_info_rec_size)) {
33023586 err = -1;
33033587 goto done;
@@ -3310,7 +3594,7 @@ static int do_test_func_type(int test_num) · 6 unmodified lines
33103594 }
33113595
33123596 finfo = func_info;
3313− for (i = 0; i < 2; i++) {
3597+ for (i = 0; i < test->func_info_cnt; i++) {
33143598 if (CHECK(finfo->type_id != test->func_info[i][1],
33153599 "incorrect func_type %u expected %u",
33163600 finfo->type_id, test->func_info[i][1])) {
@@ -3320,7 +3604,307 @@ static int do_test_func_type(int test_num) · 3 unmodified lines
33203604 finfo = (void *)finfo + rec_size;
33213605 }
33223606
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+
33233816 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+
33243908 if (*btf_log_buf && (err || args.always_log))
33253909 fprintf(stderr, "\n%s", btf_log_buf);
33263910
@@ -3328,33 +3912,41 @@ done: · 1 unmodified line
33283912 close(btf_fd);
33293913 if (prog_fd != -1)
33303914 close(prog_fd);
3331− free(func_info);
3915+
3916+ if (!IS_ERR(patched_linfo))
3917+ free(patched_linfo);
3918+
33323919 return err;
33333920 }
33343921
3335−static int test_func_type(void)
3922+static int test_info_raw(void)
33363923 {
33373924 unsigned int i;
33383925 int err = 0;
33393926
3340− for (i = 0; i < ARRAY_SIZE(func_type_test); i++)
3341− err |= count_result(do_test_func_type(i));
3927+ if (args.info_raw_test_num)
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));
33423932
33433933 return err;
33443934 }
33453935
33463936 static void usage(const char *cmd)
33473937 {
3348− fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] |"
3349− " [-g test_num (1 - %zu)] |"
3350− " [-f test_num (1 - %zu)] | [-p] | [-k] ]\n",
3938+ fprintf(stderr, "Usage: %s [-l] [[-r btf_raw_test_num (1 - %zu)] |\n"
3939+ "\t[-g btf_get_info_test_num (1 - %zu)] |\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",
33513943 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));
33533945 }
33543946
33553947 static int parse_args(int argc, char **argv)
33563948 {
3357− const char *optstr = "lpkf:r:g:";
3949+ const char *optstr = "lpk:f:r:g:";
33583950 int opt;
33593951
33603952 while ((opt = getopt(argc, argv, optstr)) != -1) {
@@ -3378,7 +3970,8 @@ static int parse_args(int argc, char **argv) · 17 unmodified lines
33783970 args.pprint_test = true;
33793971 break;
33803972 case 'k':
3381− args.func_type_test = true;
3973+ args.info_raw_test_num = atoi(optarg);
3974+ args.info_raw_test = true;
33823975 break;
33833976 case 'h':
33843977 usage(argv[0]);
@@ -3413,6 +4006,14 @@ static int parse_args(int argc, char **argv) · 28 unmodified lines
34134006 return -1;
34144007 }
34154008
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+
34164017 return 0;
34174018 }
34184019
@@ -3445,16 +4046,17 @@ int main(int argc, char **argv) · 26 unmodified lines
34454046 if (args.pprint_test)
34464047 err |= test_pprint();
34474048
3448− if (args.func_type_test)
3449− err |= test_func_type();
4049+ if (args.info_raw_test)
4050+ err |= test_info_raw();
34504051
34514052 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)
34534054 goto done;
34544055
34554056 err |= test_raw();
34564057 err |= test_get_info();
34574058 err |= test_file();
4059+ err |= test_info_raw();
34584060
34594061 done:
34604062 print_summary();

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t