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