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