1 // SPDX-License-Identifier: GPL-2.0
6 #include <bpf/libbpf.h>
9 #include <linux/string.h>
10 #include <internal/lib.h>
11 #include <symbol/kallsyms.h>
12 #include "bpf-event.h"
22 #include "util/synthetic-events.h"
24 #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
26 static int snprintf_hex(char *buf
, size_t size
, unsigned char *data
, size_t len
)
31 for (i
= 0; i
< len
; i
++)
32 ret
+= snprintf(buf
+ ret
, size
- ret
, "%02x", data
[i
]);
36 static int machine__process_bpf_event_load(struct machine
*machine
,
37 union perf_event
*event
,
38 struct perf_sample
*sample __maybe_unused
)
40 struct bpf_prog_info_linear
*info_linear
;
41 struct bpf_prog_info_node
*info_node
;
42 struct perf_env
*env
= machine
->env
;
43 int id
= event
->bpf
.id
;
46 /* perf-record, no need to handle bpf-event */
50 info_node
= perf_env__find_bpf_prog_info(env
, id
);
53 info_linear
= info_node
->info_linear
;
55 for (i
= 0; i
< info_linear
->info
.nr_jited_ksyms
; i
++) {
56 u64
*addrs
= (u64
*)(uintptr_t)(info_linear
->info
.jited_ksyms
);
58 struct map
*map
= maps__find(&machine
->kmaps
, addr
);
61 map
->dso
->binary_type
= DSO_BINARY_TYPE__BPF_PROG_INFO
;
62 map
->dso
->bpf_prog
.id
= id
;
63 map
->dso
->bpf_prog
.sub_id
= i
;
64 map
->dso
->bpf_prog
.env
= env
;
70 int machine__process_bpf(struct machine
*machine
, union perf_event
*event
,
71 struct perf_sample
*sample
)
74 perf_event__fprintf_bpf(event
, stdout
);
76 switch (event
->bpf
.type
) {
77 case PERF_BPF_EVENT_PROG_LOAD
:
78 return machine__process_bpf_event_load(machine
, event
, sample
);
80 case PERF_BPF_EVENT_PROG_UNLOAD
:
82 * Do not free bpf_prog_info and btf of the program here,
83 * as annotation still need them. They will be freed at
84 * the end of the session.
88 pr_debug("unexpected bpf event type of %d\n", event
->bpf
.type
);
94 static int perf_env__fetch_btf(struct perf_env
*env
,
98 struct btf_node
*node
;
102 data
= btf__get_raw_data(btf
, &data_size
);
104 node
= malloc(data_size
+ sizeof(struct btf_node
));
109 node
->data_size
= data_size
;
110 memcpy(node
->data
, data
, data_size
);
112 perf_env__insert_btf(env
, node
);
116 static int synthesize_bpf_prog_name(char *buf
, int size
,
117 struct bpf_prog_info
*info
,
121 u8 (*prog_tags
)[BPF_TAG_SIZE
] = (void *)(uintptr_t)(info
->prog_tags
);
122 void *func_infos
= (void *)(uintptr_t)(info
->func_info
);
123 u32 sub_prog_cnt
= info
->nr_jited_ksyms
;
124 const struct bpf_func_info
*finfo
;
125 const char *short_name
= NULL
;
126 const struct btf_type
*t
;
129 name_len
= snprintf(buf
, size
, "bpf_prog_");
130 name_len
+= snprintf_hex(buf
+ name_len
, size
- name_len
,
131 prog_tags
[sub_id
], BPF_TAG_SIZE
);
133 finfo
= func_infos
+ sub_id
* info
->func_info_rec_size
;
134 t
= btf__type_by_id(btf
, finfo
->type_id
);
135 short_name
= btf__name_by_offset(btf
, t
->name_off
);
136 } else if (sub_id
== 0 && sub_prog_cnt
== 1) {
139 short_name
= info
->name
;
143 name_len
+= snprintf(buf
+ name_len
, size
- name_len
,
149 * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf
150 * program. One PERF_RECORD_BPF_EVENT is generated for the program. And
151 * one PERF_RECORD_KSYMBOL is generated for each sub program.
156 * -2 for lack of kernel support.
158 static int perf_event__synthesize_one_bpf_prog(struct perf_session
*session
,
159 perf_event__handler_t process
,
160 struct machine
*machine
,
162 union perf_event
*event
,
163 struct record_opts
*opts
)
165 struct perf_record_ksymbol
*ksymbol_event
= &event
->ksymbol
;
166 struct perf_record_bpf_event
*bpf_event
= &event
->bpf
;
167 struct bpf_prog_info_linear
*info_linear
;
168 struct perf_tool
*tool
= session
->tool
;
169 struct bpf_prog_info_node
*info_node
;
170 struct bpf_prog_info
*info
;
171 struct btf
*btf
= NULL
;
172 struct perf_env
*env
;
178 * for perf-record and perf-report use header.env;
179 * otherwise, use global perf_env.
181 env
= session
->data
? &session
->header
.env
: &perf_env
;
183 arrays
= 1UL << BPF_PROG_INFO_JITED_KSYMS
;
184 arrays
|= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS
;
185 arrays
|= 1UL << BPF_PROG_INFO_FUNC_INFO
;
186 arrays
|= 1UL << BPF_PROG_INFO_PROG_TAGS
;
187 arrays
|= 1UL << BPF_PROG_INFO_JITED_INSNS
;
188 arrays
|= 1UL << BPF_PROG_INFO_LINE_INFO
;
189 arrays
|= 1UL << BPF_PROG_INFO_JITED_LINE_INFO
;
191 info_linear
= bpf_program__get_prog_info_linear(fd
, arrays
);
192 if (IS_ERR_OR_NULL(info_linear
)) {
194 pr_debug("%s: failed to get BPF program info. aborting\n", __func__
);
198 if (info_linear
->info_len
< offsetof(struct bpf_prog_info
, prog_tags
)) {
199 pr_debug("%s: the kernel is too old, aborting\n", __func__
);
203 info
= &info_linear
->info
;
205 /* number of ksyms, func_lengths, and tags should match */
206 sub_prog_cnt
= info
->nr_jited_ksyms
;
207 if (sub_prog_cnt
!= info
->nr_prog_tags
||
208 sub_prog_cnt
!= info
->nr_jited_func_lens
)
211 /* check BTF func info support */
212 if (info
->btf_id
&& info
->nr_func_info
&& info
->func_info_rec_size
) {
213 /* btf func info number should be same as sub_prog_cnt */
214 if (sub_prog_cnt
!= info
->nr_func_info
) {
215 pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__
);
219 if (btf__get_from_id(info
->btf_id
, &btf
)) {
220 pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__
, info
->btf_id
);
225 perf_env__fetch_btf(env
, info
->btf_id
, btf
);
228 /* Synthesize PERF_RECORD_KSYMBOL */
229 for (i
= 0; i
< sub_prog_cnt
; i
++) {
230 __u32
*prog_lens
= (__u32
*)(uintptr_t)(info
->jited_func_lens
);
231 __u64
*prog_addrs
= (__u64
*)(uintptr_t)(info
->jited_ksyms
);
234 *ksymbol_event
= (struct perf_record_ksymbol
) {
236 .type
= PERF_RECORD_KSYMBOL
,
237 .size
= offsetof(struct perf_record_ksymbol
, name
),
239 .addr
= prog_addrs
[i
],
241 .ksym_type
= PERF_RECORD_KSYMBOL_TYPE_BPF
,
245 name_len
= synthesize_bpf_prog_name(ksymbol_event
->name
,
246 KSYM_NAME_LEN
, info
, btf
, i
);
247 ksymbol_event
->header
.size
+= PERF_ALIGN(name_len
+ 1,
250 memset((void *)event
+ event
->header
.size
, 0, machine
->id_hdr_size
);
251 event
->header
.size
+= machine
->id_hdr_size
;
252 err
= perf_tool__process_synth_event(tool
, event
,
256 if (!opts
->no_bpf_event
) {
257 /* Synthesize PERF_RECORD_BPF_EVENT */
258 *bpf_event
= (struct perf_record_bpf_event
) {
260 .type
= PERF_RECORD_BPF_EVENT
,
261 .size
= sizeof(struct perf_record_bpf_event
),
263 .type
= PERF_BPF_EVENT_PROG_LOAD
,
267 memcpy(bpf_event
->tag
, info
->tag
, BPF_TAG_SIZE
);
268 memset((void *)event
+ event
->header
.size
, 0, machine
->id_hdr_size
);
269 event
->header
.size
+= machine
->id_hdr_size
;
271 /* save bpf_prog_info to env */
272 info_node
= malloc(sizeof(struct bpf_prog_info_node
));
278 info_node
->info_linear
= info_linear
;
279 perf_env__insert_bpf_prog_info(env
, info_node
);
283 * process after saving bpf_prog_info to env, so that
284 * required information is ready for look up
286 err
= perf_tool__process_synth_event(tool
, event
,
296 struct kallsyms_parse
{
297 union perf_event
*event
;
298 perf_event__handler_t process
;
299 struct machine
*machine
;
300 struct perf_tool
*tool
;
304 process_bpf_image(char *name
, u64 addr
, struct kallsyms_parse
*data
)
306 struct machine
*machine
= data
->machine
;
307 union perf_event
*event
= data
->event
;
308 struct perf_record_ksymbol
*ksymbol
;
311 ksymbol
= &event
->ksymbol
;
313 *ksymbol
= (struct perf_record_ksymbol
) {
315 .type
= PERF_RECORD_KSYMBOL
,
316 .size
= offsetof(struct perf_record_ksymbol
, name
),
320 .ksym_type
= PERF_RECORD_KSYMBOL_TYPE_BPF
,
324 len
= scnprintf(ksymbol
->name
, KSYM_NAME_LEN
, "%s", name
);
325 ksymbol
->header
.size
+= PERF_ALIGN(len
+ 1, sizeof(u64
));
326 memset((void *) event
+ event
->header
.size
, 0, machine
->id_hdr_size
);
327 event
->header
.size
+= machine
->id_hdr_size
;
329 return perf_tool__process_synth_event(data
->tool
, event
, machine
,
334 kallsyms_process_symbol(void *data
, const char *_name
,
335 char type __maybe_unused
, u64 start
)
337 char disp
[KSYM_NAME_LEN
];
342 module
= strchr(_name
, '\t');
346 /* We are going after [bpf] module ... */
347 if (strcmp(module
+ 1, "[bpf]"))
350 name
= memdup(_name
, (module
- _name
) + 1);
354 name
[module
- _name
] = 0;
356 /* .. and only for trampolines and dispatchers */
357 if ((sscanf(name
, "bpf_trampoline_%lu", &id
) == 1) ||
358 (sscanf(name
, "bpf_dispatcher_%s", disp
) == 1))
359 err
= process_bpf_image(name
, start
, data
);
365 int perf_event__synthesize_bpf_events(struct perf_session
*session
,
366 perf_event__handler_t process
,
367 struct machine
*machine
,
368 struct record_opts
*opts
)
370 const char *kallsyms_filename
= "/proc/kallsyms";
371 struct kallsyms_parse arg
;
372 union perf_event
*event
;
377 event
= malloc(sizeof(event
->bpf
) + KSYM_NAME_LEN
+ machine
->id_hdr_size
);
381 /* Synthesize all the bpf programs in system. */
383 err
= bpf_prog_get_next_id(id
, &id
);
385 if (errno
== ENOENT
) {
389 pr_debug("%s: can't get next program: %s%s\n",
390 __func__
, strerror(errno
),
391 errno
== EINVAL
? " -- kernel too old?" : "");
392 /* don't report error on old kernel or EPERM */
393 err
= (errno
== EINVAL
|| errno
== EPERM
) ? 0 : -1;
396 fd
= bpf_prog_get_fd_by_id(id
);
398 pr_debug("%s: failed to get fd for prog_id %u\n",
403 err
= perf_event__synthesize_one_bpf_prog(session
, process
,
408 /* do not return error for old kernel */
415 /* Synthesize all the bpf images - trampolines/dispatchers. */
416 if (symbol_conf
.kallsyms_name
!= NULL
)
417 kallsyms_filename
= symbol_conf
.kallsyms_name
;
419 arg
= (struct kallsyms_parse
) {
423 .tool
= session
->tool
,
426 if (kallsyms__parse(kallsyms_filename
, &arg
, kallsyms_process_symbol
)) {
427 pr_err("%s: failed to synthesize bpf images: %s\n",
428 __func__
, strerror(errno
));
435 static void perf_env__add_bpf_info(struct perf_env
*env
, u32 id
)
437 struct bpf_prog_info_linear
*info_linear
;
438 struct bpf_prog_info_node
*info_node
;
439 struct btf
*btf
= NULL
;
444 fd
= bpf_prog_get_fd_by_id(id
);
448 arrays
= 1UL << BPF_PROG_INFO_JITED_KSYMS
;
449 arrays
|= 1UL << BPF_PROG_INFO_JITED_FUNC_LENS
;
450 arrays
|= 1UL << BPF_PROG_INFO_FUNC_INFO
;
451 arrays
|= 1UL << BPF_PROG_INFO_PROG_TAGS
;
452 arrays
|= 1UL << BPF_PROG_INFO_JITED_INSNS
;
453 arrays
|= 1UL << BPF_PROG_INFO_LINE_INFO
;
454 arrays
|= 1UL << BPF_PROG_INFO_JITED_LINE_INFO
;
456 info_linear
= bpf_program__get_prog_info_linear(fd
, arrays
);
457 if (IS_ERR_OR_NULL(info_linear
)) {
458 pr_debug("%s: failed to get BPF program info. aborting\n", __func__
);
462 btf_id
= info_linear
->info
.btf_id
;
464 info_node
= malloc(sizeof(struct bpf_prog_info_node
));
466 info_node
->info_linear
= info_linear
;
467 perf_env__insert_bpf_prog_info(env
, info_node
);
474 if (btf__get_from_id(btf_id
, &btf
)) {
475 pr_debug("%s: failed to get BTF of id %u, aborting\n",
479 perf_env__fetch_btf(env
, btf_id
, btf
);
486 static int bpf_event__sb_cb(union perf_event
*event
, void *data
)
488 struct perf_env
*env
= data
;
490 if (event
->header
.type
!= PERF_RECORD_BPF_EVENT
)
493 switch (event
->bpf
.type
) {
494 case PERF_BPF_EVENT_PROG_LOAD
:
495 perf_env__add_bpf_info(env
, event
->bpf
.id
);
497 case PERF_BPF_EVENT_PROG_UNLOAD
:
499 * Do not free bpf_prog_info and btf of the program here,
500 * as annotation still need them. They will be freed at
501 * the end of the session.
505 pr_debug("unexpected bpf event type of %d\n", event
->bpf
.type
);
512 int evlist__add_bpf_sb_event(struct evlist
*evlist
, struct perf_env
*env
)
514 struct perf_event_attr attr
= {
515 .type
= PERF_TYPE_SOFTWARE
,
516 .config
= PERF_COUNT_SW_DUMMY
,
520 .size
= sizeof(attr
), /* to capture ABI version */
524 * Older gcc versions don't support designated initializers, like above,
525 * for unnamed union members, such as the following:
527 attr
.wakeup_watermark
= 1;
529 return evlist__add_sb_event(evlist
, &attr
, bpf_event__sb_cb
, env
);
532 void bpf_event__print_bpf_prog_info(struct bpf_prog_info
*info
,
533 struct perf_env
*env
,
536 __u32
*prog_lens
= (__u32
*)(uintptr_t)(info
->jited_func_lens
);
537 __u64
*prog_addrs
= (__u64
*)(uintptr_t)(info
->jited_ksyms
);
538 char name
[KSYM_NAME_LEN
];
539 struct btf
*btf
= NULL
;
542 sub_prog_cnt
= info
->nr_jited_ksyms
;
543 if (sub_prog_cnt
!= info
->nr_prog_tags
||
544 sub_prog_cnt
!= info
->nr_jited_func_lens
)
548 struct btf_node
*node
;
550 node
= perf_env__find_btf(env
, info
->btf_id
);
552 btf
= btf__new((__u8
*)(node
->data
),
556 if (sub_prog_cnt
== 1) {
557 synthesize_bpf_prog_name(name
, KSYM_NAME_LEN
, info
, btf
, 0);
558 fprintf(fp
, "# bpf_prog_info %u: %s addr 0x%llx size %u\n",
559 info
->id
, name
, prog_addrs
[0], prog_lens
[0]);
563 fprintf(fp
, "# bpf_prog_info %u:\n", info
->id
);
564 for (i
= 0; i
< sub_prog_cnt
; i
++) {
565 synthesize_bpf_prog_name(name
, KSYM_NAME_LEN
, info
, btf
, i
);
567 fprintf(fp
, "# \tsub_prog %u: %s addr 0x%llx size %u\n",
568 i
, name
, prog_addrs
[i
], prog_lens
[i
]);