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 <head> opt_pmu_config 77 %type <term> event_term 78 %type <head> event_pmu 79 %type <head> event_legacy_symbol 80 %type <head> event_legacy_cache 81 %type <head> event_legacy_mem 82 %type <head> event_legacy_tracepoint 83 %type <tracepoint_name> tracepoint_name 84 %type <head> event_legacy_numeric 85 %type <head> event_legacy_raw 86 %type <head> event_bpf_file 87 %type <head> event_def 88 %type <head> event_mod 89 %type <head> event_name 90 %type <head> event 91 %type <head> events 92 %type <head> group_def 93 %type <head> group 94 %type <head> groups 95 %type <array> array 96 %type <array> array_term 97 %type <array> array_terms 98 99 %union 100 { 101 char *str; 102 u64 num; 103 struct list_head *head; 104 struct parse_events_term *term; 105 struct tracepoint_name { 106 char *sys; 107 char *event; 108 } tracepoint_name; 109 struct parse_events_array array; 110 } 111 %% 112 113 start: 114 PE_START_EVENTS start_events 115 | 116 PE_START_TERMS start_terms 117 118 start_events: groups 119 { 120 struct parse_events_state *parse_state = _parse_state; 121 122 parse_events_update_lists($1, &parse_state->list); 123 } 124 125 groups: 126 groups ',' group 127 { 128 struct list_head *list = $1; 129 struct list_head *group = $3; 130 131 parse_events_update_lists(group, list); 132 $$ = list; 133 } 134 | 135 groups ',' event 136 { 137 struct list_head *list = $1; 138 struct list_head *event = $3; 139 140 parse_events_update_lists(event, list); 141 $$ = list; 142 } 143 | 144 group 145 | 146 event 147 148 group: 149 group_def ':' PE_MODIFIER_EVENT 150 { 151 struct list_head *list = $1; 152 153 ABORT_ON(parse_events__modifier_group(list, $3)); 154 $$ = list; 155 } 156 | 157 group_def 158 159 group_def: 160 PE_NAME '{' events '}' 161 { 162 struct list_head *list = $3; 163 164 inc_group_count(list, _parse_state); 165 parse_events__set_leader($1, list, _parse_state); 166 $$ = list; 167 } 168 | 169 '{' events '}' 170 { 171 struct list_head *list = $2; 172 173 inc_group_count(list, _parse_state); 174 parse_events__set_leader(NULL, list, _parse_state); 175 $$ = list; 176 } 177 178 events: 179 events ',' event 180 { 181 struct list_head *event = $3; 182 struct list_head *list = $1; 183 184 parse_events_update_lists(event, list); 185 $$ = list; 186 } 187 | 188 event 189 190 event: event_mod 191 192 event_mod: 193 event_name PE_MODIFIER_EVENT 194 { 195 struct list_head *list = $1; 196 197 /* 198 * Apply modifier on all events added by single event definition 199 * (there could be more events added for multiple tracepoint 200 * definitions via '*?'. 201 */ 202 ABORT_ON(parse_events__modifier_event(list, $2, false)); 203 $$ = list; 204 } 205 | 206 event_name 207 208 event_name: 209 PE_EVENT_NAME event_def 210 { 211 ABORT_ON(parse_events_name($2, $1)); 212 free($1); 213 $$ = $2; 214 } 215 | 216 event_def 217 218 event_def: event_pmu | 219 event_legacy_symbol | 220 event_legacy_cache sep_dc | 221 event_legacy_mem | 222 event_legacy_tracepoint sep_dc | 223 event_legacy_numeric sep_dc | 224 event_legacy_raw sep_dc | 225 event_bpf_file 226 227 event_pmu: 228 PE_NAME opt_pmu_config 229 { 230 struct parse_events_state *parse_state = _parse_state; 231 struct parse_events_error *error = parse_state->error; 232 struct list_head *list, *orig_terms, *terms; 233 234 if (parse_events_copy_term_list($2, &orig_terms)) 235 YYABORT; 236 237 if (error) 238 error->idx = @1.first_column; 239 240 ALLOC_LIST(list); 241 if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) { 242 struct perf_pmu *pmu = NULL; 243 int ok = 0; 244 char *pattern; 245 246 if (asprintf(&pattern, "%s*", $1) < 0) 247 YYABORT; 248 249 while ((pmu = perf_pmu__scan(pmu)) != NULL) { 250 char *name = pmu->name; 251 252 if (!strncmp(name, "uncore_", 7) && 253 strncmp($1, "uncore_", 7)) 254 name += 7; 255 if (!fnmatch(pattern, name, 0)) { 256 if (parse_events_copy_term_list(orig_terms, &terms)) { 257 free(pattern); 258 YYABORT; 259 } 260 if (!parse_events_add_pmu(_parse_state, list, pmu->name, terms, true, false)) 261 ok++; 262 parse_events_terms__delete(terms); 263 } 264 } 265 266 free(pattern); 267 268 if (!ok) 269 YYABORT; 270 } 271 parse_events_terms__delete($2); 272 parse_events_terms__delete(orig_terms); 273 $$ = list; 274 } 275 | 276 PE_KERNEL_PMU_EVENT sep_dc 277 { 278 struct list_head *list; 279 280 if (parse_events_multi_pmu_add(_parse_state, $1, &list) < 0) 281 YYABORT; 282 $$ = list; 283 } 284 | 285 PE_PMU_EVENT_PRE '-' PE_PMU_EVENT_SUF sep_dc 286 { 287 struct list_head *list; 288 char pmu_name[128]; 289 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 $$ = list; 294 } 295 296 value_sym: 297 PE_VALUE_SYM_HW 298 | 299 PE_VALUE_SYM_SW 300 301 event_legacy_symbol: 302 value_sym '/' event_config '/' 303 { 304 struct list_head *list; 305 int type = $1 >> 16; 306 int config = $1 & 255; 307 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_slash_dc 315 { 316 struct list_head *list; 317 int type = $1 >> 16; 318 int config = $1 & 255; 319 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 struct parse_events_state *parse_state = _parse_state; 329 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 struct parse_events_state *parse_state = _parse_state; 341 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 struct parse_events_state *parse_state = _parse_state; 353 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 PE_PREFIX_MEM PE_VALUE '/' PE_VALUE ':' PE_MODIFIER_BP sep_dc 364 { 365 struct parse_events_state *parse_state = _parse_state; 366 struct list_head *list; 367 368 ALLOC_LIST(list); 369 ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx, 370 (void *) $2, $6, $4)); 371 $$ = list; 372 } 373 | 374 PE_PREFIX_MEM PE_VALUE '/' PE_VALUE sep_dc 375 { 376 struct parse_events_state *parse_state = _parse_state; 377 struct list_head *list; 378 379 ALLOC_LIST(list); 380 ABORT_ON(parse_events_add_breakpoint(list, &parse_state->idx, 381 (void *) $2, NULL, $4)); 382 $$ = list; 383 } 384 | 385 PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 386 { 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 PE_PREFIX_MEM PE_VALUE sep_dc 397 { 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 struct parse_events_state *parse_state = _parse_state; 411 struct parse_events_error *error = parse_state->error; 412 struct list_head *list; 413 414 ALLOC_LIST(list); 415 if (error) 416 error->idx = @1.first_column; 417 418 if (parse_events_add_tracepoint(list, &parse_state->idx, $1.sys, $1.event, 419 error, $2)) 420 return -1; 421 422 $$ = list; 423 } 424 425 tracepoint_name: 426 PE_NAME '-' PE_NAME ':' PE_NAME 427 { 428 char sys_name[128]; 429 struct tracepoint_name tracepoint; 430 431 snprintf(&sys_name, 128, "%s-%s", $1, $3); 432 tracepoint.sys = &sys_name; 433 tracepoint.event = $5; 434 435 $$ = tracepoint; 436 } 437 | 438 PE_NAME ':' PE_NAME 439 { 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 struct parse_events_state *parse_state = _parse_state; 471 struct parse_events_error *error = parse_state->error; 472 struct list_head *list; 473 474 ALLOC_LIST(list); 475 ABORT_ON(parse_events_load_bpf(parse_state, list, $1, false, $2)); 476 parse_events_terms__delete($2); 477 $$ = list; 478 } 479 | 480 PE_BPF_SOURCE opt_event_config 481 { 482 struct list_head *list; 483 484 ALLOC_LIST(list); 485 ABORT_ON(parse_events_load_bpf(_parse_state, list, $1, true, $2)); 486 parse_events_terms__delete($2); 487 $$ = list; 488 } 489 490 opt_event_config: 491 '/' event_config '/' 492 { 493 $$ = $2; 494 } 495 | 496 '/' '/' 497 { 498 $$ = NULL; 499 } 500 | 501 { 502 $$ = NULL; 503 } 504 505 opt_pmu_config: 506 '/' event_config '/' 507 { 508 $$ = $2; 509 } 510 | 511 '/' '/' 512 { 513 $$ = NULL; 514 } 515 516 start_terms: event_config 517 { 518 struct parse_events_state *parse_state = _parse_state; 519 parse_state->terms = $1; 520 } 521 522 event_config: 523 event_config ',' event_term 524 { 525 struct list_head *head = $1; 526 struct parse_events_term *term = $3; 527 528 ABORT_ON(!head); 529 list_add_tail(&term->list, head); 530 $$ = $1; 531 } 532 | 533 event_term 534 { 535 struct list_head *head = malloc(sizeof(*head)); 536 struct parse_events_term *term = $1; 537 538 ABORT_ON(!head); 539 INIT_LIST_HEAD(head); 540 list_add_tail(&term->list, head); 541 $$ = head; 542 } 543 544 event_term: 545 PE_NAME '=' PE_NAME 546 { 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 $$ = term; 552 } 553 | 554 PE_NAME '=' PE_VALUE 555 { 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 $$ = term; 561 } 562 | 563 PE_NAME '=' PE_VALUE_SYM_HW 564 { 565 struct parse_events_term *term; 566 int config = $3 & 255; 567 568 ABORT_ON(parse_events_term__sym_hw(&term, $1, config)); 569 $$ = term; 570 } 571 | 572 PE_NAME 573 { 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 $$ = term; 579 } 580 | 581 PE_VALUE_SYM_HW 582 { 583 struct parse_events_term *term; 584 int config = $1 & 255; 585 586 ABORT_ON(parse_events_term__sym_hw(&term, NULL, config)); 587 $$ = term; 588 } 589 | 590 PE_TERM '=' PE_NAME 591 { 592 struct parse_events_term *term; 593 594 ABORT_ON(parse_events_term__str(&term, (int)$1, NULL, $3, &@1, &@3)); 595 $$ = term; 596 } 597 | 598 PE_TERM '=' PE_VALUE 599 { 600 struct parse_events_term *term; 601 602 ABORT_ON(parse_events_term__num(&term, (int)$1, NULL, $3, false, &@1, &@3)); 603 $$ = term; 604 } 605 | 606 PE_TERM 607 { 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 PE_NAME array '=' PE_NAME 615 { 616 struct parse_events_term *term; 617 int i; 618 619 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_USER, 620 $1, $4, &@1, &@4)); 621 622 term->array = $2; 623 $$ = term; 624 } 625 | 626 PE_NAME array '=' PE_VALUE 627 { 628 struct parse_events_term *term; 629 630 ABORT_ON(parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER, 631 $1, $4, false, &@1, &@4)); 632 term->array = $2; 633 $$ = term; 634 } 635 | 636 PE_DRV_CFG_TERM 637 { 638 struct parse_events_term *term; 639 640 ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG, 641 $1, $1, &@1, NULL)); 642 $$ = term; 643 } 644 645 array: 646 '[' array_terms ']' 647 { 648 $$ = $2; 649 } 650 | 651 PE_ARRAY_ALL 652 { 653 $$.nr_ranges = 0; 654 $$.ranges = NULL; 655 } 656 657 array_terms: 658 array_terms ',' array_term 659 { 660 struct parse_events_array new_array; 661 662 new_array.nr_ranges = $1.nr_ranges + $3.nr_ranges; 663 new_array.ranges = malloc(sizeof(new_array.ranges[0]) * 664 new_array.nr_ranges); 665 ABORT_ON(!new_array.ranges); 666 memcpy(&new_array.ranges[0], $1.ranges, 667 $1.nr_ranges * sizeof(new_array.ranges[0])); 668 memcpy(&new_array.ranges[$1.nr_ranges], $3.ranges, 669 $3.nr_ranges * sizeof(new_array.ranges[0])); 670 free($1.ranges); 671 free($3.ranges); 672 $$ = new_array; 673 } 674 | 675 array_term 676 677 array_term: 678 PE_VALUE 679 { 680 struct parse_events_array array; 681 682 array.nr_ranges = 1; 683 array.ranges = malloc(sizeof(array.ranges[0])); 684 ABORT_ON(!array.ranges); 685 array.ranges[0].start = $1; 686 array.ranges[0].length = 1; 687 $$ = array; 688 } 689 | 690 PE_VALUE PE_ARRAY_RANGE PE_VALUE 691 { 692 struct parse_events_array array; 693 694 ABORT_ON($3 < $1); 695 array.nr_ranges = 1; 696 array.ranges = malloc(sizeof(array.ranges[0])); 697 ABORT_ON(!array.ranges); 698 array.ranges[0].start = $1; 699 array.ranges[0].length = $3 - $1 + 1; 700 $$ = array; 701 } 702 703 sep_dc: ':' | 704 705 sep_slash_slash_dc: '/' '/' | ':' | 706 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 } 715