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