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