aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/bpf_prog_linfo.c
diff options
context:
space:
mode:
authorMartin KaFai Lau <kafai@fb.com>2018-12-07 19:42:32 -0500
committerAlexei Starovoitov <ast@kernel.org>2018-12-09 16:54:38 -0500
commitb053b439b72ad152257ecc3f71cfb4c619b0137e (patch)
tree9cb7c5a026580ee81dff5af7fd84eee3eb2571a4 /tools/lib/bpf/bpf_prog_linfo.c
parent3d65014146c69bbc4d2947f60dbd722d352cdc46 (diff)
bpf: libbpf: bpftool: Print bpf_line_info during prog dump
This patch adds print bpf_line_info function in 'prog dump jitted' and 'prog dump xlated': [root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv [...] int test_long_fname_2(struct dummy_tracepoint_args * arg): bpf_prog_44a040bf25481309_test_long_fname_2: ; static int test_long_fname_2(struct dummy_tracepoint_args *arg) 0: push %rbp 1: mov %rsp,%rbp 4: sub $0x30,%rsp b: sub $0x28,%rbp f: mov %rbx,0x0(%rbp) 13: mov %r13,0x8(%rbp) 17: mov %r14,0x10(%rbp) 1b: mov %r15,0x18(%rbp) 1f: xor %eax,%eax 21: mov %rax,0x20(%rbp) 25: xor %esi,%esi ; int key = 0; 27: mov %esi,-0x4(%rbp) ; if (!arg->sock) 2a: mov 0x8(%rdi),%rdi ; if (!arg->sock) 2e: cmp $0x0,%rdi 32: je 0x0000000000000070 34: mov %rbp,%rsi ; counts = bpf_map_lookup_elem(&btf_map, &key); 37: add $0xfffffffffffffffc,%rsi 3b: movabs $0xffff8881139d7480,%rdi 45: add $0x110,%rdi 4c: mov 0x0(%rsi),%eax 4f: cmp $0x4,%rax 53: jae 0x000000000000005e 55: shl $0x3,%rax 59: add %rdi,%rax 5c: jmp 0x0000000000000060 5e: xor %eax,%eax ; if (!counts) 60: cmp $0x0,%rax 64: je 0x0000000000000070 ; counts->v6++; 66: mov 0x4(%rax),%edi 69: add $0x1,%rdi 6d: mov %edi,0x4(%rax) 70: mov 0x0(%rbp),%rbx 74: mov 0x8(%rbp),%r13 78: mov 0x10(%rbp),%r14 7c: mov 0x18(%rbp),%r15 80: add $0x28,%rbp 84: leaveq 85: retq [...] With linum: [root@arch-fb-vm1 bpf]# ~/devshare/fb-kernel/linux/tools/bpf/bpftool/bpftool prog dump jited pinned /sys/fs/bpf/test_btf_haskv linum int _dummy_tracepoint(struct dummy_tracepoint_args * arg): bpf_prog_b07ccb89267cf242__dummy_tracepoint: ; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:9] 0: push %rbp 1: mov %rsp,%rbp 4: sub $0x28,%rsp b: sub $0x28,%rbp f: mov %rbx,0x0(%rbp) 13: mov %r13,0x8(%rbp) 17: mov %r14,0x10(%rbp) 1b: mov %r15,0x18(%rbp) 1f: xor %eax,%eax 21: mov %rax,0x20(%rbp) 25: callq 0x000000000000851e ; return test_long_fname_1(arg); [file:/data/users/kafai/fb-kernel/linux/tools/testing/selftests/bpf/test_btf_haskv.c line_num:54 line_col:2] 2a: xor %eax,%eax 2c: mov 0x0(%rbp),%rbx 30: mov 0x8(%rbp),%r13 34: mov 0x10(%rbp),%r14 38: mov 0x18(%rbp),%r15 3c: add $0x28,%rbp 40: leaveq 41: retq [...] Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Yonghong Song <yhs@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/lib/bpf/bpf_prog_linfo.c')
-rw-r--r--tools/lib/bpf/bpf_prog_linfo.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/tools/lib/bpf/bpf_prog_linfo.c b/tools/lib/bpf/bpf_prog_linfo.c
new file mode 100644
index 000000000000..b8af65145408
--- /dev/null
+++ b/tools/lib/bpf/bpf_prog_linfo.c
@@ -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
14struct 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
25static 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
87errout:
88 return -EINVAL;
89}
90
91void 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
103struct 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
182err_free:
183 bpf_prog_linfo__free(prog_linfo);
184 return NULL;
185}
186
187const struct bpf_line_info *
188bpf_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
225const struct bpf_line_info *
226bpf_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}