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