Fix: Fix self-assign warning on struct ustfork_clone_info init
[lttng-ust.git] / liblttng-ust / lttng-filter.c
index 999a82f9b8b08a2ea49f0a7a1a45802b8ffc1b53..1a0921fd72ac0ca78b4cc7c3f08667ab5767c300 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include <errno.h>
-#include <stdio.h>
-#include <helper.h>
-#include <lttng/ust-events.h>
-#include <stdint.h>
-#include <errno.h>
-#include <string.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <usterr-signal-safe.h>
-#include "filter-bytecode.h"
-
-#define NR_REG         2
-
-#ifndef min_t
-#define min_t(type, a, b)      \
-               ((type) (a) < (type) (b) ? (type) (a) : (type) (b))
-#endif
-
-#ifndef likely
-#define likely(x)      __builtin_expect(!!(x), 1)
-#endif
-
-#ifndef unlikely
-#define unlikely(x)    __builtin_expect(!!(x), 0)
-#endif
-
-#ifdef DEBUG
-#define dbg_printf(fmt, args...)     printf("[debug bytecode] " fmt, ## args)
-#else
-#define dbg_printf(fmt, args...)                               \
-do {                                                           \
-       /* do nothing but check printf format */                \
-       if (0)                                                  \
-               printf("[debug bytecode] " fmt, ## args);       \
-} while (0)
-#endif
-
-/* Linked bytecode */
-struct bytecode_runtime {
-       uint16_t len;
-       char data[0];
-};
-
-enum reg_type {
-       REG_S64,
-       REG_DOUBLE,
-       REG_STRING,
-};
-
-/* Validation registers */
-struct vreg {
-       enum reg_type type;
-       int literal;            /* is string literal ? */
-};
-
-/* Execution registers */
-struct reg {
-       enum reg_type type;
-       int64_t v;
-       double d;
-
-       const char *str;
-       size_t seq_len;
-       int literal;            /* is string literal ? */
-};
+#include "lttng-filter.h"
 
 static const char *opnames[] = {
        [ FILTER_OP_UNKNOWN ] = "UNKNOWN",
@@ -103,6 +38,8 @@ static const char *opnames[] = {
        [ FILTER_OP_BIN_AND ] = "BIN_AND",
        [ FILTER_OP_BIN_OR ] = "BIN_OR",
        [ FILTER_OP_BIN_XOR ] = "BIN_XOR",
+
+       /* binary comparators */
        [ FILTER_OP_EQ ] = "EQ",
        [ FILTER_OP_NE ] = "NE",
        [ FILTER_OP_GT ] = "GT",
@@ -110,10 +47,55 @@ static const char *opnames[] = {
        [ FILTER_OP_GE ] = "GE",
        [ FILTER_OP_LE ] = "LE",
 
+       /* string binary comparators */
+       [ FILTER_OP_EQ_STRING ] = "EQ_STRING",
+       [ FILTER_OP_NE_STRING ] = "NE_STRING",
+       [ FILTER_OP_GT_STRING ] = "GT_STRING",
+       [ FILTER_OP_LT_STRING ] = "LT_STRING",
+       [ FILTER_OP_GE_STRING ] = "GE_STRING",
+       [ FILTER_OP_LE_STRING ] = "LE_STRING",
+
+       /* s64 binary comparators */
+       [ FILTER_OP_EQ_S64 ] = "EQ_S64",
+       [ FILTER_OP_NE_S64 ] = "NE_S64",
+       [ FILTER_OP_GT_S64 ] = "GT_S64",
+       [ FILTER_OP_LT_S64 ] = "LT_S64",
+       [ FILTER_OP_GE_S64 ] = "GE_S64",
+       [ FILTER_OP_LE_S64 ] = "LE_S64",
+
+       /* double binary comparators */
+       [ FILTER_OP_EQ_DOUBLE ] = "EQ_DOUBLE",
+       [ FILTER_OP_NE_DOUBLE ] = "NE_DOUBLE",
+       [ FILTER_OP_GT_DOUBLE ] = "GT_DOUBLE",
+       [ FILTER_OP_LT_DOUBLE ] = "LT_DOUBLE",
+       [ FILTER_OP_GE_DOUBLE ] = "GE_DOUBLE",
+       [ FILTER_OP_LE_DOUBLE ] = "LE_DOUBLE",
+
+       /* Mixed S64-double binary comparators */
+       [ FILTER_OP_EQ_DOUBLE_S64 ] = "EQ_DOUBLE_S64",
+       [ FILTER_OP_NE_DOUBLE_S64 ] = "NE_DOUBLE_S64",
+       [ FILTER_OP_GT_DOUBLE_S64 ] = "GT_DOUBLE_S64",
+       [ FILTER_OP_LT_DOUBLE_S64 ] = "LT_DOUBLE_S64",
+       [ FILTER_OP_GE_DOUBLE_S64 ] = "GE_DOUBLE_S64",
+       [ FILTER_OP_LE_DOUBLE_S64 ] = "LE_DOUBLE_S64",
+
+       [ FILTER_OP_EQ_S64_DOUBLE ] = "EQ_S64_DOUBLE",
+       [ FILTER_OP_NE_S64_DOUBLE ] = "NE_S64_DOUBLE",
+       [ FILTER_OP_GT_S64_DOUBLE ] = "GT_S64_DOUBLE",
+       [ FILTER_OP_LT_S64_DOUBLE ] = "LT_S64_DOUBLE",
+       [ FILTER_OP_GE_S64_DOUBLE ] = "GE_S64_DOUBLE",
+       [ FILTER_OP_LE_S64_DOUBLE ] = "LE_S64_DOUBLE",
+
        /* unary */
        [ FILTER_OP_UNARY_PLUS ] = "UNARY_PLUS",
        [ FILTER_OP_UNARY_MINUS ] = "UNARY_MINUS",
        [ FILTER_OP_UNARY_NOT ] = "UNARY_NOT",
+       [ FILTER_OP_UNARY_PLUS_S64 ] = "UNARY_PLUS_S64",
+       [ FILTER_OP_UNARY_MINUS_S64 ] = "UNARY_MINUS_S64",
+       [ FILTER_OP_UNARY_NOT_S64 ] = "UNARY_NOT_S64",
+       [ FILTER_OP_UNARY_PLUS_DOUBLE ] = "UNARY_PLUS_DOUBLE",
+       [ FILTER_OP_UNARY_MINUS_DOUBLE ] = "UNARY_MINUS_DOUBLE",
+       [ FILTER_OP_UNARY_NOT_DOUBLE ] = "UNARY_NOT_DOUBLE",
 
        /* logical */
        [ FILTER_OP_AND ] = "AND",
@@ -121,12 +103,21 @@ static const char *opnames[] = {
 
        /* load */
        [ FILTER_OP_LOAD_FIELD_REF ] = "LOAD_FIELD_REF",
+       [ FILTER_OP_LOAD_FIELD_REF_STRING ] = "LOAD_FIELD_REF_STRING",
+       [ FILTER_OP_LOAD_FIELD_REF_SEQUENCE ] = "LOAD_FIELD_REF_SEQUENCE",
+       [ FILTER_OP_LOAD_FIELD_REF_S64 ] = "LOAD_FIELD_REF_S64",
+       [ FILTER_OP_LOAD_FIELD_REF_DOUBLE ] = "LOAD_FIELD_REF_DOUBLE",
+
        [ FILTER_OP_LOAD_STRING ] = "LOAD_STRING",
        [ FILTER_OP_LOAD_S64 ] = "LOAD_S64",
        [ FILTER_OP_LOAD_DOUBLE ] = "LOAD_DOUBLE",
+
+       /* cast */
+       [ FILTER_OP_CAST_TO_S64 ] = "CAST_TO_S64",
+       [ FILTER_OP_CAST_DOUBLE_TO_S64 ] = "CAST_DOUBLE_TO_S64",
+       [ FILTER_OP_CAST_NOP ] = "CAST_NOP",
 };
 
-static
 const char *print_op(enum filter_op op)
 {
        if (op >= NR_FILTER_OPS)
@@ -135,1044 +126,6 @@ const char *print_op(enum filter_op op)
                return opnames[op];
 }
 
-/*
- * -1: wildcard found.
- * -2: unknown escape char.
- * 0: normal char.
- */
-
-static
-int parse_char(const char **p)
-{
-       switch (**p) {
-       case '\\':
-               (*p)++;
-               switch (**p) {
-               case '\\':
-               case '*':
-                       return 0;
-               default:
-                       return -2;
-               }
-       case '*':
-               return -1;
-       default:
-               return 0;
-       }
-}
-
-static
-int reg_strcmp(struct reg reg[NR_REG], const char *cmp_type)
-{
-       const char *p = reg[REG_R0].str, *q = reg[REG_R1].str;
-       int ret;
-       int diff;
-
-       for (;;) {
-               int escaped_r0 = 0;
-
-               if (unlikely(p - reg[REG_R0].str > reg[REG_R0].seq_len || *p == '\0')) {
-                       if (q - reg[REG_R1].str > reg[REG_R1].seq_len || *q == '\0')
-                               diff = 0;
-                       else
-                               diff = -1;
-                       break;
-               }
-               if (unlikely(q - reg[REG_R1].str > reg[REG_R1].seq_len || *q == '\0')) {
-                       if (p - reg[REG_R0].str > reg[REG_R0].seq_len || *p == '\0')
-                               diff = 0;
-                       else
-                               diff = 1;
-                       break;
-               }
-               if (reg[REG_R0].literal) {
-                       ret = parse_char(&p);
-                       if (ret == -1) {
-                               return 0;
-                       } else if (ret == -2) {
-                               escaped_r0 = 1;
-                       }
-                       /* else compare both char */
-               }
-               if (reg[REG_R1].literal) {
-                       ret = parse_char(&q);
-                       if (ret == -1) {
-                               return 0;
-                       } else if (ret == -2) {
-                               if (!escaped_r0)
-                                       return -1;
-                       } else {
-                               if (escaped_r0)
-                                       return 1;
-                       }
-               } else {
-                       if (escaped_r0)
-                               return 1;
-               }
-               diff = *p - *q;
-               if (diff != 0)
-                       break;
-               p++;
-               q++;
-       }
-       return diff;
-}
-
-static
-int lttng_filter_false(void *filter_data,
-               const char *filter_stack_data)
-{
-       return 0;
-}
-
-static
-int lttng_filter_interpret_bytecode(void *filter_data,
-               const char *filter_stack_data)
-{
-       struct bytecode_runtime *bytecode = filter_data;
-       void *pc, *next_pc, *start_pc;
-       int ret = -EINVAL;
-       int retval = 0;
-       struct reg reg[NR_REG];
-       int i;
-
-       for (i = 0; i < NR_REG; i++) {
-               reg[i].type = REG_S64;
-               reg[i].v = 0;
-               reg[i].d = 0.0;
-               reg[i].str = NULL;
-               reg[i].seq_len = 0;
-               reg[i].literal = 0;
-       }
-
-       start_pc = &bytecode->data[0];
-       for (pc = next_pc = start_pc; pc - start_pc < bytecode->len;
-                       pc = next_pc) {
-               if (unlikely(pc >= start_pc + bytecode->len)) {
-                       ERR("filter bytecode overflow\n");
-                       ret = -EINVAL;
-                       goto end;
-               }
-               dbg_printf("Executing op %s (%u)\n",
-                       print_op((unsigned int) *(filter_opcode_t *) pc),
-                       (unsigned int) *(filter_opcode_t *) pc);
-               switch (*(filter_opcode_t *) pc) {
-               case FILTER_OP_UNKNOWN:
-               default:
-                       ERR("unknown bytecode op %u\n",
-                               (unsigned int) *(filter_opcode_t *) pc);
-                       ret = -EINVAL;
-                       goto end;
-
-               case FILTER_OP_RETURN:
-                       retval = !!reg[0].v;
-                       ret = 0;
-                       goto end;
-
-               /* binary */
-               case FILTER_OP_MUL:
-               case FILTER_OP_DIV:
-               case FILTER_OP_MOD:
-               case FILTER_OP_PLUS:
-               case FILTER_OP_MINUS:
-               case FILTER_OP_RSHIFT:
-               case FILTER_OP_LSHIFT:
-               case FILTER_OP_BIN_AND:
-               case FILTER_OP_BIN_OR:
-               case FILTER_OP_BIN_XOR:
-                       ERR("unsupported bytecode op %u\n",
-                               (unsigned int) *(filter_opcode_t *) pc);
-                       ret = -EINVAL;
-                       goto end;
-
-               case FILTER_OP_EQ:
-               {
-                       if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING)
-                                       || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) {
-                               ERR("type mismatch for '==' binary operator\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[REG_R0].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               reg[REG_R0].v = (reg_strcmp(reg, "==") == 0);
-                               break;
-                       case REG_S64:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].v == reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].v == reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       case REG_DOUBLE:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].d == reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].d == reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       }
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_NE:
-               {
-                       if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING)
-                                       || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) {
-                               ERR("type mismatch for '!=' binary operator\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[REG_R0].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               reg[REG_R0].v = (reg_strcmp(reg, "!=") != 0);
-                               break;
-                       case REG_S64:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].v != reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].v != reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       case REG_DOUBLE:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].d != reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].d != reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       }
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_GT:
-               {
-                       if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING)
-                                       || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) {
-                               ERR("type mismatch for '>' binary operator\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[REG_R0].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               reg[REG_R0].v = (reg_strcmp(reg, ">") > 0);
-                               break;
-                       case REG_S64:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].v > reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].v > reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       case REG_DOUBLE:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].d > reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].d > reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       }
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_LT:
-               {
-                       if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING)
-                                       || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) {
-                               ERR("type mismatch for '<' binary operator\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[REG_R0].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               reg[REG_R0].v = (reg_strcmp(reg, "<") < 0);
-                               break;
-                       case REG_S64:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].v < reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].v < reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       case REG_DOUBLE:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].d < reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].d < reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       }
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_GE:
-               {
-                       if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING)
-                                       || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) {
-                               ERR("type mismatch for '>=' binary operator\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[REG_R0].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               reg[REG_R0].v = (reg_strcmp(reg, ">=") >= 0);
-                               break;
-                       case REG_S64:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].v >= reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].v >= reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       case REG_DOUBLE:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].d >= reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].d >= reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       }
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_LE:
-               {
-                       if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING)
-                                       || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) {
-                               ERR("type mismatch for '<=' binary operator\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[REG_R0].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               reg[REG_R0].v = (reg_strcmp(reg, "<=") <= 0);
-                               break;
-                       case REG_S64:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].v <= reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].v <= reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       case REG_DOUBLE:
-                               switch (reg[REG_R1].type) {
-                               default:
-                                       ERR("unknown register type\n");
-                                       ret = -EINVAL;
-                                       goto end;
-
-                               case REG_S64:
-                                       reg[REG_R0].v = (reg[REG_R0].d <= reg[REG_R1].v);
-                                       break;
-                               case REG_DOUBLE:
-                                       reg[REG_R0].v = (reg[REG_R0].d <= reg[REG_R1].d);
-                                       break;
-                               }
-                               break;
-                       }
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-
-               /* unary */
-               case FILTER_OP_UNARY_PLUS:
-               {
-                       struct unary_op *insn = (struct unary_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[insn->reg].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               ERR("Unary plus can only be applied to numeric or floating point registers\n");
-                               ret = -EINVAL;
-                               goto end;
-                       case REG_S64:
-                               break;
-                       case REG_DOUBLE:
-                               break;
-                       }
-                       next_pc += sizeof(struct unary_op);
-                       break;
-               }
-               case FILTER_OP_UNARY_MINUS:
-               {
-                       struct unary_op *insn = (struct unary_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[insn->reg].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               ERR("Unary minus can only be applied to numeric or floating point registers\n");
-                               ret = -EINVAL;
-                               goto end;
-                       case REG_S64:
-                               reg[insn->reg].v = -reg[insn->reg].v;
-                               break;
-                       case REG_DOUBLE:
-                               reg[insn->reg].d = -reg[insn->reg].d;
-                               break;
-                       }
-                       next_pc += sizeof(struct unary_op);
-                       break;
-               }
-               case FILTER_OP_UNARY_NOT:
-               {
-                       struct unary_op *insn = (struct unary_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[insn->reg].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               ERR("Unary not can only be applied to numeric or floating point registers\n");
-                               ret = -EINVAL;
-                               goto end;
-                       case REG_S64:
-                               reg[insn->reg].v = !reg[insn->reg].v;
-                               break;
-                       case REG_DOUBLE:
-                               reg[insn->reg].d = !reg[insn->reg].d;
-                               break;
-                       }
-                       if (unlikely(reg[insn->reg].type != REG_S64)) {
-                               ERR("Unary not can only be applied to numeric register\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       reg[insn->reg].v = !reg[insn->reg].v;
-                       next_pc += sizeof(struct unary_op);
-                       break;
-               }
-               /* logical */
-               case FILTER_OP_AND:
-               {
-                       struct logical_op *insn = (struct logical_op *) pc;
-
-                       if (unlikely(reg[REG_R0].type == REG_STRING)) {
-                               ERR("Logical operator 'and' can only be applied to numeric and floating point registers\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-
-                       /* If REG_R0 is 0, skip and evaluate to 0 */
-                       if ((reg[REG_R0].type == REG_S64 && reg[REG_R0].v == 0)
-                                       || (reg[REG_R0].type == REG_DOUBLE && reg[REG_R0].d == 0.0)) {
-                               dbg_printf("Jumping to bytecode offset %u\n",
-                                       (unsigned int) insn->skip_offset);
-                               next_pc = start_pc + insn->skip_offset;
-                               if (unlikely(next_pc <= pc)) {
-                                       ERR("Loops are not allowed in bytecode\n");
-                                       ret = -EINVAL;
-                                       goto end;
-                               }
-                       } else {
-                               next_pc += sizeof(struct logical_op);
-                       }
-                       break;
-               }
-               case FILTER_OP_OR:
-               {
-                       struct logical_op *insn = (struct logical_op *) pc;
-
-                       if (unlikely(reg[REG_R0].type == REG_STRING)) {
-                               ERR("Logical operator 'or' can only be applied to numeric and floating point registers\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-
-                       /* If REG_R0 is nonzero, skip and evaluate to 1 */
-
-                       if ((reg[REG_R0].type == REG_S64 && reg[REG_R0].v != 0)
-                                       || (reg[REG_R0].type == REG_DOUBLE && reg[REG_R0].d != 0.0)) {
-                               reg[REG_R0].v = 1;
-                               dbg_printf("Jumping to bytecode offset %u\n",
-                                       (unsigned int) insn->skip_offset);
-                               next_pc = start_pc + insn->skip_offset;
-                               if (unlikely(next_pc <= pc)) {
-                                       ERR("Loops are not allowed in bytecode\n");
-                                       ret = -EINVAL;
-                                       goto end;
-                               }
-                       } else {
-                               next_pc += sizeof(struct logical_op);
-                       }
-                       break;
-               }
-
-               /* load */
-               case FILTER_OP_LOAD_FIELD_REF:
-               {
-                       struct load_op *insn = (struct load_op *) pc;
-                       struct field_ref *ref = (struct field_ref *) insn->data;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       dbg_printf("load field ref offset %u type %u\n",
-                               ref->offset, ref->type);
-                       switch (ref->type) {
-                       case FIELD_REF_UNKNOWN:
-                       default:
-                               ERR("unknown field ref type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case FIELD_REF_STRING:
-                               reg[insn->reg].str =
-                                       *(const char * const *) &filter_stack_data[ref->offset];
-                               reg[insn->reg].type = REG_STRING;
-                               reg[insn->reg].seq_len = UINT_MAX;
-                               reg[insn->reg].literal = 0;
-                               dbg_printf("ref load string %s\n", reg[insn->reg].str);
-                               break;
-                       case FIELD_REF_SEQUENCE:
-                               reg[insn->reg].seq_len =
-                                       *(unsigned long *) &filter_stack_data[ref->offset];
-                               reg[insn->reg].str =
-                                       *(const char **) (&filter_stack_data[ref->offset
-                                                                       + sizeof(unsigned long)]);
-                               reg[insn->reg].type = REG_STRING;
-                               reg[insn->reg].literal = 0;
-                               break;
-                       case FIELD_REF_S64:
-                               memcpy(&reg[insn->reg].v, &filter_stack_data[ref->offset],
-                                       sizeof(struct literal_numeric));
-                               reg[insn->reg].type = REG_S64;
-                               reg[insn->reg].literal = 0;
-                               dbg_printf("ref load s64 %" PRIi64 "\n", reg[insn->reg].v);
-                               break;
-                       case FIELD_REF_DOUBLE:
-                               memcpy(&reg[insn->reg].d, &filter_stack_data[ref->offset],
-                                       sizeof(struct literal_double));
-                               reg[insn->reg].type = REG_DOUBLE;
-                               reg[insn->reg].literal = 0;
-                               dbg_printf("ref load double %g\n", reg[insn->reg].d);
-                               break;
-                       }
-
-                       next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
-                       break;
-               }
-
-               case FILTER_OP_LOAD_STRING:
-               {
-                       struct load_op *insn = (struct load_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       dbg_printf("load string %s\n", insn->data);
-                       reg[insn->reg].str = insn->data;
-                       reg[insn->reg].type = REG_STRING;
-                       reg[insn->reg].seq_len = UINT_MAX;
-                       reg[insn->reg].literal = 1;
-                       next_pc += sizeof(struct load_op) + strlen(insn->data) + 1;
-                       break;
-               }
-
-               case FILTER_OP_LOAD_S64:
-               {
-                       struct load_op *insn = (struct load_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       memcpy(&reg[insn->reg].v, insn->data,
-                               sizeof(struct literal_numeric));
-                       dbg_printf("load s64 %" PRIi64 "\n", reg[insn->reg].v);
-                       reg[insn->reg].type = REG_S64;
-                       next_pc += sizeof(struct load_op)
-                                       + sizeof(struct literal_numeric);
-                       break;
-               }
-
-               case FILTER_OP_LOAD_DOUBLE:
-               {
-                       struct load_op *insn = (struct load_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       memcpy(&reg[insn->reg].d, insn->data,
-                               sizeof(struct literal_double));
-                       dbg_printf("load s64 %g\n", reg[insn->reg].d);
-                       reg[insn->reg].type = REG_DOUBLE;
-                       next_pc += sizeof(struct load_op)
-                                       + sizeof(struct literal_double);
-                       break;
-               }
-               }
-       }
-end:
-       /* return 0 (discard) on error */
-       if (ret)
-               return 0;
-       return retval;
-}
-
-static
-int bin_op_compare_check(struct vreg reg[NR_REG], const char *str)
-{
-       switch (reg[REG_R0].type) {
-       default:
-               goto error_unknown;
-
-       case REG_STRING:
-               switch (reg[REG_R1].type) {
-               default:
-                       goto error_unknown;
-
-               case REG_STRING:
-                       break;
-               case REG_S64:
-               case REG_DOUBLE:
-                       goto error_mismatch;
-               }
-               break;
-       case REG_S64:
-       case REG_DOUBLE:
-               switch (reg[REG_R1].type) {
-               default:
-                       goto error_unknown;
-
-               case REG_STRING:
-                       goto error_mismatch;
-
-               case REG_S64:
-               case REG_DOUBLE:
-                       break;
-               }
-               break;
-       }
-       return 0;
-
-error_unknown:
-
-       return -EINVAL;
-error_mismatch:
-       ERR("type mismatch for '%s' binary operator\n", str);
-       return -EINVAL;
-}
-
-static
-int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode)
-{
-       void *pc, *next_pc, *start_pc;
-       int ret = -EINVAL;
-       struct vreg reg[NR_REG];
-       int i;
-
-       for (i = 0; i < NR_REG; i++) {
-               reg[i].type = REG_S64;
-               reg[i].literal = 0;
-       }
-
-       start_pc = &bytecode->data[0];
-       for (pc = next_pc = start_pc; pc - start_pc < bytecode->len;
-                       pc = next_pc) {
-               if (unlikely(pc >= start_pc + bytecode->len)) {
-                       ERR("filter bytecode overflow\n");
-                       ret = -EINVAL;
-                       goto end;
-               }
-               dbg_printf("Validating op %s (%u)\n",
-                       print_op((unsigned int) *(filter_opcode_t *) pc),
-                       (unsigned int) *(filter_opcode_t *) pc);
-               switch (*(filter_opcode_t *) pc) {
-               case FILTER_OP_UNKNOWN:
-               default:
-                       ERR("unknown bytecode op %u\n",
-                               (unsigned int) *(filter_opcode_t *) pc);
-                       ret = -EINVAL;
-                       goto end;
-
-               case FILTER_OP_RETURN:
-                       ret = 0;
-                       goto end;
-
-               /* binary */
-               case FILTER_OP_MUL:
-               case FILTER_OP_DIV:
-               case FILTER_OP_MOD:
-               case FILTER_OP_PLUS:
-               case FILTER_OP_MINUS:
-               case FILTER_OP_RSHIFT:
-               case FILTER_OP_LSHIFT:
-               case FILTER_OP_BIN_AND:
-               case FILTER_OP_BIN_OR:
-               case FILTER_OP_BIN_XOR:
-                       ERR("unsupported bytecode op %u\n",
-                               (unsigned int) *(filter_opcode_t *) pc);
-                       ret = -EINVAL;
-                       goto end;
-
-               case FILTER_OP_EQ:
-               {
-                       ret = bin_op_compare_check(reg, "==");
-                       if (ret)
-                               goto end;
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_NE:
-               {
-                       ret = bin_op_compare_check(reg, "!=");
-                       if (ret)
-                               goto end;
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_GT:
-               {
-                       ret = bin_op_compare_check(reg, ">");
-                       if (ret)
-                               goto end;
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_LT:
-               {
-                       ret = bin_op_compare_check(reg, "<");
-                       if (ret)
-                               goto end;
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_GE:
-               {
-                       ret = bin_op_compare_check(reg, ">=");
-                       if (ret)
-                               goto end;
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-               case FILTER_OP_LE:
-               {
-                       ret = bin_op_compare_check(reg, "<=");
-                       if (ret)
-                               goto end;
-                       reg[REG_R0].type = REG_S64;
-                       next_pc += sizeof(struct binary_op);
-                       break;
-               }
-
-               /* unary */
-               case FILTER_OP_UNARY_PLUS:
-               case FILTER_OP_UNARY_MINUS:
-               case FILTER_OP_UNARY_NOT:
-               {
-                       struct unary_op *insn = (struct unary_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       switch (reg[insn->reg].type) {
-                       default:
-                               ERR("unknown register type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case REG_STRING:
-                               ERR("Unary op can only be applied to numeric or floating point registers\n");
-                               ret = -EINVAL;
-                               goto end;
-                       case REG_S64:
-                               break;
-                       case REG_DOUBLE:
-                               break;
-                       }
-                       next_pc += sizeof(struct unary_op);
-                       break;
-               }
-               /* logical */
-               case FILTER_OP_AND:
-               case FILTER_OP_OR:
-               {
-                       struct logical_op *insn = (struct logical_op *) pc;
-
-                       if (unlikely(reg[REG_R0].type == REG_STRING)) {
-                               ERR("Logical operator 'and' can only be applied to numeric and floating point registers\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-
-                       dbg_printf("Validate jumping to bytecode offset %u\n",
-                               (unsigned int) insn->skip_offset);
-                       if (unlikely(start_pc + insn->skip_offset <= pc)) {
-                               ERR("Loops are not allowed in bytecode\n");
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       next_pc += sizeof(struct logical_op);
-                       break;
-               }
-
-               /* load */
-               case FILTER_OP_LOAD_FIELD_REF:
-               {
-                       struct load_op *insn = (struct load_op *) pc;
-                       struct field_ref *ref = (struct field_ref *) insn->data;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       dbg_printf("Validate load field ref offset %u type %u\n",
-                               ref->offset, ref->type);
-                       switch (ref->type) {
-                       case FIELD_REF_UNKNOWN:
-                       default:
-                               ERR("unknown field ref type\n");
-                               ret = -EINVAL;
-                               goto end;
-
-                       case FIELD_REF_STRING:
-                               reg[insn->reg].type = REG_STRING;
-                               reg[insn->reg].literal = 0;
-                               break;
-                       case FIELD_REF_SEQUENCE:
-                               reg[insn->reg].type = REG_STRING;
-                               reg[insn->reg].literal = 0;
-                               break;
-                       case FIELD_REF_S64:
-                               reg[insn->reg].type = REG_S64;
-                               reg[insn->reg].literal = 0;
-                               break;
-                       case FIELD_REF_DOUBLE:
-                               reg[insn->reg].type = REG_DOUBLE;
-                               reg[insn->reg].literal = 0;
-                               break;
-                       }
-
-                       next_pc += sizeof(struct load_op) + sizeof(struct field_ref);
-                       break;
-               }
-
-               case FILTER_OP_LOAD_STRING:
-               {
-                       struct load_op *insn = (struct load_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       reg[insn->reg].type = REG_STRING;
-                       reg[insn->reg].literal = 1;
-                       next_pc += sizeof(struct load_op) + strlen(insn->data) + 1;
-                       break;
-               }
-
-               case FILTER_OP_LOAD_S64:
-               {
-                       struct load_op *insn = (struct load_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       reg[insn->reg].type = REG_S64;
-                       next_pc += sizeof(struct load_op)
-                                       + sizeof(struct literal_numeric);
-                       break;
-               }
-
-               case FILTER_OP_LOAD_DOUBLE:
-               {
-                       struct load_op *insn = (struct load_op *) pc;
-
-                       if (unlikely(insn->reg >= REG_ERROR)) {
-                               ERR("invalid register %u\n",
-                                       (unsigned int) insn->reg);
-                               ret = -EINVAL;
-                               goto end;
-                       }
-                       reg[insn->reg].type = REG_DOUBLE;
-                       next_pc += sizeof(struct load_op)
-                                       + sizeof(struct literal_double);
-                       break;
-               }
-               }
-       }
-end:
-       return ret;
-}
-
 static
 int apply_field_reloc(struct ltt_event *event,
                struct bytecode_runtime *runtime,
@@ -1184,6 +137,7 @@ int apply_field_reloc(struct ltt_event *event,
        const struct lttng_event_field *fields, *field = NULL;
        unsigned int nr_fields, i;
        struct field_ref *field_ref;
+       struct load_op *op;
        uint32_t field_offset = 0;
 
        dbg_printf("Apply reloc: %u %s\n", reloc_offset, field_name);
@@ -1230,26 +184,26 @@ int apply_field_reloc(struct ltt_event *event,
                return -EINVAL;
 
        /* Check if field offset is too large for 16-bit offset */
-       if (field_offset > FILTER_BYTECODE_MAX_LEN)
+       if (field_offset > FILTER_BYTECODE_MAX_LEN - 1)
                return -EINVAL;
 
        /* set type */
-       field_ref = (struct field_ref *) &runtime->data[reloc_offset];
+       op = (struct load_op *) &runtime->data[reloc_offset];
+       field_ref = (struct field_ref *) op->data;
        switch (field->type.atype) {
        case atype_integer:
        case atype_enum:
-               field_ref->type = FIELD_REF_S64;
-               field_ref->type = FIELD_REF_S64;
+               op->op = FILTER_OP_LOAD_FIELD_REF_S64;
                break;
        case atype_array:
        case atype_sequence:
-               field_ref->type = FIELD_REF_SEQUENCE;
+               op->op = FILTER_OP_LOAD_FIELD_REF_SEQUENCE;
                break;
        case atype_string:
-               field_ref->type = FIELD_REF_STRING;
+               op->op = FILTER_OP_LOAD_FIELD_REF_STRING;
                break;
        case atype_float:
-               field_ref->type = FIELD_REF_DOUBLE;
+               op->op = FILTER_OP_LOAD_FIELD_REF_DOUBLE;
                break;
        default:
                return -EINVAL;
@@ -1315,6 +269,11 @@ int _lttng_filter_event_link_bytecode(struct ltt_event *event,
        if (ret) {
                goto link_error;
        }
+       /* Specialize bytecode */
+       ret = lttng_filter_specialize_bytecode(runtime);
+       if (ret) {
+               goto link_error;
+       }
        event->filter_data = runtime;
        event->filter = lttng_filter_interpret_bytecode;
        return 0;
@@ -1332,7 +291,7 @@ void lttng_filter_event_link_bytecode(struct ltt_event *event,
 
        ret = _lttng_filter_event_link_bytecode(event, filter_bytecode);
        if (ret) {
-               fprintf(stderr, "[lttng filter] error linking event bytecode\n");
+               dbg_printf("[lttng filter] warning: cannot link event bytecode\n");
        }
 }
 
@@ -1356,7 +315,7 @@ void lttng_filter_wildcard_link_bytecode(struct session_wildcard *wildcard)
                ret = _lttng_filter_event_link_bytecode(event,
                                wildcard->filter_bytecode);
                if (ret) {
-                       fprintf(stderr, "[lttng filter] error linking wildcard bytecode\n");
+                       dbg_printf("[lttng filter] error linking wildcard bytecode");
                }
 
        }
This page took 0.039298 seconds and 4 git commands to generate.