Tests: add session auto-loading test cases
[lttng-tools.git] / src / lib / lttng-ctl / filter / filter-visitor-generate-ir.c
CommitLineData
953192ba
MD
1/*
2 * filter-visitor-generate-ir.c
3 *
4 * LTTng filter generate intermediate representation
5 *
6 * Copyright 2012 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License, version 2.1 only,
10 * as published by the Free Software Foundation.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <stdio.h>
23#include <unistd.h>
24#include <string.h>
25#include <stdlib.h>
26#include <assert.h>
27#include <errno.h>
28#include <inttypes.h>
953192ba 29#include "filter-ast.h"
95b9bd90 30#include "filter-parser.h"
953192ba
MD
31#include "filter-ir.h"
32
a187da1a 33#include <common/macros.h>
9f449915 34#include <common/string-utils/string-utils.h>
a187da1a 35
953192ba
MD
36static
37struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
38 struct filter_node *node, enum ir_side side);
39
40static
41struct ir_op *make_op_root(struct ir_op *child, enum ir_side side)
42{
43 struct ir_op *op;
44
45 op = calloc(sizeof(struct ir_op), 1);
46 if (!op)
47 return NULL;
48 switch (child->data_type) {
49 case IR_DATA_UNKNOWN:
50 default:
51 fprintf(stderr, "[error] Unknown root child data type\n");
7d8868f9 52 free(op);
953192ba
MD
53 return NULL;
54 case IR_DATA_STRING:
55 fprintf(stderr, "[error] String cannot be root data type\n");
7d8868f9 56 free(op);
953192ba
MD
57 return NULL;
58 case IR_DATA_NUMERIC:
59 case IR_DATA_FIELD_REF:
586dc72f 60 case IR_DATA_GET_CONTEXT_REF:
953192ba
MD
61 /* ok */
62 break;
63 }
64 op->op = IR_OP_ROOT;
65 op->side = side;
66 op->data_type = child->data_type;
67 op->signedness = child->signedness;
68 op->u.root.child = child;
69 return op;
70}
71
9f449915
PP
72static
73enum ir_load_string_type get_literal_string_type(const char *string)
74{
75 assert(string);
76
77 if (strutils_is_star_glob_pattern(string)) {
78 if (strutils_is_star_at_the_end_only_glob_pattern(string)) {
79 return IR_LOAD_STRING_TYPE_GLOB_STAR_END;
80 }
81
82 return IR_LOAD_STRING_TYPE_GLOB_STAR;
83 }
84
85 return IR_LOAD_STRING_TYPE_PLAIN;
86}
87
953192ba
MD
88static
89struct ir_op *make_op_load_string(char *string, enum ir_side side)
90{
91 struct ir_op *op;
92
93 op = calloc(sizeof(struct ir_op), 1);
94 if (!op)
95 return NULL;
96 op->op = IR_OP_LOAD;
97 op->data_type = IR_DATA_STRING;
98 op->signedness = IR_SIGN_UNKNOWN;
99 op->side = side;
9f449915
PP
100 op->u.load.u.string.type = get_literal_string_type(string);
101 op->u.load.u.string.value = strdup(string);
102 if (!op->u.load.u.string.value) {
953192ba
MD
103 free(op);
104 return NULL;
105 }
106 return op;
107}
108
109static
110struct ir_op *make_op_load_numeric(int64_t v, enum ir_side side)
111{
112 struct ir_op *op;
113
114 op = calloc(sizeof(struct ir_op), 1);
115 if (!op)
116 return NULL;
117 op->op = IR_OP_LOAD;
118 op->data_type = IR_DATA_NUMERIC;
119 /* TODO: for now, all numeric values are signed */
120 op->signedness = IR_SIGNED;
121 op->side = side;
122 op->u.load.u.num = v;
123 return op;
124}
125
e90d8561
MD
126static
127struct ir_op *make_op_load_float(double v, enum ir_side side)
128{
129 struct ir_op *op;
130
131 op = calloc(sizeof(struct ir_op), 1);
132 if (!op)
133 return NULL;
134 op->op = IR_OP_LOAD;
135 op->data_type = IR_DATA_FLOAT;
136 op->signedness = IR_SIGN_UNKNOWN;
137 op->side = side;
138 op->u.load.u.flt = v;
139 return op;
140}
141
953192ba
MD
142static
143struct ir_op *make_op_load_field_ref(char *string, enum ir_side side)
144{
145 struct ir_op *op;
146
147 op = calloc(sizeof(struct ir_op), 1);
148 if (!op)
149 return NULL;
150 op->op = IR_OP_LOAD;
151 op->data_type = IR_DATA_FIELD_REF;
152 op->signedness = IR_SIGN_DYN;
153 op->side = side;
154 op->u.load.u.ref = strdup(string);
155 if (!op->u.load.u.ref) {
156 free(op);
157 return NULL;
158 }
159 return op;
160}
161
586dc72f
MD
162static
163struct ir_op *make_op_load_get_context_ref(char *string, enum ir_side side)
164{
165 struct ir_op *op;
166
167 op = calloc(sizeof(struct ir_op), 1);
168 if (!op)
169 return NULL;
170 op->op = IR_OP_LOAD;
171 op->data_type = IR_DATA_GET_CONTEXT_REF;
172 op->signedness = IR_SIGN_DYN;
173 op->side = side;
174 op->u.load.u.ref = strdup(string);
175 if (!op->u.load.u.ref) {
176 free(op);
177 return NULL;
178 }
179 return op;
180}
181
953192ba
MD
182static
183struct ir_op *make_op_unary(enum unary_op_type unary_op_type,
184 const char *op_str, enum ir_op_signedness signedness,
185 struct ir_op *child, enum ir_side side)
186{
187 struct ir_op *op = NULL;
188
189 if (child->data_type == IR_DATA_STRING) {
190 fprintf(stderr, "[error] unary operation '%s' not allowed on string literal\n", op_str);
191 goto error;
192 }
193
194 op = calloc(sizeof(struct ir_op), 1);
195 if (!op)
196 return NULL;
197 op->op = IR_OP_UNARY;
198 op->data_type = child->data_type;
199 op->signedness = signedness;
200 op->side = side;
201 op->u.unary.type = unary_op_type;
202 op->u.unary.child = child;
203 return op;
204
205error:
206 free(op);
207 return NULL;
208}
209
210/*
211 * unary + is pretty much useless.
212 */
213static
214struct ir_op *make_op_unary_plus(struct ir_op *child, enum ir_side side)
215{
216 return make_op_unary(AST_UNARY_PLUS, "+", child->signedness,
217 child, side);
218}
219
220static
221struct ir_op *make_op_unary_minus(struct ir_op *child, enum ir_side side)
222{
223 return make_op_unary(AST_UNARY_MINUS, "-", child->signedness,
224 child, side);
225}
226
227static
228struct ir_op *make_op_unary_not(struct ir_op *child, enum ir_side side)
229{
230 return make_op_unary(AST_UNARY_NOT, "!", child->signedness,
231 child, side);
232}
233
953192ba
MD
234static
235struct ir_op *make_op_binary_compare(enum op_type bin_op_type,
236 const char *op_str, struct ir_op *left, struct ir_op *right,
237 enum ir_side side)
238{
239 struct ir_op *op = NULL;
240
241 if (left->data_type == IR_DATA_UNKNOWN
242 || right->data_type == IR_DATA_UNKNOWN) {
243 fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
244 goto error;
245
246 }
247 if ((left->data_type == IR_DATA_STRING
e90d8561
MD
248 && (right->data_type == IR_DATA_NUMERIC || right->data_type == IR_DATA_FLOAT))
249 || ((left->data_type == IR_DATA_NUMERIC || left->data_type == IR_DATA_FLOAT) &&
953192ba
MD
250 right->data_type == IR_DATA_STRING)) {
251 fprintf(stderr, "[error] binary operation '%s' operand type mismatch\n", op_str);
252 goto error;
253 }
254
255 op = calloc(sizeof(struct ir_op), 1);
256 if (!op)
257 return NULL;
258 op->op = IR_OP_BINARY;
259 op->u.binary.type = bin_op_type;
260 op->u.binary.left = left;
261 op->u.binary.right = right;
262
263 /* we return a boolean, represented as signed numeric */
264 op->data_type = IR_DATA_NUMERIC;
265 op->signedness = IR_SIGNED;
266 op->side = side;
267
268 return op;
269
270error:
271 free(op);
272 return NULL;
273}
274
275static
276struct ir_op *make_op_binary_eq(struct ir_op *left, struct ir_op *right,
277 enum ir_side side)
278{
279 return make_op_binary_compare(AST_OP_EQ, "==", left, right, side);
280}
281
282static
283struct ir_op *make_op_binary_ne(struct ir_op *left, struct ir_op *right,
284 enum ir_side side)
285{
286 return make_op_binary_compare(AST_OP_NE, "!=", left, right, side);
287}
288
289static
290struct ir_op *make_op_binary_gt(struct ir_op *left, struct ir_op *right,
291 enum ir_side side)
292{
293 return make_op_binary_compare(AST_OP_GT, ">", left, right, side);
294}
295
296static
297struct ir_op *make_op_binary_lt(struct ir_op *left, struct ir_op *right,
298 enum ir_side side)
299{
300 return make_op_binary_compare(AST_OP_LT, "<", left, right, side);
301}
302
303static
304struct ir_op *make_op_binary_ge(struct ir_op *left, struct ir_op *right,
305 enum ir_side side)
306{
307 return make_op_binary_compare(AST_OP_GE, ">=", left, right, side);
308}
309
310static
311struct ir_op *make_op_binary_le(struct ir_op *left, struct ir_op *right,
312 enum ir_side side)
313{
314 return make_op_binary_compare(AST_OP_LE, "<=", left, right, side);
315}
316
317static
318struct ir_op *make_op_binary_logical(enum op_type bin_op_type,
319 const char *op_str, struct ir_op *left, struct ir_op *right,
320 enum ir_side side)
321{
322 struct ir_op *op = NULL;
323
324 if (left->data_type == IR_DATA_UNKNOWN
325 || right->data_type == IR_DATA_UNKNOWN) {
326 fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
327 goto error;
328
329 }
330 if (left->data_type == IR_DATA_STRING
331 || right->data_type == IR_DATA_STRING) {
332 fprintf(stderr, "[error] logical binary operation '%s' cannot have string operand\n", op_str);
333 goto error;
334 }
335
336 op = calloc(sizeof(struct ir_op), 1);
337 if (!op)
338 return NULL;
339 op->op = IR_OP_LOGICAL;
340 op->u.binary.type = bin_op_type;
341 op->u.binary.left = left;
342 op->u.binary.right = right;
343
344 /* we return a boolean, represented as signed numeric */
345 op->data_type = IR_DATA_NUMERIC;
346 op->signedness = IR_SIGNED;
347 op->side = side;
348
349 return op;
350
351error:
352 free(op);
353 return NULL;
354}
355
356static
357struct ir_op *make_op_binary_logical_and(struct ir_op *left, struct ir_op *right,
358 enum ir_side side)
359{
360 return make_op_binary_logical(AST_OP_AND, "&&", left, right, side);
361}
362
363static
364struct ir_op *make_op_binary_logical_or(struct ir_op *left, struct ir_op *right,
365 enum ir_side side)
366{
367 return make_op_binary_logical(AST_OP_OR, "||", left, right, side);
368}
369
370static
371void filter_free_ir_recursive(struct ir_op *op)
372{
373 if (!op)
374 return;
375 switch (op->op) {
376 case IR_OP_UNKNOWN:
377 default:
378 fprintf(stderr, "[error] Unknown op type in %s\n",
379 __func__);
380 break;
381 case IR_OP_ROOT:
382 filter_free_ir_recursive(op->u.root.child);
383 break;
384 case IR_OP_LOAD:
385 switch (op->data_type) {
386 case IR_DATA_STRING:
9f449915 387 free(op->u.load.u.string.value);
953192ba 388 break;
586dc72f
MD
389 case IR_DATA_FIELD_REF: /* fall-through */
390 case IR_DATA_GET_CONTEXT_REF:
953192ba
MD
391 free(op->u.load.u.ref);
392 break;
393 default:
394 break;
395 }
396 break;
397 case IR_OP_UNARY:
398 filter_free_ir_recursive(op->u.unary.child);
399 break;
400 case IR_OP_BINARY:
401 filter_free_ir_recursive(op->u.binary.left);
402 filter_free_ir_recursive(op->u.binary.right);
403 break;
404 case IR_OP_LOGICAL:
405 filter_free_ir_recursive(op->u.logical.left);
406 filter_free_ir_recursive(op->u.logical.right);
407 break;
408 }
409 free(op);
410}
411
412static
413struct ir_op *make_expression(struct filter_parser_ctx *ctx,
414 struct filter_node *node, enum ir_side side)
415{
416 switch (node->u.expression.type) {
417 case AST_EXP_UNKNOWN:
418 default:
419 fprintf(stderr, "[error] %s: unknown expression type\n", __func__);
420 return NULL;
421
422 case AST_EXP_STRING:
423 return make_op_load_string(node->u.expression.u.string, side);
424 case AST_EXP_CONSTANT:
425 return make_op_load_numeric(node->u.expression.u.constant,
426 side);
e90d8561
MD
427 case AST_EXP_FLOAT_CONSTANT:
428 return make_op_load_float(node->u.expression.u.float_constant,
429 side);
953192ba
MD
430 case AST_EXP_IDENTIFIER:
431 if (node->u.expression.pre_op != AST_LINK_UNKNOWN) {
432 fprintf(stderr, "[error] %s: dotted and dereferenced identifiers not supported\n", __func__);
433 return NULL;
434 }
435 return make_op_load_field_ref(node->u.expression.u.identifier,
436 side);
586dc72f
MD
437 case AST_EXP_GLOBAL_IDENTIFIER:
438 {
a1f68b22 439 const char *name;
586dc72f 440
a1f68b22
MD
441 /*
442 * We currently only support $ctx (context) and $app
443 * identifiers.
444 */
586dc72f 445 if (strncmp(node->u.expression.u.identifier,
a1f68b22
MD
446 "$ctx.", strlen("$ctx.")) != 0
447 && strncmp(node->u.expression.u.identifier,
448 "$app.", strlen("$app.")) != 0) {
449 fprintf(stderr, "[error] %s: \"%s\" global identifier is unknown. Only \"$ctx\" and \"$app\" are currently implemented.\n", __func__, node->u.expression.u.identifier);
586dc72f
MD
450 return NULL;
451 }
a1f68b22
MD
452 name = strchr(node->u.expression.u.identifier, '.');
453 if (!name) {
454 fprintf(stderr, "[error] %s: Expecting '.'\n", __func__);
586dc72f
MD
455 return NULL;
456 }
a1f68b22
MD
457 name++; /* Skip . */
458 if (!strlen(name)) {
459 fprintf(stderr, "[error] %s: Expecting a context name, e.g. \'$ctx.name\'.\n", __func__);
586dc72f
MD
460 return NULL;
461 }
a1f68b22 462 return make_op_load_get_context_ref(node->u.expression.u.identifier,
586dc72f
MD
463 side);
464 }
953192ba
MD
465 case AST_EXP_NESTED:
466 return generate_ir_recursive(ctx, node->u.expression.u.child,
467 side);
468 }
469}
470
471static
472struct ir_op *make_op(struct filter_parser_ctx *ctx,
473 struct filter_node *node, enum ir_side side)
474{
475 struct ir_op *op = NULL, *lchild, *rchild;
476 const char *op_str = "?";
477
478 switch (node->u.op.type) {
479 case AST_OP_UNKNOWN:
480 default:
481 fprintf(stderr, "[error] %s: unknown binary op type\n", __func__);
482 return NULL;
483
484 /*
485 * Binary operators other than comparators and logical and/or
486 * are not supported. If we ever want to support those, we will
487 * need a stack for the general case rather than just 2
488 * registers (see bytecode).
489 */
490 case AST_OP_MUL:
491 op_str = "*";
492 goto error_not_supported;
493 case AST_OP_DIV:
494 op_str = "/";
495 goto error_not_supported;
496 case AST_OP_MOD:
497 op_str = "%";
498 goto error_not_supported;
499 case AST_OP_PLUS:
500 op_str = "+";
501 goto error_not_supported;
502 case AST_OP_MINUS:
503 op_str = "-";
504 goto error_not_supported;
505 case AST_OP_RSHIFT:
506 op_str = ">>";
507 goto error_not_supported;
508 case AST_OP_LSHIFT:
509 op_str = "<<";
510 goto error_not_supported;
511 case AST_OP_BIN_AND:
512 op_str = "&";
513 goto error_not_supported;
514 case AST_OP_BIN_OR:
515 op_str = "|";
516 goto error_not_supported;
517 case AST_OP_BIN_XOR:
518 op_str = "^";
519 goto error_not_supported;
520
521 case AST_OP_EQ:
522 case AST_OP_NE:
523 case AST_OP_GT:
524 case AST_OP_LT:
525 case AST_OP_GE:
526 case AST_OP_LE:
527 lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
528 if (!lchild)
529 return NULL;
530 rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_RIGHT);
531 if (!rchild) {
532 filter_free_ir_recursive(lchild);
533 return NULL;
534 }
535 break;
536
537 case AST_OP_AND:
538 case AST_OP_OR:
539 /*
540 * Both children considered as left, since we need to
541 * populate R0.
542 */
543 lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
544 if (!lchild)
545 return NULL;
546 rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_LEFT);
547 if (!rchild) {
548 filter_free_ir_recursive(lchild);
549 return NULL;
550 }
551 break;
552 }
553
554 switch (node->u.op.type) {
555 case AST_OP_AND:
556 op = make_op_binary_logical_and(lchild, rchild, side);
557 break;
558 case AST_OP_OR:
559 op = make_op_binary_logical_or(lchild, rchild, side);
560 break;
561 case AST_OP_EQ:
562 op = make_op_binary_eq(lchild, rchild, side);
563 break;
564 case AST_OP_NE:
565 op = make_op_binary_ne(lchild, rchild, side);
566 break;
567 case AST_OP_GT:
568 op = make_op_binary_gt(lchild, rchild, side);
569 break;
570 case AST_OP_LT:
571 op = make_op_binary_lt(lchild, rchild, side);
572 break;
573 case AST_OP_GE:
574 op = make_op_binary_ge(lchild, rchild, side);
575 break;
576 case AST_OP_LE:
577 op = make_op_binary_le(lchild, rchild, side);
578 break;
579 default:
580 break;
581 }
582
583 if (!op) {
584 filter_free_ir_recursive(rchild);
585 filter_free_ir_recursive(lchild);
586 }
587 return op;
588
589error_not_supported:
590 fprintf(stderr, "[error] %s: binary operation '%s' not supported\n",
591 __func__, op_str);
592 return NULL;
593}
594
595static
596struct ir_op *make_unary_op(struct filter_parser_ctx *ctx,
597 struct filter_node *node, enum ir_side side)
598{
ab78f161
CB
599 const char *op_str = "?";
600
953192ba
MD
601 switch (node->u.unary_op.type) {
602 case AST_UNARY_UNKNOWN:
603 default:
604 fprintf(stderr, "[error] %s: unknown unary op type\n", __func__);
605 return NULL;
606
607 case AST_UNARY_PLUS:
608 {
609 struct ir_op *op, *child;
610
611 child = generate_ir_recursive(ctx, node->u.unary_op.child,
612 side);
613 if (!child)
614 return NULL;
615 op = make_op_unary_plus(child, side);
616 if (!op) {
617 filter_free_ir_recursive(child);
618 return NULL;
619 }
620 return op;
621 }
622 case AST_UNARY_MINUS:
623 {
624 struct ir_op *op, *child;
625
626 child = generate_ir_recursive(ctx, node->u.unary_op.child,
627 side);
628 if (!child)
629 return NULL;
630 op = make_op_unary_minus(child, side);
631 if (!op) {
632 filter_free_ir_recursive(child);
633 return NULL;
634 }
635 return op;
636 }
637 case AST_UNARY_NOT:
638 {
639 struct ir_op *op, *child;
640
641 child = generate_ir_recursive(ctx, node->u.unary_op.child,
642 side);
643 if (!child)
644 return NULL;
645 op = make_op_unary_not(child, side);
646 if (!op) {
647 filter_free_ir_recursive(child);
648 return NULL;
649 }
650 return op;
651 }
ab78f161
CB
652 case AST_UNARY_BIN_NOT:
653 {
654 op_str = "~";
655 goto error_not_supported;
656 }
953192ba 657 }
ab78f161
CB
658
659error_not_supported:
660 fprintf(stderr, "[error] %s: unary operation '%s' not supported\n",
661 __func__, op_str);
662 return NULL;
953192ba
MD
663}
664
665static
666struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
667 struct filter_node *node, enum ir_side side)
668{
669 switch (node->type) {
670 case NODE_UNKNOWN:
671 default:
672 fprintf(stderr, "[error] %s: unknown node type\n", __func__);
673 return NULL;
674
675 case NODE_ROOT:
676 {
677 struct ir_op *op, *child;
678
679 child = generate_ir_recursive(ctx, node->u.root.child,
680 side);
681 if (!child)
682 return NULL;
683 op = make_op_root(child, side);
684 if (!op) {
685 filter_free_ir_recursive(child);
686 return NULL;
687 }
688 return op;
689 }
690 case NODE_EXPRESSION:
691 return make_expression(ctx, node, side);
692 case NODE_OP:
693 return make_op(ctx, node, side);
694 case NODE_UNARY_OP:
695 return make_unary_op(ctx, node, side);
696 }
697 return 0;
698}
699
a187da1a 700LTTNG_HIDDEN
953192ba
MD
701void filter_ir_free(struct filter_parser_ctx *ctx)
702{
703 filter_free_ir_recursive(ctx->ir_root);
704 ctx->ir_root = NULL;
705}
706
a187da1a 707LTTNG_HIDDEN
953192ba
MD
708int filter_visitor_ir_generate(struct filter_parser_ctx *ctx)
709{
710 struct ir_op *op;
711
712 op = generate_ir_recursive(ctx, &ctx->ast->root, IR_LEFT);
713 if (!op) {
714 return -EINVAL;
715 }
716 ctx->ir_root = op;
717 return 0;
718}
This page took 0.083542 seconds and 4 git commands to generate.