xref: /openbmc/linux/tools/perf/util/parse-events.y (revision 2359ccdd)
1 %pure-parser
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 <linux/compiler.h>
13 #include <linux/list.h>
14 #include <linux/types.h>
15 #include "util.h"
16 #include "pmu.h"
17 #include "debug.h"
18 #include "parse-events.h"
19 #include "parse-events-bison.h"
20 
21 void parse_events_error(YYLTYPE *loc, void *parse_state, void *scanner, char const *msg);
22 
23 #define ABORT_ON(val) \
24 do { \
25 	if (val) \
26 		YYABORT; \
27 } while (0)
28 
29 #define ALLOC_LIST(list) \
30 do { \
31 	list = malloc(sizeof(*list)); \
32 	ABORT_ON(!list);              \
33 	INIT_LIST_HEAD(list);         \
34 } while (0)
35 
36 static void inc_group_count(struct list_head *list,
37 		       struct parse_events_state *parse_state)
38 {
39 	/* Count groups only have more than 1 members */
40 	if (!list_is_last(list->next, list))
41 		parse_state->nr_groups++;
42 }
43 
44 %}
45 
46 %token PE_START_EVENTS PE_START_TERMS
47 %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
48 %token PE_EVENT_NAME
49 %token PE_NAME
50 %token PE_BPF_OBJECT PE_BPF_SOURCE
51 %token PE_MODIFIER_EVENT PE_MODIFIER_BP
52 %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
53 %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
54 %token PE_ERROR
55 %token PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
56 %token PE_ARRAY_ALL PE_ARRAY_RANGE
57 %token PE_DRV_CFG_TERM
58 %type <num> PE_VALUE
59 %type <num> PE_VALUE_SYM_HW
60 %type <num> PE_VALUE_SYM_SW
61 %type <num> PE_RAW
62 %type <num> PE_TERM
63 %type <str> PE_NAME
64 %type <str> PE_BPF_OBJECT
65 %type <str> PE_BPF_SOURCE
66 %type <str> PE_NAME_CACHE_TYPE
67 %type <str> PE_NAME_CACHE_OP_RESULT
68 %type <str> PE_MODIFIER_EVENT
69 %type <str> PE_MODIFIER_BP
70 %type <str> PE_EVENT_NAME
71 %type <str> PE_PMU_EVENT_PRE PE_PMU_EVENT_SUF PE_KERNEL_PMU_EVENT
72 %type <str> PE_DRV_CFG_TERM
73 %type <num> value_sym
74 %type <head> event_config
75 %type <head> opt_event_config
76 %type <term> event_term
77 %type <head> event_pmu
78 %type <head> event_legacy_symbol
79 %type <head> event_legacy_cache
80 %type <head> event_legacy_mem
81 %type <head> event_legacy_tracepoint
82 %type <tracepoint_name> tracepoint_name
83 %type <head> event_legacy_numeric
84 %type <head> event_legacy_raw
85 %type <head> event_bpf_file
86 %type <head> event_def
87 %type <head> event_mod
88 %type <head> event_name
89 %type <head> event
90 %type <head> events
91 %type <head> group_def
92 %type <head> group
93 %type <head> groups
94 %type <array> array
95 %type <array> array_term
96 %type <array> array_terms
97 
98 %union
99 {
100 	char *str;
101 	u64 num;
102 	struct list_head *head;
103 	struct parse_events_term *term;
104 	struct tracepoint_name {
105 		char *sys;
106 		char *event;
107 	} tracepoint_name;
108 	struct parse_events_array array;
109 }
110 %%
111 
112 start:
113 PE_START_EVENTS start_events
114 |
115 PE_START_TERMS  start_terms
116 
117 start_events: groups
118 {
119 	struct parse_events_state *parse_state = _parse_state;
120 
121 	parse_events_update_lists($1, &parse_state->list);
122 }
123 
124 groups:
125 groups ',' group
126 {
127 	struct list_head *list  = $1;
128 	struct list_head *group = $3;
129 
130 	parse_events_update_lists(group, list);
131 	$$ = list;
132 }
133 |
134 groups ',' event
135 {
136 	struct list_head *list  = $1;
137 	struct list_head *event = $3;
138 
139 	parse_events_update_lists(event, list);
140 	$$ = list;
141 }
142 |
143 group
144 |
145 event
146 
147 group:
148 group_def ':' PE_MODIFIER_EVENT
149 {
150 	struct list_head *list = $1;
151 
152 	ABORT_ON(parse_events__modifier_group(list, $3));
153 	$$ = list;
154 }
155 |
156 group_def
157 
158 group_def:
159 PE_NAME '{' events '}'
160 {
161 	struct list_head *list = $3;
162 
163 	inc_group_count(list, _parse_state);
164 	parse_events__set_leader($1, list);
165 	$$ = list;
166 }
167 |
168 '{' events '}'
169 {
170 	struct list_head *list = $2;
171 
172 	inc_group_count(list, _parse_state);
173 	parse_events__set_leader(NULL, list);
174 	$$ = list;
175 }
176 
177 events:
178 events ',' event
179 {
180 	struct list_head *event = $3;
181 	struct list_head *list  = $1;
182 
183 	parse_events_update_lists(event, list);
184 	$$ = list;
185 }
186 |
187 event
188 
189 event: event_mod
190 
191 event_mod:
192 event_name PE_MODIFIER_EVENT
193 {
194 	struct list_head *list = $1;
195 
196 	/*
197 	 * Apply modifier on all events added by single event definition
198 	 * (there could be more events added for multiple tracepoint
199 	 * definitions via '*?'.
200 	 */
201 	ABORT_ON(parse_events__modifier_event(list, $2, false));
202 	$$ = list;
203 }
204 |
205 event_name
206 
207 event_name:
208 PE_EVENT_NAME event_def
209 {
210 	ABORT_ON(parse_events_name($2, $1));
211 	free($1);
212 	$$ = $2;
213 }
214 |
215 event_def
216 
217 event_def: event_pmu |
218 	   event_legacy_symbol |
219 	   event_legacy_cache sep_dc |
220 	   event_legacy_mem |
221 	   event_legacy_tracepoint sep_dc |
222 	   event_legacy_numeric sep_dc |
223 	   event_legacy_raw sep_dc |
224 	   event_bpf_file
225 
226 event_pmu:
227 PE_NAME opt_event_config
228 {
229 	struct list_head *list, *orig_terms, *terms;
230 
231 	if (parse_events_copy_term_list($2, &orig_terms))
232 		YYABORT;
233 
234 	ALLOC_LIST(list);
235 	if (parse_events_add_pmu(_parse_state, list, $1, $2, false)) {
236 		struct perf_pmu *pmu = NULL;
237 		int ok = 0;
238 		char *pattern;
239 
240 		if (asprintf(&pattern, "%s*", $1) < 0)
241 			YYABORT;
242 
243 		while ((pmu = perf_pmu__scan(pmu)) != NULL) {
244 			char *name = pmu->name;
245 
246 			if (!strncmp(name, "uncore_", 7) &&
247 			    strncmp($1, "uncore_", 7))
248 				name += 7;
249 			if (!fnmatch(pattern, name, 0)) {
250 				if (parse_events_copy_term_list(orig_terms, &terms)) {
251 					free(pattern);
252 					YYABORT;
253 				}
254 				if (!parse_events_add_pmu(_parse_state, list, pmu->name, terms, true))
255 					ok++;
256 				parse_events_terms__delete(terms);
257 			}
258 		}
259 
260 		free(pattern);
261 
262 		if (!ok)
263 			YYABORT;
264 	}
265 	parse_events_terms__delete($2);
266 	parse_events_terms__delete(orig_terms);
267 	$$ = list;
268 }
269 |
270 PE_KERNEL_PMU_EVENT sep_dc
271 {
272 	struct list_head *list;
273 
274 	if (parse_events_multi_pmu_add(_parse_state, $1, &list) < 0)
275 		YYABORT;
276 	$$ = list;
277 }
278 |
279 PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
280 {
281 	struct list_head *list;
282 	char pmu_name[128];
283 
284 	snprintf(&pmu_name, 128, "%s-%s", $1, $3);
285 	if (parse_events_multi_pmu_add(_parse_state, pmu_name, &list) < 0)
286 		YYABORT;
287 	$$ = list;
288 }
289 
290 value_sym:
291 PE_VALUE_SYM_HW
292 |
293 PE_VALUE_SYM_SW
294 
295 event_legacy_symbol:
296 value_sym '/' event_config '/'
297 {
298 	struct list_head *list;
299 	int type = $1 >> 16;
300 	int config = $1 & 255;
301 
302 	ALLOC_LIST(list);
303 	ABORT_ON(parse_events_add_numeric(_parse_state, list, type, config, $3));
304 	parse_events_terms__delete($3);
305 	$$ = list;
306 }
307 |
308 value_sym sep_slash_dc
309 {
310 	struct list_head *list;
311 	int type = $1 >> 16;
312 	int config = $1 & 255;
313 
314 	ALLOC_LIST(list);
315 	ABORT_ON(parse_events_add_numeric(_parse_state, list, type, config, NULL));
316 	$$ = list;
317 }
318 
319 event_legacy_cache:
320 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT opt_event_config
321 {
322 	struct parse_events_state *parse_state = _parse_state;
323 	struct parse_events_error *error = parse_state->error;
324 	struct list_head *list;
325 
326 	ALLOC_LIST(list);
327 	ABORT_ON(parse_events_add_cache(list, &parse_state->idx, $1, $3, $5, error, $6));
328 	parse_events_terms__delete($6);
329 	$$ = list;
330 }
331 |
332 PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT opt_event_config
333 {
334 	struct parse_events_state *parse_state = _parse_state;
335 	struct parse_events_error *error = parse_state->error;
336 	struct list_head *list;
337 
338 	ALLOC_LIST(list);
339 	ABORT_ON(parse_events_add_cache(list, &parse_state->idx, $1, $3, NULL, error, $4));
340 	parse_events_terms__delete($4);
341 	$$ = list;
342 }
343 |
344 PE_NAME_CACHE_TYPE opt_event_config
345 {
346 	struct parse_events_state *parse_state = _parse_state;
347 	struct parse_events_error *error = parse_state->error;
348 	struct list_head *list;
349 
350 	ALLOC_LIST(list);
351 	ABORT_ON(parse_events_add_cache(list, &parse_state->idx, $1, NULL, NULL, error, $2));
352 	parse_events_terms__delete($2);
353 	$$ = list;
354 }
355 
356 event_legacy_mem:
357 PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc
358 {
359 	struct parse_events_state *parse_state = _parse_state;
360 	struct list_head *list;
361 
362 	ALLOC_LIST(list);
363 	ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx,
364 					     (void *) $2, $6, $4));
365 	$$ = list;
366 }
367 |
368 PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc
369 {
370 	struct parse_events_state *parse_state = _parse_state;
371 	struct list_head *list;
372 
373 	ALLOC_LIST(list);
374 	ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx,
375 					     (void *) $2, NULL, $4));
376 	$$ = list;
377 }
378 |
379 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
380 {
381 	struct parse_events_state *parse_state = _parse_state;
382 	struct list_head *list;
383 
384 	ALLOC_LIST(list);
385 	ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx,
386 					     (void *) $2, $4, 0));
387 	$$ = list;
388 }
389 |
390 PE_PREFIX_MEM PE_VALUE sep_dc
391 {
392 	struct parse_events_state *parse_state = _parse_state;
393 	struct list_head *list;
394 
395 	ALLOC_LIST(list);
396 	ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx,
397 					     (void *) $2, NULL, 0));
398 	$$ = list;
399 }
400 
401 event_legacy_tracepoint:
402 tracepoint_name opt_event_config
403 {
404 	struct parse_events_state *parse_state = _parse_state;
405 	struct parse_events_error *error = parse_state->error;
406 	struct list_head *list;
407 
408 	ALLOC_LIST(list);
409 	if (error)
410 		error->idx = @1.first_column;
411 
412 	if (parse_events_add_tracepoint(list, &parse_state->idx, $1.sys, $1.event,
413 					error, $2))
414 		return -1;
415 
416 	$$ = list;
417 }
418 
419 tracepoint_name:
420 PE_NAME '-' PE_NAME ':' PE_NAME
421 {
422 	char sys_name[128];
423 	struct tracepoint_name tracepoint;
424 
425 	snprintf(&sys_name, 128, "%s-%s", $1, $3);
426 	tracepoint.sys = &sys_name;
427 	tracepoint.event = $5;
428 
429 	$$ = tracepoint;
430 }
431 |
432 PE_NAME ':' PE_NAME
433 {
434 	struct tracepoint_name tracepoint = {$1, $3};
435 
436 	$$ = tracepoint;
437 }
438 
439 event_legacy_numeric:
440 PE_VALUE ':' PE_VALUE opt_event_config
441 {
442 	struct list_head *list;
443 
444 	ALLOC_LIST(list);
445 	ABORT_ON(parse_events_add_numeric(_parse_state, list, (u32)$1, $3, $4));
446 	parse_events_terms__delete($4);
447 	$$ = list;
448 }
449 
450 event_legacy_raw:
451 PE_RAW opt_event_config
452 {
453 	struct list_head *list;
454 
455 	ALLOC_LIST(list);
456 	ABORT_ON(parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, $1, $2));
457 	parse_events_terms__delete($2);
458 	$$ = list;
459 }
460 
461 event_bpf_file:
462 PE_BPF_OBJECT opt_event_config
463 {
464 	struct parse_events_state *parse_state = _parse_state;
465 	struct parse_events_error *error = parse_state->error;
466 	struct list_head *list;
467 
468 	ALLOC_LIST(list);
469 	ABORT_ON(parse_events_load_bpf(parse_state, list, $1, false, $2));
470 	parse_events_terms__delete($2);
471 	$$ = list;
472 }
473 |
474 PE_BPF_SOURCE opt_event_config
475 {
476 	struct list_head *list;
477 
478 	ALLOC_LIST(list);
479 	ABORT_ON(parse_events_load_bpf(_parse_state, list, $1, true, $2));
480 	parse_events_terms__delete($2);
481 	$$ = list;
482 }
483 
484 opt_event_config:
485 '/' event_config '/'
486 {
487 	$$ = $2;
488 }
489 |
490 '/' '/'
491 {
492 	$$ = NULL;
493 }
494 |
495 {
496 	$$ = NULL;
497 }
498 
499 start_terms: event_config
500 {
501 	struct parse_events_state *parse_state = _parse_state;
502 	parse_state->terms = $1;
503 }
504 
505 event_config:
506 event_config ',' event_term
507 {
508 	struct list_head *head = $1;
509 	struct parse_events_term *term = $3;
510 
511 	ABORT_ON(!head);
512 	list_add_tail(&term->list, head);
513 	$$ = $1;
514 }
515 |
516 event_term
517 {
518 	struct list_head *head = malloc(sizeof(*head));
519 	struct parse_events_term *term = $1;
520 
521 	ABORT_ON(!head);
522 	INIT_LIST_HEAD(head);
523 	list_add_tail(&term->list, head);
524 	$$ = head;
525 }
526 
527 event_term:
528 PE_NAME '=' PE_NAME
529 {
530 	struct parse_events_term *term;
531 
532 	ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
533 					$1, $3, &@1, &@3));
534 	$$ = term;
535 }
536 |
537 PE_NAME '=' PE_VALUE
538 {
539 	struct parse_events_term *term;
540 
541 	ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
542 					$1, $3, false, &@1, &@3));
543 	$$ = term;
544 }
545 |
546 PE_NAME '=' PE_VALUE_SYM_HW
547 {
548 	struct parse_events_term *term;
549 	int config = $3 & 255;
550 
551 	ABORT_ON(parse_events_term__sym_hw(&term, $1, config));
552 	$$ = term;
553 }
554 |
555 PE_NAME
556 {
557 	struct parse_events_term *term;
558 
559 	ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
560 					$1, 1, true, &@1, NULL));
561 	$$ = term;
562 }
563 |
564 PE_VALUE_SYM_HW
565 {
566 	struct parse_events_term *term;
567 	int config = $1 & 255;
568 
569 	ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
570 	$$ = term;
571 }
572 |
573 PE_TERM '=' PE_NAME
574 {
575 	struct parse_events_term *term;
576 
577 	ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3, &@1, &@3));
578 	$$ = term;
579 }
580 |
581 PE_TERM '=' PE_VALUE
582 {
583 	struct parse_events_term *term;
584 
585 	ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3, false, &@1, &@3));
586 	$$ = term;
587 }
588 |
589 PE_TERM
590 {
591 	struct parse_events_term *term;
592 
593 	ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, true, &@1, NULL));
594 	$$ = term;
595 }
596 |
597 PE_NAME array '=' PE_NAME
598 {
599 	struct parse_events_term *term;
600 	int i;
601 
602 	ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
603 					$1, $4, &@1, &@4));
604 
605 	term->array = $2;
606 	$$ = term;
607 }
608 |
609 PE_NAME array '=' PE_VALUE
610 {
611 	struct parse_events_term *term;
612 
613 	ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
614 					$1, $4, false, &@1, &@4));
615 	term->array = $2;
616 	$$ = term;
617 }
618 |
619 PE_DRV_CFG_TERM
620 {
621 	struct parse_events_term *term;
622 
623 	ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG,
624 					$1, $1, &@1, NULL));
625 	$$ = term;
626 }
627 
628 array:
629 '[' array_terms ']'
630 {
631 	$$ = $2;
632 }
633 |
634 PE_ARRAY_ALL
635 {
636 	$$.nr_ranges = 0;
637 	$$.ranges = NULL;
638 }
639 
640 array_terms:
641 array_terms ',' array_term
642 {
643 	struct parse_events_array new_array;
644 
645 	new_array.nr_ranges = $1.nr_ranges + $3.nr_ranges;
646 	new_array.ranges = malloc(sizeof(new_array.ranges[0]) *
647 				  new_array.nr_ranges);
648 	ABORT_ON(!new_array.ranges);
649 	memcpy(&new_array.ranges[0], $1.ranges,
650 	       $1.nr_ranges * sizeof(new_array.ranges[0]));
651 	memcpy(&new_array.ranges[$1.nr_ranges], $3.ranges,
652 	       $3.nr_ranges * sizeof(new_array.ranges[0]));
653 	free($1.ranges);
654 	free($3.ranges);
655 	$$ = new_array;
656 }
657 |
658 array_term
659 
660 array_term:
661 PE_VALUE
662 {
663 	struct parse_events_array array;
664 
665 	array.nr_ranges = 1;
666 	array.ranges = malloc(sizeof(array.ranges[0]));
667 	ABORT_ON(!array.ranges);
668 	array.ranges[0].start = $1;
669 	array.ranges[0].length = 1;
670 	$$ = array;
671 }
672 |
673 PE_VALUE PE_ARRAY_RANGE PE_VALUE
674 {
675 	struct parse_events_array array;
676 
677 	ABORT_ON($3 < $1);
678 	array.nr_ranges = 1;
679 	array.ranges = malloc(sizeof(array.ranges[0]));
680 	ABORT_ON(!array.ranges);
681 	array.ranges[0].start = $1;
682 	array.ranges[0].length = $3 - $1 + 1;
683 	$$ = array;
684 }
685 
686 sep_dc: ':' |
687 
688 sep_slash_dc: '/' | ':' |
689 
690 %%
691 
692 void parse_events_error(YYLTYPE *loc, void *parse_state,
693 			void *scanner __maybe_unused,
694 			char const *msg __maybe_unused)
695 {
696 	parse_events_evlist_error(parse_state, loc->last_column, "parser error");
697 }
698