1*f7c14bbaSAndroid Build Coastguard Worker // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2*f7c14bbaSAndroid Build Coastguard Worker /* Copyright (c) 2018 Facebook */
3*f7c14bbaSAndroid Build Coastguard Worker
4*f7c14bbaSAndroid Build Coastguard Worker #include <string.h>
5*f7c14bbaSAndroid Build Coastguard Worker #include <stdlib.h>
6*f7c14bbaSAndroid Build Coastguard Worker #include <linux/err.h>
7*f7c14bbaSAndroid Build Coastguard Worker #include <linux/bpf.h>
8*f7c14bbaSAndroid Build Coastguard Worker #include "libbpf.h"
9*f7c14bbaSAndroid Build Coastguard Worker #include "libbpf_internal.h"
10*f7c14bbaSAndroid Build Coastguard Worker
11*f7c14bbaSAndroid Build Coastguard Worker struct bpf_prog_linfo {
12*f7c14bbaSAndroid Build Coastguard Worker void *raw_linfo;
13*f7c14bbaSAndroid Build Coastguard Worker void *raw_jited_linfo;
14*f7c14bbaSAndroid Build Coastguard Worker __u32 *nr_jited_linfo_per_func;
15*f7c14bbaSAndroid Build Coastguard Worker __u32 *jited_linfo_func_idx;
16*f7c14bbaSAndroid Build Coastguard Worker __u32 nr_linfo;
17*f7c14bbaSAndroid Build Coastguard Worker __u32 nr_jited_func;
18*f7c14bbaSAndroid Build Coastguard Worker __u32 rec_size;
19*f7c14bbaSAndroid Build Coastguard Worker __u32 jited_rec_size;
20*f7c14bbaSAndroid Build Coastguard Worker };
21*f7c14bbaSAndroid Build Coastguard Worker
dissect_jited_func(struct bpf_prog_linfo * prog_linfo,const __u64 * ksym_func,const __u32 * ksym_len)22*f7c14bbaSAndroid Build Coastguard Worker static int dissect_jited_func(struct bpf_prog_linfo *prog_linfo,
23*f7c14bbaSAndroid Build Coastguard Worker const __u64 *ksym_func, const __u32 *ksym_len)
24*f7c14bbaSAndroid Build Coastguard Worker {
25*f7c14bbaSAndroid Build Coastguard Worker __u32 nr_jited_func, nr_linfo;
26*f7c14bbaSAndroid Build Coastguard Worker const void *raw_jited_linfo;
27*f7c14bbaSAndroid Build Coastguard Worker const __u64 *jited_linfo;
28*f7c14bbaSAndroid Build Coastguard Worker __u64 last_jited_linfo;
29*f7c14bbaSAndroid Build Coastguard Worker /*
30*f7c14bbaSAndroid Build Coastguard Worker * Index to raw_jited_linfo:
31*f7c14bbaSAndroid Build Coastguard Worker * i: Index for searching the next ksym_func
32*f7c14bbaSAndroid Build Coastguard Worker * prev_i: Index to the last found ksym_func
33*f7c14bbaSAndroid Build Coastguard Worker */
34*f7c14bbaSAndroid Build Coastguard Worker __u32 i, prev_i;
35*f7c14bbaSAndroid Build Coastguard Worker __u32 f; /* Index to ksym_func */
36*f7c14bbaSAndroid Build Coastguard Worker
37*f7c14bbaSAndroid Build Coastguard Worker raw_jited_linfo = prog_linfo->raw_jited_linfo;
38*f7c14bbaSAndroid Build Coastguard Worker jited_linfo = raw_jited_linfo;
39*f7c14bbaSAndroid Build Coastguard Worker if (ksym_func[0] != *jited_linfo)
40*f7c14bbaSAndroid Build Coastguard Worker goto errout;
41*f7c14bbaSAndroid Build Coastguard Worker
42*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->jited_linfo_func_idx[0] = 0;
43*f7c14bbaSAndroid Build Coastguard Worker nr_jited_func = prog_linfo->nr_jited_func;
44*f7c14bbaSAndroid Build Coastguard Worker nr_linfo = prog_linfo->nr_linfo;
45*f7c14bbaSAndroid Build Coastguard Worker
46*f7c14bbaSAndroid Build Coastguard Worker for (prev_i = 0, i = 1, f = 1;
47*f7c14bbaSAndroid Build Coastguard Worker i < nr_linfo && f < nr_jited_func;
48*f7c14bbaSAndroid Build Coastguard Worker i++) {
49*f7c14bbaSAndroid Build Coastguard Worker raw_jited_linfo += prog_linfo->jited_rec_size;
50*f7c14bbaSAndroid Build Coastguard Worker last_jited_linfo = *jited_linfo;
51*f7c14bbaSAndroid Build Coastguard Worker jited_linfo = raw_jited_linfo;
52*f7c14bbaSAndroid Build Coastguard Worker
53*f7c14bbaSAndroid Build Coastguard Worker if (ksym_func[f] == *jited_linfo) {
54*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->jited_linfo_func_idx[f] = i;
55*f7c14bbaSAndroid Build Coastguard Worker
56*f7c14bbaSAndroid Build Coastguard Worker /* Sanity check */
57*f7c14bbaSAndroid Build Coastguard Worker if (last_jited_linfo - ksym_func[f - 1] + 1 >
58*f7c14bbaSAndroid Build Coastguard Worker ksym_len[f - 1])
59*f7c14bbaSAndroid Build Coastguard Worker goto errout;
60*f7c14bbaSAndroid Build Coastguard Worker
61*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->nr_jited_linfo_per_func[f - 1] =
62*f7c14bbaSAndroid Build Coastguard Worker i - prev_i;
63*f7c14bbaSAndroid Build Coastguard Worker prev_i = i;
64*f7c14bbaSAndroid Build Coastguard Worker
65*f7c14bbaSAndroid Build Coastguard Worker /*
66*f7c14bbaSAndroid Build Coastguard Worker * The ksym_func[f] is found in jited_linfo.
67*f7c14bbaSAndroid Build Coastguard Worker * Look for the next one.
68*f7c14bbaSAndroid Build Coastguard Worker */
69*f7c14bbaSAndroid Build Coastguard Worker f++;
70*f7c14bbaSAndroid Build Coastguard Worker } else if (*jited_linfo <= last_jited_linfo) {
71*f7c14bbaSAndroid Build Coastguard Worker /* Ensure the addr is increasing _within_ a func */
72*f7c14bbaSAndroid Build Coastguard Worker goto errout;
73*f7c14bbaSAndroid Build Coastguard Worker }
74*f7c14bbaSAndroid Build Coastguard Worker }
75*f7c14bbaSAndroid Build Coastguard Worker
76*f7c14bbaSAndroid Build Coastguard Worker if (f != nr_jited_func)
77*f7c14bbaSAndroid Build Coastguard Worker goto errout;
78*f7c14bbaSAndroid Build Coastguard Worker
79*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->nr_jited_linfo_per_func[nr_jited_func - 1] =
80*f7c14bbaSAndroid Build Coastguard Worker nr_linfo - prev_i;
81*f7c14bbaSAndroid Build Coastguard Worker
82*f7c14bbaSAndroid Build Coastguard Worker return 0;
83*f7c14bbaSAndroid Build Coastguard Worker
84*f7c14bbaSAndroid Build Coastguard Worker errout:
85*f7c14bbaSAndroid Build Coastguard Worker return -EINVAL;
86*f7c14bbaSAndroid Build Coastguard Worker }
87*f7c14bbaSAndroid Build Coastguard Worker
bpf_prog_linfo__free(struct bpf_prog_linfo * prog_linfo)88*f7c14bbaSAndroid Build Coastguard Worker void bpf_prog_linfo__free(struct bpf_prog_linfo *prog_linfo)
89*f7c14bbaSAndroid Build Coastguard Worker {
90*f7c14bbaSAndroid Build Coastguard Worker if (!prog_linfo)
91*f7c14bbaSAndroid Build Coastguard Worker return;
92*f7c14bbaSAndroid Build Coastguard Worker
93*f7c14bbaSAndroid Build Coastguard Worker free(prog_linfo->raw_linfo);
94*f7c14bbaSAndroid Build Coastguard Worker free(prog_linfo->raw_jited_linfo);
95*f7c14bbaSAndroid Build Coastguard Worker free(prog_linfo->nr_jited_linfo_per_func);
96*f7c14bbaSAndroid Build Coastguard Worker free(prog_linfo->jited_linfo_func_idx);
97*f7c14bbaSAndroid Build Coastguard Worker free(prog_linfo);
98*f7c14bbaSAndroid Build Coastguard Worker }
99*f7c14bbaSAndroid Build Coastguard Worker
bpf_prog_linfo__new(const struct bpf_prog_info * info)100*f7c14bbaSAndroid Build Coastguard Worker struct bpf_prog_linfo *bpf_prog_linfo__new(const struct bpf_prog_info *info)
101*f7c14bbaSAndroid Build Coastguard Worker {
102*f7c14bbaSAndroid Build Coastguard Worker struct bpf_prog_linfo *prog_linfo;
103*f7c14bbaSAndroid Build Coastguard Worker __u32 nr_linfo, nr_jited_func;
104*f7c14bbaSAndroid Build Coastguard Worker __u64 data_sz;
105*f7c14bbaSAndroid Build Coastguard Worker
106*f7c14bbaSAndroid Build Coastguard Worker nr_linfo = info->nr_line_info;
107*f7c14bbaSAndroid Build Coastguard Worker
108*f7c14bbaSAndroid Build Coastguard Worker if (!nr_linfo)
109*f7c14bbaSAndroid Build Coastguard Worker return errno = EINVAL, NULL;
110*f7c14bbaSAndroid Build Coastguard Worker
111*f7c14bbaSAndroid Build Coastguard Worker /*
112*f7c14bbaSAndroid Build Coastguard Worker * The min size that bpf_prog_linfo has to access for
113*f7c14bbaSAndroid Build Coastguard Worker * searching purpose.
114*f7c14bbaSAndroid Build Coastguard Worker */
115*f7c14bbaSAndroid Build Coastguard Worker if (info->line_info_rec_size <
116*f7c14bbaSAndroid Build Coastguard Worker offsetof(struct bpf_line_info, file_name_off))
117*f7c14bbaSAndroid Build Coastguard Worker return errno = EINVAL, NULL;
118*f7c14bbaSAndroid Build Coastguard Worker
119*f7c14bbaSAndroid Build Coastguard Worker prog_linfo = calloc(1, sizeof(*prog_linfo));
120*f7c14bbaSAndroid Build Coastguard Worker if (!prog_linfo)
121*f7c14bbaSAndroid Build Coastguard Worker return errno = ENOMEM, NULL;
122*f7c14bbaSAndroid Build Coastguard Worker
123*f7c14bbaSAndroid Build Coastguard Worker /* Copy xlated line_info */
124*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->nr_linfo = nr_linfo;
125*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->rec_size = info->line_info_rec_size;
126*f7c14bbaSAndroid Build Coastguard Worker data_sz = (__u64)nr_linfo * prog_linfo->rec_size;
127*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->raw_linfo = malloc(data_sz);
128*f7c14bbaSAndroid Build Coastguard Worker if (!prog_linfo->raw_linfo)
129*f7c14bbaSAndroid Build Coastguard Worker goto err_free;
130*f7c14bbaSAndroid Build Coastguard Worker memcpy(prog_linfo->raw_linfo, (void *)(long)info->line_info, data_sz);
131*f7c14bbaSAndroid Build Coastguard Worker
132*f7c14bbaSAndroid Build Coastguard Worker nr_jited_func = info->nr_jited_ksyms;
133*f7c14bbaSAndroid Build Coastguard Worker if (!nr_jited_func ||
134*f7c14bbaSAndroid Build Coastguard Worker !info->jited_line_info ||
135*f7c14bbaSAndroid Build Coastguard Worker info->nr_jited_line_info != nr_linfo ||
136*f7c14bbaSAndroid Build Coastguard Worker info->jited_line_info_rec_size < sizeof(__u64) ||
137*f7c14bbaSAndroid Build Coastguard Worker info->nr_jited_func_lens != nr_jited_func ||
138*f7c14bbaSAndroid Build Coastguard Worker !info->jited_ksyms ||
139*f7c14bbaSAndroid Build Coastguard Worker !info->jited_func_lens)
140*f7c14bbaSAndroid Build Coastguard Worker /* Not enough info to provide jited_line_info */
141*f7c14bbaSAndroid Build Coastguard Worker return prog_linfo;
142*f7c14bbaSAndroid Build Coastguard Worker
143*f7c14bbaSAndroid Build Coastguard Worker /* Copy jited_line_info */
144*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->nr_jited_func = nr_jited_func;
145*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->jited_rec_size = info->jited_line_info_rec_size;
146*f7c14bbaSAndroid Build Coastguard Worker data_sz = (__u64)nr_linfo * prog_linfo->jited_rec_size;
147*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->raw_jited_linfo = malloc(data_sz);
148*f7c14bbaSAndroid Build Coastguard Worker if (!prog_linfo->raw_jited_linfo)
149*f7c14bbaSAndroid Build Coastguard Worker goto err_free;
150*f7c14bbaSAndroid Build Coastguard Worker memcpy(prog_linfo->raw_jited_linfo,
151*f7c14bbaSAndroid Build Coastguard Worker (void *)(long)info->jited_line_info, data_sz);
152*f7c14bbaSAndroid Build Coastguard Worker
153*f7c14bbaSAndroid Build Coastguard Worker /* Number of jited_line_info per jited func */
154*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->nr_jited_linfo_per_func = malloc(nr_jited_func *
155*f7c14bbaSAndroid Build Coastguard Worker sizeof(__u32));
156*f7c14bbaSAndroid Build Coastguard Worker if (!prog_linfo->nr_jited_linfo_per_func)
157*f7c14bbaSAndroid Build Coastguard Worker goto err_free;
158*f7c14bbaSAndroid Build Coastguard Worker
159*f7c14bbaSAndroid Build Coastguard Worker /*
160*f7c14bbaSAndroid Build Coastguard Worker * For each jited func,
161*f7c14bbaSAndroid Build Coastguard Worker * the start idx to the "linfo" and "jited_linfo" array,
162*f7c14bbaSAndroid Build Coastguard Worker */
163*f7c14bbaSAndroid Build Coastguard Worker prog_linfo->jited_linfo_func_idx = malloc(nr_jited_func *
164*f7c14bbaSAndroid Build Coastguard Worker sizeof(__u32));
165*f7c14bbaSAndroid Build Coastguard Worker if (!prog_linfo->jited_linfo_func_idx)
166*f7c14bbaSAndroid Build Coastguard Worker goto err_free;
167*f7c14bbaSAndroid Build Coastguard Worker
168*f7c14bbaSAndroid Build Coastguard Worker if (dissect_jited_func(prog_linfo,
169*f7c14bbaSAndroid Build Coastguard Worker (__u64 *)(long)info->jited_ksyms,
170*f7c14bbaSAndroid Build Coastguard Worker (__u32 *)(long)info->jited_func_lens))
171*f7c14bbaSAndroid Build Coastguard Worker goto err_free;
172*f7c14bbaSAndroid Build Coastguard Worker
173*f7c14bbaSAndroid Build Coastguard Worker return prog_linfo;
174*f7c14bbaSAndroid Build Coastguard Worker
175*f7c14bbaSAndroid Build Coastguard Worker err_free:
176*f7c14bbaSAndroid Build Coastguard Worker bpf_prog_linfo__free(prog_linfo);
177*f7c14bbaSAndroid Build Coastguard Worker return errno = EINVAL, NULL;
178*f7c14bbaSAndroid Build Coastguard Worker }
179*f7c14bbaSAndroid Build Coastguard Worker
180*f7c14bbaSAndroid Build Coastguard Worker const struct bpf_line_info *
bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo * prog_linfo,__u64 addr,__u32 func_idx,__u32 nr_skip)181*f7c14bbaSAndroid Build Coastguard Worker bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo *prog_linfo,
182*f7c14bbaSAndroid Build Coastguard Worker __u64 addr, __u32 func_idx, __u32 nr_skip)
183*f7c14bbaSAndroid Build Coastguard Worker {
184*f7c14bbaSAndroid Build Coastguard Worker __u32 jited_rec_size, rec_size, nr_linfo, start, i;
185*f7c14bbaSAndroid Build Coastguard Worker const void *raw_jited_linfo, *raw_linfo;
186*f7c14bbaSAndroid Build Coastguard Worker const __u64 *jited_linfo;
187*f7c14bbaSAndroid Build Coastguard Worker
188*f7c14bbaSAndroid Build Coastguard Worker if (func_idx >= prog_linfo->nr_jited_func)
189*f7c14bbaSAndroid Build Coastguard Worker return errno = ENOENT, NULL;
190*f7c14bbaSAndroid Build Coastguard Worker
191*f7c14bbaSAndroid Build Coastguard Worker nr_linfo = prog_linfo->nr_jited_linfo_per_func[func_idx];
192*f7c14bbaSAndroid Build Coastguard Worker if (nr_skip >= nr_linfo)
193*f7c14bbaSAndroid Build Coastguard Worker return errno = ENOENT, NULL;
194*f7c14bbaSAndroid Build Coastguard Worker
195*f7c14bbaSAndroid Build Coastguard Worker start = prog_linfo->jited_linfo_func_idx[func_idx] + nr_skip;
196*f7c14bbaSAndroid Build Coastguard Worker jited_rec_size = prog_linfo->jited_rec_size;
197*f7c14bbaSAndroid Build Coastguard Worker raw_jited_linfo = prog_linfo->raw_jited_linfo +
198*f7c14bbaSAndroid Build Coastguard Worker (start * jited_rec_size);
199*f7c14bbaSAndroid Build Coastguard Worker jited_linfo = raw_jited_linfo;
200*f7c14bbaSAndroid Build Coastguard Worker if (addr < *jited_linfo)
201*f7c14bbaSAndroid Build Coastguard Worker return errno = ENOENT, NULL;
202*f7c14bbaSAndroid Build Coastguard Worker
203*f7c14bbaSAndroid Build Coastguard Worker nr_linfo -= nr_skip;
204*f7c14bbaSAndroid Build Coastguard Worker rec_size = prog_linfo->rec_size;
205*f7c14bbaSAndroid Build Coastguard Worker raw_linfo = prog_linfo->raw_linfo + (start * rec_size);
206*f7c14bbaSAndroid Build Coastguard Worker for (i = 0; i < nr_linfo; i++) {
207*f7c14bbaSAndroid Build Coastguard Worker if (addr < *jited_linfo)
208*f7c14bbaSAndroid Build Coastguard Worker break;
209*f7c14bbaSAndroid Build Coastguard Worker
210*f7c14bbaSAndroid Build Coastguard Worker raw_linfo += rec_size;
211*f7c14bbaSAndroid Build Coastguard Worker raw_jited_linfo += jited_rec_size;
212*f7c14bbaSAndroid Build Coastguard Worker jited_linfo = raw_jited_linfo;
213*f7c14bbaSAndroid Build Coastguard Worker }
214*f7c14bbaSAndroid Build Coastguard Worker
215*f7c14bbaSAndroid Build Coastguard Worker return raw_linfo - rec_size;
216*f7c14bbaSAndroid Build Coastguard Worker }
217*f7c14bbaSAndroid Build Coastguard Worker
218*f7c14bbaSAndroid Build Coastguard Worker const struct bpf_line_info *
bpf_prog_linfo__lfind(const struct bpf_prog_linfo * prog_linfo,__u32 insn_off,__u32 nr_skip)219*f7c14bbaSAndroid Build Coastguard Worker bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
220*f7c14bbaSAndroid Build Coastguard Worker __u32 insn_off, __u32 nr_skip)
221*f7c14bbaSAndroid Build Coastguard Worker {
222*f7c14bbaSAndroid Build Coastguard Worker const struct bpf_line_info *linfo;
223*f7c14bbaSAndroid Build Coastguard Worker __u32 rec_size, nr_linfo, i;
224*f7c14bbaSAndroid Build Coastguard Worker const void *raw_linfo;
225*f7c14bbaSAndroid Build Coastguard Worker
226*f7c14bbaSAndroid Build Coastguard Worker nr_linfo = prog_linfo->nr_linfo;
227*f7c14bbaSAndroid Build Coastguard Worker if (nr_skip >= nr_linfo)
228*f7c14bbaSAndroid Build Coastguard Worker return errno = ENOENT, NULL;
229*f7c14bbaSAndroid Build Coastguard Worker
230*f7c14bbaSAndroid Build Coastguard Worker rec_size = prog_linfo->rec_size;
231*f7c14bbaSAndroid Build Coastguard Worker raw_linfo = prog_linfo->raw_linfo + (nr_skip * rec_size);
232*f7c14bbaSAndroid Build Coastguard Worker linfo = raw_linfo;
233*f7c14bbaSAndroid Build Coastguard Worker if (insn_off < linfo->insn_off)
234*f7c14bbaSAndroid Build Coastguard Worker return errno = ENOENT, NULL;
235*f7c14bbaSAndroid Build Coastguard Worker
236*f7c14bbaSAndroid Build Coastguard Worker nr_linfo -= nr_skip;
237*f7c14bbaSAndroid Build Coastguard Worker for (i = 0; i < nr_linfo; i++) {
238*f7c14bbaSAndroid Build Coastguard Worker if (insn_off < linfo->insn_off)
239*f7c14bbaSAndroid Build Coastguard Worker break;
240*f7c14bbaSAndroid Build Coastguard Worker
241*f7c14bbaSAndroid Build Coastguard Worker raw_linfo += rec_size;
242*f7c14bbaSAndroid Build Coastguard Worker linfo = raw_linfo;
243*f7c14bbaSAndroid Build Coastguard Worker }
244*f7c14bbaSAndroid Build Coastguard Worker
245*f7c14bbaSAndroid Build Coastguard Worker return raw_linfo - rec_size;
246*f7c14bbaSAndroid Build Coastguard Worker }
247