Commit | Line | Data |
---|---|---|
97b58163 MD |
1 | /* |
2 | * lttng-filter-specialize.c | |
3 | * | |
4 | * LTTng UST filter code specializer. | |
5 | * | |
6 | * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
7 | * | |
8 | * This library is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License as published by the Free Software Foundation; only | |
11 | * version 2.1 of the License. | |
12 | * | |
13 | * This library is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public | |
19 | * License along with this library; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
21 | */ | |
22 | ||
23 | #include "lttng-filter.h" | |
24 | ||
25 | int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) | |
26 | { | |
27 | void *pc, *next_pc, *start_pc; | |
28 | int ret = -EINVAL; | |
0305960f MD |
29 | struct vstack _stack; |
30 | struct vstack *stack = &_stack; | |
97b58163 | 31 | |
0305960f | 32 | vstack_init(stack); |
97b58163 MD |
33 | |
34 | start_pc = &bytecode->data[0]; | |
35 | for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; | |
36 | pc = next_pc) { | |
37 | switch (*(filter_opcode_t *) pc) { | |
38 | case FILTER_OP_UNKNOWN: | |
39 | default: | |
40 | ERR("unknown bytecode op %u\n", | |
41 | (unsigned int) *(filter_opcode_t *) pc); | |
42 | ret = -EINVAL; | |
43 | goto end; | |
44 | ||
45 | case FILTER_OP_RETURN: | |
46 | ret = 0; | |
47 | goto end; | |
48 | ||
49 | /* binary */ | |
50 | case FILTER_OP_MUL: | |
51 | case FILTER_OP_DIV: | |
52 | case FILTER_OP_MOD: | |
53 | case FILTER_OP_PLUS: | |
54 | case FILTER_OP_MINUS: | |
55 | case FILTER_OP_RSHIFT: | |
56 | case FILTER_OP_LSHIFT: | |
57 | case FILTER_OP_BIN_AND: | |
58 | case FILTER_OP_BIN_OR: | |
59 | case FILTER_OP_BIN_XOR: | |
60 | ERR("unsupported bytecode op %u\n", | |
61 | (unsigned int) *(filter_opcode_t *) pc); | |
62 | ret = -EINVAL; | |
63 | goto end; | |
64 | ||
65 | case FILTER_OP_EQ: | |
66 | { | |
67 | struct binary_op *insn = (struct binary_op *) pc; | |
68 | ||
0305960f | 69 | switch(vstack_ax(stack)->type) { |
97b58163 MD |
70 | default: |
71 | ERR("unknown register type\n"); | |
72 | ret = -EINVAL; | |
73 | goto end; | |
74 | ||
75 | case REG_STRING: | |
76 | insn->op = FILTER_OP_EQ_STRING; | |
77 | break; | |
78 | case REG_S64: | |
0305960f | 79 | if (vstack_bx(stack)->type == REG_S64) |
97b58163 MD |
80 | insn->op = FILTER_OP_EQ_S64; |
81 | else | |
82 | insn->op = FILTER_OP_EQ_DOUBLE; | |
83 | break; | |
84 | case REG_DOUBLE: | |
85 | insn->op = FILTER_OP_EQ_DOUBLE; | |
86 | break; | |
87 | } | |
0305960f MD |
88 | /* Pop 2, push 1 */ |
89 | if (vstack_pop(stack)) { | |
90 | ret = -EINVAL; | |
91 | goto end; | |
92 | } | |
93 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
94 | next_pc += sizeof(struct binary_op); |
95 | break; | |
96 | } | |
97 | ||
98 | case FILTER_OP_NE: | |
99 | { | |
100 | struct binary_op *insn = (struct binary_op *) pc; | |
101 | ||
0305960f | 102 | switch(vstack_ax(stack)->type) { |
97b58163 MD |
103 | default: |
104 | ERR("unknown register type\n"); | |
105 | ret = -EINVAL; | |
106 | goto end; | |
107 | ||
108 | case REG_STRING: | |
109 | insn->op = FILTER_OP_NE_STRING; | |
110 | break; | |
111 | case REG_S64: | |
0305960f | 112 | if (vstack_bx(stack)->type == REG_S64) |
97b58163 MD |
113 | insn->op = FILTER_OP_NE_S64; |
114 | else | |
115 | insn->op = FILTER_OP_NE_DOUBLE; | |
116 | break; | |
117 | case REG_DOUBLE: | |
118 | insn->op = FILTER_OP_NE_DOUBLE; | |
119 | break; | |
120 | } | |
0305960f MD |
121 | /* Pop 2, push 1 */ |
122 | if (vstack_pop(stack)) { | |
123 | ret = -EINVAL; | |
124 | goto end; | |
125 | } | |
126 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
127 | next_pc += sizeof(struct binary_op); |
128 | break; | |
129 | } | |
130 | ||
131 | case FILTER_OP_GT: | |
132 | { | |
133 | struct binary_op *insn = (struct binary_op *) pc; | |
134 | ||
0305960f | 135 | switch(vstack_ax(stack)->type) { |
97b58163 MD |
136 | default: |
137 | ERR("unknown register type\n"); | |
138 | ret = -EINVAL; | |
139 | goto end; | |
140 | ||
141 | case REG_STRING: | |
142 | insn->op = FILTER_OP_GT_STRING; | |
143 | break; | |
144 | case REG_S64: | |
0305960f | 145 | if (vstack_bx(stack)->type == REG_S64) |
97b58163 MD |
146 | insn->op = FILTER_OP_GT_S64; |
147 | else | |
148 | insn->op = FILTER_OP_GT_DOUBLE; | |
149 | break; | |
150 | case REG_DOUBLE: | |
151 | insn->op = FILTER_OP_GT_DOUBLE; | |
152 | break; | |
153 | } | |
0305960f MD |
154 | /* Pop 2, push 1 */ |
155 | if (vstack_pop(stack)) { | |
156 | ret = -EINVAL; | |
157 | goto end; | |
158 | } | |
159 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
160 | next_pc += sizeof(struct binary_op); |
161 | break; | |
162 | } | |
163 | ||
164 | case FILTER_OP_LT: | |
165 | { | |
166 | struct binary_op *insn = (struct binary_op *) pc; | |
167 | ||
0305960f | 168 | switch(vstack_ax(stack)->type) { |
97b58163 MD |
169 | default: |
170 | ERR("unknown register type\n"); | |
171 | ret = -EINVAL; | |
172 | goto end; | |
173 | ||
174 | case REG_STRING: | |
175 | insn->op = FILTER_OP_LT_STRING; | |
176 | break; | |
177 | case REG_S64: | |
0305960f | 178 | if (vstack_bx(stack)->type == REG_S64) |
97b58163 MD |
179 | insn->op = FILTER_OP_LT_S64; |
180 | else | |
181 | insn->op = FILTER_OP_LT_DOUBLE; | |
182 | break; | |
183 | case REG_DOUBLE: | |
184 | insn->op = FILTER_OP_LT_DOUBLE; | |
185 | break; | |
186 | } | |
0305960f MD |
187 | /* Pop 2, push 1 */ |
188 | if (vstack_pop(stack)) { | |
189 | ret = -EINVAL; | |
190 | goto end; | |
191 | } | |
192 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
193 | next_pc += sizeof(struct binary_op); |
194 | break; | |
195 | } | |
196 | ||
197 | case FILTER_OP_GE: | |
198 | { | |
199 | struct binary_op *insn = (struct binary_op *) pc; | |
200 | ||
0305960f | 201 | switch(vstack_ax(stack)->type) { |
97b58163 MD |
202 | default: |
203 | ERR("unknown register type\n"); | |
204 | ret = -EINVAL; | |
205 | goto end; | |
206 | ||
207 | case REG_STRING: | |
208 | insn->op = FILTER_OP_GE_STRING; | |
209 | break; | |
210 | case REG_S64: | |
0305960f | 211 | if (vstack_bx(stack)->type == REG_S64) |
97b58163 MD |
212 | insn->op = FILTER_OP_GE_S64; |
213 | else | |
214 | insn->op = FILTER_OP_GE_DOUBLE; | |
215 | break; | |
216 | case REG_DOUBLE: | |
217 | insn->op = FILTER_OP_GE_DOUBLE; | |
218 | break; | |
219 | } | |
0305960f MD |
220 | /* Pop 2, push 1 */ |
221 | if (vstack_pop(stack)) { | |
222 | ret = -EINVAL; | |
223 | goto end; | |
224 | } | |
225 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
226 | next_pc += sizeof(struct binary_op); |
227 | break; | |
228 | } | |
229 | case FILTER_OP_LE: | |
230 | { | |
231 | struct binary_op *insn = (struct binary_op *) pc; | |
232 | ||
0305960f | 233 | switch(vstack_ax(stack)->type) { |
97b58163 MD |
234 | default: |
235 | ERR("unknown register type\n"); | |
236 | ret = -EINVAL; | |
237 | goto end; | |
238 | ||
239 | case REG_STRING: | |
240 | insn->op = FILTER_OP_LE_STRING; | |
241 | break; | |
242 | case REG_S64: | |
0305960f | 243 | if (vstack_bx(stack)->type == REG_S64) |
97b58163 MD |
244 | insn->op = FILTER_OP_LE_S64; |
245 | else | |
246 | insn->op = FILTER_OP_LE_DOUBLE; | |
247 | break; | |
248 | case REG_DOUBLE: | |
249 | insn->op = FILTER_OP_LE_DOUBLE; | |
250 | break; | |
251 | } | |
0305960f | 252 | vstack_ax(stack)->type = REG_S64; |
97b58163 MD |
253 | next_pc += sizeof(struct binary_op); |
254 | break; | |
255 | } | |
256 | ||
257 | case FILTER_OP_EQ_STRING: | |
258 | case FILTER_OP_NE_STRING: | |
259 | case FILTER_OP_GT_STRING: | |
260 | case FILTER_OP_LT_STRING: | |
261 | case FILTER_OP_GE_STRING: | |
262 | case FILTER_OP_LE_STRING: | |
263 | case FILTER_OP_EQ_S64: | |
264 | case FILTER_OP_NE_S64: | |
265 | case FILTER_OP_GT_S64: | |
266 | case FILTER_OP_LT_S64: | |
267 | case FILTER_OP_GE_S64: | |
268 | case FILTER_OP_LE_S64: | |
269 | case FILTER_OP_EQ_DOUBLE: | |
270 | case FILTER_OP_NE_DOUBLE: | |
271 | case FILTER_OP_GT_DOUBLE: | |
272 | case FILTER_OP_LT_DOUBLE: | |
273 | case FILTER_OP_GE_DOUBLE: | |
274 | case FILTER_OP_LE_DOUBLE: | |
275 | { | |
0305960f MD |
276 | /* Pop 2, push 1 */ |
277 | if (vstack_pop(stack)) { | |
278 | ret = -EINVAL; | |
279 | goto end; | |
280 | } | |
281 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
282 | next_pc += sizeof(struct binary_op); |
283 | break; | |
284 | } | |
285 | ||
286 | /* unary */ | |
287 | case FILTER_OP_UNARY_PLUS: | |
288 | { | |
289 | struct unary_op *insn = (struct unary_op *) pc; | |
290 | ||
0305960f | 291 | switch(vstack_ax(stack)->type) { |
97b58163 MD |
292 | default: |
293 | ERR("unknown register type\n"); | |
294 | ret = -EINVAL; | |
295 | goto end; | |
296 | ||
297 | case REG_S64: | |
298 | insn->op = FILTER_OP_UNARY_PLUS_S64; | |
299 | break; | |
300 | case REG_DOUBLE: | |
301 | insn->op = FILTER_OP_UNARY_PLUS_DOUBLE; | |
302 | break; | |
303 | } | |
0305960f | 304 | /* Pop 1, push 1 */ |
97b58163 MD |
305 | next_pc += sizeof(struct unary_op); |
306 | break; | |
307 | } | |
308 | ||
309 | case FILTER_OP_UNARY_MINUS: | |
310 | { | |
311 | struct unary_op *insn = (struct unary_op *) pc; | |
312 | ||
0305960f | 313 | switch(vstack_ax(stack)->type) { |
97b58163 MD |
314 | default: |
315 | ERR("unknown register type\n"); | |
316 | ret = -EINVAL; | |
317 | goto end; | |
318 | ||
319 | case REG_S64: | |
320 | insn->op = FILTER_OP_UNARY_MINUS_S64; | |
321 | break; | |
322 | case REG_DOUBLE: | |
323 | insn->op = FILTER_OP_UNARY_MINUS_DOUBLE; | |
324 | break; | |
325 | } | |
0305960f | 326 | /* Pop 1, push 1 */ |
97b58163 MD |
327 | next_pc += sizeof(struct unary_op); |
328 | break; | |
329 | } | |
330 | ||
331 | case FILTER_OP_UNARY_NOT: | |
332 | { | |
333 | struct unary_op *insn = (struct unary_op *) pc; | |
334 | ||
0305960f | 335 | switch(vstack_ax(stack)->type) { |
97b58163 MD |
336 | default: |
337 | ERR("unknown register type\n"); | |
338 | ret = -EINVAL; | |
339 | goto end; | |
340 | ||
341 | case REG_S64: | |
342 | insn->op = FILTER_OP_UNARY_NOT_S64; | |
343 | break; | |
344 | case REG_DOUBLE: | |
345 | insn->op = FILTER_OP_UNARY_NOT_DOUBLE; | |
346 | break; | |
347 | } | |
0305960f | 348 | /* Pop 1, push 1 */ |
97b58163 MD |
349 | next_pc += sizeof(struct unary_op); |
350 | break; | |
351 | } | |
352 | ||
353 | case FILTER_OP_UNARY_PLUS_S64: | |
354 | case FILTER_OP_UNARY_MINUS_S64: | |
355 | case FILTER_OP_UNARY_NOT_S64: | |
356 | case FILTER_OP_UNARY_PLUS_DOUBLE: | |
357 | case FILTER_OP_UNARY_MINUS_DOUBLE: | |
358 | case FILTER_OP_UNARY_NOT_DOUBLE: | |
359 | { | |
0305960f | 360 | /* Pop 1, push 1 */ |
97b58163 MD |
361 | next_pc += sizeof(struct unary_op); |
362 | break; | |
363 | } | |
364 | ||
365 | /* logical */ | |
366 | case FILTER_OP_AND: | |
367 | case FILTER_OP_OR: | |
368 | { | |
369 | next_pc += sizeof(struct logical_op); | |
370 | break; | |
371 | } | |
372 | ||
373 | /* load */ | |
374 | case FILTER_OP_LOAD_FIELD_REF: | |
375 | { | |
376 | ERR("Unknown field ref type\n"); | |
377 | ret = -EINVAL; | |
378 | goto end; | |
379 | } | |
380 | case FILTER_OP_LOAD_FIELD_REF_STRING: | |
381 | case FILTER_OP_LOAD_FIELD_REF_SEQUENCE: | |
382 | { | |
0305960f MD |
383 | if (vstack_push(stack)) { |
384 | ret = -EINVAL; | |
385 | goto end; | |
386 | } | |
387 | vstack_ax(stack)->type = REG_STRING; | |
97b58163 MD |
388 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); |
389 | break; | |
390 | } | |
391 | case FILTER_OP_LOAD_FIELD_REF_S64: | |
392 | { | |
0305960f MD |
393 | if (vstack_push(stack)) { |
394 | ret = -EINVAL; | |
395 | goto end; | |
396 | } | |
397 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
398 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); |
399 | break; | |
400 | } | |
401 | case FILTER_OP_LOAD_FIELD_REF_DOUBLE: | |
402 | { | |
0305960f MD |
403 | if (vstack_push(stack)) { |
404 | ret = -EINVAL; | |
405 | goto end; | |
406 | } | |
407 | vstack_ax(stack)->type = REG_DOUBLE; | |
97b58163 MD |
408 | next_pc += sizeof(struct load_op) + sizeof(struct field_ref); |
409 | break; | |
410 | } | |
411 | ||
412 | case FILTER_OP_LOAD_STRING: | |
413 | { | |
414 | struct load_op *insn = (struct load_op *) pc; | |
415 | ||
0305960f MD |
416 | if (vstack_push(stack)) { |
417 | ret = -EINVAL; | |
418 | goto end; | |
419 | } | |
420 | vstack_ax(stack)->type = REG_STRING; | |
97b58163 MD |
421 | next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; |
422 | break; | |
423 | } | |
424 | ||
425 | case FILTER_OP_LOAD_S64: | |
426 | { | |
0305960f MD |
427 | if (vstack_push(stack)) { |
428 | ret = -EINVAL; | |
429 | goto end; | |
430 | } | |
431 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
432 | next_pc += sizeof(struct load_op) |
433 | + sizeof(struct literal_numeric); | |
434 | break; | |
435 | } | |
436 | ||
437 | case FILTER_OP_LOAD_DOUBLE: | |
438 | { | |
0305960f MD |
439 | if (vstack_push(stack)) { |
440 | ret = -EINVAL; | |
441 | goto end; | |
442 | } | |
443 | vstack_ax(stack)->type = REG_DOUBLE; | |
97b58163 MD |
444 | next_pc += sizeof(struct load_op) |
445 | + sizeof(struct literal_double); | |
446 | break; | |
447 | } | |
448 | ||
449 | /* cast */ | |
450 | case FILTER_OP_CAST_TO_S64: | |
451 | { | |
452 | struct cast_op *insn = (struct cast_op *) pc; | |
453 | ||
0305960f | 454 | switch (vstack_ax(stack)->type) { |
97b58163 MD |
455 | default: |
456 | ERR("unknown register type\n"); | |
457 | ret = -EINVAL; | |
458 | goto end; | |
459 | ||
460 | case REG_STRING: | |
461 | ERR("Cast op can only be applied to numeric or floating point registers\n"); | |
462 | ret = -EINVAL; | |
463 | goto end; | |
464 | case REG_S64: | |
465 | insn->op = FILTER_OP_CAST_NOP; | |
466 | break; | |
467 | case REG_DOUBLE: | |
468 | insn->op = FILTER_OP_CAST_DOUBLE_TO_S64; | |
469 | break; | |
470 | } | |
0305960f MD |
471 | /* Pop 1, push 1 */ |
472 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
473 | next_pc += sizeof(struct cast_op); |
474 | break; | |
475 | } | |
476 | case FILTER_OP_CAST_DOUBLE_TO_S64: | |
477 | { | |
0305960f MD |
478 | /* Pop 1, push 1 */ |
479 | vstack_ax(stack)->type = REG_S64; | |
97b58163 MD |
480 | next_pc += sizeof(struct cast_op); |
481 | break; | |
482 | } | |
483 | case FILTER_OP_CAST_NOP: | |
484 | { | |
485 | next_pc += sizeof(struct cast_op); | |
486 | break; | |
487 | } | |
488 | ||
489 | ||
490 | } | |
491 | } | |
492 | end: | |
493 | return ret; | |
494 | } |