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