File Index
Files and directories
Sign in
FILE

parse-events.y

File preview with syntax highlighting.

linux-6.19.14/tools/perf/util/parse-events.y PLAIN TEXT
  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}
~/ Read-only file preview.