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