parse-events.y 13.8 KB
Newer Older
1
%pure-parser
2
%parse-param {void *_parse_state}
3 4
%parse-param {void *scanner}
%lex-param {void* scanner}
5
%locations
6 7 8 9 10

%{

#define YYDEBUG 1

11
#include <fnmatch.h>
12 13
#include <linux/compiler.h>
#include <linux/list.h>
B
Borislav Petkov 已提交
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 24 25 26 27 28
#define ABORT_ON(val) \
do { \
	if (val) \
		YYABORT; \
} while (0)

29 30 31 32 33 34 35
#define ALLOC_LIST(list) \
do { \
	list = malloc(sizeof(*list)); \
	ABORT_ON(!list);              \
	INIT_LIST_HEAD(list);         \
} while (0)

36
static void inc_group_count(struct list_head *list,
37
		       struct parse_events_state *parse_state)
38 39 40
{
	/* Count groups only have more than 1 members */
	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 52
%token PE_MODIFIER_EVENT PE_MODIFIER_BP
%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 60
%type <num> PE_VALUE_SYM_HW
%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 67 68 69
%type <str> PE_NAME_CACHE_TYPE
%type <str> PE_NAME_CACHE_OP_RESULT
%type <str> PE_MODIFIER_EVENT
%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 <head> opt_pmu_config
77
%type <term> event_term
78 79 80 81 82
%type <head> event_pmu
%type <head> event_legacy_symbol
%type <head> event_legacy_cache
%type <head> event_legacy_mem
%type <head> event_legacy_tracepoint
83
%type <tracepoint_name> tracepoint_name
84 85
%type <head> event_legacy_numeric
%type <head> event_legacy_raw
86
%type <head> event_bpf_file
87
%type <head> event_def
88 89
%type <head> event_mod
%type <head> event_name
90 91 92 93 94
%type <head> event
%type <head> events
%type <head> group_def
%type <head> group
%type <head> groups
95 96 97
%type <array> array
%type <array> array_term
%type <array> array_terms
98 99 100 101

%union
{
	char *str;
102
	u64 num;
103
	struct list_head *head;
104
	struct parse_events_term *term;
105 106 107 108
	struct tracepoint_name {
		char *sys;
		char *event;
	} tracepoint_name;
109
	struct parse_events_array array;
110 111 112
}
%%

113
start:
114
PE_START_EVENTS start_events
115
|
116 117 118 119
PE_START_TERMS  start_terms

start_events: groups
{
120
	struct parse_events_state *parse_state = _parse_state;
121

122
	parse_events_update_lists($1, &parse_state->list);
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
}

groups:
groups ',' group
{
	struct list_head *list  = $1;
	struct list_head *group = $3;

	parse_events_update_lists(group, list);
	$$ = list;
}
|
groups ',' event
{
	struct list_head *list  = $1;
	struct list_head *event = $3;

	parse_events_update_lists(event, list);
	$$ = list;
}
|
group
|
event

group:
group_def ':' PE_MODIFIER_EVENT
{
	struct list_head *list = $1;

	ABORT_ON(parse_events__modifier_group(list, $3));
	$$ = list;
}
|
group_def

group_def:
PE_NAME '{' events '}'
{
	struct list_head *list = $3;

164
	inc_group_count(list, _parse_state);
165
	parse_events__set_leader($1, list, _parse_state);
166 167 168 169 170 171 172
	$$ = list;
}
|
'{' events '}'
{
	struct list_head *list = $2;

173
	inc_group_count(list, _parse_state);
174
	parse_events__set_leader(NULL, list, _parse_state);
175 176
	$$ = list;
}
177

178
events:
179 180 181 182 183 184 185 186 187 188
events ',' event
{
	struct list_head *event = $3;
	struct list_head *list  = $1;

	parse_events_update_lists(event, list);
	$$ = list;
}
|
event
189

190 191 192 193
event: event_mod

event_mod:
event_name PE_MODIFIER_EVENT
194
{
195
	struct list_head *list = $1;
196

197 198 199 200 201
	/*
	 * Apply modifier on all events added by single event definition
	 * (there could be more events added for multiple tracepoint
	 * definitions via '*?'.
	 */
202
	ABORT_ON(parse_events__modifier_event(list, $2, false));
203
	$$ = list;
204 205
}
|
206 207 208 209 210 211 212 213 214 215
event_name

event_name:
PE_EVENT_NAME event_def
{
	ABORT_ON(parse_events_name($2, $1));
	free($1);
	$$ = $2;
}
|
216 217
event_def

218 219
event_def: event_pmu |
	   event_legacy_symbol |
220 221 222 223
	   event_legacy_cache sep_dc |
	   event_legacy_mem |
	   event_legacy_tracepoint sep_dc |
	   event_legacy_numeric sep_dc |
224 225
	   event_legacy_raw sep_dc |
	   event_bpf_file
226

227
event_pmu:
228
PE_NAME opt_pmu_config
229
{
230 231
	struct parse_events_state *parse_state = _parse_state;
	struct parse_events_error *error = parse_state->error;
232 233
	struct list_head *list, *orig_terms, *terms;

234
	if (parse_events_copy_term_list($2, &orig_terms))
235
		YYABORT;
236

237 238 239
	if (error)
		error->idx = @1.first_column;

240
	ALLOC_LIST(list);
241
	if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) {
242 243
		struct perf_pmu *pmu = NULL;
		int ok = 0;
244 245 246 247
		char *pattern;

		if (asprintf(&pattern, "%s*", $1) < 0)
			YYABORT;
248 249 250 251

		while ((pmu = perf_pmu__scan(pmu)) != NULL) {
			char *name = pmu->name;

252 253 254
			if (!strncmp(name, "uncore_", 7) &&
			    strncmp($1, "uncore_", 7))
				name += 7;
255 256 257
			if (!fnmatch(pattern, name, 0)) {
				if (parse_events_copy_term_list(orig_terms, &terms)) {
					free(pattern);
258
					YYABORT;
259
				}
260
				if (!parse_events_add_pmu(_parse_state, list, pmu->name, terms, true, false))
261 262 263 264
					ok++;
				parse_events_terms__delete(terms);
			}
		}
265 266 267

		free(pattern);

268 269 270
		if (!ok)
			YYABORT;
	}
271
	parse_events_terms__delete($2);
272
	parse_events_terms__delete(orig_terms);
273
	$$ = list;
274
}
275
|
276 277 278 279
PE_KERNEL_PMU_EVENT sep_dc
{
	struct list_head *list;

280
	if (parse_events_multi_pmu_add(_parse_state, $1, &list) < 0)
281
		YYABORT;
282 283 284 285 286 287 288 289
	$$ = list;
}
|
PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc
{
	struct list_head *list;
	char pmu_name[128];

290
	snprintf(&pmu_name, 128, "%s-%s", $1, $3);
291
	if (parse_events_multi_pmu_add(_parse_state, pmu_name, &list) < 0)
292
		YYABORT;
293 294
	$$ = list;
}
295

296 297 298 299 300
value_sym:
PE_VALUE_SYM_HW
|
PE_VALUE_SYM_SW

301
event_legacy_symbol:
302
value_sym '/' event_config '/'
303
{
304
	struct list_head *list;
305 306 307
	int type = $1 >> 16;
	int config = $1 & 255;

308
	ALLOC_LIST(list);
309
	ABORT_ON(parse_events_add_numeric(_parse_state, list, type, config, $3));
310
	parse_events_terms__delete($3);
311
	$$ = list;
312 313
}
|
314
value_sym sep_slash_dc
315
{
316
	struct list_head *list;
317 318 319
	int type = $1 >> 16;
	int config = $1 & 255;

320
	ALLOC_LIST(list);
321
	ABORT_ON(parse_events_add_numeric(_parse_state, list, type, config, NULL));
322
	$$ = list;
323 324 325
}

event_legacy_cache:
326
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT opt_event_config
327
{
328 329
	struct parse_events_state *parse_state = _parse_state;
	struct parse_events_error *error = parse_state->error;
330
	struct list_head *list;
331

332
	ALLOC_LIST(list);
333
	ABORT_ON(parse_events_add_cache(list, &parse_state->idx, $1, $3, $5, error, $6));
334
	parse_events_terms__delete($6);
335
	$$ = list;
336 337
}
|
338
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT opt_event_config
339
{
340 341
	struct parse_events_state *parse_state = _parse_state;
	struct parse_events_error *error = parse_state->error;
342
	struct list_head *list;
343

344
	ALLOC_LIST(list);
345
	ABORT_ON(parse_events_add_cache(list, &parse_state->idx, $1, $3, NULL, error, $4));
346
	parse_events_terms__delete($4);
347
	$$ = list;
348 349
}
|
350
PE_NAME_CACHE_TYPE opt_event_config
351
{
352 353
	struct parse_events_state *parse_state = _parse_state;
	struct parse_events_error *error = parse_state->error;
354
	struct list_head *list;
355

356
	ALLOC_LIST(list);
357
	ABORT_ON(parse_events_add_cache(list, &parse_state->idx, $1, NULL, NULL, error, $2));
358
	parse_events_terms__delete($2);
359
	$$ = list;
360 361 362
}

event_legacy_mem:
363 364
PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc
{
365
	struct parse_events_state *parse_state = _parse_state;
366 367 368
	struct list_head *list;

	ALLOC_LIST(list);
369
	ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx,
370 371 372 373 374 375
					     (void *) $2, $6, $4));
	$$ = list;
}
|
PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc
{
376
	struct parse_events_state *parse_state = _parse_state;
377 378 379
	struct list_head *list;

	ALLOC_LIST(list);
380
	ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx,
381 382 383 384
					     (void *) $2, NULL, $4));
	$$ = list;
}
|
385 386
PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
{
387
	struct parse_events_state *parse_state = _parse_state;
388
	struct list_head *list;
389

390
	ALLOC_LIST(list);
391
	ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx,
392
					     (void *) $2, $4, 0));
393
	$$ = list;
394 395 396 397
}
|
PE_PREFIX_MEM PE_VALUE sep_dc
{
398
	struct parse_events_state *parse_state = _parse_state;
399
	struct list_head *list;
400

401
	ALLOC_LIST(list);
402
	ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx,
403
					     (void *) $2, NULL, 0));
404
	$$ = list;
405 406 407
}

event_legacy_tracepoint:
408
tracepoint_name opt_event_config
409
{
410 411
	struct parse_events_state *parse_state = _parse_state;
	struct parse_events_error *error = parse_state->error;
412 413 414
	struct list_head *list;

	ALLOC_LIST(list);
415 416 417
	if (error)
		error->idx = @1.first_column;

418
	if (parse_events_add_tracepoint(list, &parse_state->idx, $1.sys, $1.event,
419
					error, $2))
420 421
		return -1;

422 423
	$$ = list;
}
424 425 426 427 428 429 430 431 432 433 434 435 436

tracepoint_name:
PE_NAME '-' PE_NAME ':' PE_NAME
{
	char sys_name[128];
	struct tracepoint_name tracepoint;

	snprintf(&sys_name, 128, "%s-%s", $1, $3);
	tracepoint.sys = &sys_name;
	tracepoint.event = $5;

	$$ = tracepoint;
}
437
|
438 439
PE_NAME ':' PE_NAME
{
440
	struct tracepoint_name tracepoint = {$1, $3};
441

442
	$$ = tracepoint;
443 444 445
}

event_legacy_numeric:
446
PE_VALUE ':' PE_VALUE opt_event_config
447
{
448
	struct list_head *list;
449

450
	ALLOC_LIST(list);
451
	ABORT_ON(parse_events_add_numeric(_parse_state, list, (u32)$1, $3, $4));
452
	parse_events_terms__delete($4);
453
	$$ = list;
454 455 456
}

event_legacy_raw:
457
PE_RAW opt_event_config
458
{
459
	struct list_head *list;
460

461
	ALLOC_LIST(list);
462
	ABORT_ON(parse_events_add_numeric(_parse_state, list, PERF_TYPE_RAW, $1, $2));
463
	parse_events_terms__delete($2);
464
	$$ = list;
465 466
}

467
event_bpf_file:
468
PE_BPF_OBJECT opt_event_config
469
{
470 471
	struct parse_events_state *parse_state = _parse_state;
	struct parse_events_error *error = parse_state->error;
472 473 474
	struct list_head *list;

	ALLOC_LIST(list);
475
	ABORT_ON(parse_events_load_bpf(parse_state, list, $1, false, $2));
476
	parse_events_terms__delete($2);
477 478 479
	$$ = list;
}
|
480
PE_BPF_SOURCE opt_event_config
481 482 483 484
{
	struct list_head *list;

	ALLOC_LIST(list);
485
	ABORT_ON(parse_events_load_bpf(_parse_state, list, $1, true, $2));
486
	parse_events_terms__delete($2);
487 488 489
	$$ = list;
}

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
opt_event_config:
'/' event_config '/'
{
	$$ = $2;
}
|
'/' '/'
{
	$$ = NULL;
}
|
{
	$$ = NULL;
}

505 506 507 508 509 510 511 512 513 514 515
opt_pmu_config:
'/' event_config '/'
{
	$$ = $2;
}
|
'/' '/'
{
	$$ = NULL;
}

516
start_terms: event_config
517
{
518 519
	struct parse_events_state *parse_state = _parse_state;
	parse_state->terms = $1;
520 521
}

522 523 524 525
event_config:
event_config ',' event_term
{
	struct list_head *head = $1;
526
	struct parse_events_term *term = $3;
527 528 529 530 531 532 533 534 535

	ABORT_ON(!head);
	list_add_tail(&term->list, head);
	$$ = $1;
}
|
event_term
{
	struct list_head *head = malloc(sizeof(*head));
536
	struct parse_events_term *term = $1;
537 538 539 540 541 542 543 544 545 546

	ABORT_ON(!head);
	INIT_LIST_HEAD(head);
	list_add_tail(&term->list, head);
	$$ = head;
}

event_term:
PE_NAME '=' PE_NAME
{
547
	struct parse_events_term *term;
548

549
	ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
550
					$1, $3, &@1, &@3));
551 552 553 554 555
	$$ = term;
}
|
PE_NAME '=' PE_VALUE
{
556
	struct parse_events_term *term;
557

558
	ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
559
					$1, $3, false, &@1, &@3));
560 561 562
	$$ = term;
}
|
563 564
PE_NAME '=' PE_VALUE_SYM_HW
{
565
	struct parse_events_term *term;
566 567
	int config = $3 & 255;

568
	ABORT_ON(parse_events_term__sym_hw(&term, $1, config));
569 570 571
	$$ = term;
}
|
572 573
PE_NAME
{
574
	struct parse_events_term *term;
575

576
	ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
577
					$1, 1, true, &@1, NULL));
578 579 580
	$$ = term;
}
|
581 582
PE_VALUE_SYM_HW
{
583
	struct parse_events_term *term;
584 585
	int config = $1 & 255;

586
	ABORT_ON(parse_events_term__sym_hw(&term, NULL, config));
587 588 589
	$$ = term;
}
|
590 591
PE_TERM '=' PE_NAME
{
592
	struct parse_events_term *term;
593

594
	ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3, &@1, &@3));
595 596 597
	$$ = term;
}
|
598 599
PE_TERM '=' PE_VALUE
{
600
	struct parse_events_term *term;
601

602
	ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3, false, &@1, &@3));
603 604 605 606 607
	$$ = term;
}
|
PE_TERM
{
608
	struct parse_events_term *term;
609

610
	ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, 1, true, &@1, NULL));
611
	$$ = term;
612
}
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
|
PE_NAME array '=' PE_NAME
{
	struct parse_events_term *term;
	int i;

	ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER,
					$1, $4, &@1, &@4));

	term->array = $2;
	$$ = term;
}
|
PE_NAME array '=' PE_VALUE
{
	struct parse_events_term *term;

	ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
631
					$1, $4, false, &@1, &@4));
632 633 634
	term->array = $2;
	$$ = term;
}
635 636 637 638 639 640 641 642 643
|
PE_DRV_CFG_TERM
{
	struct parse_events_term *term;

	ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG,
					$1, $1, &@1, NULL));
	$$ = term;
}
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701

array:
'[' array_terms ']'
{
	$$ = $2;
}
|
PE_ARRAY_ALL
{
	$$.nr_ranges = 0;
	$$.ranges = NULL;
}

array_terms:
array_terms ',' array_term
{
	struct parse_events_array new_array;

	new_array.nr_ranges = $1.nr_ranges + $3.nr_ranges;
	new_array.ranges = malloc(sizeof(new_array.ranges[0]) *
				  new_array.nr_ranges);
	ABORT_ON(!new_array.ranges);
	memcpy(&new_array.ranges[0], $1.ranges,
	       $1.nr_ranges * sizeof(new_array.ranges[0]));
	memcpy(&new_array.ranges[$1.nr_ranges], $3.ranges,
	       $3.nr_ranges * sizeof(new_array.ranges[0]));
	free($1.ranges);
	free($3.ranges);
	$$ = new_array;
}
|
array_term

array_term:
PE_VALUE
{
	struct parse_events_array array;

	array.nr_ranges = 1;
	array.ranges = malloc(sizeof(array.ranges[0]));
	ABORT_ON(!array.ranges);
	array.ranges[0].start = $1;
	array.ranges[0].length = 1;
	$$ = array;
}
|
PE_VALUE PE_ARRAY_RANGE PE_VALUE
{
	struct parse_events_array array;

	ABORT_ON($3 < $1);
	array.nr_ranges = 1;
	array.ranges = malloc(sizeof(array.ranges[0]));
	ABORT_ON(!array.ranges);
	array.ranges[0].start = $1;
	array.ranges[0].length = $3 - $1 + 1;
	$$ = array;
}
702 703 704

sep_dc: ':' |

705 706
sep_slash_dc: '/' | ':' |

707 708
%%

709
void parse_events_error(YYLTYPE *loc, void *parse_state,
710
			void *scanner __maybe_unused,
711
			char const *msg __maybe_unused)
712
{
713
	parse_events_evlist_error(parse_state, loc->last_column, "parser error");
714
}