blob: 5a79a8e7a45b1a98905dd0b7527d0c5cf514a040 [file] [log] [blame]
%parse-param {struct list_head *expr_head}
%define parse.error verbose
%{
#ifndef NDEBUG
#define YYDEBUG 1
#endif
#include <stdio.h>
#include <string.h>
#include <linux/compiler.h>
#include <linux/list.h>
#include "bpf-filter.h"
#include "cgroup.h"
int perf_bpf_filter_lex(void);
/* To indicate if the current term needs a pathname or not */
int perf_bpf_filter_needs_path;
static void perf_bpf_filter_error(struct list_head *expr __maybe_unused,
char const *msg)
{
printf("perf_bpf_filter: %s\n", msg);
}
%}
%union
{
unsigned long num;
char *path;
struct {
enum perf_bpf_filter_term term;
int part;
} sample;
enum perf_bpf_filter_op op;
struct perf_bpf_filter_expr *expr;
}
%token BFT_SAMPLE BFT_SAMPLE_PATH BFT_OP BFT_ERROR BFT_NUM BFT_LOGICAL_OR BFT_PATH
%type <expr> filter_term filter_expr
%destructor { free ($$); } <expr>
%type <sample> BFT_SAMPLE BFT_SAMPLE_PATH
%type <op> BFT_OP
%type <num> BFT_NUM
%type <path> BFT_PATH
%%
filter:
filter ',' filter_term
{
list_add_tail(&$3->list, expr_head);
}
|
filter_term
{
list_add_tail(&$1->list, expr_head);
}
filter_term:
filter_term BFT_LOGICAL_OR filter_expr
{
struct perf_bpf_filter_expr *expr;
if ($1->op == PBF_OP_GROUP_BEGIN) {
expr = $1;
} else {
expr = perf_bpf_filter_expr__new(PBF_TERM_NONE, /*part=*/0,
PBF_OP_GROUP_BEGIN, /*val=*/1);
list_add_tail(&$1->list, &expr->groups);
}
expr->val++;
list_add_tail(&$3->list, &expr->groups);
$$ = expr;
}
|
filter_expr
{
$$ = $1;
}
filter_expr:
BFT_SAMPLE BFT_OP BFT_NUM
{
$$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, $3);
}
|
BFT_SAMPLE_PATH BFT_OP BFT_PATH
{
struct cgroup *cgrp;
unsigned long cgroup_id = 0;
if ($2 != PBF_OP_EQ && $2 != PBF_OP_NEQ) {
printf("perf_bpf_filter: cgroup accepts '==' or '!=' only\n");
YYERROR;
}
cgrp = cgroup__new($3, /*do_open=*/false);
if (cgrp && read_cgroup_id(cgrp) == 0)
cgroup_id = cgrp->id;
$$ = perf_bpf_filter_expr__new($1.term, $1.part, $2, cgroup_id);
cgroup__put(cgrp);
}
%%