Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
17char *parse_events_get_text(yyscan_t yyscanner);
18YYSTYPE *parse_events_get_lval(yyscan_t yyscanner);
19int parse_events_get_column(yyscan_t yyscanner);
20int parse_events_get_leng(yyscan_t yyscanner);
21
22static int get_column(yyscan_t scanner)
23{
24 return parse_events_get_column(scanner) - parse_events_get_leng(scanner);
25}
26
27static 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
49static 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
58static 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 */
86static 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) \
102do { \
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
113static 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
121static 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
131static 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 \
195do { \
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
207group [^,{}/]*[{][^}]*[}][^,{}/]*
208event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
209event [^,{}/]+
210
211num_dec [0-9]+
212num_hex 0x[a-fA-F0-9]{1,16}
213num_raw_hex [a-fA-F0-9]{1,16}
214/* Regular pattern to match the token PE_NAME. */
215name_start [a-zA-Z0-9_*?\[\]]
216name {name_start}[a-zA-Z0-9_*?.\[\]!\-]*
217/* PE_NAME token when inside a config term list, allows ':'. */
218term_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 */
223quoted_name [\']{name_start}[a-zA-Z0-9_*?.\[\]!\-:,\.=]*[\']
224drv_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 */
229modifier_event [ukhpPGHSDIWebRX]{1,17}
230modifier_bp [rwx]{1,3}
231digit [0-9]
232non_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 */
286config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); }
287config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
288config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
289config3 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG3); }
290config4 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG4); }
291name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); }
292period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
293freq { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_FREQ); }
294branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
295time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); }
296call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); }
297stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); }
298max-stack { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_STACK); }
299nr { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_MAX_EVENTS); }
300inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); }
301no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); }
302overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); }
303no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); }
304percore { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); }
305aux-output { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); }
306aux-action { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_ACTION); }
307aux-sample-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_SAMPLE_SIZE); }
308metric-id { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_METRIC_ID); }
309cpu { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CPU); }
310ratio-to-prev { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_RATIO_TO_PREV); }
311legacy-hardware-config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_LEGACY_HARDWARE_CONFIG); }
312legacy-cache-config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_LEGACY_CACHE_CONFIG); }
313r{num_raw_hex} { return str(yyscanner, PE_RAW); }
314r0x{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
355mem: { BEGIN(mem); return PE_PREFIX_MEM; }
356r{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%%