1990a71e9SNamhyung Kim /* SPDX-License-Identifier: GPL-2.0 */ 2990a71e9SNamhyung Kim #include <stdlib.h> 3990a71e9SNamhyung Kim 456ec9457SNamhyung Kim #include <bpf/bpf.h> 556ec9457SNamhyung Kim #include <linux/err.h> 656ec9457SNamhyung Kim #include <internal/xyarray.h> 756ec9457SNamhyung Kim 856ec9457SNamhyung Kim #include "util/debug.h" 956ec9457SNamhyung Kim #include "util/evsel.h" 1056ec9457SNamhyung Kim 11990a71e9SNamhyung Kim #include "util/bpf-filter.h" 12*c7e97f21SNamhyung Kim #include <util/bpf-filter-flex.h> 13*c7e97f21SNamhyung Kim #include <util/bpf-filter-bison.h> 14990a71e9SNamhyung Kim 1556ec9457SNamhyung Kim #include "bpf_skel/sample-filter.h" 1656ec9457SNamhyung Kim #include "bpf_skel/sample_filter.skel.h" 1756ec9457SNamhyung Kim 1856ec9457SNamhyung Kim #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) 1956ec9457SNamhyung Kim 204310551bSNamhyung Kim #define __PERF_SAMPLE_TYPE(st, opt) { st, #st, opt } 214310551bSNamhyung Kim #define PERF_SAMPLE_TYPE(_st, opt) __PERF_SAMPLE_TYPE(PERF_SAMPLE_##_st, opt) 224310551bSNamhyung Kim 234310551bSNamhyung Kim static const struct perf_sample_info { 244310551bSNamhyung Kim u64 type; 254310551bSNamhyung Kim const char *name; 264310551bSNamhyung Kim const char *option; 274310551bSNamhyung Kim } sample_table[] = { 284310551bSNamhyung Kim /* default sample flags */ 294310551bSNamhyung Kim PERF_SAMPLE_TYPE(IP, NULL), 304310551bSNamhyung Kim PERF_SAMPLE_TYPE(TID, NULL), 314310551bSNamhyung Kim PERF_SAMPLE_TYPE(PERIOD, NULL), 324310551bSNamhyung Kim /* flags mostly set by default, but still have options */ 334310551bSNamhyung Kim PERF_SAMPLE_TYPE(ID, "--sample-identifier"), 344310551bSNamhyung Kim PERF_SAMPLE_TYPE(CPU, "--sample-cpu"), 354310551bSNamhyung Kim PERF_SAMPLE_TYPE(TIME, "-T"), 364310551bSNamhyung Kim /* optional sample flags */ 374310551bSNamhyung Kim PERF_SAMPLE_TYPE(ADDR, "-d"), 384310551bSNamhyung Kim PERF_SAMPLE_TYPE(DATA_SRC, "-d"), 394310551bSNamhyung Kim PERF_SAMPLE_TYPE(PHYS_ADDR, "--phys-data"), 404310551bSNamhyung Kim PERF_SAMPLE_TYPE(WEIGHT, "-W"), 414310551bSNamhyung Kim PERF_SAMPLE_TYPE(WEIGHT_STRUCT, "-W"), 424310551bSNamhyung Kim PERF_SAMPLE_TYPE(TRANSACTION, "--transaction"), 434310551bSNamhyung Kim PERF_SAMPLE_TYPE(CODE_PAGE_SIZE, "--code-page-size"), 444310551bSNamhyung Kim PERF_SAMPLE_TYPE(DATA_PAGE_SIZE, "--data-page-size"), 454310551bSNamhyung Kim }; 464310551bSNamhyung Kim 474310551bSNamhyung Kim static const struct perf_sample_info *get_sample_info(u64 flags) 484310551bSNamhyung Kim { 494310551bSNamhyung Kim size_t i; 504310551bSNamhyung Kim 514310551bSNamhyung Kim for (i = 0; i < ARRAY_SIZE(sample_table); i++) { 524310551bSNamhyung Kim if (sample_table[i].type == flags) 534310551bSNamhyung Kim return &sample_table[i]; 544310551bSNamhyung Kim } 554310551bSNamhyung Kim return NULL; 564310551bSNamhyung Kim } 574310551bSNamhyung Kim 584310551bSNamhyung Kim static int check_sample_flags(struct evsel *evsel, struct perf_bpf_filter_expr *expr) 594310551bSNamhyung Kim { 604310551bSNamhyung Kim const struct perf_sample_info *info; 614310551bSNamhyung Kim 624310551bSNamhyung Kim if (evsel->core.attr.sample_type & expr->sample_flags) 634310551bSNamhyung Kim return 0; 644310551bSNamhyung Kim 654310551bSNamhyung Kim info = get_sample_info(expr->sample_flags); 664310551bSNamhyung Kim if (info == NULL) { 674310551bSNamhyung Kim pr_err("Error: %s event does not have sample flags %lx\n", 684310551bSNamhyung Kim evsel__name(evsel), expr->sample_flags); 694310551bSNamhyung Kim return -1; 704310551bSNamhyung Kim } 714310551bSNamhyung Kim 724310551bSNamhyung Kim pr_err("Error: %s event does not have %s\n", evsel__name(evsel), info->name); 734310551bSNamhyung Kim if (info->option) 744310551bSNamhyung Kim pr_err(" Hint: please add %s option to perf record\n", info->option); 754310551bSNamhyung Kim return -1; 764310551bSNamhyung Kim } 774310551bSNamhyung Kim 7856ec9457SNamhyung Kim int perf_bpf_filter__prepare(struct evsel *evsel) 7956ec9457SNamhyung Kim { 8056ec9457SNamhyung Kim int i, x, y, fd; 8156ec9457SNamhyung Kim struct sample_filter_bpf *skel; 8256ec9457SNamhyung Kim struct bpf_program *prog; 8356ec9457SNamhyung Kim struct bpf_link *link; 8456ec9457SNamhyung Kim struct perf_bpf_filter_expr *expr; 8556ec9457SNamhyung Kim 8656ec9457SNamhyung Kim skel = sample_filter_bpf__open_and_load(); 8756ec9457SNamhyung Kim if (!skel) { 8856ec9457SNamhyung Kim pr_err("Failed to load perf sample-filter BPF skeleton\n"); 8956ec9457SNamhyung Kim return -1; 9056ec9457SNamhyung Kim } 9156ec9457SNamhyung Kim 9256ec9457SNamhyung Kim i = 0; 9356ec9457SNamhyung Kim fd = bpf_map__fd(skel->maps.filters); 9456ec9457SNamhyung Kim list_for_each_entry(expr, &evsel->bpf_filters, list) { 9556ec9457SNamhyung Kim struct perf_bpf_filter_entry entry = { 9656ec9457SNamhyung Kim .op = expr->op, 9733581847SNamhyung Kim .part = expr->part, 9856ec9457SNamhyung Kim .flags = expr->sample_flags, 9956ec9457SNamhyung Kim .value = expr->val, 10056ec9457SNamhyung Kim }; 1014310551bSNamhyung Kim 1024310551bSNamhyung Kim if (check_sample_flags(evsel, expr) < 0) 1034310551bSNamhyung Kim return -1; 1044310551bSNamhyung Kim 10556ec9457SNamhyung Kim bpf_map_update_elem(fd, &i, &entry, BPF_ANY); 10656ec9457SNamhyung Kim i++; 10746996dd7SNamhyung Kim 10846996dd7SNamhyung Kim if (expr->op == PBF_OP_GROUP_BEGIN) { 10946996dd7SNamhyung Kim struct perf_bpf_filter_expr *group; 11046996dd7SNamhyung Kim 11146996dd7SNamhyung Kim list_for_each_entry(group, &expr->groups, list) { 11246996dd7SNamhyung Kim struct perf_bpf_filter_entry group_entry = { 11346996dd7SNamhyung Kim .op = group->op, 11446996dd7SNamhyung Kim .part = group->part, 11546996dd7SNamhyung Kim .flags = group->sample_flags, 11646996dd7SNamhyung Kim .value = group->val, 11746996dd7SNamhyung Kim }; 11846996dd7SNamhyung Kim bpf_map_update_elem(fd, &i, &group_entry, BPF_ANY); 11946996dd7SNamhyung Kim i++; 12056ec9457SNamhyung Kim } 12156ec9457SNamhyung Kim 12246996dd7SNamhyung Kim memset(&entry, 0, sizeof(entry)); 12346996dd7SNamhyung Kim entry.op = PBF_OP_GROUP_END; 12446996dd7SNamhyung Kim bpf_map_update_elem(fd, &i, &entry, BPF_ANY); 12546996dd7SNamhyung Kim i++; 12646996dd7SNamhyung Kim } 12746996dd7SNamhyung Kim } 12846996dd7SNamhyung Kim 12946996dd7SNamhyung Kim if (i > MAX_FILTERS) { 13046996dd7SNamhyung Kim pr_err("Too many filters: %d (max = %d)\n", i, MAX_FILTERS); 13146996dd7SNamhyung Kim return -1; 13246996dd7SNamhyung Kim } 13356ec9457SNamhyung Kim prog = skel->progs.perf_sample_filter; 13456ec9457SNamhyung Kim for (x = 0; x < xyarray__max_x(evsel->core.fd); x++) { 13556ec9457SNamhyung Kim for (y = 0; y < xyarray__max_y(evsel->core.fd); y++) { 13656ec9457SNamhyung Kim link = bpf_program__attach_perf_event(prog, FD(evsel, x, y)); 13756ec9457SNamhyung Kim if (IS_ERR(link)) { 13856ec9457SNamhyung Kim pr_err("Failed to attach perf sample-filter program\n"); 13956ec9457SNamhyung Kim return PTR_ERR(link); 14056ec9457SNamhyung Kim } 14156ec9457SNamhyung Kim } 14256ec9457SNamhyung Kim } 14356ec9457SNamhyung Kim evsel->bpf_skel = skel; 14456ec9457SNamhyung Kim return 0; 14556ec9457SNamhyung Kim } 14656ec9457SNamhyung Kim 14756ec9457SNamhyung Kim int perf_bpf_filter__destroy(struct evsel *evsel) 14856ec9457SNamhyung Kim { 14956ec9457SNamhyung Kim struct perf_bpf_filter_expr *expr, *tmp; 15056ec9457SNamhyung Kim 15156ec9457SNamhyung Kim list_for_each_entry_safe(expr, tmp, &evsel->bpf_filters, list) { 15256ec9457SNamhyung Kim list_del(&expr->list); 15356ec9457SNamhyung Kim free(expr); 15456ec9457SNamhyung Kim } 15556ec9457SNamhyung Kim sample_filter_bpf__destroy(evsel->bpf_skel); 15656ec9457SNamhyung Kim return 0; 15756ec9457SNamhyung Kim } 15856ec9457SNamhyung Kim 15927c6f245SNamhyung Kim u64 perf_bpf_filter__lost_count(struct evsel *evsel) 16027c6f245SNamhyung Kim { 16127c6f245SNamhyung Kim struct sample_filter_bpf *skel = evsel->bpf_skel; 16227c6f245SNamhyung Kim 16327c6f245SNamhyung Kim return skel ? skel->bss->dropped : 0; 16427c6f245SNamhyung Kim } 16527c6f245SNamhyung Kim 16633581847SNamhyung Kim struct perf_bpf_filter_expr *perf_bpf_filter_expr__new(unsigned long sample_flags, int part, 167990a71e9SNamhyung Kim enum perf_bpf_filter_op op, 168990a71e9SNamhyung Kim unsigned long val) 169990a71e9SNamhyung Kim { 170990a71e9SNamhyung Kim struct perf_bpf_filter_expr *expr; 171990a71e9SNamhyung Kim 172990a71e9SNamhyung Kim expr = malloc(sizeof(*expr)); 173990a71e9SNamhyung Kim if (expr != NULL) { 174990a71e9SNamhyung Kim expr->sample_flags = sample_flags; 17533581847SNamhyung Kim expr->part = part; 176990a71e9SNamhyung Kim expr->op = op; 177990a71e9SNamhyung Kim expr->val = val; 17846996dd7SNamhyung Kim INIT_LIST_HEAD(&expr->groups); 179990a71e9SNamhyung Kim } 180990a71e9SNamhyung Kim return expr; 181990a71e9SNamhyung Kim } 182990a71e9SNamhyung Kim 183990a71e9SNamhyung Kim int perf_bpf_filter__parse(struct list_head *expr_head, const char *str) 184990a71e9SNamhyung Kim { 185990a71e9SNamhyung Kim YY_BUFFER_STATE buffer; 186990a71e9SNamhyung Kim int ret; 187990a71e9SNamhyung Kim 188990a71e9SNamhyung Kim buffer = perf_bpf_filter__scan_string(str); 189990a71e9SNamhyung Kim 190990a71e9SNamhyung Kim ret = perf_bpf_filter_parse(expr_head); 191990a71e9SNamhyung Kim 192990a71e9SNamhyung Kim perf_bpf_filter__flush_buffer(buffer); 193990a71e9SNamhyung Kim perf_bpf_filter__delete_buffer(buffer); 194990a71e9SNamhyung Kim perf_bpf_filter_lex_destroy(); 195990a71e9SNamhyung Kim 196990a71e9SNamhyung Kim return ret; 197990a71e9SNamhyung Kim } 198