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