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"
13 #include "bpf-utils.h"
23 #include "util/synthetic-events.h"
25 static int snprintf_hex(char *buf
, size_t size
, unsigned char *data
, size_t len
)
30 for (i
= 0; i
< len
; i
++)
31 ret
+= snprintf(buf
+ ret
, size
- ret
, "%02x", data
[i
]);
35 static int machine__process_bpf_event_load(struct machine
*machine
,
36 union perf_event
*event
,
37 struct perf_sample
*sample __maybe_unused
)
39 struct bpf_prog_info_node
*info_node
;
40 struct perf_env
*env
= machine
->env
;
41 struct perf_bpil
*info_linear
;
42 int id
= event
->bpf
.id
;
45 /* perf-record, no need to handle bpf-event */
49 info_node
= perf_env__find_bpf_prog_info(env
, id
);
52 info_linear
= info_node
->info_linear
;
54 for (i
= 0; i
< info_linear
->info
.nr_jited_ksyms
; i
++) {
55 u64
*addrs
= (u64
*)(uintptr_t)(info_linear
->info
.jited_ksyms
);
57 struct map
*map
= maps__find(machine__kernel_maps(machine
), addr
);
60 struct dso
*dso
= map__dso(map
);
62 dso__set_binary_type(dso
, DSO_BINARY_TYPE__BPF_PROG_INFO
);
63 dso__bpf_prog(dso
)->id
= id
;
64 dso__bpf_prog(dso
)->sub_id
= i
;
65 dso__bpf_prog(dso
)->env
= env
;
72 int machine__process_bpf(struct machine
*machine
, union perf_event
*event
,
73 struct perf_sample
*sample
)
76 perf_event__fprintf_bpf(event
, stdout
);
78 switch (event
->bpf
.type
) {
79 case PERF_BPF_EVENT_PROG_LOAD
:
80 return machine__process_bpf_event_load(machine
, event
, sample
);
82 case PERF_BPF_EVENT_PROG_UNLOAD
:
84 * Do not free bpf_prog_info and btf of the program here,
85 * as annotation still need them. They will be freed at
86 * the end of the session.
90 pr_debug("unexpected bpf event type of %d\n", event
->bpf
.type
);
96 static int perf_env__fetch_btf(struct perf_env
*env
,
100 struct btf_node
*node
;
104 data
= btf__raw_data(btf
, &data_size
);
106 node
= malloc(data_size
+ sizeof(struct btf_node
));
111 node
->data_size
= data_size
;
112 memcpy(node
->data
, data
, data_size
);
114 if (!perf_env__insert_btf(env
, node
)) {
115 /* Insertion failed because of a duplicate. */
122 static int synthesize_bpf_prog_name(char *buf
, int size
,
123 struct bpf_prog_info
*info
,
127 u8 (*prog_tags
)[BPF_TAG_SIZE
] = (void *)(uintptr_t)(info
->prog_tags
);
128 void *func_infos
= (void *)(uintptr_t)(info
->func_info
);
129 u32 sub_prog_cnt
= info
->nr_jited_ksyms
;
130 const struct bpf_func_info
*finfo
;
131 const char *short_name
= NULL
;
132 const struct btf_type
*t
;
135 name_len
= snprintf(buf
, size
, "bpf_prog_");
136 name_len
+= snprintf_hex(buf
+ name_len
, size
- name_len
,
137 prog_tags
[sub_id
], BPF_TAG_SIZE
);
139 finfo
= func_infos
+ sub_id
* info
->func_info_rec_size
;
140 t
= btf__type_by_id(btf
, finfo
->type_id
);
141 short_name
= btf__name_by_offset(btf
, t
->name_off
);
142 } else if (sub_id
== 0 && sub_prog_cnt
== 1) {
145 short_name
= info
->name
;
149 name_len
+= snprintf(buf
+ name_len
, size
- name_len
,
155 * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf
156 * program. One PERF_RECORD_BPF_EVENT is generated for the program. And
157 * one PERF_RECORD_KSYMBOL is generated for each sub program.
162 * -2 for lack of kernel support.
164 static int perf_event__synthesize_one_bpf_prog(struct perf_session
*session
,
165 perf_event__handler_t process
,
166 struct machine
*machine
,
168 union perf_event
*event
,
169 struct record_opts
*opts
)
171 struct perf_record_ksymbol
*ksymbol_event
= &event
->ksymbol
;
172 struct perf_record_bpf_event
*bpf_event
= &event
->bpf
;
173 const struct perf_tool
*tool
= session
->tool
;
174 struct bpf_prog_info_node
*info_node
;
175 struct perf_bpil
*info_linear
;
176 struct bpf_prog_info
*info
;
177 struct btf
*btf
= NULL
;
178 struct perf_env
*env
;
184 * for perf-record and perf-report use header.env;
185 * otherwise, use global perf_env.
187 env
= session
->data
? &session
->header
.env
: &perf_env
;
189 arrays
= 1UL << PERF_BPIL_JITED_KSYMS
;
190 arrays
|= 1UL << PERF_BPIL_JITED_FUNC_LENS
;
191 arrays
|= 1UL << PERF_BPIL_FUNC_INFO
;
192 arrays
|= 1UL << PERF_BPIL_PROG_TAGS
;
193 arrays
|= 1UL << PERF_BPIL_JITED_INSNS
;
194 arrays
|= 1UL << PERF_BPIL_LINE_INFO
;
195 arrays
|= 1UL << PERF_BPIL_JITED_LINE_INFO
;
197 info_linear
= get_bpf_prog_info_linear(fd
, arrays
);
198 if (IS_ERR_OR_NULL(info_linear
)) {
200 pr_debug("%s: failed to get BPF program info. aborting\n", __func__
);
204 if (info_linear
->info_len
< offsetof(struct bpf_prog_info
, prog_tags
)) {
206 pr_debug("%s: the kernel is too old, aborting\n", __func__
);
210 info
= &info_linear
->info
;
211 if (!info
->jited_ksyms
) {
216 /* number of ksyms, func_lengths, and tags should match */
217 sub_prog_cnt
= info
->nr_jited_ksyms
;
218 if (sub_prog_cnt
!= info
->nr_prog_tags
||
219 sub_prog_cnt
!= info
->nr_jited_func_lens
) {
224 /* check BTF func info support */
225 if (info
->btf_id
&& info
->nr_func_info
&& info
->func_info_rec_size
) {
226 /* btf func info number should be same as sub_prog_cnt */
227 if (sub_prog_cnt
!= info
->nr_func_info
) {
228 pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__
);
232 btf
= btf__load_from_kernel_by_id(info
->btf_id
);
233 if (libbpf_get_error(btf
)) {
234 pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__
, info
->btf_id
);
238 perf_env__fetch_btf(env
, info
->btf_id
, btf
);
241 /* Synthesize PERF_RECORD_KSYMBOL */
242 for (i
= 0; i
< sub_prog_cnt
; i
++) {
243 __u32
*prog_lens
= (__u32
*)(uintptr_t)(info
->jited_func_lens
);
244 __u64
*prog_addrs
= (__u64
*)(uintptr_t)(info
->jited_ksyms
);
247 *ksymbol_event
= (struct perf_record_ksymbol
) {
249 .type
= PERF_RECORD_KSYMBOL
,
250 .size
= offsetof(struct perf_record_ksymbol
, name
),
252 .addr
= prog_addrs
[i
],
254 .ksym_type
= PERF_RECORD_KSYMBOL_TYPE_BPF
,
258 name_len
= synthesize_bpf_prog_name(ksymbol_event
->name
,
259 KSYM_NAME_LEN
, info
, btf
, i
);
260 ksymbol_event
->header
.size
+= PERF_ALIGN(name_len
+ 1,
263 memset((void *)event
+ event
->header
.size
, 0, machine
->id_hdr_size
);
264 event
->header
.size
+= machine
->id_hdr_size
;
265 err
= perf_tool__process_synth_event(tool
, event
,
269 if (!opts
->no_bpf_event
) {
270 /* Synthesize PERF_RECORD_BPF_EVENT */
271 *bpf_event
= (struct perf_record_bpf_event
) {
273 .type
= PERF_RECORD_BPF_EVENT
,
274 .size
= sizeof(struct perf_record_bpf_event
),
276 .type
= PERF_BPF_EVENT_PROG_LOAD
,
280 memcpy(bpf_event
->tag
, info
->tag
, BPF_TAG_SIZE
);
281 memset((void *)event
+ event
->header
.size
, 0, machine
->id_hdr_size
);
282 event
->header
.size
+= machine
->id_hdr_size
;
284 /* save bpf_prog_info to env */
285 info_node
= malloc(sizeof(struct bpf_prog_info_node
));
291 info_node
->info_linear
= info_linear
;
292 perf_env__insert_bpf_prog_info(env
, info_node
);
296 * process after saving bpf_prog_info to env, so that
297 * required information is ready for look up
299 err
= perf_tool__process_synth_event(tool
, event
,
309 struct kallsyms_parse
{
310 union perf_event
*event
;
311 perf_event__handler_t process
;
312 struct machine
*machine
;
313 const struct perf_tool
*tool
;
317 process_bpf_image(char *name
, u64 addr
, struct kallsyms_parse
*data
)
319 struct machine
*machine
= data
->machine
;
320 union perf_event
*event
= data
->event
;
321 struct perf_record_ksymbol
*ksymbol
;
324 ksymbol
= &event
->ksymbol
;
326 *ksymbol
= (struct perf_record_ksymbol
) {
328 .type
= PERF_RECORD_KSYMBOL
,
329 .size
= offsetof(struct perf_record_ksymbol
, name
),
333 .ksym_type
= PERF_RECORD_KSYMBOL_TYPE_BPF
,
337 len
= scnprintf(ksymbol
->name
, KSYM_NAME_LEN
, "%s", name
);
338 ksymbol
->header
.size
+= PERF_ALIGN(len
+ 1, sizeof(u64
));
339 memset((void *) event
+ event
->header
.size
, 0, machine
->id_hdr_size
);
340 event
->header
.size
+= machine
->id_hdr_size
;
342 return perf_tool__process_synth_event(data
->tool
, event
, machine
,
347 kallsyms_process_symbol(void *data
, const char *_name
,
348 char type __maybe_unused
, u64 start
)
350 char disp
[KSYM_NAME_LEN
];
355 module
= strchr(_name
, '\t');
359 /* We are going after [bpf] module ... */
360 if (strcmp(module
+ 1, "[bpf]"))
363 name
= memdup(_name
, (module
- _name
) + 1);
367 name
[module
- _name
] = 0;
369 /* .. and only for trampolines and dispatchers */
370 if ((sscanf(name
, "bpf_trampoline_%lu", &id
) == 1) ||
371 (sscanf(name
, "bpf_dispatcher_%s", disp
) == 1))
372 err
= process_bpf_image(name
, start
, data
);
378 int perf_event__synthesize_bpf_events(struct perf_session
*session
,
379 perf_event__handler_t process
,
380 struct machine
*machine
,
381 struct record_opts
*opts
)
383 const char *kallsyms_filename
= "/proc/kallsyms";
384 struct kallsyms_parse arg
;
385 union perf_event
*event
;
390 if (opts
->no_bpf_event
)
393 event
= malloc(sizeof(event
->bpf
) + KSYM_NAME_LEN
+ machine
->id_hdr_size
);
397 /* Synthesize all the bpf programs in system. */
399 err
= bpf_prog_get_next_id(id
, &id
);
401 if (errno
== ENOENT
) {
405 pr_debug("%s: can't get next program: %s%s\n",
406 __func__
, strerror(errno
),
407 errno
== EINVAL
? " -- kernel too old?" : "");
408 /* don't report error on old kernel or EPERM */
409 err
= (errno
== EINVAL
|| errno
== EPERM
) ? 0 : -1;
412 fd
= bpf_prog_get_fd_by_id(id
);
414 pr_debug("%s: failed to get fd for prog_id %u\n",
419 err
= perf_event__synthesize_one_bpf_prog(session
, process
,
424 /* do not return error for old kernel */
431 /* Synthesize all the bpf images - trampolines/dispatchers. */
432 if (symbol_conf
.kallsyms_name
!= NULL
)
433 kallsyms_filename
= symbol_conf
.kallsyms_name
;
435 arg
= (struct kallsyms_parse
) {
439 .tool
= session
->tool
,
442 if (kallsyms__parse(kallsyms_filename
, &arg
, kallsyms_process_symbol
)) {
443 pr_err("%s: failed to synthesize bpf images: %s\n",
444 __func__
, strerror(errno
));
451 static void perf_env__add_bpf_info(struct perf_env
*env
, u32 id
)
453 struct bpf_prog_info_node
*info_node
;
454 struct perf_bpil
*info_linear
;
455 struct btf
*btf
= NULL
;
460 fd
= bpf_prog_get_fd_by_id(id
);
464 arrays
= 1UL << PERF_BPIL_JITED_KSYMS
;
465 arrays
|= 1UL << PERF_BPIL_JITED_FUNC_LENS
;
466 arrays
|= 1UL << PERF_BPIL_FUNC_INFO
;
467 arrays
|= 1UL << PERF_BPIL_PROG_TAGS
;
468 arrays
|= 1UL << PERF_BPIL_JITED_INSNS
;
469 arrays
|= 1UL << PERF_BPIL_LINE_INFO
;
470 arrays
|= 1UL << PERF_BPIL_JITED_LINE_INFO
;
472 info_linear
= get_bpf_prog_info_linear(fd
, arrays
);
473 if (IS_ERR_OR_NULL(info_linear
)) {
474 pr_debug("%s: failed to get BPF program info. aborting\n", __func__
);
478 btf_id
= info_linear
->info
.btf_id
;
480 info_node
= malloc(sizeof(struct bpf_prog_info_node
));
482 info_node
->info_linear
= info_linear
;
483 perf_env__insert_bpf_prog_info(env
, info_node
);
490 btf
= btf__load_from_kernel_by_id(btf_id
);
491 if (libbpf_get_error(btf
)) {
492 pr_debug("%s: failed to get BTF of id %u, aborting\n",
496 perf_env__fetch_btf(env
, btf_id
, btf
);
503 static int bpf_event__sb_cb(union perf_event
*event
, void *data
)
505 struct perf_env
*env
= data
;
507 if (event
->header
.type
!= PERF_RECORD_BPF_EVENT
)
510 switch (event
->bpf
.type
) {
511 case PERF_BPF_EVENT_PROG_LOAD
:
512 perf_env__add_bpf_info(env
, event
->bpf
.id
);
514 case PERF_BPF_EVENT_PROG_UNLOAD
:
516 * Do not free bpf_prog_info and btf of the program here,
517 * as annotation still need them. They will be freed at
518 * the end of the session.
522 pr_debug("unexpected bpf event type of %d\n", event
->bpf
.type
);
529 int evlist__add_bpf_sb_event(struct evlist
*evlist
, struct perf_env
*env
)
531 struct perf_event_attr attr
= {
532 .type
= PERF_TYPE_SOFTWARE
,
533 .config
= PERF_COUNT_SW_DUMMY
,
537 .size
= sizeof(attr
), /* to capture ABI version */
541 * Older gcc versions don't support designated initializers, like above,
542 * for unnamed union members, such as the following:
544 attr
.wakeup_watermark
= 1;
546 return evlist__add_sb_event(evlist
, &attr
, bpf_event__sb_cb
, env
);
549 void __bpf_event__print_bpf_prog_info(struct bpf_prog_info
*info
,
550 struct perf_env
*env
,
553 __u32
*prog_lens
= (__u32
*)(uintptr_t)(info
->jited_func_lens
);
554 __u64
*prog_addrs
= (__u64
*)(uintptr_t)(info
->jited_ksyms
);
555 char name
[KSYM_NAME_LEN
];
556 struct btf
*btf
= NULL
;
559 sub_prog_cnt
= info
->nr_jited_ksyms
;
560 if (sub_prog_cnt
!= info
->nr_prog_tags
||
561 sub_prog_cnt
!= info
->nr_jited_func_lens
)
565 struct btf_node
*node
;
567 node
= __perf_env__find_btf(env
, info
->btf_id
);
569 btf
= btf__new((__u8
*)(node
->data
),
573 if (sub_prog_cnt
== 1) {
574 synthesize_bpf_prog_name(name
, KSYM_NAME_LEN
, info
, btf
, 0);
575 fprintf(fp
, "# bpf_prog_info %u: %s addr 0x%llx size %u\n",
576 info
->id
, name
, prog_addrs
[0], prog_lens
[0]);
580 fprintf(fp
, "# bpf_prog_info %u:\n", info
->id
);
581 for (i
= 0; i
< sub_prog_cnt
; i
++) {
582 synthesize_bpf_prog_name(name
, KSYM_NAME_LEN
, info
, btf
, i
);
584 fprintf(fp
, "# \tsub_prog %u: %s addr 0x%llx size %u\n",
585 i
, name
, prog_addrs
[i
], prog_lens
[i
]);