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 #ifndef NDEBUG
10 #define YYDEBUG 1
11 #endif
12
13 #include <errno.h>
14 #include <linux/compiler.h>
15 #include <linux/types.h>
16 #include "pmu.h"
17 #include "pmus.h"
18 #include "evsel.h"
19 #include "parse-events.h"
20 #include "parse-events-bison.h"
21
22 int parse_events_lex(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , void *yyscanner);
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
alloc_list(void)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
free_list_evsel(struct list_head * list_evsel)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_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH
63 %token PE_LEGACY_CACHE
64 %token PE_PREFIX_MEM
65 %token PE_ERROR
66 %token PE_DRV_CFG_TERM
67 %token PE_TERM_HW
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 <mod> PE_MODIFIER_EVENT
73 %type <term_type> 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_BP
79 %type <str> PE_EVENT_NAME
80 %type <str> PE_DRV_CFG_TERM
81 %type <str> name_or_raw
82 %destructor { free ($$); } <str>
83 %type <term> event_term
84 %destructor { parse_events_term__delete ($$); } <term>
85 %type <list_terms> event_config
86 %type <list_terms> opt_event_config
87 %type <list_terms> opt_pmu_config
88 %destructor { parse_events_terms__delete ($$); } <list_terms>
89 %type <list_evsel> event_pmu
90 %type <list_evsel> event_legacy_symbol
91 %type <list_evsel> event_legacy_cache
92 %type <list_evsel> event_legacy_mem
93 %type <list_evsel> event_legacy_tracepoint
94 %type <list_evsel> event_legacy_numeric
95 %type <list_evsel> event_legacy_raw
96 %type <list_evsel> event_def
97 %type <list_evsel> event_mod
98 %type <list_evsel> event_name
99 %type <list_evsel> event
100 %type <list_evsel> events
101 %type <list_evsel> group_def
102 %type <list_evsel> group
103 %type <list_evsel> groups
104 %destructor { free_list_evsel ($$); } <list_evsel>
105 %type <tracepoint_name> tracepoint_name
106 %destructor { free ($$.sys); free ($$.event); } <tracepoint_name>
107 %type <hardware_term> PE_TERM_HW
108 %destructor { free ($$.str); } <hardware_term>
109
110 %union
111 {
112 char *str;
113 u64 num;
114 struct parse_events_modifier mod;
115 enum parse_events__term_type term_type;
116 struct list_head *list_evsel;
117 struct parse_events_terms *list_terms;
118 struct parse_events_term *term;
119 struct tracepoint_name {
120 char *sys;
121 char *event;
122 } tracepoint_name;
123 struct hardware_term {
124 char *str;
125 u64 num;
126 } hardware_term;
127 }
128 %%
129
130 /*
131 * Entry points. We are either parsing events or terminals. Just terminal
132 * parsing is used for parsing events in sysfs.
133 */
134 start:
135 PE_START_EVENTS start_events
136 |
137 PE_START_TERMS start_terms
138
139 start_events: groups
140 {
141 /* Take the parsed events, groups.. and place into parse_state. */
142 struct list_head *groups = $1;
143 struct parse_events_state *parse_state = _parse_state;
144
145 list_splice_tail(groups, &parse_state->list);
146 free(groups);
147 }
148
149 groups: /* A list of groups or events. */
150 groups ',' group
151 {
152 /* Merge group into the list of events/groups. */
153 struct list_head *groups = $1;
154 struct list_head *group = $3;
155
156 list_splice_tail(group, groups);
157 free(group);
158 $$ = groups;
159 }
160 |
161 groups ',' event
162 {
163 /* Merge event into the list of events/groups. */
164 struct list_head *groups = $1;
165 struct list_head *event = $3;
166
167
168 list_splice_tail(event, groups);
169 free(event);
170 $$ = groups;
171 }
172 |
173 group
174 |
175 event
176
177 group:
178 group_def ':' PE_MODIFIER_EVENT
179 {
180 /* Apply the modifier to the events in the group_def. */
181 struct list_head *list = $1;
182 int err;
183
184 err = parse_events__modifier_group(_parse_state, &@3, list, $3);
185 if (err)
186 YYABORT;
187 $$ = list;
188 }
189 |
190 group_def
191
192 group_def:
193 PE_NAME '{' events '}'
194 {
195 struct list_head *list = $3;
196
197 /*
198 * Set the first entry of list to be the leader. Set the group name on
199 * the leader to $1 taking ownership.
200 */
201 parse_events__set_leader($1, list);
202 $$ = list;
203 }
204 |
205 '{' events '}'
206 {
207 struct list_head *list = $2;
208
209 /* Set the first entry of list to be the leader clearing the group name. */
210 parse_events__set_leader(NULL, list);
211 $$ = list;
212 }
213
214 events:
215 events ',' event
216 {
217 struct list_head *events = $1;
218 struct list_head *event = $3;
219
220 list_splice_tail(event, events);
221 free(event);
222 $$ = events;
223 }
224 |
225 event
226
227 event: event_mod
228
229 event_mod:
230 event_name PE_MODIFIER_EVENT
231 {
232 struct list_head *list = $1;
233 int err;
234
235 /*
236 * Apply modifier on all events added by single event definition
237 * (there could be more events added for multiple tracepoint
238 * definitions via '*?'.
239 */
240 err = parse_events__modifier_event(_parse_state, &@2, list, $2);
241 if (err)
242 YYABORT;
243 $$ = list;
244 }
245 |
246 event_name
247
248 event_name:
249 PE_EVENT_NAME event_def
250 {
251 /*
252 * When an event is parsed the text is rewound and the entire text of
253 * the event is set to the str of PE_EVENT_NAME token matched here. If
254 * no name was on an event via a term, set the name to the entire text
255 * taking ownership of the allocation.
256 */
257 int err = parse_events__set_default_name($2, $1);
258
259 if (err) {
260 free_list_evsel($2);
261 YYNOMEM;
262 }
263 $$ = $2;
264 }
265 |
266 event_def
267
268 event_def: event_pmu |
269 event_legacy_symbol |
270 event_legacy_cache sep_dc |
271 event_legacy_mem sep_dc |
272 event_legacy_tracepoint sep_dc |
273 event_legacy_numeric sep_dc |
274 event_legacy_raw sep_dc
275
276 event_pmu:
277 PE_NAME opt_pmu_config
278 {
279 /* List of created evsels. */
280 struct list_head *list = NULL;
281 int err = parse_events_multi_pmu_add_or_add_pmu(_parse_state, $1, $2, &list, &@1);
282
283 parse_events_terms__delete($2);
284 free($1);
285 if (err)
286 PE_ABORT(err);
287 $$ = list;
288 }
289 |
290 PE_NAME sep_dc
291 {
292 struct list_head *list;
293 int err;
294
295 err = parse_events_multi_pmu_add(_parse_state, $1, NULL, &list, &@1);
296 if (err < 0) {
297 struct parse_events_state *parse_state = _parse_state;
298 struct parse_events_error *error = parse_state->error;
299 char *help;
300
301 if (asprintf(&help, "Unable to find event on a PMU of '%s'", $1) < 0)
302 help = NULL;
303 parse_events_error__handle(error, @1.first_column, strdup("Bad event name"), help);
304 free($1);
305 PE_ABORT(err);
306 }
307 free($1);
308 $$ = list;
309 }
310
311 value_sym:
312 PE_VALUE_SYM_HW
313 |
314 PE_VALUE_SYM_SW
315
316 event_legacy_symbol:
317 value_sym '/' event_config '/'
318 {
319 struct list_head *list;
320 int type = $1 >> 16;
321 int config = $1 & 255;
322 int err;
323 bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);
324
325 list = alloc_list();
326 if (!list)
327 YYNOMEM;
328 err = parse_events_add_numeric(_parse_state, list, type, config, $3, wildcard);
329 parse_events_terms__delete($3);
330 if (err) {
331 free_list_evsel(list);
332 PE_ABORT(err);
333 }
334 $$ = list;
335 }
336 |
337 value_sym sep_slash_slash_dc
338 {
339 struct list_head *list;
340 int type = $1 >> 16;
341 int config = $1 & 255;
342 bool wildcard = (type == PERF_TYPE_HARDWARE || type == PERF_TYPE_HW_CACHE);
343 int err;
344
345 list = alloc_list();
346 if (!list)
347 YYNOMEM;
348 err = parse_events_add_numeric(_parse_state, list, type, config, /*head_config=*/NULL, wildcard);
349 if (err)
350 PE_ABORT(err);
351 $$ = list;
352 }
353 |
354 PE_VALUE_SYM_TOOL sep_slash_slash_dc
355 {
356 struct list_head *list;
357 int err;
358
359 list = alloc_list();
360 if (!list)
361 YYNOMEM;
362 err = parse_events_add_tool(_parse_state, list, $1);
363 if (err)
364 YYNOMEM;
365 $$ = list;
366 }
367
368 event_legacy_cache:
369 PE_LEGACY_CACHE opt_event_config
370 {
371 struct parse_events_state *parse_state = _parse_state;
372 struct list_head *list;
373 int err;
374
375 list = alloc_list();
376 if (!list)
377 YYNOMEM;
378
379 err = parse_events_add_cache(list, &parse_state->idx, $1, parse_state, $2);
380
381 parse_events_terms__delete($2);
382 free($1);
383 if (err) {
384 free_list_evsel(list);
385 PE_ABORT(err);
386 }
387 $$ = list;
388 }
389
390 event_legacy_mem:
391 PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
392 {
393 struct list_head *list;
394 int err;
395
396 list = alloc_list();
397 if (!list)
398 YYNOMEM;
399
400 err = parse_events_add_breakpoint(_parse_state, list,
401 $2, $6, $4, $7);
402 parse_events_terms__delete($7);
403 free($6);
404 if (err) {
405 free(list);
406 PE_ABORT(err);
407 }
408 $$ = list;
409 }
410 |
411 PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE opt_event_config
412 {
413 struct list_head *list;
414 int err;
415
416 list = alloc_list();
417 if (!list)
418 YYNOMEM;
419
420 err = parse_events_add_breakpoint(_parse_state, list,
421 $2, NULL, $4, $5);
422 parse_events_terms__delete($5);
423 if (err) {
424 free(list);
425 PE_ABORT(err);
426 }
427 $$ = list;
428 }
429 |
430 PE_PREFIX_MEM PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
431 {
432 struct list_head *list;
433 int err;
434
435 list = alloc_list();
436 if (!list)
437 YYNOMEM;
438
439 err = parse_events_add_breakpoint(_parse_state, list,
440 $2, $4, 0, $5);
441 parse_events_terms__delete($5);
442 free($4);
443 if (err) {
444 free(list);
445 PE_ABORT(err);
446 }
447 $$ = list;
448 }
449 |
450 PE_PREFIX_MEM PE_VALUE opt_event_config
451 {
452 struct list_head *list;
453 int err;
454
455 list = alloc_list();
456 if (!list)
457 YYNOMEM;
458 err = parse_events_add_breakpoint(_parse_state, list,
459 $2, NULL, 0, $3);
460 parse_events_terms__delete($3);
461 if (err) {
462 free(list);
463 PE_ABORT(err);
464 }
465 $$ = list;
466 }
467
468 event_legacy_tracepoint:
469 tracepoint_name opt_event_config
470 {
471 struct parse_events_state *parse_state = _parse_state;
472 struct parse_events_error *error = parse_state->error;
473 struct list_head *list;
474 int err;
475
476 list = alloc_list();
477 if (!list)
478 YYNOMEM;
479
480 err = parse_events_add_tracepoint(parse_state, list, $1.sys, $1.event,
481 error, $2, &@1);
482
483 parse_events_terms__delete($2);
484 free($1.sys);
485 free($1.event);
486 if (err) {
487 free(list);
488 PE_ABORT(err);
489 }
490 $$ = list;
491 }
492
493 tracepoint_name:
494 PE_NAME ':' PE_NAME
495 {
496 struct tracepoint_name tracepoint = {$1, $3};
497
498 $$ = tracepoint;
499 }
500
501 event_legacy_numeric:
502 PE_VALUE ':' PE_VALUE opt_event_config
503 {
504 struct list_head *list;
505 int err;
506
507 list = alloc_list();
508 if (!list)
509 YYNOMEM;
510 err = parse_events_add_numeric(_parse_state, list, (u32)$1, $3, $4,
511 /*wildcard=*/false);
512 parse_events_terms__delete($4);
513 if (err) {
514 free(list);
515 PE_ABORT(err);
516 }
517 $$ = list;
518 }
519
520 event_legacy_raw:
521 PE_RAW opt_event_config
522 {
523 struct list_head *list;
524 int err;
525 u64 num;
526
527 list = alloc_list();
528 if (!list)
529 YYNOMEM;
530 errno = 0;
531 num = strtoull($1 + 1, NULL, 16);
532 /* Given the lexer will only give [a-fA-F0-9]+ a failure here should be impossible. */
533 if (errno)
534 YYABORT;
535 free($1);
536 err = parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, num, $2,
537 /*wildcard=*/false);
538 parse_events_terms__delete($2);
539 if (err) {
540 free(list);
541 PE_ABORT(err);
542 }
543 $$ = list;
544 }
545
546 opt_event_config:
547 '/' event_config '/'
548 {
549 $$ = $2;
550 }
551 |
552 '/' '/'
553 {
554 $$ = NULL;
555 }
556 |
557 {
558 $$ = NULL;
559 }
560
561 opt_pmu_config:
562 '/' event_config '/'
563 {
564 $$ = $2;
565 }
566 |
567 '/' '/'
568 {
569 $$ = NULL;
570 }
571
572 start_terms: event_config
573 {
574 struct parse_events_state *parse_state = _parse_state;
575 if (parse_state->terms) {
576 parse_events_terms__delete ($1);
577 YYABORT;
578 }
579 parse_state->terms = $1;
580 }
581
582 event_config:
583 event_config ',' event_term
584 {
585 struct parse_events_terms *head = $1;
586 struct parse_events_term *term = $3;
587
588 if (!head) {
589 parse_events_term__delete(term);
590 YYABORT;
591 }
592 list_add_tail(&term->list, &head->terms);
593 $$ = $1;
594 }
595 |
596 event_term
597 {
598 struct parse_events_terms *head = malloc(sizeof(*head));
599 struct parse_events_term *term = $1;
600
601 if (!head)
602 YYNOMEM;
603 parse_events_terms__init(head);
604 list_add_tail(&term->list, &head->terms);
605 $$ = head;
606 }
607
608 name_or_raw: PE_RAW | PE_NAME | PE_LEGACY_CACHE
609 |
610 PE_TERM_HW
611 {
612 $$ = $1.str;
613 }
614
615 event_term:
616 PE_RAW
617 {
618 struct parse_events_term *term;
619 int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_RAW,
620 strdup("raw"), $1, &@1, &@1);
621
622 if (err) {
623 free($1);
624 PE_ABORT(err);
625 }
626 $$ = term;
627 }
628 |
629 name_or_raw '=' name_or_raw
630 {
631 struct parse_events_term *term;
632 int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $3, &@1, &@3);
633
634 if (err) {
635 free($1);
636 free($3);
637 PE_ABORT(err);
638 }
639 $$ = term;
640 }
641 |
642 name_or_raw '=' PE_VALUE
643 {
644 struct parse_events_term *term;
645 int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
646 $1, $3, /*novalue=*/false, &@1, &@3);
647
648 if (err) {
649 free($1);
650 PE_ABORT(err);
651 }
652 $$ = term;
653 }
654 |
655 PE_LEGACY_CACHE
656 {
657 struct parse_events_term *term;
658 int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE,
659 $1, /*num=*/1, /*novalue=*/true, &@1, /*loc_val=*/NULL);
660
661 if (err) {
662 free($1);
663 PE_ABORT(err);
664 }
665 $$ = term;
666 }
667 |
668 PE_NAME
669 {
670 struct parse_events_term *term;
671 int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
672 $1, /*num=*/1, /*novalue=*/true, &@1, /*loc_val=*/NULL);
673
674 if (err) {
675 free($1);
676 PE_ABORT(err);
677 }
678 $$ = term;
679 }
680 |
681 PE_TERM_HW
682 {
683 struct parse_events_term *term;
684 int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_HARDWARE,
685 $1.str, $1.num & 255, /*novalue=*/false,
686 &@1, /*loc_val=*/NULL);
687
688 if (err) {
689 free($1.str);
690 PE_ABORT(err);
691 }
692 $$ = term;
693 }
694 |
695 PE_TERM '=' name_or_raw
696 {
697 struct parse_events_term *term;
698 int err = parse_events_term__str(&term, $1, /*config=*/NULL, $3, &@1, &@3);
699
700 if (err) {
701 free($3);
702 PE_ABORT(err);
703 }
704 $$ = term;
705 }
706 |
707 PE_TERM '=' PE_TERM
708 {
709 struct parse_events_term *term;
710 int err = parse_events_term__term(&term, $1, $3, &@1, &@3);
711
712 if (err)
713 PE_ABORT(err);
714
715 $$ = term;
716 }
717 |
718 PE_TERM '=' PE_VALUE
719 {
720 struct parse_events_term *term;
721 int err = parse_events_term__num(&term, $1,
722 /*config=*/NULL, $3, /*novalue=*/false,
723 &@1, &@3);
724
725 if (err)
726 PE_ABORT(err);
727
728 $$ = term;
729 }
730 |
731 PE_TERM
732 {
733 struct parse_events_term *term;
734 int err = parse_events_term__num(&term, $1,
735 /*config=*/NULL, /*num=*/1, /*novalue=*/true,
736 &@1, /*loc_val=*/NULL);
737
738 if (err)
739 PE_ABORT(err);
740
741 $$ = term;
742 }
743 |
744 PE_DRV_CFG_TERM
745 {
746 struct parse_events_term *term;
747 char *config = strdup($1);
748 int err;
749
750 if (!config)
751 YYNOMEM;
752 err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, config, $1, &@1, NULL);
753 if (err) {
754 free($1);
755 free(config);
756 PE_ABORT(err);
757 }
758 $$ = term;
759 }
760
761 sep_dc: ':' |
762
763 sep_slash_slash_dc: '/' '/' | ':' |
764
765 %%
766
767 void parse_events_error(YYLTYPE *loc, void *_parse_state,
768 void *scanner __maybe_unused,
769 char const *msg __maybe_unused)
770 {
771 struct parse_events_state *parse_state = _parse_state;
772
773 if (!parse_state->error || !list_empty(&parse_state->error->list))
774 return;
775
776 parse_events_error__handle(parse_state->error, loc->last_column,
777 strdup("Unrecognized input"), NULL);
778 }
779