Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
22int parse_events_lex(YYSTYPE * yylval_param, YYLTYPE * yylloc_param , void *yyscanner);
23void parse_events_error(YYLTYPE *loc, void *parse_state, void *scanner, char const *msg);
24
25#define PE_ABORT(val) \
26do { \
27 if (val == -ENOMEM) \
28 YYNOMEM; \
29 YYABORT; \
30} while (0)
31
32static 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
44static 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_TERM
59%token PE_EVENT_NAME
60%token PE_RAW PE_NAME
61%token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH
62%token PE_PREFIX_MEM
63%token PE_ERROR
64%token PE_DRV_CFG_TERM
65%type <num> PE_VALUE
66%type <mod> PE_MODIFIER_EVENT
67%type <term_type> PE_TERM
68%type <str> PE_RAW
69%type <str> PE_NAME
70%type <str> PE_MODIFIER_BP
71%type <str> PE_EVENT_NAME
72%type <str> PE_DRV_CFG_TERM
73%type <str> name_or_raw
74%destructor { free ($$); } <str>
75%type <term> event_term
76%destructor { parse_events_term__delete ($$); } <term>
77%type <list_terms> event_config
78%type <list_terms> opt_event_config
79%type <list_terms> opt_pmu_config
80%destructor { parse_events_terms__delete ($$); } <list_terms>
81%type <list_evsel> event_pmu
82%type <list_evsel> event_legacy_mem
83%type <list_evsel> event_legacy_tracepoint
84%type <list_evsel> event_legacy_numeric
85%type <list_evsel> event_legacy_raw
86%type <list_evsel> event_def
87%type <list_evsel> event_mod
88%type <list_evsel> event_name
89%type <list_evsel> event
90%type <list_evsel> events
91%type <list_evsel> group_def
92%type <list_evsel> group
93%type <list_evsel> groups
94%destructor { free_list_evsel ($$); } <list_evsel>
95%type <tracepoint_name> tracepoint_name
96%destructor { free ($$.sys); free ($$.event); } <tracepoint_name>
97
98%union
99{
100 char *str;
101 u64 num;
102 struct parse_events_modifier mod;
103 enum parse_events__term_type term_type;
104 struct list_head *list_evsel;
105 struct parse_events_terms *list_terms;
106 struct parse_events_term *term;
107 struct tracepoint_name {
108 char *sys;
109 char *event;
110 } tracepoint_name;
111}
112%%
113
114 /*
115 * Entry points. We are either parsing events or terminals. Just terminal
116 * parsing is used for parsing events in sysfs.
117 */
118start:
119PE_START_EVENTS start_events
120|
121PE_START_TERMS start_terms
122
123start_events: groups
124{
125 /* Take the parsed events, groups.. and place into parse_state. */
126 struct list_head *groups = $1;
127 struct parse_events_state *parse_state = _parse_state;
128
129 list_splice_tail(groups, &parse_state->list);
130 free(groups);
131}
132
133groups: /* A list of groups or events. */
134groups ',' group
135{
136 /* Merge group into the list of events/groups. */
137 struct list_head *groups = $1;
138 struct list_head *group = $3;
139
140 list_splice_tail(group, groups);
141 free(group);
142 $$ = groups;
143}
144|
145groups ',' event
146{
147 /* Merge event into the list of events/groups. */
148 struct list_head *groups = $1;
149 struct list_head *event = $3;
150
151
152 list_splice_tail(event, groups);
153 free(event);
154 $$ = groups;
155}
156|
157group
158|
159event
160
161group:
162group_def ':' PE_MODIFIER_EVENT
163{
164 /* Apply the modifier to the events in the group_def. */
165 struct list_head *list = $1;
166 int err;
167
168 err = parse_events__modifier_group(_parse_state, &@3, list, $3);
169 if (err)
170 YYABORT;
171 $$ = list;
172}
173|
174group_def
175
176group_def:
177PE_NAME '{' events '}'
178{
179 struct list_head *list = $3;
180
181 /*
182 * Set the first entry of list to be the leader. Set the group name on
183 * the leader to $1 taking ownership.
184 */
185 parse_events__set_leader($1, list);
186 $$ = list;
187}
188|
189'{' events '}'
190{
191 struct list_head *list = $2;
192
193 /* Set the first entry of list to be the leader clearing the group name. */
194 parse_events__set_leader(NULL, list);
195 $$ = list;
196}
197
198events:
199events ',' event
200{
201 struct list_head *events = $1;
202 struct list_head *event = $3;
203
204 list_splice_tail(event, events);
205 free(event);
206 $$ = events;
207}
208|
209event
210
211event: event_mod
212
213event_mod:
214event_name PE_MODIFIER_EVENT
215{
216 struct list_head *list = $1;
217 int err;
218
219 /*
220 * Apply modifier on all events added by single event definition
221 * (there could be more events added for multiple tracepoint
222 * definitions via '*?'.
223 */
224 err = parse_events__modifier_event(_parse_state, &@2, list, $2);
225 if (err)
226 YYABORT;
227 $$ = list;
228}
229|
230event_name
231
232event_name:
233PE_EVENT_NAME event_def
234{
235 /*
236 * When an event is parsed the text is rewound and the entire text of
237 * the event is set to the str of PE_EVENT_NAME token matched here. If
238 * no name was on an event via a term, set the name to the entire text
239 * taking ownership of the allocation.
240 */
241 int err = parse_events__set_default_name($2, $1);
242
243 if (err) {
244 free_list_evsel($2);
245 YYNOMEM;
246 }
247 $$ = $2;
248}
249|
250event_def
251
252event_def: event_pmu |
253 event_legacy_mem sep_dc |
254 event_legacy_tracepoint sep_dc |
255 event_legacy_numeric sep_dc |
256 event_legacy_raw sep_dc
257
258event_pmu:
259PE_NAME opt_pmu_config
260{
261 /* List of created evsels. */
262 struct list_head *list = NULL;
263 int err = parse_events_multi_pmu_add_or_add_pmu(_parse_state, $1, $2, &list, &@1);
264
265 parse_events_terms__delete($2);
266 free($1);
267 if (err)
268 PE_ABORT(err);
269 $$ = list;
270}
271|
272PE_NAME sep_dc
273{
274 struct list_head *list;
275 int err;
276
277 err = parse_events_multi_pmu_add(_parse_state, $1, /*const_parsed_terms*/NULL, &list, &@1);
278 if (err < 0) {
279 struct parse_events_state *parse_state = _parse_state;
280 struct parse_events_error *error = parse_state->error;
281 char *help;
282
283 if (asprintf(&help, "Unable to find event on a PMU of '%s'", $1) < 0)
284 help = NULL;
285 parse_events_error__handle(error, @1.first_column, strdup("Bad event name"), help);
286 free($1);
287 PE_ABORT(err);
288 }
289 free($1);
290 $$ = list;
291}
292
293event_legacy_mem:
294PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
295{
296 struct list_head *list;
297 int err;
298
299 list = alloc_list();
300 if (!list)
301 YYNOMEM;
302
303 err = parse_events_add_breakpoint(_parse_state, list,
304 $2, $6, $4, $7);
305 parse_events_terms__delete($7);
306 free($6);
307 if (err) {
308 free(list);
309 PE_ABORT(err);
310 }
311 $$ = list;
312}
313|
314PE_PREFIX_MEM PE_VALUE PE_BP_SLASH PE_VALUE opt_event_config
315{
316 struct list_head *list;
317 int err;
318
319 list = alloc_list();
320 if (!list)
321 YYNOMEM;
322
323 err = parse_events_add_breakpoint(_parse_state, list,
324 $2, NULL, $4, $5);
325 parse_events_terms__delete($5);
326 if (err) {
327 free(list);
328 PE_ABORT(err);
329 }
330 $$ = list;
331}
332|
333PE_PREFIX_MEM PE_VALUE PE_BP_COLON PE_MODIFIER_BP opt_event_config
334{
335 struct list_head *list;
336 int err;
337
338 list = alloc_list();
339 if (!list)
340 YYNOMEM;
341
342 err = parse_events_add_breakpoint(_parse_state, list,
343 $2, $4, 0, $5);
344 parse_events_terms__delete($5);
345 free($4);
346 if (err) {
347 free(list);
348 PE_ABORT(err);
349 }
350 $$ = list;
351}
352|
353PE_PREFIX_MEM PE_VALUE opt_event_config
354{
355 struct list_head *list;
356 int err;
357
358 list = alloc_list();
359 if (!list)
360 YYNOMEM;
361 err = parse_events_add_breakpoint(_parse_state, list,
362 $2, NULL, 0, $3);
363 parse_events_terms__delete($3);
364 if (err) {
365 free(list);
366 PE_ABORT(err);
367 }
368 $$ = list;
369}
370
371event_legacy_tracepoint:
372tracepoint_name opt_event_config
373{
374 struct parse_events_state *parse_state = _parse_state;
375 struct parse_events_error *error = parse_state->error;
376 struct list_head *list;
377 int err;
378
379 list = alloc_list();
380 if (!list)
381 YYNOMEM;
382
383 err = parse_events_add_tracepoint(parse_state, list, $1.sys, $1.event,
384 error, $2, &@1);
385
386 parse_events_terms__delete($2);
387 free($1.sys);
388 free($1.event);
389 if (err) {
390 free(list);
391 PE_ABORT(err);
392 }
393 $$ = list;
394}
395
396tracepoint_name:
397PE_NAME ':' PE_NAME
398{
399 struct tracepoint_name tracepoint = {$1, $3};
400
401 $$ = tracepoint;
402}
403
404event_legacy_numeric:
405PE_VALUE ':' PE_VALUE opt_event_config
406{
407 struct list_head *list;
408 int err;
409
410 list = alloc_list();
411 if (!list)
412 YYNOMEM;
413 err = parse_events_add_numeric(_parse_state, list, (u32)$1, $3, $4,
414 /*wildcard=*/false);
415 parse_events_terms__delete($4);
416 if (err) {
417 free(list);
418 PE_ABORT(err);
419 }
420 $$ = list;
421}
422
423event_legacy_raw:
424PE_RAW opt_event_config
425{
426 struct list_head *list;
427 int err;
428 u64 num;
429
430 list = alloc_list();
431 if (!list)
432 YYNOMEM;
433 errno = 0;
434 num = strtoull($1 + 1, NULL, 16);
435 /* Given the lexer will only give [a-fA-F0-9]+ a failure here should be impossible. */
436 if (errno)
437 YYABORT;
438 free($1);
439 err = parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, num, $2,
440 /*wildcard=*/false);
441 parse_events_terms__delete($2);
442 if (err) {
443 free(list);
444 PE_ABORT(err);
445 }
446 $$ = list;
447}
448
449opt_event_config:
450'/' event_config '/'
451{
452 $$ = $2;
453}
454|
455'/' '/'
456{
457 $$ = NULL;
458}
459|
460{
461 $$ = NULL;
462}
463
464opt_pmu_config:
465'/' event_config '/'
466{
467 $$ = $2;
468}
469|
470'/' '/'
471{
472 $$ = NULL;
473}
474
475start_terms: event_config
476{
477 struct parse_events_state *parse_state = _parse_state;
478 if (parse_state->terms) {
479 parse_events_terms__delete ($1);
480 YYABORT;
481 }
482 parse_state->terms = $1;
483}
484
485event_config:
486event_config ',' event_term
487{
488 struct parse_events_terms *head = $1;
489 struct parse_events_term *term = $3;
490
491 if (!head) {
492 parse_events_term__delete(term);
493 YYABORT;
494 }
495 list_add_tail(&term->list, &head->terms);
496 $$ = $1;
497}
498|
499event_term
500{
501 struct parse_events_terms *head = malloc(sizeof(*head));
502 struct parse_events_term *term = $1;
503
504 if (!head)
505 YYNOMEM;
506 parse_events_terms__init(head);
507 list_add_tail(&term->list, &head->terms);
508 $$ = head;
509}
510
511name_or_raw: PE_RAW | PE_NAME
512
513event_term:
514PE_RAW
515{
516 struct parse_events_term *term;
517 int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_RAW,
518 strdup("raw"), $1, &@1, &@1);
519
520 if (err) {
521 free($1);
522 PE_ABORT(err);
523 }
524 $$ = term;
525}
526|
527name_or_raw '=' name_or_raw
528{
529 struct parse_events_term *term;
530 int err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, $1, $3, &@1, &@3);
531
532 if (err) {
533 free($1);
534 free($3);
535 PE_ABORT(err);
536 }
537 $$ = term;
538}
539|
540name_or_raw '=' PE_VALUE
541{
542 struct parse_events_term *term;
543 int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
544 $1, $3, /*novalue=*/false, &@1, &@3);
545
546 if (err) {
547 free($1);
548 PE_ABORT(err);
549 }
550 $$ = term;
551}
552|
553PE_NAME
554{
555 struct parse_events_term *term;
556 int err = parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
557 $1, /*num=*/1, /*novalue=*/true, &@1, /*loc_val=*/NULL);
558
559 if (err) {
560 free($1);
561 PE_ABORT(err);
562 }
563 $$ = term;
564}
565|
566PE_TERM '=' name_or_raw
567{
568 struct parse_events_term *term;
569 int err = parse_events_term__str(&term, $1, /*config=*/NULL, $3, &@1, &@3);
570
571 if (err) {
572 free($3);
573 PE_ABORT(err);
574 }
575 $$ = term;
576}
577|
578PE_TERM '=' PE_TERM
579{
580 struct parse_events_term *term;
581 int err = parse_events_term__term(&term, $1, $3, &@1, &@3);
582
583 if (err)
584 PE_ABORT(err);
585
586 $$ = term;
587}
588|
589PE_TERM '=' PE_VALUE
590{
591 struct parse_events_term *term;
592 int err = parse_events_term__num(&term, $1,
593 /*config=*/NULL, $3, /*novalue=*/false,
594 &@1, &@3);
595
596 if (err)
597 PE_ABORT(err);
598
599 $$ = term;
600}
601|
602PE_TERM
603{
604 struct parse_events_term *term;
605 int err = parse_events_term__num(&term, $1,
606 /*config=*/NULL, /*num=*/1, /*novalue=*/true,
607 &@1, /*loc_val=*/NULL);
608
609 if (err)
610 PE_ABORT(err);
611
612 $$ = term;
613}
614|
615PE_DRV_CFG_TERM
616{
617 struct parse_events_term *term;
618 char *config = strdup($1);
619 int err;
620
621 if (!config)
622 YYNOMEM;
623 err = parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, config, $1, &@1, NULL);
624 if (err) {
625 free($1);
626 free(config);
627 PE_ABORT(err);
628 }
629 $$ = term;
630}
631
632sep_dc: ':' |
633
634%%
635
636void parse_events_error(YYLTYPE *loc, void *_parse_state,
637 void *scanner __maybe_unused,
638 char const *msg __maybe_unused)
639{
640 struct parse_events_state *parse_state = _parse_state;
641
642 if (!parse_state->error || !list_empty(&parse_state->error->list))
643 return;
644
645 parse_events_error__handle(parse_state->error, loc->last_column,
646 strdup("Unrecognized input"), NULL);
647}