1 // SPDX-License-Identifier: GPL-2.0
6 #include <bpf/libbpf.h>
18 #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
20 static int snprintf_hex(char *buf
, size_t size
, unsigned char *data
, size_t len
)
25 for (i
= 0; i
< len
; i
++)
26 ret
+= snprintf(buf
+ ret
, size
- ret
, "%02x", data
[i
]);
30 static int machine__process_bpf_event_load(struct machine
*machine
,
31 union perf_event
*event
,
32 struct perf_sample
*sample __maybe_unused
)
34 struct bpf_prog_info_linear
*info_linear
;
35 struct bpf_prog_info_node
*info_node
;
36 struct perf_env
*env
= machine
->env
;
37 int id
= event
->bpf_event
.id
;
40 /* perf-record, no need to handle bpf-event */
44 info_node
= perf_env__find_bpf_prog_info(env
, id
);
47 info_linear
= info_node
->info_linear
;
49 for (i
= 0; i
< info_linear
->info
.nr_jited_ksyms
; i
++) {
50 u64
*addrs
= (u64
*)(uintptr_t)(info_linear
->info
.jited_ksyms
);
54 map
= map_groups__find(&machine
->kmaps
, addr
);
57 map
->dso
->binary_type
= DSO_BINARY_TYPE__BPF_PROG_INFO
;
58 map
->dso
->bpf_prog
.id
= id
;
59 map
->dso
->bpf_prog
.sub_id
= i
;
60 map
->dso
->bpf_prog
.env
= env
;
66 int machine__process_bpf_event(struct machine
*machine __maybe_unused
,
67 union perf_event
*event
,
68 struct perf_sample
*sample __maybe_unused
)
71 perf_event__fprintf_bpf_event(event
, stdout
);
73 switch (event
->bpf_event
.type
) {
74 case PERF_BPF_EVENT_PROG_LOAD
:
75 return machine__process_bpf_event_load(machine
, event
, sample
);
77 case PERF_BPF_EVENT_PROG_UNLOAD
:
79 * Do not free bpf_prog_info and btf of the program here,
80 * as annotation still need them. They will be freed at
81 * the end of the session.
85 pr_debug("unexpected bpf_event type of %d\n",
86 event
->bpf_event
.type
);
92 static int perf_env__fetch_btf(struct perf_env
*env
,
96 struct btf_node
*node
;
100 data
= btf__get_raw_data(btf
, &data_size
);
102 node
= malloc(data_size
+ sizeof(struct btf_node
));
107 node
->data_size
= data_size
;
108 memcpy(node
->data
, data
, data_size
);
110 perf_env__insert_btf(env
, node
);
114 static int synthesize_bpf_prog_name(char *buf
, int size
,
115 struct bpf_prog_info
*info
,
119 u8 (*prog_tags
)[BPF_TAG_SIZE
] = (void *)(uintptr_t)(info
->prog_tags
);
120 void *func_infos
= (void *)(uintptr_t)(info
->func_info
);
121 u32 sub_prog_cnt
= info
->nr_jited_ksyms
;
122 const struct bpf_func_info
*finfo
;
123 const char *short_name
= NULL
;
124 const struct btf_type
*t
;
127 name_len
= snprintf(buf
, size
, "bpf_prog_");
128 name_len
+= snprintf_hex(buf
+ name_len
, size
- name_len
,
129 prog_tags
[sub_id
], BPF_TAG_SIZE
);
131 finfo
= func_infos
+ sub_id
* info
->func_info_rec_size
;
132 t
= btf__type_by_id(btf
, finfo
->type_id
);
133 short_name
= btf__name_by_offset(btf
, t
->name_off
);
134 } else if (sub_id
== 0 && sub_prog_cnt
== 1) {
137 short_name
= info
->name
;
141 name_len
+= snprintf(buf
+ name_len
, size
- name_len
,
147 * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf
148 * program. One PERF_RECORD_BPF_EVENT is generated for the program. And
149 * one PERF_RECORD_KSYMBOL is generated for each sub program.
154 * -2 for lack of kernel support.
156 static int perf_event__synthesize_one_bpf_prog(struct perf_session
*session
,
157 perf_event__handler_t process
,
158 struct machine
*machine
,
160 union perf_event
*event
,
161 struct record_opts
*opts
)
163 struct ksymbol_event
*ksymbol_event
= &event
->ksymbol_event
;
164 struct bpf_event
*bpf_event
= &event
->bpf_event
;
165 struct bpf_prog_info_linear
*info_linear
;
166 struct perf_tool
*tool
= session
->tool
;
167 struct bpf_prog_info_node
*info_node
;
168 struct bpf_prog_info
*info
;
169 struct btf
*btf
= NULL
;
170 struct perf_env
*env
;
176 * for perf-record and perf-report use header.env;
177 * otherwise, use global perf_env.
179 env
= session
->data
? &session
->header
.env
: &perf_env
;
181 arrays
= 1UL << BPF_PROG_INFO_JITED_KSYMS
;
182 arrays
|= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS
;
183 arrays
|= 1UL << BPF_PROG_INFO_FUNC_INFO
;
184 arrays
|= 1UL << BPF_PROG_INFO_PROG_TAGS
;
185 arrays
|= 1UL << BPF_PROG_INFO_JITED_INSNS
;
186 arrays
|= 1UL << BPF_PROG_INFO_LINE_INFO
;
187 arrays
|= 1UL << BPF_PROG_INFO_JITED_LINE_INFO
;
189 info_linear
= bpf_program__get_prog_info_linear(fd
, arrays
);
190 if (IS_ERR_OR_NULL(info_linear
)) {
192 pr_debug("%s: failed to get BPF program info. aborting\n", __func__
);
196 if (info_linear
->info_len
< offsetof(struct bpf_prog_info
, prog_tags
)) {
197 pr_debug("%s: the kernel is too old, aborting\n", __func__
);
201 info
= &info_linear
->info
;
203 /* number of ksyms, func_lengths, and tags should match */
204 sub_prog_cnt
= info
->nr_jited_ksyms
;
205 if (sub_prog_cnt
!= info
->nr_prog_tags
||
206 sub_prog_cnt
!= info
->nr_jited_func_lens
)
209 /* check BTF func info support */
210 if (info
->btf_id
&& info
->nr_func_info
&& info
->func_info_rec_size
) {
211 /* btf func info number should be same as sub_prog_cnt */
212 if (sub_prog_cnt
!= info
->nr_func_info
) {
213 pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__
);
217 if (btf__get_from_id(info
->btf_id
, &btf
)) {
218 pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__
, info
->btf_id
);
223 perf_env__fetch_btf(env
, info
->btf_id
, btf
);
226 /* Synthesize PERF_RECORD_KSYMBOL */
227 for (i
= 0; i
< sub_prog_cnt
; i
++) {
228 __u32
*prog_lens
= (__u32
*)(uintptr_t)(info
->jited_func_lens
);
229 __u64
*prog_addrs
= (__u64
*)(uintptr_t)(info
->jited_ksyms
);
232 *ksymbol_event
= (struct ksymbol_event
){
234 .type
= PERF_RECORD_KSYMBOL
,
235 .size
= offsetof(struct ksymbol_event
, name
),
237 .addr
= prog_addrs
[i
],
239 .ksym_type
= PERF_RECORD_KSYMBOL_TYPE_BPF
,
243 name_len
= synthesize_bpf_prog_name(ksymbol_event
->name
,
244 KSYM_NAME_LEN
, info
, btf
, i
);
245 ksymbol_event
->header
.size
+= PERF_ALIGN(name_len
+ 1,
248 memset((void *)event
+ event
->header
.size
, 0, machine
->id_hdr_size
);
249 event
->header
.size
+= machine
->id_hdr_size
;
250 err
= perf_tool__process_synth_event(tool
, event
,
254 if (!opts
->no_bpf_event
) {
255 /* Synthesize PERF_RECORD_BPF_EVENT */
256 *bpf_event
= (struct bpf_event
){
258 .type
= PERF_RECORD_BPF_EVENT
,
259 .size
= sizeof(struct bpf_event
),
261 .type
= PERF_BPF_EVENT_PROG_LOAD
,
265 memcpy(bpf_event
->tag
, info
->tag
, BPF_TAG_SIZE
);
266 memset((void *)event
+ event
->header
.size
, 0, machine
->id_hdr_size
);
267 event
->header
.size
+= machine
->id_hdr_size
;
269 /* save bpf_prog_info to env */
270 info_node
= malloc(sizeof(struct bpf_prog_info_node
));
276 info_node
->info_linear
= info_linear
;
277 perf_env__insert_bpf_prog_info(env
, info_node
);
281 * process after saving bpf_prog_info to env, so that
282 * required information is ready for look up
284 err
= perf_tool__process_synth_event(tool
, event
,
294 int perf_event__synthesize_bpf_events(struct perf_session
*session
,
295 perf_event__handler_t process
,
296 struct machine
*machine
,
297 struct record_opts
*opts
)
299 union perf_event
*event
;
304 event
= malloc(sizeof(event
->bpf_event
) + KSYM_NAME_LEN
+ machine
->id_hdr_size
);
308 err
= bpf_prog_get_next_id(id
, &id
);
310 if (errno
== ENOENT
) {
314 pr_debug("%s: can't get next program: %s%s\n",
315 __func__
, strerror(errno
),
316 errno
== EINVAL
? " -- kernel too old?" : "");
317 /* don't report error on old kernel or EPERM */
318 err
= (errno
== EINVAL
|| errno
== EPERM
) ? 0 : -1;
321 fd
= bpf_prog_get_fd_by_id(id
);
323 pr_debug("%s: failed to get fd for prog_id %u\n",
328 err
= perf_event__synthesize_one_bpf_prog(session
, process
,
333 /* do not return error for old kernel */
343 static void perf_env__add_bpf_info(struct perf_env
*env
, u32 id
)
345 struct bpf_prog_info_linear
*info_linear
;
346 struct bpf_prog_info_node
*info_node
;
347 struct btf
*btf
= NULL
;
352 fd
= bpf_prog_get_fd_by_id(id
);
356 arrays
= 1UL << BPF_PROG_INFO_JITED_KSYMS
;
357 arrays
|= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS
;
358 arrays
|= 1UL << BPF_PROG_INFO_FUNC_INFO
;
359 arrays
|= 1UL << BPF_PROG_INFO_PROG_TAGS
;
360 arrays
|= 1UL << BPF_PROG_INFO_JITED_INSNS
;
361 arrays
|= 1UL << BPF_PROG_INFO_LINE_INFO
;
362 arrays
|= 1UL << BPF_PROG_INFO_JITED_LINE_INFO
;
364 info_linear
= bpf_program__get_prog_info_linear(fd
, arrays
);
365 if (IS_ERR_OR_NULL(info_linear
)) {
366 pr_debug("%s: failed to get BPF program info. aborting\n", __func__
);
370 btf_id
= info_linear
->info
.btf_id
;
372 info_node
= malloc(sizeof(struct bpf_prog_info_node
));
374 info_node
->info_linear
= info_linear
;
375 perf_env__insert_bpf_prog_info(env
, info_node
);
382 if (btf__get_from_id(btf_id
, &btf
)) {
383 pr_debug("%s: failed to get BTF of id %u, aborting\n",
387 perf_env__fetch_btf(env
, btf_id
, btf
);
394 static int bpf_event__sb_cb(union perf_event
*event
, void *data
)
396 struct perf_env
*env
= data
;
398 if (event
->header
.type
!= PERF_RECORD_BPF_EVENT
)
401 switch (event
->bpf_event
.type
) {
402 case PERF_BPF_EVENT_PROG_LOAD
:
403 perf_env__add_bpf_info(env
, event
->bpf_event
.id
);
405 case PERF_BPF_EVENT_PROG_UNLOAD
:
407 * Do not free bpf_prog_info and btf of the program here,
408 * as annotation still need them. They will be freed at
409 * the end of the session.
413 pr_debug("unexpected bpf_event type of %d\n",
414 event
->bpf_event
.type
);
421 int bpf_event__add_sb_event(struct perf_evlist
**evlist
,
422 struct perf_env
*env
)
424 struct perf_event_attr attr
= {
425 .type
= PERF_TYPE_SOFTWARE
,
426 .config
= PERF_COUNT_SW_DUMMY
,
430 .size
= sizeof(attr
), /* to capture ABI version */
434 * Older gcc versions don't support designated initializers, like above,
435 * for unnamed union members, such as the following:
437 attr
.wakeup_watermark
= 1;
439 return perf_evlist__add_sb_event(evlist
, &attr
, bpf_event__sb_cb
, env
);
442 void bpf_event__print_bpf_prog_info(struct bpf_prog_info
*info
,
443 struct perf_env
*env
,
446 __u32
*prog_lens
= (__u32
*)(uintptr_t)(info
->jited_func_lens
);
447 __u64
*prog_addrs
= (__u64
*)(uintptr_t)(info
->jited_ksyms
);
448 char name
[KSYM_NAME_LEN
];
449 struct btf
*btf
= NULL
;
452 sub_prog_cnt
= info
->nr_jited_ksyms
;
453 if (sub_prog_cnt
!= info
->nr_prog_tags
||
454 sub_prog_cnt
!= info
->nr_jited_func_lens
)
458 struct btf_node
*node
;
460 node
= perf_env__find_btf(env
, info
->btf_id
);
462 btf
= btf__new((__u8
*)(node
->data
),
466 if (sub_prog_cnt
== 1) {
467 synthesize_bpf_prog_name(name
, KSYM_NAME_LEN
, info
, btf
, 0);
468 fprintf(fp
, "# bpf_prog_info %u: %s addr 0x%llx size %u\n",
469 info
->id
, name
, prog_addrs
[0], prog_lens
[0]);
473 fprintf(fp
, "# bpf_prog_info %u:\n", info
->id
);
474 for (i
= 0; i
< sub_prog_cnt
; i
++) {
475 synthesize_bpf_prog_name(name
, KSYM_NAME_LEN
, info
, btf
, i
);
477 fprintf(fp
, "# \tsub_prog %u: %s addr 0x%llx size %u\n",
478 i
, name
, prog_addrs
[i
], prog_lens
[i
]);