perf bpf filter: Implement event sample filtering
[platform/kernel/linux-starfive.git] / tools / perf / util / bpf-filter.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <stdlib.h>
3
4 #include <bpf/bpf.h>
5 #include <linux/err.h>
6 #include <internal/xyarray.h>
7
8 #include "util/debug.h"
9 #include "util/evsel.h"
10
11 #include "util/bpf-filter.h"
12 #include "util/bpf-filter-flex.h"
13 #include "util/bpf-filter-bison.h"
14
15 #include "bpf_skel/sample-filter.h"
16 #include "bpf_skel/sample_filter.skel.h"
17
18 #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
19
20 int perf_bpf_filter__prepare(struct evsel *evsel)
21 {
22         int i, x, y, fd;
23         struct sample_filter_bpf *skel;
24         struct bpf_program *prog;
25         struct bpf_link *link;
26         struct perf_bpf_filter_expr *expr;
27
28         skel = sample_filter_bpf__open_and_load();
29         if (!skel) {
30                 pr_err("Failed to load perf sample-filter BPF skeleton\n");
31                 return -1;
32         }
33
34         i = 0;
35         fd = bpf_map__fd(skel->maps.filters);
36         list_for_each_entry(expr, &evsel->bpf_filters, list) {
37                 struct perf_bpf_filter_entry entry = {
38                         .op = expr->op,
39                         .flags = expr->sample_flags,
40                         .value = expr->val,
41                 };
42                 bpf_map_update_elem(fd, &i, &entry, BPF_ANY);
43                 i++;
44         }
45
46         prog = skel->progs.perf_sample_filter;
47         for (x = 0; x < xyarray__max_x(evsel->core.fd); x++) {
48                 for (y = 0; y < xyarray__max_y(evsel->core.fd); y++) {
49                         link = bpf_program__attach_perf_event(prog, FD(evsel, x, y));
50                         if (IS_ERR(link)) {
51                                 pr_err("Failed to attach perf sample-filter program\n");
52                                 return PTR_ERR(link);
53                         }
54                 }
55         }
56         evsel->bpf_skel = skel;
57         return 0;
58 }
59
60 int perf_bpf_filter__destroy(struct evsel *evsel)
61 {
62         struct perf_bpf_filter_expr *expr, *tmp;
63
64         list_for_each_entry_safe(expr, tmp, &evsel->bpf_filters, list) {
65                 list_del(&expr->list);
66                 free(expr);
67         }
68         sample_filter_bpf__destroy(evsel->bpf_skel);
69         return 0;
70 }
71
72 struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags,
73                                                        enum perf_bpf_filter_op op,
74                                                        unsigned long val)
75 {
76         struct perf_bpf_filter_expr *expr;
77
78         expr = malloc(sizeof(*expr));
79         if (expr != NULL) {
80                 expr->sample_flags = sample_flags;
81                 expr->op = op;
82                 expr->val = val;
83         }
84         return expr;
85 }
86
87 int perf_bpf_filter__parse(struct list_head *expr_head, const char *str)
88 {
89         YY_BUFFER_STATE buffer;
90         int ret;
91
92         buffer = perf_bpf_filter__scan_string(str);
93
94         ret = perf_bpf_filter_parse(expr_head);
95
96         perf_bpf_filter__flush_buffer(buffer);
97         perf_bpf_filter__delete_buffer(buffer);
98         perf_bpf_filter_lex_destroy();
99
100         return ret;
101 }