Filters: generate backward compatible "get field" and "get context" instructions
[lttng-tools.git] / src / lib / lttng-ctl / filter / filter-visitor-generate-bytecode.c
index 1cf7cb5c3cf0324048c7d360980564494eb1450e..d548da749e88ff2279b16b77673d290d4de7c16f 100644 (file)
@@ -22,7 +22,9 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include "align.h"
+#include <common/align.h>
+#include <common/compat/string.h>
+
 #include "filter-bytecode.h"
 #include "filter-ir.h"
 #include "filter-ast.h"
 #define max_t(type, a, b)      ((type) ((a) > (b) ? (a) : (b)))
 #endif
 
-//#define INIT_ALLOC_SIZE              PAGE_SIZE
 #define INIT_ALLOC_SIZE                4
 
 static
 int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
                struct ir_op *node);
 
-static inline int fls(unsigned int x)
-{
-       int r = 32;
-
-       if (!x)
-               return 0;
-       if (!(x & 0xFFFF0000U)) {
-               x <<= 16;
-               r -= 16;
-       }
-       if (!(x & 0xFF000000U)) {
-               x <<= 8;
-               r -= 8;
-       }
-       if (!(x & 0xF0000000U)) {
-               x <<= 4;
-               r -= 4;
-       }
-       if (!(x & 0xC0000000U)) {
-               x <<= 2;
-               r -= 2;
-       }
-       if (!(x & 0x80000000U)) {
-               x <<= 1;
-               r -= 1;
-       }
-       return r;
-}
-
 static inline int get_count_order(unsigned int count)
 {
        int order;
 
-       order = fls(count) - 1;
+       order = lttng_fls(count) - 1;
        if (count & (count - 1))
                order++;
        return order;
@@ -185,6 +157,322 @@ int visit_node_root(struct filter_parser_ctx *ctx, struct ir_op *node)
        return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
 }
 
+static
+int append_str(char **s, const char *append)
+{
+       char *old = *s;
+       char *new;
+       size_t oldlen = (old == NULL) ? 0 : strlen(old);
+       size_t appendlen = strlen(append);
+
+       new = calloc(oldlen + appendlen + 1, 1);
+       if (!new) {
+               return -ENOMEM;
+       }
+       if (oldlen) {
+               strcpy(new, old);
+       }
+       strcat(new, append);
+       *s = new;
+       free(old);
+       return 0;
+}
+
+/*
+ * 1: match
+ * 0: no match
+ * < 0: error
+ */
+static
+int load_expression_legacy_match(const struct ir_load_expression *exp,
+               enum filter_op *op_type,
+               char **symbol)
+{
+       const struct ir_load_expression_op *op;
+       bool need_dot = false;
+
+       op = exp->child;
+       switch (op->type) {
+       case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+               *op_type = FILTER_OP_GET_CONTEXT_REF;
+               if (append_str(symbol, "$ctx.")) {
+                       return -ENOMEM;
+               }
+               need_dot = false;
+               break;
+       case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+               *op_type = FILTER_OP_GET_CONTEXT_REF;
+               if (append_str(symbol, "$app.")) {
+                       return -ENOMEM;
+               }
+               need_dot = false;
+               break;
+       case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+               *op_type = FILTER_OP_LOAD_FIELD_REF;
+               need_dot = false;
+               break;
+
+       case IR_LOAD_EXPRESSION_GET_SYMBOL:
+       case IR_LOAD_EXPRESSION_GET_INDEX:
+       case IR_LOAD_EXPRESSION_LOAD_FIELD:
+       default:
+               return 0;       /* no match */
+       }
+
+       for (;;) {
+               op = op->next;
+               if (!op) {
+                       return 0;       /* no match */
+               }
+               switch (op->type) {
+               case IR_LOAD_EXPRESSION_LOAD_FIELD:
+                       goto end;
+               case IR_LOAD_EXPRESSION_GET_SYMBOL:
+                       if (need_dot && append_str(symbol, ".")) {
+                               return -ENOMEM;
+                       }
+                       if (append_str(symbol, op->u.symbol)) {
+                               return -ENOMEM;
+                       }
+                       break;
+               default:
+                       return 0;        /* no match */
+               }
+               need_dot = true;
+       }
+end:
+       return 1;       /* Legacy match */
+}
+
+/*
+ * 1: legacy match
+ * 0: no legacy match
+ * < 0: error
+ */
+static
+int visit_node_load_expression_legacy(struct filter_parser_ctx *ctx,
+               const struct ir_load_expression *exp,
+               const struct ir_load_expression_op *op)
+{
+       struct load_op *insn = NULL;
+       uint32_t insn_len = sizeof(struct load_op)
+               + sizeof(struct field_ref);
+       struct field_ref ref_offset;
+       uint32_t reloc_offset_u32;
+       uint16_t reloc_offset;
+       enum filter_op op_type;
+       char *symbol = NULL;
+       int ret;
+
+       ret = load_expression_legacy_match(exp, &op_type, &symbol);
+       if (ret <= 0) {
+               goto end;
+       }
+       insn = calloc(insn_len, 1);
+       if (!insn) {
+               ret = -ENOMEM;
+               goto end;
+       }
+       insn->op = op_type;
+       ref_offset.offset = (uint16_t) -1U;
+       memcpy(insn->data, &ref_offset, sizeof(ref_offset));
+       /* reloc_offset points to struct load_op */
+       reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
+       if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
+               ret = -EINVAL;
+               goto end;
+       }
+       reloc_offset = (uint16_t) reloc_offset_u32;
+       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+       if (ret) {
+               goto end;
+       }
+       /* append reloc */
+       ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
+                               1, sizeof(reloc_offset));
+       if (ret) {
+               goto end;
+       }
+       ret = bytecode_push(&ctx->bytecode_reloc, symbol,
+                               1, strlen(symbol) + 1);
+       ret = 1;        /* legacy */
+end:
+       free(insn);
+       free(symbol);
+       return ret;
+}
+
+static
+int visit_node_load_expression(struct filter_parser_ctx *ctx,
+               const struct ir_op *node)
+{
+       struct ir_load_expression *exp;
+       struct ir_load_expression_op *op;
+       int ret;
+
+       exp = node->u.load.u.expression;
+       if (!exp) {
+               return -EINVAL;
+       }
+       op = exp->child;
+       if (!op) {
+               return -EINVAL;
+       }
+
+       ret = visit_node_load_expression_legacy(ctx, exp, op);
+       if (ret < 0) {
+               return ret;
+       }
+       if (ret > 0) {
+               return 0;       /* legacy */
+       }
+
+       for (; op != NULL; op = op->next) {
+               switch (op->type) {
+               case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op);
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_CONTEXT_ROOT;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op);
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_APP_CONTEXT_ROOT;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op);
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_PAYLOAD_ROOT;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_SYMBOL:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op)
+                               + sizeof(struct get_symbol);
+                       struct get_symbol symbol_offset;
+                       uint32_t reloc_offset_u32;
+                       uint16_t reloc_offset;
+                       uint32_t bytecode_reloc_offset_u32;
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_SYMBOL;
+                       bytecode_reloc_offset_u32 =
+                                       bytecode_get_len(&ctx->bytecode_reloc->b)
+                                       + sizeof(reloc_offset);
+                       symbol_offset.offset =
+                                       (uint16_t) bytecode_reloc_offset_u32;
+                       memcpy(insn->data, &symbol_offset,
+                                       sizeof(symbol_offset));
+                       /* reloc_offset points to struct load_op */
+                       reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
+                       if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
+                               free(insn);
+                               return -EINVAL;
+                       }
+                       reloc_offset = (uint16_t) reloc_offset_u32;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       if (ret) {
+                               free(insn);
+                               return ret;
+                       }
+                       /* append reloc */
+                       ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
+                                       1, sizeof(reloc_offset));
+                       if (ret) {
+                               free(insn);
+                               return ret;
+                       }
+                       ret = bytecode_push(&ctx->bytecode_reloc,
+                                       op->u.symbol,
+                                       1, strlen(op->u.symbol) + 1);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_INDEX:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op)
+                               + sizeof(struct get_index_u64);
+                       struct get_index_u64 index;
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_GET_INDEX_U64;
+                       index.index = op->u.index;
+                       memcpy(insn->data, &index, sizeof(index));
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_LOAD_FIELD:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op);
+                       int ret;
+
+                       insn = calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = FILTER_OP_LOAD_FIELD;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               }
+       }
+       return 0;
+}
+
 static
 int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node)
 {
@@ -201,13 +489,38 @@ int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node)
        {
                struct load_op *insn;
                uint32_t insn_len = sizeof(struct load_op)
-                       + strlen(node->u.load.u.string) + 1;
+                       + strlen(node->u.load.u.string.value) + 1;
 
                insn = calloc(insn_len, 1);
                if (!insn)
                        return -ENOMEM;
-               insn->op = FILTER_OP_LOAD_STRING;
-               strcpy(insn->data, node->u.load.u.string);
+
+               switch (node->u.load.u.string.type) {
+               case IR_LOAD_STRING_TYPE_GLOB_STAR:
+                       /*
+                        * We explicitly tell the interpreter here that
+                        * this load is a full star globbing pattern so
+                        * that the appropriate matching function can be
+                        * called. Also, see comment below.
+                        */
+                       insn->op = FILTER_OP_LOAD_STAR_GLOB_STRING;
+                       break;
+               default:
+                       /*
+                        * This is the "legacy" string, which includes
+                        * star globbing patterns with a star only at
+                        * the end. Both "plain" and "star at the end"
+                        * literal strings are handled at the same place
+                        * by the tracer's filter bytecode interpreter,
+                        * whereas full star globbing patterns (stars
+                        * can be anywhere in the string) is a special
+                        * case.
+                        */
+                       insn->op = FILTER_OP_LOAD_STRING;
+                       break;
+               }
+
+               strcpy(insn->data, node->u.load.u.string.value);
                ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
                free(insn);
                return ret;
@@ -242,56 +555,8 @@ int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node)
                free(insn);
                return ret;
        }
-       case IR_DATA_FIELD_REF: /* fall-through */
-       case IR_DATA_GET_CONTEXT_REF:
-       {
-               struct load_op *insn;
-               uint32_t insn_len = sizeof(struct load_op)
-                       + sizeof(struct field_ref);
-               struct field_ref ref_offset;
-               uint32_t reloc_offset_u32;
-               uint16_t reloc_offset;
-
-               insn = calloc(insn_len, 1);
-               if (!insn)
-                       return -ENOMEM;
-               switch(node->data_type) {
-               case IR_DATA_FIELD_REF:
-                       insn->op = FILTER_OP_LOAD_FIELD_REF;
-                       break;
-               case IR_DATA_GET_CONTEXT_REF:
-                       insn->op = FILTER_OP_GET_CONTEXT_REF;
-                       break;
-               default:
-                       free(insn);
-                       return -EINVAL;
-               }
-               ref_offset.offset = (uint16_t) -1U;
-               memcpy(insn->data, &ref_offset, sizeof(ref_offset));
-               /* reloc_offset points to struct load_op */
-               reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
-               if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
-                       free(insn);
-                       return -EINVAL;
-               }
-               reloc_offset = (uint16_t) reloc_offset_u32;
-               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-               if (ret) {
-                       free(insn);
-                       return ret;
-               }
-               /* append reloc */
-               ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
-                                       1, sizeof(reloc_offset));
-               if (ret) {
-                       free(insn);
-                       return ret;
-               }
-               ret = bytecode_push(&ctx->bytecode_reloc, node->u.load.u.ref,
-                                       1, strlen(node->u.load.u.ref) + 1);
-               free(insn);
-               return ret;
-       }
+       case IR_DATA_EXPRESSION:
+               return visit_node_load_expression(ctx, node);
        }
 }
 
@@ -377,14 +642,14 @@ int visit_node_binary(struct filter_parser_ctx *ctx, struct ir_op *node)
        case AST_OP_LSHIFT:
                insn.op = FILTER_OP_LSHIFT;
                break;
-       case AST_OP_BIN_AND:
-               insn.op = FILTER_OP_BIN_AND;
+       case AST_OP_BIT_AND:
+               insn.op = FILTER_OP_BIT_AND;
                break;
-       case AST_OP_BIN_OR:
-               insn.op = FILTER_OP_BIN_OR;
+       case AST_OP_BIT_OR:
+               insn.op = FILTER_OP_BIT_OR;
                break;
-       case AST_OP_BIN_XOR:
-               insn.op = FILTER_OP_BIN_XOR;
+       case AST_OP_BIT_XOR:
+               insn.op = FILTER_OP_BIT_XOR;
                break;
 
        case AST_OP_EQ:
@@ -426,12 +691,14 @@ int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node)
                return ret;
        /* Cast to s64 if float or field ref */
        if ((node->u.binary.left->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF)
+                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION)
                        || node->u.binary.left->data_type == IR_DATA_FLOAT) {
                struct cast_op cast_insn;
 
                if (node->u.binary.left->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF) {
+                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION) {
                        cast_insn.op = FILTER_OP_CAST_TO_S64;
                } else {
                        cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64;
@@ -465,12 +732,14 @@ int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node)
                return ret;
        /* Cast to s64 if float or field ref */
        if ((node->u.binary.right->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF)
+                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION)
                        || node->u.binary.right->data_type == IR_DATA_FLOAT) {
                struct cast_op cast_insn;
 
                if (node->u.binary.right->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF) {
+                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION) {
                        cast_insn.op = FILTER_OP_CAST_TO_S64;
                } else {
                        cast_insn.op = FILTER_OP_CAST_DOUBLE_TO_S64;
This page took 0.033449 seconds and 4 git commands to generate.