cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

parse-events.y (18898B)


      1%define api.pure full
      2%parse-param {void *_parse_state}
      3%parse-param {void *scanner}
      4%lex-param {void* scanner}
      5%locations
      6
      7%{
      8
      9#define YYDEBUG 1
     10
     11#include <fnmatch.h>
     12#include <stdio.h>
     13#include <linux/compiler.h>
     14#include <linux/types.h>
     15#include <linux/zalloc.h>
     16#include "pmu.h"
     17#include "evsel.h"
     18#include "parse-events.h"
     19#include "parse-events-bison.h"
     20
     21void parse_events_error(YYLTYPE *loc, void *parse_state, void *scanner, char const *msg);
     22
     23#define ABORT_ON(val) \
     24do { \
     25	if (val) \
     26		YYABORT; \
     27} while (0)
     28
     29static struct list_head* alloc_list(void)
     30{
     31	struct list_head *list;
     32
     33	list = malloc(sizeof(*list));
     34	if (!list)
     35		return NULL;
     36
     37	INIT_LIST_HEAD(list);
     38	return list;
     39}
     40
     41static void free_list_evsel(struct list_head* list_evsel)
     42{
     43	struct evsel *evsel, *tmp;
     44
     45	list_for_each_entry_safe(evsel, tmp, list_evsel, core.node) {
     46		list_del_init(&evsel->core.node);
     47		evsel__delete(evsel);
     48	}
     49	free(list_evsel);
     50}
     51
     52static void inc_group_count(struct list_head *list,
     53		       struct parse_events_state *parse_state)
     54{
     55	/* Count groups only have more than 1 members */
     56	if (!list_is_last(list->next, list))
     57		parse_state->nr_groups++;
     58}
     59
     60%}
     61
     62%token PE_START_EVENTS PE_START_TERMS
     63%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
     64%token PE_VALUE_SYM_TOOL
     65%token PE_EVENT_NAME
     66%token PE_NAME
     67%token PE_BPF_OBJECT PE_BPF_SOURCE
     68%token PE_MODIFIER_EVENT PE_MODIFIER_BP
     69%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
     70%token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
     71%token PE_ERROR
     72%token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_PMU_EVENT_SUF2 PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE
     73%token PE_ARRAY_ALL PE_ARRAY_RANGE
     74%token PE_DRV_CFG_TERM
     75%type <num> PE_VALUE
     76%type <num> PE_VALUE_SYM_HW
     77%type <num> PE_VALUE_SYM_SW
     78%type <num> PE_VALUE_SYM_TOOL
     79%type <num> PE_RAW
     80%type <num> PE_TERM
     81%type <num> value_sym
     82%type <str> PE_NAME
     83%type <str> PE_BPF_OBJECT
     84%type <str> PE_BPF_SOURCE
     85%type <str> PE_NAME_CACHE_TYPE
     86%type <str> PE_NAME_CACHE_OP_RESULT
     87%type <str> PE_MODIFIER_EVENT
     88%type <str> PE_MODIFIER_BP
     89%type <str> PE_EVENT_NAME
     90%type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_PMU_EVENT_SUF2 PE_KERNEL_PMU_EVENT PE_PMU_EVENT_FAKE
     91%type <str> PE_DRV_CFG_TERM
     92%type <str> event_pmu_name
     93%destructor { free ($$); } <str>
     94%type <term> event_term
     95%destructor { parse_events_term__delete ($$); } <term>
     96%type <list_terms> event_config
     97%type <list_terms> opt_event_config
     98%type <list_terms> opt_pmu_config
     99%destructor { parse_events_terms__delete ($$); } <list_terms>
    100%type <list_evsel> event_pmu
    101%type <list_evsel> event_legacy_symbol
    102%type <list_evsel> event_legacy_cache
    103%type <list_evsel> event_legacy_mem
    104%type <list_evsel> event_legacy_tracepoint
    105%type <list_evsel> event_legacy_numeric
    106%type <list_evsel> event_legacy_raw
    107%type <list_evsel> event_bpf_file
    108%type <list_evsel> event_def
    109%type <list_evsel> event_mod
    110%type <list_evsel> event_name
    111%type <list_evsel> event
    112%type <list_evsel> events
    113%type <list_evsel> group_def
    114%type <list_evsel> group
    115%type <list_evsel> groups
    116%destructor { free_list_evsel ($$); } <list_evsel>
    117%type <tracepoint_name> tracepoint_name
    118%destructor { free ($$.sys); free ($$.event); } <tracepoint_name>
    119%type <array> array
    120%type <array> array_term
    121%type <array> array_terms
    122%destructor { free ($$.ranges); } <array>
    123
    124%union
    125{
    126	char *str;
    127	u64 num;
    128	struct list_head *list_evsel;
    129	struct list_head *list_terms;
    130	struct parse_events_term *term;
    131	struct tracepoint_name {
    132		char *sys;
    133		char *event;
    134	} tracepoint_name;
    135	struct parse_events_array array;
    136}
    137%%
    138
    139start:
    140PE_START_EVENTS start_events
    141|
    142PE_START_TERMS  start_terms
    143
    144start_events: groups
    145{
    146	struct parse_events_state *parse_state = _parse_state;
    147
    148	/* frees $1 */
    149	parse_events_update_lists($1, &parse_state->list);
    150}
    151
    152groups:
    153groups ',' group
    154{
    155	struct list_head *list  = $1;
    156	struct list_head *group = $3;
    157
    158	/* frees $3 */
    159	parse_events_update_lists(group, list);
    160	$$ = list;
    161}
    162|
    163groups ',' event
    164{
    165	struct list_head *list  = $1;
    166	struct list_head *event = $3;
    167
    168	/* frees $3 */
    169	parse_events_update_lists(event, list);
    170	$$ = list;
    171}
    172|
    173group
    174|
    175event
    176
    177group:
    178group_def ':' PE_MODIFIER_EVENT
    179{
    180	struct list_head *list = $1;
    181	int err;
    182
    183	err = parse_events__modifier_group(list, $3);
    184	free($3);
    185	if (err) {
    186		struct parse_events_state *parse_state = _parse_state;
    187		struct parse_events_error *error = parse_state->error;
    188
    189		parse_events_error__handle(error, @3.first_column,
    190					   strdup("Bad modifier"), NULL);
    191		free_list_evsel(list);
    192		YYABORT;
    193	}
    194	$$ = list;
    195}
    196|
    197group_def
    198
    199group_def:
    200PE_NAME '{' events '}'
    201{
    202	struct list_head *list = $3;
    203
    204	inc_group_count(list, _parse_state);
    205	parse_events__set_leader($1, list, _parse_state);
    206	free($1);
    207	$$ = list;
    208}
    209|
    210'{' events '}'
    211{
    212	struct list_head *list = $2;
    213
    214	inc_group_count(list, _parse_state);
    215	parse_events__set_leader(NULL, list, _parse_state);
    216	$$ = list;
    217}
    218
    219events:
    220events ',' event
    221{
    222	struct list_head *event = $3;
    223	struct list_head *list  = $1;
    224
    225	/* frees $3 */
    226	parse_events_update_lists(event, list);
    227	$$ = list;
    228}
    229|
    230event
    231
    232event: event_mod
    233
    234event_mod:
    235event_name PE_MODIFIER_EVENT
    236{
    237	struct list_head *list = $1;
    238	int err;
    239
    240	/*
    241	 * Apply modifier on all events added by single event definition
    242	 * (there could be more events added for multiple tracepoint
    243	 * definitions via '*?'.
    244	 */
    245	err = parse_events__modifier_event(list, $2, false);
    246	free($2);
    247	if (err) {
    248		struct parse_events_state *parse_state = _parse_state;
    249		struct parse_events_error *error = parse_state->error;
    250
    251		parse_events_error__handle(error, @2.first_column,
    252					   strdup("Bad modifier"), NULL);
    253		free_list_evsel(list);
    254		YYABORT;
    255	}
    256	$$ = list;
    257}
    258|
    259event_name
    260
    261event_name:
    262PE_EVENT_NAME event_def
    263{
    264	int err;
    265
    266	err = parse_events_name($2, $1);
    267	free($1);
    268	if (err) {
    269		free_list_evsel($2);
    270		YYABORT;
    271	}
    272	$$ = $2;
    273}
    274|
    275event_def
    276
    277event_def: event_pmu |
    278	   event_legacy_symbol |
    279	   event_legacy_cache sep_dc |
    280	   event_legacy_mem |
    281	   event_legacy_tracepoint sep_dc |
    282	   event_legacy_numeric sep_dc |
    283	   event_legacy_raw sep_dc |
    284	   event_bpf_file
    285
    286event_pmu_name:
    287PE_NAME | PE_PMU_EVENT_PRE
    288
    289event_pmu:
    290event_pmu_name opt_pmu_config
    291{
    292	struct parse_events_state *parse_state = _parse_state;
    293	struct parse_events_error *error = parse_state->error;
    294	struct list_head *list = NULL, *orig_terms = NULL, *terms= NULL;
    295	char *pattern = NULL;
    296
    297#define CLEANUP_YYABORT					\
    298	do {						\
    299		parse_events_terms__delete($2);		\
    300		parse_events_terms__delete(orig_terms);	\
    301		free(list);				\
    302		free($1);				\
    303		free(pattern);				\
    304		YYABORT;				\
    305	} while(0)
    306
    307	if (parse_events_copy_term_list($2, &orig_terms))
    308		CLEANUP_YYABORT;
    309
    310	if (error)
    311		error->idx = @1.first_column;
    312
    313	list = alloc_list();
    314	if (!list)
    315		CLEANUP_YYABORT;
    316	if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) {
    317		struct perf_pmu *pmu = NULL;
    318		int ok = 0;
    319
    320		if (asprintf(&pattern, "%s*", $1) < 0)
    321			CLEANUP_YYABORT;
    322
    323		while ((pmu = perf_pmu__scan(pmu)) != NULL) {
    324			char *name = pmu->name;
    325
    326			if (!strncmp(name, "uncore_", 7) &&
    327			    strncmp($1, "uncore_", 7))
    328				name += 7;
    329			if (!perf_pmu__match(pattern, name, $1) ||
    330			    !perf_pmu__match(pattern, pmu->alias_name, $1)) {
    331				if (parse_events_copy_term_list(orig_terms, &terms))
    332					CLEANUP_YYABORT;
    333				if (!parse_events_add_pmu(_parse_state, list, pmu->name, terms, true, false))
    334					ok++;
    335				parse_events_terms__delete(terms);
    336			}
    337		}
    338
    339		if (!ok)
    340			CLEANUP_YYABORT;
    341	}
    342	parse_events_terms__delete($2);
    343	parse_events_terms__delete(orig_terms);
    344	free(pattern);
    345	free($1);
    346	$$ = list;
    347#undef CLEANUP_YYABORT
    348}
    349|
    350PE_KERNEL_PMU_EVENT sep_dc
    351{
    352	struct list_head *list;
    353	int err;
    354
    355	err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list);
    356	free($1);
    357	if (err < 0)
    358		YYABORT;
    359	$$ = list;
    360}
    361|
    362PE_KERNEL_PMU_EVENT opt_pmu_config
    363{
    364	struct list_head *list;
    365	int err;
    366
    367	/* frees $2 */
    368	err = parse_events_multi_pmu_add(_parse_state, $1, $2, &list);
    369	free($1);
    370	if (err < 0)
    371		YYABORT;
    372	$$ = list;
    373}
    374|
    375PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF '-' PE_PMU_EVENT_SUF2 sep_dc
    376{
    377	struct list_head *list;
    378	char pmu_name[128];
    379	snprintf(pmu_name, sizeof(pmu_name), "%s-%s-%s", $1, $3, $5);
    380	free($1);
    381	free($3);
    382	free($5);
    383	if (parse_events_multi_pmu_add(_parse_state, pmu_name, NULL, &list) < 0)
    384		YYABORT;
    385	$$ = list;
    386}
    387|
    388PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
    389{
    390	struct list_head *list;
    391	char pmu_name[128];
    392
    393	snprintf(pmu_name, sizeof(pmu_name), "%s-%s", $1, $3);
    394	free($1);
    395	free($3);
    396	if (parse_events_multi_pmu_add(_parse_state, pmu_name, NULL, &list) < 0)
    397		YYABORT;
    398	$$ = list;
    399}
    400|
    401PE_PMU_EVENT_FAKE sep_dc
    402{
    403	struct list_head *list;
    404	int err;
    405
    406	list = alloc_list();
    407	if (!list)
    408		YYABORT;
    409
    410	err = parse_events_add_pmu(_parse_state, list, $1, NULL, false, false);
    411	free($1);
    412	if (err < 0) {
    413		free(list);
    414		YYABORT;
    415	}
    416	$$ = list;
    417}
    418|
    419PE_PMU_EVENT_FAKE opt_pmu_config
    420{
    421	struct list_head *list;
    422	int err;
    423
    424	list = alloc_list();
    425	if (!list)
    426		YYABORT;
    427
    428	err = parse_events_add_pmu(_parse_state, list, $1, $2, false, false);
    429	free($1);
    430	parse_events_terms__delete($2);
    431	if (err < 0) {
    432		free(list);
    433		YYABORT;
    434	}
    435	$$ = list;
    436}
    437
    438value_sym:
    439PE_VALUE_SYM_HW
    440|
    441PE_VALUE_SYM_SW
    442
    443event_legacy_symbol:
    444value_sym '/' event_config '/'
    445{
    446	struct list_head *list;
    447	int type = $1 >> 16;
    448	int config = $1 & 255;
    449	int err;
    450
    451	list = alloc_list();
    452	ABORT_ON(!list);
    453	err = parse_events_add_numeric(_parse_state, list, type, config, $3);
    454	parse_events_terms__delete($3);
    455	if (err) {
    456		free_list_evsel(list);
    457		YYABORT;
    458	}
    459	$$ = list;
    460}
    461|
    462value_sym sep_slash_slash_dc
    463{
    464	struct list_head *list;
    465	int type = $1 >> 16;
    466	int config = $1 & 255;
    467
    468	list = alloc_list();
    469	ABORT_ON(!list);
    470	ABORT_ON(parse_events_add_numeric(_parse_state, list, type, config, NULL));
    471	$$ = list;
    472}
    473|
    474PE_VALUE_SYM_TOOL sep_slash_slash_dc
    475{
    476	struct list_head *list;
    477
    478	list = alloc_list();
    479	ABORT_ON(!list);
    480	ABORT_ON(parse_events_add_tool(_parse_state, list, $1));
    481	$$ = list;
    482}
    483
    484event_legacy_cache:
    485PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT opt_event_config
    486{
    487	struct parse_events_state *parse_state = _parse_state;
    488	struct parse_events_error *error = parse_state->error;
    489	struct list_head *list;
    490	int err;
    491
    492	list = alloc_list();
    493	ABORT_ON(!list);
    494	err = parse_events_add_cache(list, &parse_state->idx, $1, $3, $5, error, $6,
    495				     parse_state);
    496	parse_events_terms__delete($6);
    497	free($1);
    498	free($3);
    499	free($5);
    500	if (err) {
    501		free_list_evsel(list);
    502		YYABORT;
    503	}
    504	$$ = list;
    505}
    506|
    507PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT opt_event_config
    508{
    509	struct parse_events_state *parse_state = _parse_state;
    510	struct parse_events_error *error = parse_state->error;
    511	struct list_head *list;
    512	int err;
    513
    514	list = alloc_list();
    515	ABORT_ON(!list);
    516	err = parse_events_add_cache(list, &parse_state->idx, $1, $3, NULL, error, $4,
    517				     parse_state);
    518	parse_events_terms__delete($4);
    519	free($1);
    520	free($3);
    521	if (err) {
    522		free_list_evsel(list);
    523		YYABORT;
    524	}
    525	$$ = list;
    526}
    527|
    528PE_NAME_CACHE_TYPE opt_event_config
    529{
    530	struct parse_events_state *parse_state = _parse_state;
    531	struct parse_events_error *error = parse_state->error;
    532	struct list_head *list;
    533	int err;
    534
    535	list = alloc_list();
    536	ABORT_ON(!list);
    537	err = parse_events_add_cache(list, &parse_state->idx, $1, NULL, NULL, error, $2,
    538				     parse_state);
    539	parse_events_terms__delete($2);
    540	free($1);
    541	if (err) {
    542		free_list_evsel(list);
    543		YYABORT;
    544	}
    545	$$ = list;
    546}
    547
    548event_legacy_mem:
    549PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc
    550{
    551	struct parse_events_state *parse_state = _parse_state;
    552	struct list_head *list;
    553	int err;
    554
    555	list = alloc_list();
    556	ABORT_ON(!list);
    557	err = parse_events_add_breakpoint(list, &parse_state->idx,
    558					  $2, $6, $4);
    559	free($6);
    560	if (err) {
    561		free(list);
    562		YYABORT;
    563	}
    564	$$ = list;
    565}
    566|
    567PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc
    568{
    569	struct parse_events_state *parse_state = _parse_state;
    570	struct list_head *list;
    571
    572	list = alloc_list();
    573	ABORT_ON(!list);
    574	if (parse_events_add_breakpoint(list, &parse_state->idx,
    575					$2, NULL, $4)) {
    576		free(list);
    577		YYABORT;
    578	}
    579	$$ = list;
    580}
    581|
    582PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
    583{
    584	struct parse_events_state *parse_state = _parse_state;
    585	struct list_head *list;
    586	int err;
    587
    588	list = alloc_list();
    589	ABORT_ON(!list);
    590	err = parse_events_add_breakpoint(list, &parse_state->idx,
    591					  $2, $4, 0);
    592	free($4);
    593	if (err) {
    594		free(list);
    595		YYABORT;
    596	}
    597	$$ = list;
    598}
    599|
    600PE_PREFIX_MEM PE_VALUE sep_dc
    601{
    602	struct parse_events_state *parse_state = _parse_state;
    603	struct list_head *list;
    604
    605	list = alloc_list();
    606	ABORT_ON(!list);
    607	if (parse_events_add_breakpoint(list, &parse_state->idx,
    608					$2, NULL, 0)) {
    609		free(list);
    610		YYABORT;
    611	}
    612	$$ = list;
    613}
    614
    615event_legacy_tracepoint:
    616tracepoint_name opt_event_config
    617{
    618	struct parse_events_state *parse_state = _parse_state;
    619	struct parse_events_error *error = parse_state->error;
    620	struct list_head *list;
    621	int err;
    622
    623	list = alloc_list();
    624	ABORT_ON(!list);
    625	if (error)
    626		error->idx = @1.first_column;
    627
    628	err = parse_events_add_tracepoint(list, &parse_state->idx, $1.sys, $1.event,
    629					error, $2);
    630
    631	parse_events_terms__delete($2);
    632	free($1.sys);
    633	free($1.event);
    634	if (err) {
    635		free(list);
    636		YYABORT;
    637	}
    638	$$ = list;
    639}
    640
    641tracepoint_name:
    642PE_NAME '-' PE_NAME ':' PE_NAME
    643{
    644	struct tracepoint_name tracepoint;
    645
    646	ABORT_ON(asprintf(&tracepoint.sys, "%s-%s", $1, $3) < 0);
    647	tracepoint.event = $5;
    648	free($1);
    649	free($3);
    650	$$ = tracepoint;
    651}
    652|
    653PE_NAME ':' PE_NAME
    654{
    655	struct tracepoint_name tracepoint = {$1, $3};
    656
    657	$$ = tracepoint;
    658}
    659
    660event_legacy_numeric:
    661PE_VALUE ':' PE_VALUE opt_event_config
    662{
    663	struct list_head *list;
    664	int err;
    665
    666	list = alloc_list();
    667	ABORT_ON(!list);
    668	err = parse_events_add_numeric(_parse_state, list, (u32)$1, $3, $4);
    669	parse_events_terms__delete($4);
    670	if (err) {
    671		free(list);
    672		YYABORT;
    673	}
    674	$$ = list;
    675}
    676
    677event_legacy_raw:
    678PE_RAW opt_event_config
    679{
    680	struct list_head *list;
    681	int err;
    682
    683	list = alloc_list();
    684	ABORT_ON(!list);
    685	err = parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, $1, $2);
    686	parse_events_terms__delete($2);
    687	if (err) {
    688		free(list);
    689		YYABORT;
    690	}
    691	$$ = list;
    692}
    693
    694event_bpf_file:
    695PE_BPF_OBJECT opt_event_config
    696{
    697	struct parse_events_state *parse_state = _parse_state;
    698	struct list_head *list;
    699	int err;
    700
    701	list = alloc_list();
    702	ABORT_ON(!list);
    703	err = parse_events_load_bpf(parse_state, list, $1, false, $2);
    704	parse_events_terms__delete($2);
    705	free($1);
    706	if (err) {
    707		free(list);
    708		YYABORT;
    709	}
    710	$$ = list;
    711}
    712|
    713PE_BPF_SOURCE opt_event_config
    714{
    715	struct list_head *list;
    716	int err;
    717
    718	list = alloc_list();
    719	ABORT_ON(!list);
    720	err = parse_events_load_bpf(_parse_state, list, $1, true, $2);
    721	parse_events_terms__delete($2);
    722	if (err) {
    723		free(list);
    724		YYABORT;
    725	}
    726	$$ = list;
    727}
    728
    729opt_event_config:
    730'/' event_config '/'
    731{
    732	$$ = $2;
    733}
    734|
    735'/' '/'
    736{
    737	$$ = NULL;
    738}
    739|
    740{
    741	$$ = NULL;
    742}
    743
    744opt_pmu_config:
    745'/' event_config '/'
    746{
    747	$$ = $2;
    748}
    749|
    750'/' '/'
    751{
    752	$$ = NULL;
    753}
    754
    755start_terms: event_config
    756{
    757	struct parse_events_state *parse_state = _parse_state;
    758	if (parse_state->terms) {
    759		parse_events_terms__delete ($1);
    760		YYABORT;
    761	}
    762	parse_state->terms = $1;
    763}
    764
    765event_config:
    766event_config ',' event_term
    767{
    768	struct list_head *head = $1;
    769	struct parse_events_term *term = $3;
    770
    771	if (!head) {
    772		parse_events_term__delete(term);
    773		YYABORT;
    774	}
    775	list_add_tail(&term->list, head);
    776	$$ = $1;
    777}
    778|
    779event_term
    780{
    781	struct list_head *head = malloc(sizeof(*head));
    782	struct parse_events_term *term = $1;
    783
    784	ABORT_ON(!head);
    785	INIT_LIST_HEAD(head);
    786	list_add_tail(&term->list, head);
    787	$$ = head;
    788}
    789
    790event_term:
    791PE_RAW
    792{
    793	struct parse_events_term *term;
    794
    795	ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_CONFIG,
    796					NULL, $1, false, &@1, NULL));
    797	$$ = term;
    798}
    799|
    800PE_NAME '=' PE_NAME
    801{
    802	struct parse_events_term *term;
    803
    804	if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
    805					$1, $3, &@1, &@3)) {
    806		free($1);
    807		free($3);
    808		YYABORT;
    809	}
    810	$$ = term;
    811}
    812|
    813PE_NAME '=' PE_VALUE
    814{
    815	struct parse_events_term *term;
    816
    817	if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
    818					$1, $3, false, &@1, &@3)) {
    819		free($1);
    820		YYABORT;
    821	}
    822	$$ = term;
    823}
    824|
    825PE_NAME '=' PE_VALUE_SYM_HW
    826{
    827	struct parse_events_term *term;
    828	int config = $3 & 255;
    829
    830	if (parse_events_term__sym_hw(&term, $1, config)) {
    831		free($1);
    832		YYABORT;
    833	}
    834	$$ = term;
    835}
    836|
    837PE_NAME
    838{
    839	struct parse_events_term *term;
    840
    841	if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
    842					$1, 1, true, &@1, NULL)) {
    843		free($1);
    844		YYABORT;
    845	}
    846	$$ = term;
    847}
    848|
    849PE_VALUE_SYM_HW
    850{
    851	struct parse_events_term *term;
    852	int config = $1 & 255;
    853
    854	ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
    855	$$ = term;
    856}
    857|
    858PE_TERM '=' PE_NAME
    859{
    860	struct parse_events_term *term;
    861
    862	if (parse_events_term__str(&term, (int)$1, NULL, $3, &@1, &@3)) {
    863		free($3);
    864		YYABORT;
    865	}
    866	$$ = term;
    867}
    868|
    869PE_TERM '=' PE_VALUE
    870{
    871	struct parse_events_term *term;
    872
    873	ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3, false, &@1, &@3));
    874	$$ = term;
    875}
    876|
    877PE_TERM
    878{
    879	struct parse_events_term *term;
    880
    881	ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, true, &@1, NULL));
    882	$$ = term;
    883}
    884|
    885PE_NAME array '=' PE_NAME
    886{
    887	struct parse_events_term *term;
    888
    889	if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
    890					$1, $4, &@1, &@4)) {
    891		free($1);
    892		free($4);
    893		free($2.ranges);
    894		YYABORT;
    895	}
    896	term->array = $2;
    897	$$ = term;
    898}
    899|
    900PE_NAME array '=' PE_VALUE
    901{
    902	struct parse_events_term *term;
    903
    904	if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
    905					$1, $4, false, &@1, &@4)) {
    906		free($1);
    907		free($2.ranges);
    908		YYABORT;
    909	}
    910	term->array = $2;
    911	$$ = term;
    912}
    913|
    914PE_DRV_CFG_TERM
    915{
    916	struct parse_events_term *term;
    917	char *config = strdup($1);
    918
    919	ABORT_ON(!config);
    920	if (parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG,
    921					config, $1, &@1, NULL)) {
    922		free($1);
    923		free(config);
    924		YYABORT;
    925	}
    926	$$ = term;
    927}
    928
    929array:
    930'[' array_terms ']'
    931{
    932	$$ = $2;
    933}
    934|
    935PE_ARRAY_ALL
    936{
    937	$$.nr_ranges = 0;
    938	$$.ranges = NULL;
    939}
    940
    941array_terms:
    942array_terms ',' array_term
    943{
    944	struct parse_events_array new_array;
    945
    946	new_array.nr_ranges = $1.nr_ranges + $3.nr_ranges;
    947	new_array.ranges = realloc($1.ranges,
    948				sizeof(new_array.ranges[0]) *
    949				new_array.nr_ranges);
    950	ABORT_ON(!new_array.ranges);
    951	memcpy(&new_array.ranges[$1.nr_ranges], $3.ranges,
    952	       $3.nr_ranges * sizeof(new_array.ranges[0]));
    953	free($3.ranges);
    954	$$ = new_array;
    955}
    956|
    957array_term
    958
    959array_term:
    960PE_VALUE
    961{
    962	struct parse_events_array array;
    963
    964	array.nr_ranges = 1;
    965	array.ranges = malloc(sizeof(array.ranges[0]));
    966	ABORT_ON(!array.ranges);
    967	array.ranges[0].start = $1;
    968	array.ranges[0].length = 1;
    969	$$ = array;
    970}
    971|
    972PE_VALUE PE_ARRAY_RANGE PE_VALUE
    973{
    974	struct parse_events_array array;
    975
    976	ABORT_ON($3 < $1);
    977	array.nr_ranges = 1;
    978	array.ranges = malloc(sizeof(array.ranges[0]));
    979	ABORT_ON(!array.ranges);
    980	array.ranges[0].start = $1;
    981	array.ranges[0].length = $3 - $1 + 1;
    982	$$ = array;
    983}
    984
    985sep_dc: ':' |
    986
    987sep_slash_slash_dc: '/' '/' | ':' |
    988
    989%%
    990
    991void parse_events_error(YYLTYPE *loc, void *parse_state,
    992			void *scanner __maybe_unused,
    993			char const *msg __maybe_unused)
    994{
    995	parse_events_evlist_error(parse_state, loc->last_column, "parser error");
    996}