1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 /* Copyright (c) 2018 Facebook */
9 #include "libbpf_internal.h"
11 struct bpf_prog_linfo
{
13 void *raw_jited_linfo
;
14 __u32
*nr_jited_linfo_per_func
;
15 __u32
*jited_linfo_func_idx
;
22 static int dissect_jited_func(struct bpf_prog_linfo
*prog_linfo
,
23 const __u64
*ksym_func
, const __u32
*ksym_len
)
25 __u32 nr_jited_func
, nr_linfo
;
26 const void *raw_jited_linfo
;
27 const __u64
*jited_linfo
;
28 __u64 last_jited_linfo
;
30 * Index to raw_jited_linfo:
31 * i: Index for searching the next ksym_func
32 * prev_i: Index to the last found ksym_func
35 __u32 f
; /* Index to ksym_func */
37 raw_jited_linfo
= prog_linfo
->raw_jited_linfo
;
38 jited_linfo
= raw_jited_linfo
;
39 if (ksym_func
[0] != *jited_linfo
)
42 prog_linfo
->jited_linfo_func_idx
[0] = 0;
43 nr_jited_func
= prog_linfo
->nr_jited_func
;
44 nr_linfo
= prog_linfo
->nr_linfo
;
46 for (prev_i
= 0, i
= 1, f
= 1;
47 i
< nr_linfo
&& f
< nr_jited_func
;
49 raw_jited_linfo
+= prog_linfo
->jited_rec_size
;
50 last_jited_linfo
= *jited_linfo
;
51 jited_linfo
= raw_jited_linfo
;
53 if (ksym_func
[f
] == *jited_linfo
) {
54 prog_linfo
->jited_linfo_func_idx
[f
] = i
;
57 if (last_jited_linfo
- ksym_func
[f
- 1] + 1 >
61 prog_linfo
->nr_jited_linfo_per_func
[f
- 1] =
66 * The ksym_func[f] is found in jited_linfo.
67 * Look for the next one.
70 } else if (*jited_linfo
<= last_jited_linfo
) {
71 /* Ensure the addr is increasing _within_ a func */
76 if (f
!= nr_jited_func
)
79 prog_linfo
->nr_jited_linfo_per_func
[nr_jited_func
- 1] =
88 void bpf_prog_linfo__free(struct bpf_prog_linfo
*prog_linfo
)
93 free(prog_linfo
->raw_linfo
);
94 free(prog_linfo
->raw_jited_linfo
);
95 free(prog_linfo
->nr_jited_linfo_per_func
);
96 free(prog_linfo
->jited_linfo_func_idx
);
100 struct bpf_prog_linfo
*bpf_prog_linfo__new(const struct bpf_prog_info
*info
)
102 struct bpf_prog_linfo
*prog_linfo
;
103 __u32 nr_linfo
, nr_jited_func
;
106 nr_linfo
= info
->nr_line_info
;
112 * The min size that bpf_prog_linfo has to access for
115 if (info
->line_info_rec_size
<
116 offsetof(struct bpf_line_info
, file_name_off
))
119 prog_linfo
= calloc(1, sizeof(*prog_linfo
));
123 /* Copy xlated line_info */
124 prog_linfo
->nr_linfo
= nr_linfo
;
125 prog_linfo
->rec_size
= info
->line_info_rec_size
;
126 data_sz
= (__u64
)nr_linfo
* prog_linfo
->rec_size
;
127 prog_linfo
->raw_linfo
= malloc(data_sz
);
128 if (!prog_linfo
->raw_linfo
)
130 memcpy(prog_linfo
->raw_linfo
, (void *)(long)info
->line_info
, data_sz
);
132 nr_jited_func
= info
->nr_jited_ksyms
;
133 if (!nr_jited_func
||
134 !info
->jited_line_info
||
135 info
->nr_jited_line_info
!= nr_linfo
||
136 info
->jited_line_info_rec_size
< sizeof(__u64
) ||
137 info
->nr_jited_func_lens
!= nr_jited_func
||
138 !info
->jited_ksyms
||
139 !info
->jited_func_lens
)
140 /* Not enough info to provide jited_line_info */
143 /* Copy jited_line_info */
144 prog_linfo
->nr_jited_func
= nr_jited_func
;
145 prog_linfo
->jited_rec_size
= info
->jited_line_info_rec_size
;
146 data_sz
= (__u64
)nr_linfo
* prog_linfo
->jited_rec_size
;
147 prog_linfo
->raw_jited_linfo
= malloc(data_sz
);
148 if (!prog_linfo
->raw_jited_linfo
)
150 memcpy(prog_linfo
->raw_jited_linfo
,
151 (void *)(long)info
->jited_line_info
, data_sz
);
153 /* Number of jited_line_info per jited func */
154 prog_linfo
->nr_jited_linfo_per_func
= malloc(nr_jited_func
*
156 if (!prog_linfo
->nr_jited_linfo_per_func
)
160 * For each jited func,
161 * the start idx to the "linfo" and "jited_linfo" array,
163 prog_linfo
->jited_linfo_func_idx
= malloc(nr_jited_func
*
165 if (!prog_linfo
->jited_linfo_func_idx
)
168 if (dissect_jited_func(prog_linfo
,
169 (__u64
*)(long)info
->jited_ksyms
,
170 (__u32
*)(long)info
->jited_func_lens
))
176 bpf_prog_linfo__free(prog_linfo
);
180 const struct bpf_line_info
*
181 bpf_prog_linfo__lfind_addr_func(const struct bpf_prog_linfo
*prog_linfo
,
182 __u64 addr
, __u32 func_idx
, __u32 nr_skip
)
184 __u32 jited_rec_size
, rec_size
, nr_linfo
, start
, i
;
185 const void *raw_jited_linfo
, *raw_linfo
;
186 const __u64
*jited_linfo
;
188 if (func_idx
>= prog_linfo
->nr_jited_func
)
191 nr_linfo
= prog_linfo
->nr_jited_linfo_per_func
[func_idx
];
192 if (nr_skip
>= nr_linfo
)
195 start
= prog_linfo
->jited_linfo_func_idx
[func_idx
] + nr_skip
;
196 jited_rec_size
= prog_linfo
->jited_rec_size
;
197 raw_jited_linfo
= prog_linfo
->raw_jited_linfo
+
198 (start
* jited_rec_size
);
199 jited_linfo
= raw_jited_linfo
;
200 if (addr
< *jited_linfo
)
204 rec_size
= prog_linfo
->rec_size
;
205 raw_linfo
= prog_linfo
->raw_linfo
+ (start
* rec_size
);
206 for (i
= 0; i
< nr_linfo
; i
++) {
207 if (addr
< *jited_linfo
)
210 raw_linfo
+= rec_size
;
211 raw_jited_linfo
+= jited_rec_size
;
212 jited_linfo
= raw_jited_linfo
;
215 return raw_linfo
- rec_size
;
218 const struct bpf_line_info
*
219 bpf_prog_linfo__lfind(const struct bpf_prog_linfo
*prog_linfo
,
220 __u32 insn_off
, __u32 nr_skip
)
222 const struct bpf_line_info
*linfo
;
223 __u32 rec_size
, nr_linfo
, i
;
224 const void *raw_linfo
;
226 nr_linfo
= prog_linfo
->nr_linfo
;
227 if (nr_skip
>= nr_linfo
)
230 rec_size
= prog_linfo
->rec_size
;
231 raw_linfo
= prog_linfo
->raw_linfo
+ (nr_skip
* rec_size
);
233 if (insn_off
< linfo
->insn_off
)
237 for (i
= 0; i
< nr_linfo
; i
++) {
238 if (insn_off
< linfo
->insn_off
)
241 raw_linfo
+= rec_size
;
245 return raw_linfo
- rec_size
;