1 /* SPDX-License-Identifier: GPL-2.0 */
6 #include <internal/xyarray.h>
8 #include "util/debug.h"
9 #include "util/evsel.h"
11 #include "util/bpf-filter.h"
12 #include <util/bpf-filter-flex.h>
13 #include <util/bpf-filter-bison.h>
15 #include "bpf_skel/sample-filter.h"
16 #include "bpf_skel/sample_filter.skel.h"
18 #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
20 #define __PERF_SAMPLE_TYPE(tt, st, opt) { tt, #st, opt }
21 #define PERF_SAMPLE_TYPE(_st, opt) __PERF_SAMPLE_TYPE(PBF_TERM_##_st, PERF_SAMPLE_##_st, opt)
23 static const struct perf_sample_info {
24 enum perf_bpf_filter_term type;
28 /* default sample flags */
29 PERF_SAMPLE_TYPE(IP, NULL),
30 PERF_SAMPLE_TYPE(TID, NULL),
31 PERF_SAMPLE_TYPE(PERIOD, NULL),
32 /* flags mostly set by default, but still have options */
33 PERF_SAMPLE_TYPE(ID, "--sample-identifier"),
34 PERF_SAMPLE_TYPE(CPU, "--sample-cpu"),
35 PERF_SAMPLE_TYPE(TIME, "-T"),
36 /* optional sample flags */
37 PERF_SAMPLE_TYPE(ADDR, "-d"),
38 PERF_SAMPLE_TYPE(DATA_SRC, "-d"),
39 PERF_SAMPLE_TYPE(PHYS_ADDR, "--phys-data"),
40 PERF_SAMPLE_TYPE(WEIGHT, "-W"),
41 PERF_SAMPLE_TYPE(WEIGHT_STRUCT, "-W"),
42 PERF_SAMPLE_TYPE(TRANSACTION, "--transaction"),
43 PERF_SAMPLE_TYPE(CODE_PAGE_SIZE, "--code-page-size"),
44 PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"),
47 static const struct perf_sample_info *get_sample_info(enum perf_bpf_filter_term type)
51 for (i = 0; i < ARRAY_SIZE(sample_table); i++) {
52 if (sample_table[i].type == type)
53 return &sample_table[i];
58 static int check_sample_flags(struct evsel *evsel, struct perf_bpf_filter_expr *expr)
60 const struct perf_sample_info *info;
62 if (expr->term >= PBF_TERM_SAMPLE_START && expr->term <= PBF_TERM_SAMPLE_END &&
63 (evsel->core.attr.sample_type & (1 << (expr->term - PBF_TERM_SAMPLE_START))))
66 if (expr->term == PBF_TERM_UID || expr->term == PBF_TERM_GID) {
67 /* Not dependent on the sample_type as computed from a BPF helper. */
71 if (expr->op == PBF_OP_GROUP_BEGIN) {
72 struct perf_bpf_filter_expr *group;
74 list_for_each_entry(group, &expr->groups, list) {
75 if (check_sample_flags(evsel, group) < 0)
81 info = get_sample_info(expr->term);
83 pr_err("Error: %s event does not have sample flags %d\n",
84 evsel__name(evsel), expr->term);
88 pr_err("Error: %s event does not have %s\n", evsel__name(evsel), info->name);
90 pr_err(" Hint: please add %s option to perf record\n", info->option);
94 int perf_bpf_filter__prepare(struct evsel *evsel)
97 struct sample_filter_bpf *skel;
98 struct bpf_program *prog;
99 struct bpf_link *link;
100 struct perf_bpf_filter_expr *expr;
102 skel = sample_filter_bpf__open_and_load();
104 pr_err("Failed to load perf sample-filter BPF skeleton\n");
109 fd = bpf_map__fd(skel->maps.filters);
110 list_for_each_entry(expr, &evsel->bpf_filters, list) {
111 struct perf_bpf_filter_entry entry = {
118 if (check_sample_flags(evsel, expr) < 0)
121 bpf_map_update_elem(fd, &i, &entry, BPF_ANY);
124 if (expr->op == PBF_OP_GROUP_BEGIN) {
125 struct perf_bpf_filter_expr *group;
127 list_for_each_entry(group, &expr->groups, list) {
128 struct perf_bpf_filter_entry group_entry = {
134 bpf_map_update_elem(fd, &i, &group_entry, BPF_ANY);
138 memset(&entry, 0, sizeof(entry));
139 entry.op = PBF_OP_GROUP_END;
140 bpf_map_update_elem(fd, &i, &entry, BPF_ANY);
145 if (i > MAX_FILTERS) {
146 pr_err("Too many filters: %d (max = %d)\n", i, MAX_FILTERS);
149 prog = skel->progs.perf_sample_filter;
150 for (x = 0; x < xyarray__max_x(evsel->core.fd); x++) {
151 for (y = 0; y < xyarray__max_y(evsel->core.fd); y++) {
152 link = bpf_program__attach_perf_event(prog, FD(evsel, x, y));
154 pr_err("Failed to attach perf sample-filter program\n");
155 return PTR_ERR(link);
159 evsel->bpf_skel = skel;
163 int perf_bpf_filter__destroy(struct evsel *evsel)
165 struct perf_bpf_filter_expr *expr, *tmp;
167 list_for_each_entry_safe(expr, tmp, &evsel->bpf_filters, list) {
168 list_del(&expr->list);
171 sample_filter_bpf__destroy(evsel->bpf_skel);
175 u64 perf_bpf_filter__lost_count(struct evsel *evsel)
177 struct sample_filter_bpf *skel = evsel->bpf_skel;
179 return skel ? skel->bss->dropped : 0;
182 struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(enum perf_bpf_filter_term term,
184 enum perf_bpf_filter_op op,
187 struct perf_bpf_filter_expr *expr;
189 expr = malloc(sizeof(*expr));
195 INIT_LIST_HEAD(&expr->groups);
200 int perf_bpf_filter__parse(struct list_head *expr_head, const char *str)
202 YY_BUFFER_STATE buffer;
205 buffer = perf_bpf_filter__scan_string(str);
207 ret = perf_bpf_filter_parse(expr_head);
209 perf_bpf_filter__flush_buffer(buffer);
210 perf_bpf_filter__delete_buffer(buffer);
211 perf_bpf_filter_lex_destroy();