Migrate tracepoint instrumentation to TP_FIELDS
[lttng-modules.git] / lttng-filter-specialize.c
1 /*
2 * lttng-filter-specialize.c
3 *
4 * LTTng modules filter code specializer.
5 *
6 * Copyright (C) 2010-2014 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 printk(KERN_WARNING "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 printk(KERN_WARNING "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 printk(KERN_WARNING "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:
79 if (vstack_bx(stack)->type == REG_S64)
80 insn->op = FILTER_OP_EQ_S64;
81 else
82 insn->op = FILTER_OP_EQ_DOUBLE_S64;
83 break;
84 case REG_DOUBLE:
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;
89 break;
90 }
91 /* Pop 2, push 1 */
92 if (vstack_pop(stack)) {
93 ret = -EINVAL;
94 goto end;
95 }
96 vstack_ax(stack)->type = REG_S64;
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
105 switch(vstack_ax(stack)->type) {
106 default:
107 printk(KERN_WARNING "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:
115 if (vstack_bx(stack)->type == REG_S64)
116 insn->op = FILTER_OP_NE_S64;
117 else
118 insn->op = FILTER_OP_NE_DOUBLE_S64;
119 break;
120 case REG_DOUBLE:
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;
125 break;
126 }
127 /* Pop 2, push 1 */
128 if (vstack_pop(stack)) {
129 ret = -EINVAL;
130 goto end;
131 }
132 vstack_ax(stack)->type = REG_S64;
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
141 switch(vstack_ax(stack)->type) {
142 default:
143 printk(KERN_WARNING "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:
151 if (vstack_bx(stack)->type == REG_S64)
152 insn->op = FILTER_OP_GT_S64;
153 else
154 insn->op = FILTER_OP_GT_DOUBLE_S64;
155 break;
156 case REG_DOUBLE:
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;
161 break;
162 }
163 /* Pop 2, push 1 */
164 if (vstack_pop(stack)) {
165 ret = -EINVAL;
166 goto end;
167 }
168 vstack_ax(stack)->type = REG_S64;
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
177 switch(vstack_ax(stack)->type) {
178 default:
179 printk(KERN_WARNING "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:
187 if (vstack_bx(stack)->type == REG_S64)
188 insn->op = FILTER_OP_LT_S64;
189 else
190 insn->op = FILTER_OP_LT_DOUBLE_S64;
191 break;
192 case REG_DOUBLE:
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;
197 break;
198 }
199 /* Pop 2, push 1 */
200 if (vstack_pop(stack)) {
201 ret = -EINVAL;
202 goto end;
203 }
204 vstack_ax(stack)->type = REG_S64;
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
213 switch(vstack_ax(stack)->type) {
214 default:
215 printk(KERN_WARNING "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:
223 if (vstack_bx(stack)->type == REG_S64)
224 insn->op = FILTER_OP_GE_S64;
225 else
226 insn->op = FILTER_OP_GE_DOUBLE_S64;
227 break;
228 case REG_DOUBLE:
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;
233 break;
234 }
235 /* Pop 2, push 1 */
236 if (vstack_pop(stack)) {
237 ret = -EINVAL;
238 goto end;
239 }
240 vstack_ax(stack)->type = REG_S64;
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
248 switch(vstack_ax(stack)->type) {
249 default:
250 printk(KERN_WARNING "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:
258 if (vstack_bx(stack)->type == REG_S64)
259 insn->op = FILTER_OP_LE_S64;
260 else
261 insn->op = FILTER_OP_LE_DOUBLE_S64;
262 break;
263 case REG_DOUBLE:
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;
268 break;
269 }
270 vstack_ax(stack)->type = REG_S64;
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:
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:
305 {
306 /* Pop 2, push 1 */
307 if (vstack_pop(stack)) {
308 ret = -EINVAL;
309 goto end;
310 }
311 vstack_ax(stack)->type = REG_S64;
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
321 switch(vstack_ax(stack)->type) {
322 default:
323 printk(KERN_WARNING "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 }
334 /* Pop 1, push 1 */
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
343 switch(vstack_ax(stack)->type) {
344 default:
345 printk(KERN_WARNING "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 }
356 /* Pop 1, push 1 */
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
365 switch(vstack_ax(stack)->type) {
366 default:
367 printk(KERN_WARNING "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 }
378 /* Pop 1, push 1 */
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 {
390 /* Pop 1, push 1 */
391 next_pc += sizeof(struct unary_op);
392 break;
393 }
394
395 /* logical */
396 case FILTER_OP_AND:
397 case FILTER_OP_OR:
398 {
399 /* Continue to next instruction */
400 /* Pop 1 when jump not taken */
401 if (vstack_pop(stack)) {
402 ret = -EINVAL;
403 goto end;
404 }
405 next_pc += sizeof(struct logical_op);
406 break;
407 }
408
409 /* load field ref */
410 case FILTER_OP_LOAD_FIELD_REF:
411 {
412 printk(KERN_WARNING "Unknown field ref type\n");
413 ret = -EINVAL;
414 goto end;
415 }
416 /* get context ref */
417 case FILTER_OP_GET_CONTEXT_REF:
418 {
419 printk(KERN_WARNING "Unknown get context ref type\n");
420 ret = -EINVAL;
421 goto end;
422 }
423 case FILTER_OP_LOAD_FIELD_REF_STRING:
424 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE:
425 case FILTER_OP_GET_CONTEXT_REF_STRING:
426 case FILTER_OP_LOAD_FIELD_REF_USER_STRING:
427 case FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE:
428 {
429 if (vstack_push(stack)) {
430 ret = -EINVAL;
431 goto end;
432 }
433 vstack_ax(stack)->type = REG_STRING;
434 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
435 break;
436 }
437 case FILTER_OP_LOAD_FIELD_REF_S64:
438 case FILTER_OP_GET_CONTEXT_REF_S64:
439 {
440 if (vstack_push(stack)) {
441 ret = -EINVAL;
442 goto end;
443 }
444 vstack_ax(stack)->type = REG_S64;
445 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
446 break;
447 }
448 case FILTER_OP_LOAD_FIELD_REF_DOUBLE:
449 case FILTER_OP_GET_CONTEXT_REF_DOUBLE:
450 {
451 if (vstack_push(stack)) {
452 ret = -EINVAL;
453 goto end;
454 }
455 vstack_ax(stack)->type = REG_DOUBLE;
456 next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
457 break;
458 }
459
460 /* load from immediate operand */
461 case FILTER_OP_LOAD_STRING:
462 {
463 struct load_op *insn = (struct load_op *) pc;
464
465 if (vstack_push(stack)) {
466 ret = -EINVAL;
467 goto end;
468 }
469 vstack_ax(stack)->type = REG_STRING;
470 next_pc += sizeof(struct load_op) + strlen(insn->data) + 1;
471 break;
472 }
473
474 case FILTER_OP_LOAD_S64:
475 {
476 if (vstack_push(stack)) {
477 ret = -EINVAL;
478 goto end;
479 }
480 vstack_ax(stack)->type = REG_S64;
481 next_pc += sizeof(struct load_op)
482 + sizeof(struct literal_numeric);
483 break;
484 }
485
486 case FILTER_OP_LOAD_DOUBLE:
487 {
488 if (vstack_push(stack)) {
489 ret = -EINVAL;
490 goto end;
491 }
492 vstack_ax(stack)->type = REG_DOUBLE;
493 next_pc += sizeof(struct load_op)
494 + sizeof(struct literal_double);
495 break;
496 }
497
498 /* cast */
499 case FILTER_OP_CAST_TO_S64:
500 {
501 struct cast_op *insn = (struct cast_op *) pc;
502
503 switch (vstack_ax(stack)->type) {
504 default:
505 printk(KERN_WARNING "unknown register type\n");
506 ret = -EINVAL;
507 goto end;
508
509 case REG_STRING:
510 printk(KERN_WARNING "Cast op can only be applied to numeric or floating point registers\n");
511 ret = -EINVAL;
512 goto end;
513 case REG_S64:
514 insn->op = FILTER_OP_CAST_NOP;
515 break;
516 case REG_DOUBLE:
517 insn->op = FILTER_OP_CAST_DOUBLE_TO_S64;
518 break;
519 }
520 /* Pop 1, push 1 */
521 vstack_ax(stack)->type = REG_S64;
522 next_pc += sizeof(struct cast_op);
523 break;
524 }
525 case FILTER_OP_CAST_DOUBLE_TO_S64:
526 {
527 /* Pop 1, push 1 */
528 vstack_ax(stack)->type = REG_S64;
529 next_pc += sizeof(struct cast_op);
530 break;
531 }
532 case FILTER_OP_CAST_NOP:
533 {
534 next_pc += sizeof(struct cast_op);
535 break;
536 }
537
538 }
539 }
540 end:
541 return ret;
542 }
This page took 0.040251 seconds and 5 git commands to generate.