779 lines · plain
1%define api.pure full2%parse-param {void *_parse_state}3%parse-param {void *scanner}4%lex-param {void* scanner}5%locations6 7%{8 9#ifndef NDEBUG10#define YYDEBUG 111#endif12 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_TERMS58%token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_TERM59%token PE_VALUE_SYM_TOOL60%token PE_EVENT_NAME61%token PE_RAW PE_NAME62%token PE_MODIFIER_EVENT PE_MODIFIER_BP PE_BP_COLON PE_BP_SLASH63%token PE_LEGACY_CACHE64%token PE_PREFIX_MEM65%token PE_ERROR66%token PE_DRV_CFG_TERM67%token PE_TERM_HW68%type <num> PE_VALUE69%type <num> PE_VALUE_SYM_HW70%type <num> PE_VALUE_SYM_SW71%type <num> PE_VALUE_SYM_TOOL72%type <mod> PE_MODIFIER_EVENT73%type <term_type> PE_TERM74%type <num> value_sym75%type <str> PE_RAW76%type <str> PE_NAME77%type <str> PE_LEGACY_CACHE78%type <str> PE_MODIFIER_BP79%type <str> PE_EVENT_NAME80%type <str> PE_DRV_CFG_TERM81%type <str> name_or_raw82%destructor { free ($$); } <str>83%type <term> event_term84%destructor { parse_events_term__delete ($$); } <term>85%type <list_terms> event_config86%type <list_terms> opt_event_config87%type <list_terms> opt_pmu_config88%destructor { parse_events_terms__delete ($$); } <list_terms>89%type <list_evsel> event_pmu90%type <list_evsel> event_legacy_symbol91%type <list_evsel> event_legacy_cache92%type <list_evsel> event_legacy_mem93%type <list_evsel> event_legacy_tracepoint94%type <list_evsel> event_legacy_numeric95%type <list_evsel> event_legacy_raw96%type <list_evsel> event_def97%type <list_evsel> event_mod98%type <list_evsel> event_name99%type <list_evsel> event100%type <list_evsel> events101%type <list_evsel> group_def102%type <list_evsel> group103%type <list_evsel> groups104%destructor { free_list_evsel ($$); } <list_evsel>105%type <tracepoint_name> tracepoint_name106%destructor { free ($$.sys); free ($$.event); } <tracepoint_name>107%type <hardware_term> PE_TERM_HW108%destructor { free ($$.str); } <hardware_term>109 110%union111{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 terminal132 * parsing is used for parsing events in sysfs.133 */134start:135PE_START_EVENTS start_events136|137PE_START_TERMS start_terms138 139start_events: groups140{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 ',' group151{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 ',' event162{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|173group174|175event176 177group:178group_def ':' PE_MODIFIER_EVENT179{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_def191 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 on199 * 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 ',' event216{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|225event226 227event: event_mod228 229event_mod:230event_name PE_MODIFIER_EVENT231{232 struct list_head *list = $1;233 int err;234 235 /*236 * Apply modifier on all events added by single event definition237 * (there could be more events added for multiple tracepoint238 * definitions via '*?'.239 */240 err = parse_events__modifier_event(_parse_state, &@2, list, $2);241 if (err)242 YYABORT;243 $$ = list;244}245|246event_name247 248event_name:249PE_EVENT_NAME event_def250{251 /*252 * When an event is parsed the text is rewound and the entire text of253 * the event is set to the str of PE_EVENT_NAME token matched here. If254 * no name was on an event via a term, set the name to the entire text255 * 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_def267 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_dc275 276event_pmu:277PE_NAME opt_pmu_config278{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_dc291{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_HW313|314PE_VALUE_SYM_SW315 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_dc338{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_dc355{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_config370{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_config392{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_config412{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_config431{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_config451{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_config470{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_NAME495{496 struct tracepoint_name tracepoint = {$1, $3};497 498 $$ = tracepoint;499}500 501event_legacy_numeric:502PE_VALUE ':' PE_VALUE opt_event_config503{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_config522{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_config573{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_term584{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_term597{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_CACHE609|610PE_TERM_HW611{612 $$ = $1.str;613}614 615event_term:616PE_RAW617{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_raw630{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_VALUE643{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_CACHE656{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_NAME669{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_HW682{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_raw696{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_TERM708{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_VALUE719{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_TERM732{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_TERM745{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