d115585d8c9a1cc85b482a72bf981e5cad031ffa
[lttng-ust.git] / liblttng-ust / lttng-filter-specialize.c
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 #define _LGPL_SOURCE
24 #include "lttng-filter.h"
25
26 int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode)
27 {
28 void *pc, *next_pc, *start_pc;
29 int ret = -EINVAL;
30 struct vstack _stack;
31 struct vstack *stack = &_stack;
32
33 vstack_init(stack);
34
35 start_pc = &bytecode->data[0];
36 for (pc = next_pc = start_pc; pc - start_pc < bytecode->len;
37 pc = next_pc) {
38 switch (*(filter_opcode_t *) pc) {
39 case FILTER_OP_UNKNOWN:
40 default:
41 ERR("unknown bytecode op %u\n",
42 (unsigned int) *(filter_opcode_t *) pc);
43 ret = -EINVAL;
44 goto end;
45
46 case FILTER_OP_RETURN:
47 ret = 0;
48 goto end;
49
50 /* binary */
51 case FILTER_OP_MUL:
52 case FILTER_OP_DIV:
53 case FILTER_OP_MOD:
54 case FILTER_OP_PLUS:
55 case FILTER_OP_MINUS:
56 case FILTER_OP_RSHIFT:
57 case FILTER_OP_LSHIFT:
58 case FILTER_OP_BIN_AND:
59 case FILTER_OP_BIN_OR:
60 case FILTER_OP_BIN_XOR:
61 ERR("unsupported bytecode op %u\n",
62 (unsigned int) *(filter_opcode_t *) pc);
63 ret = -EINVAL;
64 goto end;
65
66 case FILTER_OP_EQ:
67 {
68 struct binary_op *insn = (struct binary_op *) pc;
69
70 switch(vstack_ax(stack)->type) {
71 default:
72 ERR("unknown register type\n");
73 ret = -EINVAL;
74 goto end;
75
76 case REG_STRING:
77 if (vstack_bx(stack)->type == REG_UNKNOWN)
78 break;
79 insn->op = FILTER_OP_EQ_STRING;
80 break;
81 case REG_S64:
82 if (vstack_bx(stack)->type == REG_UNKNOWN)
83 break;
84 if (vstack_bx(stack)->type == REG_S64)
85 insn->op = FILTER_OP_EQ_S64;
86 else
87 insn->op = FILTER_OP_EQ_DOUBLE_S64;
88 break;
89 case REG_DOUBLE:
90 if (vstack_bx(stack)->type == REG_UNKNOWN)
91 break;
92 if (vstack_bx(stack)->type == REG_S64)
93 insn->op = FILTER_OP_EQ_S64_DOUBLE;
94 else
95 insn->op = FILTER_OP_EQ_DOUBLE;
96 break;
97 case REG_UNKNOWN:
98 break; /* Dynamic typing. */
99 }
100 /* Pop 2, push 1 */
101 if (vstack_pop(stack)) {
102 ret = -EINVAL;
103 goto end;
104 }
105 vstack_ax(stack)->type = REG_S64;
106 next_pc += sizeof(struct binary_op);
107 break;
108 }
109
110 case FILTER_OP_NE:
111 {
112 struct binary_op *insn = (struct binary_op *) pc;
113
114 switch(vstack_ax(stack)->type) {
115 default:
116 ERR("unknown register type\n");
117 ret = -EINVAL;
118 goto end;
119
120 case REG_STRING:
121 if (vstack_bx(stack)->type == REG_UNKNOWN)
122 break;
123 insn->op = FILTER_OP_NE_STRING;
124 break;
125 case REG_S64:
126 if (vstack_bx(stack)->type == REG_UNKNOWN)
127 break;
128 if (vstack_bx(stack)->type == REG_S64)
129 insn->op = FILTER_OP_NE_S64;
130 else
131 insn->op = FILTER_OP_NE_DOUBLE_S64;
132 break;
133 case REG_DOUBLE:
134 if (vstack_bx(stack)->type == REG_UNKNOWN)
135 break;
136 if (vstack_bx(stack)->type == REG_S64)
137 insn->op = FILTER_OP_NE_S64_DOUBLE;
138 else
139 insn->op = FILTER_OP_NE_DOUBLE;
140 break;
141 case REG_UNKNOWN:
142 break; /* Dynamic typing. */
143 }
144 /* Pop 2, push 1 */
145 if (vstack_pop(stack)) {
146 ret = -EINVAL;
147 goto end;
148 }
149 vstack_ax(stack)->type = REG_S64;
150 next_pc += sizeof(struct binary_op);
151 break;
152 }
153
154 case FILTER_OP_GT:
155 {
156 struct binary_op *insn = (struct binary_op *) pc;
157
158 switch(vstack_ax(stack)->type) {
159 default:
160 ERR("unknown register type\n");
161 ret = -EINVAL;
162 goto end;
163
164 case REG_STRING:
165 if (vstack_bx(stack)->type == REG_UNKNOWN)
166 break;
167 insn->op = FILTER_OP_GT_STRING;
168 break;
169 case REG_S64:
170 if (vstack_bx(stack)->type == REG_UNKNOWN)
171 break;
172 if (vstack_bx(stack)->type == REG_S64)
173 insn->op = FILTER_OP_GT_S64;
174 else
175 insn->op = FILTER_OP_GT_DOUBLE_S64;
176 break;
177 case REG_DOUBLE:
178 if (vstack_bx(stack)->type == REG_UNKNOWN)
179 break;
180 if (vstack_bx(stack)->type == REG_S64)
181 insn->op = FILTER_OP_GT_S64_DOUBLE;
182 else
183 insn->op = FILTER_OP_GT_DOUBLE;
184 break;
185 case REG_UNKNOWN:
186 break; /* Dynamic typing. */
187 }
188 /* Pop 2, push 1 */
189 if (vstack_pop(stack)) {
190 ret = -EINVAL;
191 goto end;
192 }
193 vstack_ax(stack)->type = REG_S64;
194 next_pc += sizeof(struct binary_op);
195 break;
196 }
197
198 case FILTER_OP_LT:
199 {
200 struct binary_op *insn = (struct binary_op *) pc;
201
202 switch(vstack_ax(stack)->type) {
203 default:
204 ERR("unknown register type\n");
205 ret = -EINVAL;
206 goto end;
207
208 case REG_STRING:
209 if (vstack_bx(stack)->type == REG_UNKNOWN)
210 break;
211 insn->op = FILTER_OP_LT_STRING;
212 break;
213 case REG_S64:
214 if (vstack_bx(stack)->type == REG_UNKNOWN)
215 break;
216 if (vstack_bx(stack)->type == REG_S64)
217 insn->op = FILTER_OP_LT_S64;
218 else
219 insn->op = FILTER_OP_LT_DOUBLE_S64;
220 break;
221 case REG_DOUBLE:
222 if (vstack_bx(stack)->type == REG_UNKNOWN)
223 break;
224 if (vstack_bx(stack)->type == REG_S64)
225 insn->op = FILTER_OP_LT_S64_DOUBLE;
226 else
227 insn->op = FILTER_OP_LT_DOUBLE;
228 break;
229 case REG_UNKNOWN:
230 break; /* Dynamic typing. */
231 }
232 /* Pop 2, push 1 */
233 if (vstack_pop(stack)) {
234 ret = -EINVAL;
235 goto end;
236 }
237 vstack_ax(stack)->type = REG_S64;
238 next_pc += sizeof(struct binary_op);
239 break;
240 }
241
242 case FILTER_OP_GE:
243 {
244 struct binary_op *insn = (struct binary_op *) pc;
245
246 switch(vstack_ax(stack)->type) {
247 default:
248 ERR("unknown register type\n");
249 ret = -EINVAL;
250 goto end;
251
252 case REG_STRING:
253 if (vstack_bx(stack)->type == REG_UNKNOWN)
254 break;
255 insn->op = FILTER_OP_GE_STRING;
256 break;
257 case REG_S64:
258 if (vstack_bx(stack)->type == REG_UNKNOWN)
259 break;
260 if (vstack_bx(stack)->type == REG_S64)
261 insn->op = FILTER_OP_GE_S64;
262 else
263 insn->op = FILTER_OP_GE_DOUBLE_S64;
264 break;
265 case REG_DOUBLE:
266 if (vstack_bx(stack)->type == REG_UNKNOWN)
267 break;
268 if (vstack_bx(stack)->type == REG_S64)
269 insn->op = FILTER_OP_GE_S64_DOUBLE;
270 else
271 insn->op = FILTER_OP_GE_DOUBLE;
272 break;
273 case REG_UNKNOWN:
274 break; /* Dynamic typing. */
275 }
276 /* Pop 2, push 1 */
277 if (vstack_pop(stack)) {
278 ret = -EINVAL;
279 goto end;
280 }
281 vstack_ax(stack)->type = REG_S64;
282 next_pc += sizeof(struct binary_op);
283 break;
284 }
285 case FILTER_OP_LE:
286 {
287 struct binary_op *insn = (struct binary_op *) pc;
288
289 switch(vstack_ax(stack)->type) {
290 default:
291 ERR("unknown register type\n");
292 ret = -EINVAL;
293 goto end;
294
295 case REG_STRING:
296 if (vstack_bx(stack)->type == REG_UNKNOWN)
297 break;
298 insn->op = FILTER_OP_LE_STRING;
299 break;
300 case REG_S64:
301 if (vstack_bx(stack)->type == REG_UNKNOWN)
302 break;
303 if (vstack_bx(stack)->type == REG_S64)
304 insn->op = FILTER_OP_LE_S64;
305 else
306 insn->op = FILTER_OP_LE_DOUBLE_S64;
307 break;
308 case REG_DOUBLE:
309 if (vstack_bx(stack)->type == REG_UNKNOWN)
310 break;
311 if (vstack_bx(stack)->type == REG_S64)
312 insn->op = FILTER_OP_LE_S64_DOUBLE;
313 else
314 insn->op = FILTER_OP_LE_DOUBLE;
315 break;
316 case REG_UNKNOWN:
317 break; /* Dynamic typing. */
318 }
319 vstack_ax(stack)->type = REG_S64;
320 next_pc += sizeof(struct binary_op);
321 break;
322 }
323
324 case FILTER_OP_EQ_STRING:
325 case FILTER_OP_NE_STRING:
326 case FILTER_OP_GT_STRING:
327 case FILTER_OP_LT_STRING:
328 case FILTER_OP_GE_STRING:
329 case FILTER_OP_LE_STRING:
330 case FILTER_OP_EQ_S64:
331 case FILTER_OP_NE_S64:
332 case FILTER_OP_GT_S64:
333 case FILTER_OP_LT_S64:
334 case FILTER_OP_GE_S64:
335 case FILTER_OP_LE_S64:
336 case FILTER_OP_EQ_DOUBLE:
337 case FILTER_OP_NE_DOUBLE:
338 case FILTER_OP_GT_DOUBLE:
339 case FILTER_OP_LT_DOUBLE:
340 case FILTER_OP_GE_DOUBLE:
341 case FILTER_OP_LE_DOUBLE:
342 case FILTER_OP_EQ_DOUBLE_S64:
343 case FILTER_OP_NE_DOUBLE_S64:
344 case FILTER_OP_GT_DOUBLE_S64:
345 case FILTER_OP_LT_DOUBLE_S64:
346 case FILTER_OP_GE_DOUBLE_S64:
347 case FILTER_OP_LE_DOUBLE_S64:
348 case FILTER_OP_EQ_S64_DOUBLE:
349 case FILTER_OP_NE_S64_DOUBLE:
350 case FILTER_OP_GT_S64_DOUBLE:
351 case FILTER_OP_LT_S64_DOUBLE:
352 case FILTER_OP_GE_S64_DOUBLE:
353 case FILTER_OP_LE_S64_DOUBLE:
354 {
355 /* Pop 2, push 1 */
356 if (vstack_pop(stack)) {
357 ret = -EINVAL;
358 goto end;
359 }
360 vstack_ax(stack)->type = REG_S64;
361 next_pc += sizeof(struct binary_op);
362 break;
363 }
364
365 /* unary */
366 case FILTER_OP_UNARY_PLUS:
367 {
368 struct unary_op *insn = (struct unary_op *) pc;
369
370 switch(vstack_ax(stack)->type) {
371 default:
372 ERR("unknown register type\n");
373 ret = -EINVAL;
374 goto end;
375
376 case REG_S64:
377 insn->op = FILTER_OP_UNARY_PLUS_S64;
378 break;
379 case REG_DOUBLE:
380 insn->op = FILTER_OP_UNARY_PLUS_DOUBLE;
381 break;
382 case REG_UNKNOWN: /* Dynamic typing. */
383 break;
384 }
385 /* Pop 1, push 1 */
386 next_pc += sizeof(struct unary_op);
387 break;
388 }
389
390 case FILTER_OP_UNARY_MINUS:
391 {
392 struct unary_op *insn = (struct unary_op *) pc;
393
394 switch(vstack_ax(stack)->type) {
395 default:
396 ERR("unknown register type\n");
397 ret = -EINVAL;
398 goto end;
399
400 case REG_S64:
401 insn->op = FILTER_OP_UNARY_MINUS_S64;
402 break;
403 case REG_DOUBLE:
404 insn->op = FILTER_OP_UNARY_MINUS_DOUBLE;
405 break;
406 case REG_UNKNOWN: /* Dynamic typing. */
407 break;
408 }
409 /* Pop 1, push 1 */
410 next_pc += sizeof(struct unary_op);
411 break;
412 }
413
414 case FILTER_OP_UNARY_NOT:
415 {
416 struct unary_op *insn = (struct unary_op *) pc;
417
418 switch(vstack_ax(stack)->type) {
419 default:
420 ERR("unknown register type\n");
421 ret = -EINVAL;
422 goto end;
423
424 case REG_S64:
425 insn->op = FILTER_OP_UNARY_NOT_S64;
426 break;
427 case REG_DOUBLE:
428 insn->op = FILTER_OP_UNARY_NOT_DOUBLE;
429 break;
430 case REG_UNKNOWN: /* Dynamic typing. */
431 break;
432 }
433 /* Pop 1, push 1 */
434 next_pc += sizeof(struct unary_op);
435 break;
436 }
437
438 case FILTER_OP_UNARY_PLUS_S64:
439 case FILTER_OP_UNARY_MINUS_S64:
440 case FILTER_OP_UNARY_NOT_S64:
441 case FILTER_OP_UNARY_PLUS_DOUBLE:
442 case FILTER_OP_UNARY_MINUS_DOUBLE:
443 case FILTER_OP_UNARY_NOT_DOUBLE:
444 {
445 /* Pop 1, push 1 */
446 next_pc += sizeof(struct unary_op);
447 break;
448 }
449
450 /* logical */
451 case FILTER_OP_AND:
452 case FILTER_OP_OR:
453 {
454 /* Continue to next instruction */
455 /* Pop 1 when jump not taken */
456 if (vstack_pop(stack)) {
457 ret = -EINVAL;
458 goto end;
459 }
460 next_pc += sizeof(struct logical_op);
461 break;
462 }
463
464 /* load field ref */
465 case FILTER_OP_LOAD_FIELD_REF:
466 {
467 ERR("Unknown field ref type\n");
468 ret = -EINVAL;
469 goto end;
470 }
471 /* get context ref */
472 case FILTER_OP_GET_CONTEXT_REF:
473 {
474 if (vstack_push(stack)) {
475 ret = -EINVAL;
476 goto end;
477 }
478 vstack_ax(stack)->type = REG_UNKNOWN;
479 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
480 break;
481 }
482 case FILTER_OP_LOAD_FIELD_REF_STRING:
483 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
484 case FILTER_OP_GET_CONTEXT_REF_STRING:
485 {
486 if (vstack_push(stack)) {
487 ret = -EINVAL;
488 goto end;
489 }
490 vstack_ax(stack)->type = REG_STRING;
491 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
492 break;
493 }
494 case FILTER_OP_LOAD_FIELD_REF_S64:
495 case FILTER_OP_GET_CONTEXT_REF_S64:
496 {
497 if (vstack_push(stack)) {
498 ret = -EINVAL;
499 goto end;
500 }
501 vstack_ax(stack)->type = REG_S64;
502 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
503 break;
504 }
505 case FILTER_OP_LOAD_FIELD_REF_DOUBLE:
506 case FILTER_OP_GET_CONTEXT_REF_DOUBLE:
507 {
508 if (vstack_push(stack)) {
509 ret = -EINVAL;
510 goto end;
511 }
512 vstack_ax(stack)->type = REG_DOUBLE;
513 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
514 break;
515 }
516
517 /* load from immediate operand */
518 case FILTER_OP_LOAD_STRING:
519 {
520 struct load_op *insn = (struct load_op *) pc;
521
522 if (vstack_push(stack)) {
523 ret = -EINVAL;
524 goto end;
525 }
526 vstack_ax(stack)->type = REG_STRING;
527 next_pc += sizeof(struct load_op) + strlen(insn->data) + 1;
528 break;
529 }
530
531 case FILTER_OP_LOAD_S64:
532 {
533 if (vstack_push(stack)) {
534 ret = -EINVAL;
535 goto end;
536 }
537 vstack_ax(stack)->type = REG_S64;
538 next_pc += sizeof(struct load_op)
539 + sizeof(struct literal_numeric);
540 break;
541 }
542
543 case FILTER_OP_LOAD_DOUBLE:
544 {
545 if (vstack_push(stack)) {
546 ret = -EINVAL;
547 goto end;
548 }
549 vstack_ax(stack)->type = REG_DOUBLE;
550 next_pc += sizeof(struct load_op)
551 + sizeof(struct literal_double);
552 break;
553 }
554
555 /* cast */
556 case FILTER_OP_CAST_TO_S64:
557 {
558 struct cast_op *insn = (struct cast_op *) pc;
559
560 switch (vstack_ax(stack)->type) {
561 default:
562 ERR("unknown register type\n");
563 ret = -EINVAL;
564 goto end;
565
566 case REG_STRING:
567 ERR("Cast op can only be applied to numeric or floating point registers\n");
568 ret = -EINVAL;
569 goto end;
570 case REG_S64:
571 insn->op = FILTER_OP_CAST_NOP;
572 break;
573 case REG_DOUBLE:
574 insn->op = FILTER_OP_CAST_DOUBLE_TO_S64;
575 break;
576 case REG_UNKNOWN:
577 break;
578 }
579 /* Pop 1, push 1 */
580 vstack_ax(stack)->type = REG_S64;
581 next_pc += sizeof(struct cast_op);
582 break;
583 }
584 case FILTER_OP_CAST_DOUBLE_TO_S64:
585 {
586 /* Pop 1, push 1 */
587 vstack_ax(stack)->type = REG_S64;
588 next_pc += sizeof(struct cast_op);
589 break;
590 }
591 case FILTER_OP_CAST_NOP:
592 {
593 next_pc += sizeof(struct cast_op);
594 break;
595 }
596
597 }
598 }
599 end:
600 return ret;
601 }
This page took 0.040006 seconds and 3 git commands to generate.