1
2 %option reentrant
3 %option bison-bridge
4 %option prefix="parse_events_"
5 %option stack
6 %option bison-locations
7 %option yylineno
8 %option noyywrap
9
10 %{
11 #include <errno.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include "parse-events.h"
15 #include "parse-events-bison.h"
16
17 char *parse_events_get_text(yyscan_t yyscanner);
18 YYSTYPE *parse_events_get_lval(yyscan_t yyscanner);
19 int parse_events_get_column(yyscan_t yyscanner);
20 int parse_events_get_leng(yyscan_t yyscanner);
21
get_column(yyscan_t scanner)22 static int get_column(yyscan_t scanner)
23 {
24 return parse_events_get_column(scanner) - parse_events_get_leng(scanner);
25 }
26
value(struct parse_events_state * parse_state,yyscan_t scanner,int base)27 static int value(struct parse_events_state *parse_state, yyscan_t scanner, int base)
28 {
29 YYSTYPE *yylval = parse_events_get_lval(scanner);
30 char *text = parse_events_get_text(scanner);
31 u64 num;
32
33 errno = 0;
34 num = strtoull(text, NULL, base);
35 if (errno) {
36 struct parse_events_error *error = parse_state->error;
37 char *help = NULL;
38
39 if (asprintf(&help, "Bad base %d number \"%s\"", base, text) > 0)
40 parse_events_error__handle(error, get_column(scanner), help , NULL);
41
42 return PE_ERROR;
43 }
44
45 yylval->num = num;
46 return PE_VALUE;
47 }
48
str(yyscan_t scanner,int token)49 static int str(yyscan_t scanner, int token)
50 {
51 YYSTYPE *yylval = parse_events_get_lval(scanner);
52 char *text = parse_events_get_text(scanner);
53
54 yylval->str = strdup(text);
55 return token;
56 }
57
quoted_str(yyscan_t scanner,int token)58 static int quoted_str(yyscan_t scanner, int token)
59 {
60 YYSTYPE *yylval = parse_events_get_lval(scanner);
61 char *text = parse_events_get_text(scanner);
62
63 /*
64 * If a text tag specified on the command line
65 * contains opening single quite ' then it is
66 * expected that the tag ends with single quote
67 * as well, like this:
68 * name=\'CPU_CLK_UNHALTED.THREAD:cmask=1\'
69 * quotes need to be escaped to bypass shell
70 * processing.
71 */
72 yylval->str = strndup(&text[1], strlen(text) - 2);
73 return token;
74 }
75
76 /*
77 * This function is called when the parser gets two kind of input:
78 *
79 * @cfg1 or @cfg2=config
80 *
81 * The leading '@' is stripped off before 'cfg1' and 'cfg2=config' are given to
82 * bison. In the latter case it is necessary to keep the string intact so that
83 * the PMU kernel driver can determine what configurable is associated to
84 * 'config'.
85 */
drv_str(yyscan_t scanner,int token)86 static int drv_str(yyscan_t scanner, int token)
87 {
88 YYSTYPE *yylval = parse_events_get_lval(scanner);
89 char *text = parse_events_get_text(scanner);
90
91 /* Strip off the '@' */
92 yylval->str = strdup(text + 1);
93 return token;
94 }
95
96 /*
97 * Use yyless to return all the characaters to the input. Update the column for
98 * location debugging. If __alloc is non-zero set yylval to the text for the
99 * returned token's value.
100 */
101 #define REWIND(__alloc) \
102 do { \
103 YYSTYPE *__yylval = parse_events_get_lval(yyscanner); \
104 char *text = parse_events_get_text(yyscanner); \
105 \
106 if (__alloc) \
107 __yylval->str = strdup(text); \
108 \
109 yycolumn -= strlen(text); \
110 yyless(0); \
111 } while (0)
112
term(yyscan_t scanner,enum parse_events__term_type type)113 static int term(yyscan_t scanner, enum parse_events__term_type type)
114 {
115 YYSTYPE *yylval = parse_events_get_lval(scanner);
116
117 yylval->term_type = type;
118 return PE_TERM;
119 }
120
modifiers_error(struct parse_events_state * parse_state,yyscan_t scanner,int pos,char mod_char,const char * mod_name)121 static void modifiers_error(struct parse_events_state *parse_state, yyscan_t scanner,
122 int pos, char mod_char, const char *mod_name)
123 {
124 struct parse_events_error *error = parse_state->error;
125 char *help = NULL;
126
127 if (asprintf(&help, "Duplicate modifier '%c' (%s)", mod_char, mod_name) > 0)
128 parse_events_error__handle(error, get_column(scanner) + pos, help , NULL);
129 }
130
modifiers(struct parse_events_state * parse_state,yyscan_t scanner)131 static int modifiers(struct parse_events_state *parse_state, yyscan_t scanner)
132 {
133 YYSTYPE *yylval = parse_events_get_lval(scanner);
134 char *text = parse_events_get_text(scanner);
135 struct parse_events_modifier mod = { .precise = 0, };
136
137 for (size_t i = 0, n = strlen(text); i < n; i++) {
138 #define CASE(c, field) \
139 case c: \
140 if (mod.field) { \
141 modifiers_error(parse_state, scanner, i, c, #field); \
142 return PE_ERROR; \
143 } \
144 mod.field = true; \
145 break
146
147 switch (text[i]) {
148 CASE('u', user);
149 CASE('k', kernel);
150 CASE('h', hypervisor);
151 CASE('I', non_idle);
152 CASE('G', guest);
153 CASE('H', host);
154 case 'p':
155 mod.precise++;
156 /*
157 * precise ip:
158 *
159 * 0 - SAMPLE_IP can have arbitrary skid
160 * 1 - SAMPLE_IP must have constant skid
161 * 2 - SAMPLE_IP requested to have 0 skid
162 * 3 - SAMPLE_IP must have 0 skid
163 *
164 * See also PERF_RECORD_MISC_EXACT_IP
165 */
166 if (mod.precise > 3) {
167 struct parse_events_error *error = parse_state->error;
168 char *help = strdup("Maximum precise value is 3");
169
170 if (help) {
171 parse_events_error__handle(error, get_column(scanner) + i,
172 help , NULL);
173 }
174 return PE_ERROR;
175 }
176 break;
177 CASE('P', precise_max);
178 CASE('S', sample_read);
179 CASE('D', pinned);
180 CASE('W', weak);
181 CASE('e', exclusive);
182 CASE('b', bpf);
183 CASE('R', retire_lat);
184 CASE('X', dont_regroup);
185 default:
186 return PE_ERROR;
187 }
188 #undef CASE
189 }
190 yylval->mod = mod;
191 return PE_MODIFIER_EVENT;
192 }
193
194 #define YY_USER_ACTION \
195 do { \
196 yylloc->last_column = yylloc->first_column; \
197 yylloc->first_column = yycolumn; \
198 yycolumn += yyleng; \
199 } while (0);
200
201 %}
202
203 %x mem
204 %s config
205 %x event
206
207 group [^,{}/]*[{][^}]*[}][^,{}/]*
208 event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
209 event [^,{}/]+
210
211 num_dec [0-9]+
212 num_hex 0x[a-fA-F0-9]{1,16}
213 num_raw_hex [a-fA-F0-9]{1,16}
214 /* Regular pattern to match the token PE_NAME. */
215 name_start [a-zA-Z0-9_*?\[\]]
216 name {name_start}[a-zA-Z0-9_*?.\[\]!\-]*
217 /* PE_NAME token when inside a config term list, allows ':'. */
218 term_name {name_start}[a-zA-Z0-9_*?.\[\]!\-:]*
219 /*
220 * PE_NAME token when quoted, allows ':,.='.
221 * Matches the RHS of terms like: name='COMPLEX_CYCLES_NAME:orig=cycles,desc=chip-clock-ticks'.
222 */
223 quoted_name [\']{name_start}[a-zA-Z0-9_*?.\[\]!\-:,\.=]*[\']
224 drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)?
225 /*
226 * If you add a modifier you need to update modifiers().
227 * Also, the letters in modifier_event must not be in modifier_bp.
228 */
229 modifier_event [ukhpPGHSDIWebRX]{1,17}
230 modifier_bp [rwx]{1,3}
231 digit [0-9]
232 non_digit [^0-9]
233
234 %%
235
236 %{
237 struct parse_events_state *_parse_state = parse_events_get_extra(yyscanner);
238 {
239 int start_token = _parse_state->stoken;
240
241 if (start_token == PE_START_TERMS)
242 BEGIN(config);
243 else if (start_token == PE_START_EVENTS)
244 BEGIN(event);
245
246 if (start_token) {
247 _parse_state->stoken = 0;
248 /*
249 * The flex parser does not init locations variable
250 * via the scan_string interface, so we need do the
251 * init in here.
252 */
253 yycolumn = 0;
254 return start_token;
255 }
256 }
257 %}
258
259 <event>{
260
261 {group} {
262 BEGIN(INITIAL);
263 REWIND(0);
264 }
265
266 {event_pmu} |
267 {event} {
268 BEGIN(INITIAL);
269 REWIND(1);
270 return PE_EVENT_NAME;
271 }
272
273 <<EOF>> {
274 BEGIN(INITIAL);
275 REWIND(0);
276 }
277 , {
278 return ',';
279 }
280 }
281
282 <config>{
283 /*
284 * Please update config_term_names when new static term is added.
285 */
286 config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
287 config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
288 config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
289 config3 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG3); }
290 config4 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG4); }
291 name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
292 period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
293 freq { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ); }
294 branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
295 time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
296 call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); }
297 stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); }
298 max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); }
299 nr { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_EVENTS); }
300 inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); }
301 no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); }
302 overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); }
303 no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); }
304 percore { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); }
305 aux-output { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); }
306 aux-action { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_ACTION); }
307 aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE); }
308 metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); }
309 cpu { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CPU); }
310 ratio-to-prev { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV); }
311 legacy-hardware-config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG); }
312 legacy-cache-config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG); }
313 r{num_raw_hex} { return str(yyscanner, PE_RAW); }
314 r0x{num_raw_hex} { return str(yyscanner, PE_RAW); }
315 , { return ','; }
316 "/" { BEGIN(INITIAL); return '/'; }
317 {num_dec} { return value(_parse_state, yyscanner, 10); }
318 {num_hex} { return value(_parse_state, yyscanner, 16); }
319 {term_name} { return str(yyscanner, PE_NAME); }
320 @{drv_cfg_term} { return drv_str(yyscanner, PE_DRV_CFG_TERM); }
321 }
322
323 <mem>{
324 {modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
325 /*
326 * The colon before memory access modifiers can get mixed up with the
327 * colon before event modifiers. Fortunately none of the option letters
328 * are the same, so trailing context can be used disambiguate the two
329 * cases.
330 */
331 ":"/{modifier_bp} { return PE_BP_COLON; }
332 /*
333 * The slash before memory length can get mixed up with the slash before
334 * config terms. Fortunately config terms do not start with a numeric
335 * digit, so trailing context can be used disambiguate the two cases.
336 */
337 "/"/{digit} { return PE_BP_SLASH; }
338 "/"/{non_digit} { BEGIN(config); return '/'; }
339 {num_dec} { return value(_parse_state, yyscanner, 10); }
340 {num_hex} { return value(_parse_state, yyscanner, 16); }
341 /*
342 * We need to separate 'mem:' scanner part, in order to get specific
343 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
344 * and we'd need to parse it manually. During the escape from <mem>
345 * state we need to put the escaping char back, so we dont miss it.
346 */
347 . { unput(*yytext); BEGIN(INITIAL); }
348 /*
349 * We destroy the scanner after reaching EOF,
350 * but anyway just to be sure get back to INIT state.
351 */
352 <<EOF>> { BEGIN(INITIAL); }
353 }
354
355 mem: { BEGIN(mem); return PE_PREFIX_MEM; }
356 r{num_raw_hex} { return str(yyscanner, PE_RAW); }
357 {num_dec} { return value(_parse_state, yyscanner, 10); }
358 {num_hex} { return value(_parse_state, yyscanner, 16); }
359
360 {modifier_event} { return modifiers(_parse_state, yyscanner); }
361 {name} { return str(yyscanner, PE_NAME); }
362 {quoted_name} { return quoted_str(yyscanner, PE_NAME); }
363 "/" { BEGIN(config); return '/'; }
364 , { BEGIN(event); return ','; }
365 : { return ':'; }
366 "{" { BEGIN(event); return '{'; }
367 "}" { return '}'; }
368 = { return '='; }
369 \n { }
370 . { }
371
372 %%
373