X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust%2Flttng-filter.c;h=f9d512c955d571d63f5b8b6daa0b9488f214baac;hb=bbe775b260014d456e329092be19d332224e1f4c;hp=dfa917c8cf47a082fe2304aa17c7a3da14d87aad;hpb=08c84b15e5d679e686770ca43c31dfca8049b168;p=lttng-ust.git diff --git a/liblttng-ust/lttng-filter.c b/liblttng-ust/lttng-filter.c index dfa917c8..f9d512c9 100644 --- a/liblttng-ust/lttng-filter.c +++ b/liblttng-ust/lttng-filter.c @@ -104,6 +104,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", @@ -111,10 +113,41 @@ 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", + + /* 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", @@ -130,6 +163,11 @@ static const char *opnames[] = { [ 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 @@ -231,6 +269,52 @@ int lttng_filter_false(void *filter_data, return 0; } +#ifdef INTERPRETER_USE_SWITCH + +/* + * Fallback for compilers that do not support taking address of labels. + */ + +#define START_OP \ + start_pc = &bytecode->data[0]; \ + for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; \ + pc = next_pc) { \ + 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) { + +#define OP(name) case name + +#define PO break + +#define END_OP } \ + } + +#else + +/* + * Dispatch-table based interpreter. + */ + +#define START_OP \ + start_pc = &bytecode->data[0]; \ + pc = next_pc = start_pc; \ + if (unlikely(pc - start_pc >= bytecode->len)) \ + goto end; \ + goto *dispatch[*(filter_opcode_t *) pc]; + +#define OP(name) \ +LABEL_##name + +#define PO \ + pc = next_pc; \ + goto *dispatch[*(filter_opcode_t *) pc]; + +#define END_OP + +#endif + static int lttng_filter_interpret_bytecode(void *filter_data, const char *filter_stack_data) @@ -240,399 +324,357 @@ int lttng_filter_interpret_bytecode(void *filter_data, int ret = -EINVAL; int retval = 0; struct reg reg[NR_REG]; +#ifndef INTERPRETER_USE_SWITCH + static void *dispatch[NR_FILTER_OPS] = { + [ FILTER_OP_UNKNOWN ] = &&LABEL_FILTER_OP_UNKNOWN, - start_pc = &bytecode->data[0]; - for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; - pc = next_pc) { - 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: - case FILTER_OP_LOAD_FIELD_REF: + [ FILTER_OP_RETURN ] = &&LABEL_FILTER_OP_RETURN, + + /* binary */ + [ FILTER_OP_MUL ] = &&LABEL_FILTER_OP_MUL, + [ FILTER_OP_DIV ] = &&LABEL_FILTER_OP_DIV, + [ FILTER_OP_MOD ] = &&LABEL_FILTER_OP_MOD, + [ FILTER_OP_PLUS ] = &&LABEL_FILTER_OP_PLUS, + [ FILTER_OP_MINUS ] = &&LABEL_FILTER_OP_MINUS, + [ FILTER_OP_RSHIFT ] = &&LABEL_FILTER_OP_RSHIFT, + [ FILTER_OP_LSHIFT ] = &&LABEL_FILTER_OP_LSHIFT, + [ FILTER_OP_BIN_AND ] = &&LABEL_FILTER_OP_BIN_AND, + [ FILTER_OP_BIN_OR ] = &&LABEL_FILTER_OP_BIN_OR, + [ FILTER_OP_BIN_XOR ] = &&LABEL_FILTER_OP_BIN_XOR, + + /* binary comparators */ + [ FILTER_OP_EQ ] = &&LABEL_FILTER_OP_EQ, + [ FILTER_OP_NE ] = &&LABEL_FILTER_OP_NE, + [ FILTER_OP_GT ] = &&LABEL_FILTER_OP_GT, + [ FILTER_OP_LT ] = &&LABEL_FILTER_OP_LT, + [ FILTER_OP_GE ] = &&LABEL_FILTER_OP_GE, + [ FILTER_OP_LE ] = &&LABEL_FILTER_OP_LE, + + /* string binary comparator */ + [ FILTER_OP_EQ_STRING ] = &&LABEL_FILTER_OP_EQ_STRING, + [ FILTER_OP_NE_STRING ] = &&LABEL_FILTER_OP_NE_STRING, + [ FILTER_OP_GT_STRING ] = &&LABEL_FILTER_OP_GT_STRING, + [ FILTER_OP_LT_STRING ] = &&LABEL_FILTER_OP_LT_STRING, + [ FILTER_OP_GE_STRING ] = &&LABEL_FILTER_OP_GE_STRING, + [ FILTER_OP_LE_STRING ] = &&LABEL_FILTER_OP_LE_STRING, + + /* s64 binary comparator */ + [ FILTER_OP_EQ_S64 ] = &&LABEL_FILTER_OP_EQ_S64, + [ FILTER_OP_NE_S64 ] = &&LABEL_FILTER_OP_NE_S64, + [ FILTER_OP_GT_S64 ] = &&LABEL_FILTER_OP_GT_S64, + [ FILTER_OP_LT_S64 ] = &&LABEL_FILTER_OP_LT_S64, + [ FILTER_OP_GE_S64 ] = &&LABEL_FILTER_OP_GE_S64, + [ FILTER_OP_LE_S64 ] = &&LABEL_FILTER_OP_LE_S64, + + /* double binary comparator */ + [ FILTER_OP_EQ_DOUBLE ] = &&LABEL_FILTER_OP_EQ_DOUBLE, + [ FILTER_OP_NE_DOUBLE ] = &&LABEL_FILTER_OP_NE_DOUBLE, + [ FILTER_OP_GT_DOUBLE ] = &&LABEL_FILTER_OP_GT_DOUBLE, + [ FILTER_OP_LT_DOUBLE ] = &&LABEL_FILTER_OP_LT_DOUBLE, + [ FILTER_OP_GE_DOUBLE ] = &&LABEL_FILTER_OP_GE_DOUBLE, + [ FILTER_OP_LE_DOUBLE ] = &&LABEL_FILTER_OP_LE_DOUBLE, + + /* unary */ + [ FILTER_OP_UNARY_PLUS ] = &&LABEL_FILTER_OP_UNARY_PLUS, + [ FILTER_OP_UNARY_MINUS ] = &&LABEL_FILTER_OP_UNARY_MINUS, + [ FILTER_OP_UNARY_NOT ] = &&LABEL_FILTER_OP_UNARY_NOT, + [ FILTER_OP_UNARY_PLUS_S64 ] = &&LABEL_FILTER_OP_UNARY_PLUS_S64, + [ FILTER_OP_UNARY_MINUS_S64 ] = &&LABEL_FILTER_OP_UNARY_MINUS_S64, + [ FILTER_OP_UNARY_NOT_S64 ] = &&LABEL_FILTER_OP_UNARY_NOT_S64, + [ FILTER_OP_UNARY_PLUS_DOUBLE ] = &&LABEL_FILTER_OP_UNARY_PLUS_DOUBLE, + [ FILTER_OP_UNARY_MINUS_DOUBLE ] = &&LABEL_FILTER_OP_UNARY_MINUS_DOUBLE, + [ FILTER_OP_UNARY_NOT_DOUBLE ] = &&LABEL_FILTER_OP_UNARY_NOT_DOUBLE, + + /* logical */ + [ FILTER_OP_AND ] = &&LABEL_FILTER_OP_AND, + [ FILTER_OP_OR ] = &&LABEL_FILTER_OP_OR, + + /* load */ + [ FILTER_OP_LOAD_FIELD_REF ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF, + [ FILTER_OP_LOAD_FIELD_REF_STRING ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_STRING, + [ FILTER_OP_LOAD_FIELD_REF_SEQUENCE ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_SEQUENCE, + [ FILTER_OP_LOAD_FIELD_REF_S64 ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_S64, + [ FILTER_OP_LOAD_FIELD_REF_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_DOUBLE, + + [ FILTER_OP_LOAD_STRING ] = &&LABEL_FILTER_OP_LOAD_STRING, + [ FILTER_OP_LOAD_S64 ] = &&LABEL_FILTER_OP_LOAD_S64, + [ FILTER_OP_LOAD_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_DOUBLE, + + /* cast */ + [ FILTER_OP_CAST_TO_S64 ] = &&LABEL_FILTER_OP_CAST_TO_S64, + [ FILTER_OP_CAST_DOUBLE_TO_S64 ] = &&LABEL_FILTER_OP_CAST_DOUBLE_TO_S64, + [ FILTER_OP_CAST_NOP ] = &&LABEL_FILTER_OP_CAST_NOP, + }; +#endif /* #ifndef INTERPRETER_USE_SWITCH */ + + START_OP + + OP(FILTER_OP_UNKNOWN): + OP(FILTER_OP_LOAD_FIELD_REF): +#ifdef INTERPRETER_USE_SWITCH default: +#endif /* INTERPRETER_USE_SWITCH */ ERR("unknown bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; goto end; - case FILTER_OP_RETURN: + OP(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: + OP(FILTER_OP_MUL): + OP(FILTER_OP_DIV): + OP(FILTER_OP_MOD): + OP(FILTER_OP_PLUS): + OP(FILTER_OP_MINUS): + OP(FILTER_OP_RSHIFT): + OP(FILTER_OP_LSHIFT): + OP(FILTER_OP_BIN_AND): + OP(FILTER_OP_BIN_OR): + OP(FILTER_OP_BIN_XOR): ERR("unsupported bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; goto end; - case FILTER_OP_EQ: - { - 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; + OP(FILTER_OP_EQ): + OP(FILTER_OP_NE): + OP(FILTER_OP_GT): + OP(FILTER_OP_LT): + OP(FILTER_OP_GE): + OP(FILTER_OP_LE): + ERR("unsupported non-specialized bytecode op %u\n", + (unsigned int) *(filter_opcode_t *) pc); + 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; - } + OP(FILTER_OP_EQ_STRING): + { + reg[REG_R0].v = (reg_strcmp(reg, "==") == 0); reg[REG_R0].type = REG_S64; next_pc += sizeof(struct binary_op); - break; + PO; } - case FILTER_OP_NE: + OP(FILTER_OP_NE_STRING): { - 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].v = (reg_strcmp(reg, "!=") != 0); reg[REG_R0].type = REG_S64; next_pc += sizeof(struct binary_op); - break; + PO; } - case FILTER_OP_GT: + OP(FILTER_OP_GT_STRING): { - 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].v = (reg_strcmp(reg, ">") > 0); reg[REG_R0].type = REG_S64; next_pc += sizeof(struct binary_op); - break; + PO; } - case FILTER_OP_LT: + OP(FILTER_OP_LT_STRING): { - 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].v = (reg_strcmp(reg, "<") < 0); reg[REG_R0].type = REG_S64; next_pc += sizeof(struct binary_op); - break; + PO; } - case FILTER_OP_GE: + OP(FILTER_OP_GE_STRING): { - 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].v = (reg_strcmp(reg, ">=") >= 0); reg[REG_R0].type = REG_S64; next_pc += sizeof(struct binary_op); - break; + PO; } - case FILTER_OP_LE: + OP(FILTER_OP_LE_STRING): { - 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; + reg[REG_R0].v = (reg_strcmp(reg, "<=") <= 0); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } - 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; + OP(FILTER_OP_EQ_S64): + { + reg[REG_R0].v = (reg[REG_R0].v == reg[REG_R1].v); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_NE_S64): + { + reg[REG_R0].v = (reg[REG_R0].v != reg[REG_R1].v); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_GT_S64): + { + reg[REG_R0].v = (reg[REG_R0].v > reg[REG_R1].v); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_LT_S64): + { + reg[REG_R0].v = (reg[REG_R0].v < reg[REG_R1].v); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_GE_S64): + { + reg[REG_R0].v = (reg[REG_R0].v >= reg[REG_R1].v); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_LE_S64): + { + reg[REG_R0].v = (reg[REG_R0].v <= reg[REG_R1].v); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } - 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; - } + OP(FILTER_OP_EQ_DOUBLE): + { + if (unlikely(reg[REG_R0].type == REG_S64)) + reg[REG_R0].d = (double) reg[REG_R0].v; + else if (unlikely(reg[REG_R1].type == REG_S64)) + reg[REG_R1].d = (double) reg[REG_R1].v; + reg[REG_R0].v = (reg[REG_R0].d == reg[REG_R1].d); reg[REG_R0].type = REG_S64; next_pc += sizeof(struct binary_op); - break; + PO; + } + OP(FILTER_OP_NE_DOUBLE): + { + if (unlikely(reg[REG_R0].type == REG_S64)) + reg[REG_R0].d = (double) reg[REG_R0].v; + else if (unlikely(reg[REG_R1].type == REG_S64)) + reg[REG_R1].d = (double) reg[REG_R1].v; + reg[REG_R0].v = (reg[REG_R0].d != reg[REG_R1].d); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_GT_DOUBLE): + { + if (unlikely(reg[REG_R0].type == REG_S64)) + reg[REG_R0].d = (double) reg[REG_R0].v; + else if (unlikely(reg[REG_R1].type == REG_S64)) + reg[REG_R1].d = (double) reg[REG_R1].v; + reg[REG_R0].v = (reg[REG_R0].d > reg[REG_R1].d); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_LT_DOUBLE): + { + if (unlikely(reg[REG_R0].type == REG_S64)) + reg[REG_R0].d = (double) reg[REG_R0].v; + else if (unlikely(reg[REG_R1].type == REG_S64)) + reg[REG_R1].d = (double) reg[REG_R1].v; + reg[REG_R0].v = (reg[REG_R0].d < reg[REG_R1].d); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_GE_DOUBLE): + { + if (unlikely(reg[REG_R0].type == REG_S64)) + reg[REG_R0].d = (double) reg[REG_R0].v; + else if (unlikely(reg[REG_R1].type == REG_S64)) + reg[REG_R1].d = (double) reg[REG_R1].v; + reg[REG_R0].v = (reg[REG_R0].d >= reg[REG_R1].d); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_LE_DOUBLE): + { + if (unlikely(reg[REG_R0].type == REG_S64)) + reg[REG_R0].d = (double) reg[REG_R0].v; + else if (unlikely(reg[REG_R1].type == REG_S64)) + reg[REG_R1].d = (double) reg[REG_R1].v; + reg[REG_R0].v = (reg[REG_R0].d <= reg[REG_R1].d); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + PO; } /* unary */ - case FILTER_OP_UNARY_PLUS: + OP(FILTER_OP_UNARY_PLUS): + OP(FILTER_OP_UNARY_MINUS): + OP(FILTER_OP_UNARY_NOT): + ERR("unsupported non-specialized bytecode op %u\n", + (unsigned int) *(filter_opcode_t *) pc); + ret = -EINVAL; + goto end; + + + OP(FILTER_OP_UNARY_PLUS_S64): + OP(FILTER_OP_UNARY_PLUS_DOUBLE): { next_pc += sizeof(struct unary_op); - break; + PO; } - case FILTER_OP_UNARY_MINUS: + OP(FILTER_OP_UNARY_MINUS_S64): { struct unary_op *insn = (struct unary_op *) pc; - 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; - } + reg[insn->reg].v = -reg[insn->reg].v; next_pc += sizeof(struct unary_op); - break; + PO; } - case FILTER_OP_UNARY_NOT: + OP(FILTER_OP_UNARY_MINUS_DOUBLE): { struct unary_op *insn = (struct unary_op *) pc; - switch (reg[insn->reg].type) { - default: - ERR("unknown register type\n"); - ret = -EINVAL; - goto end; + reg[insn->reg].d = -reg[insn->reg].d; + next_pc += sizeof(struct unary_op); + PO; + } + OP(FILTER_OP_UNARY_NOT_S64): + { + struct unary_op *insn = (struct unary_op *) pc; - 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; - } reg[insn->reg].v = !reg[insn->reg].v; next_pc += sizeof(struct unary_op); - break; + PO; + } + OP(FILTER_OP_UNARY_NOT_DOUBLE): + { + struct unary_op *insn = (struct unary_op *) pc; + + reg[insn->reg].d = !reg[insn->reg].d; + next_pc += sizeof(struct unary_op); + PO; } + /* logical */ - case FILTER_OP_AND: + OP(FILTER_OP_AND): { struct logical_op *insn = (struct logical_op *) pc; /* 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)) { + if (unlikely(reg[REG_R0].v == 0)) { dbg_printf("Jumping to bytecode offset %u\n", (unsigned int) insn->skip_offset); next_pc = start_pc + insn->skip_offset; } else { next_pc += sizeof(struct logical_op); } - break; + PO; } - case FILTER_OP_OR: + OP(FILTER_OP_OR): { struct logical_op *insn = (struct logical_op *) pc; /* 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)) { + if (unlikely(reg[REG_R0].v != 0)) { reg[REG_R0].v = 1; dbg_printf("Jumping to bytecode offset %u\n", (unsigned int) insn->skip_offset); @@ -640,11 +682,12 @@ int lttng_filter_interpret_bytecode(void *filter_data, } else { next_pc += sizeof(struct logical_op); } - break; + PO; } + /* load */ - case FILTER_OP_LOAD_FIELD_REF_STRING: + OP(FILTER_OP_LOAD_FIELD_REF_STRING): { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; @@ -653,15 +696,20 @@ int lttng_filter_interpret_bytecode(void *filter_data, ref->offset); reg[insn->reg].str = *(const char * const *) &filter_stack_data[ref->offset]; + if (unlikely(!reg[insn->reg].str)) { + dbg_printf("Filter warning: loading a NULL string.\n"); + ret = -EINVAL; + goto end; + } 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); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); - break; + PO; } - case FILTER_OP_LOAD_FIELD_REF_SEQUENCE: + OP(FILTER_OP_LOAD_FIELD_REF_SEQUENCE): { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; @@ -673,13 +721,18 @@ int lttng_filter_interpret_bytecode(void *filter_data, reg[insn->reg].str = *(const char **) (&filter_stack_data[ref->offset + sizeof(unsigned long)]); + if (unlikely(!reg[insn->reg].str)) { + dbg_printf("Filter warning: loading a NULL sequence.\n"); + ret = -EINVAL; + goto end; + } reg[insn->reg].type = REG_STRING; reg[insn->reg].literal = 0; next_pc += sizeof(struct load_op) + sizeof(struct field_ref); - break; + PO; } - case FILTER_OP_LOAD_FIELD_REF_S64: + OP(FILTER_OP_LOAD_FIELD_REF_S64): { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; @@ -689,13 +742,12 @@ int lttng_filter_interpret_bytecode(void *filter_data, memcpy(®[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); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); - break; + PO; } - case FILTER_OP_LOAD_FIELD_REF_DOUBLE: + OP(FILTER_OP_LOAD_FIELD_REF_DOUBLE): { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; @@ -705,13 +757,12 @@ int lttng_filter_interpret_bytecode(void *filter_data, memcpy(®[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); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); - break; + PO; } - case FILTER_OP_LOAD_STRING: + OP(FILTER_OP_LOAD_STRING): { struct load_op *insn = (struct load_op *) pc; @@ -721,10 +772,10 @@ int lttng_filter_interpret_bytecode(void *filter_data, reg[insn->reg].seq_len = UINT_MAX; reg[insn->reg].literal = 1; next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; - break; + PO; } - case FILTER_OP_LOAD_S64: + OP(FILTER_OP_LOAD_S64): { struct load_op *insn = (struct load_op *) pc; @@ -732,13 +783,12 @@ int lttng_filter_interpret_bytecode(void *filter_data, sizeof(struct literal_numeric)); dbg_printf("load s64 %" PRIi64 "\n", reg[insn->reg].v); reg[insn->reg].type = REG_S64; - reg[insn->reg].literal = 1; next_pc += sizeof(struct load_op) + sizeof(struct literal_numeric); - break; + PO; } - case FILTER_OP_LOAD_DOUBLE: + OP(FILTER_OP_LOAD_DOUBLE): { struct load_op *insn = (struct load_op *) pc; @@ -746,13 +796,35 @@ int lttng_filter_interpret_bytecode(void *filter_data, sizeof(struct literal_double)); dbg_printf("load s64 %g\n", reg[insn->reg].d); reg[insn->reg].type = REG_DOUBLE; - reg[insn->reg].literal = 1; next_pc += sizeof(struct load_op) + sizeof(struct literal_double); - break; + PO; } + + /* cast */ + OP(FILTER_OP_CAST_TO_S64): + ERR("unsupported non-specialized bytecode op %u\n", + (unsigned int) *(filter_opcode_t *) pc); + ret = -EINVAL; + goto end; + + OP(FILTER_OP_CAST_DOUBLE_TO_S64): + { + struct cast_op *insn = (struct cast_op *) pc; + + reg[insn->reg].v = (int64_t) reg[insn->reg].d; + reg[insn->reg].type = REG_S64; + next_pc += sizeof(struct cast_op); + PO; } - } + + OP(FILTER_OP_CAST_NOP): + { + next_pc += sizeof(struct cast_op); + PO; + } + + END_OP end: /* return 0 (discard) on error */ if (ret) @@ -760,6 +832,11 @@ end: return retval; } +#undef START_OP +#undef OP +#undef PO +#undef END_OP + static int bin_op_compare_check(struct vreg reg[NR_REG], const char *str) { @@ -767,41 +844,221 @@ int bin_op_compare_check(struct vreg reg[NR_REG], const char *str) default: goto error_unknown; - case REG_STRING: - switch (reg[REG_R1].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; +} + +/* + * Validate bytecode range overflow within the validation pass. + * Called for each instruction encountered. + */ +static +int bytecode_validate_overflow(struct bytecode_runtime *bytecode, + void *start_pc, void *pc) +{ + int ret = 0; + + switch (*(filter_opcode_t *) pc) { + case FILTER_OP_UNKNOWN: + default: + { + ERR("unknown bytecode op %u\n", + (unsigned int) *(filter_opcode_t *) pc); + ret = -EINVAL; + break; + } + + case FILTER_OP_RETURN: + { + if (unlikely(pc + sizeof(struct return_op) + > start_pc + bytecode->len)) { + ret = -EINVAL; + } + break; + } + + /* 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; + break; + } + + case FILTER_OP_EQ: + case FILTER_OP_NE: + case FILTER_OP_GT: + case FILTER_OP_LT: + case FILTER_OP_GE: + case FILTER_OP_LE: + case FILTER_OP_EQ_STRING: + case FILTER_OP_NE_STRING: + case FILTER_OP_GT_STRING: + case FILTER_OP_LT_STRING: + case FILTER_OP_GE_STRING: + case FILTER_OP_LE_STRING: + case FILTER_OP_EQ_S64: + case FILTER_OP_NE_S64: + case FILTER_OP_GT_S64: + case FILTER_OP_LT_S64: + case FILTER_OP_GE_S64: + case FILTER_OP_LE_S64: + case FILTER_OP_EQ_DOUBLE: + case FILTER_OP_NE_DOUBLE: + case FILTER_OP_GT_DOUBLE: + case FILTER_OP_LT_DOUBLE: + case FILTER_OP_GE_DOUBLE: + case FILTER_OP_LE_DOUBLE: + { + if (unlikely(pc + sizeof(struct binary_op) + > start_pc + bytecode->len)) { + ret = -EINVAL; + } + break; + } + + /* unary */ + case FILTER_OP_UNARY_PLUS: + case FILTER_OP_UNARY_MINUS: + case FILTER_OP_UNARY_NOT: + case FILTER_OP_UNARY_PLUS_S64: + case FILTER_OP_UNARY_MINUS_S64: + case FILTER_OP_UNARY_NOT_S64: + case FILTER_OP_UNARY_PLUS_DOUBLE: + case FILTER_OP_UNARY_MINUS_DOUBLE: + case FILTER_OP_UNARY_NOT_DOUBLE: + { + if (unlikely(pc + sizeof(struct unary_op) + > start_pc + bytecode->len)) { + ret = -EINVAL; + } + break; + } + + /* logical */ + case FILTER_OP_AND: + case FILTER_OP_OR: + { + if (unlikely(pc + sizeof(struct logical_op) + > start_pc + bytecode->len)) { + ret = -EINVAL; + } + break; + } + + /* load */ + case FILTER_OP_LOAD_FIELD_REF: + { + ERR("Unknown field ref type\n"); + ret = -EINVAL; + break; + } + case FILTER_OP_LOAD_FIELD_REF_STRING: + case FILTER_OP_LOAD_FIELD_REF_SEQUENCE: + case FILTER_OP_LOAD_FIELD_REF_S64: + case FILTER_OP_LOAD_FIELD_REF_DOUBLE: + { + if (unlikely(pc + sizeof(struct load_op) + sizeof(struct field_ref) + > start_pc + bytecode->len)) { + ret = -EINVAL; + } + break; + } + + case FILTER_OP_LOAD_STRING: + { + struct load_op *insn = (struct load_op *) pc; + uint32_t str_len, maxlen; - case REG_STRING: + if (unlikely(pc + sizeof(struct load_op) + > start_pc + bytecode->len)) { + ret = -EINVAL; break; - case REG_S64: - case REG_DOUBLE: - goto error_mismatch; + } + + maxlen = start_pc + bytecode->len - pc - sizeof(struct load_op); + str_len = strnlen(insn->data, maxlen); + if (unlikely(str_len >= maxlen)) { + /* Final '\0' not found within range */ + ret = -EINVAL; } break; - case REG_S64: - case REG_DOUBLE: - switch (reg[REG_R1].type) { - default: - goto error_unknown; + } - case REG_STRING: - goto error_mismatch; + case FILTER_OP_LOAD_S64: + { + if (unlikely(pc + sizeof(struct load_op) + sizeof(struct literal_numeric) + > start_pc + bytecode->len)) { + ret = -EINVAL; + } + break; + } - case REG_S64: - case REG_DOUBLE: - break; + case FILTER_OP_LOAD_DOUBLE: + { + if (unlikely(pc + sizeof(struct load_op) + sizeof(struct literal_double) + > start_pc + bytecode->len)) { + ret = -EINVAL; } break; } - return 0; -error_unknown: + case FILTER_OP_CAST_TO_S64: + case FILTER_OP_CAST_DOUBLE_TO_S64: + case FILTER_OP_CAST_NOP: + { + if (unlikely(pc + sizeof(struct cast_op) + > start_pc + bytecode->len)) { + ret = -EINVAL; + } + break; + } + } - return -EINVAL; -error_mismatch: - ERR("type mismatch for '%s' binary operator\n", str); - return -EINVAL; + return ret; } static @@ -820,7 +1077,7 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) 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)) { + if (bytecode_validate_overflow(bytecode, start_pc, pc) != 0) { ERR("filter bytecode overflow\n"); ret = -EINVAL; goto end; @@ -911,6 +1168,65 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) break; } + case FILTER_OP_EQ_STRING: + case FILTER_OP_NE_STRING: + case FILTER_OP_GT_STRING: + case FILTER_OP_LT_STRING: + case FILTER_OP_GE_STRING: + case FILTER_OP_LE_STRING: + { + if (reg[REG_R0].type != REG_STRING + || reg[REG_R1].type != REG_STRING) { + ERR("Unexpected register type for string comparator\n"); + ret = -EINVAL; + goto end; + } + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + + case FILTER_OP_EQ_S64: + case FILTER_OP_NE_S64: + case FILTER_OP_GT_S64: + case FILTER_OP_LT_S64: + case FILTER_OP_GE_S64: + case FILTER_OP_LE_S64: + { + if (reg[REG_R0].type != REG_S64 + || reg[REG_R1].type != REG_S64) { + ERR("Unexpected register type for s64 comparator\n"); + ret = -EINVAL; + goto end; + } + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + + case FILTER_OP_EQ_DOUBLE: + case FILTER_OP_NE_DOUBLE: + case FILTER_OP_GT_DOUBLE: + case FILTER_OP_LT_DOUBLE: + case FILTER_OP_GE_DOUBLE: + case FILTER_OP_LE_DOUBLE: + { + if ((reg[REG_R0].type != REG_DOUBLE && reg[REG_R0].type != REG_S64) + || (reg[REG_R1].type != REG_DOUBLE && reg[REG_R1].type != REG_S64)) { + ERR("Unexpected register type for double comparator\n"); + ret = -EINVAL; + goto end; + } + if (reg[REG_R0].type != REG_DOUBLE && reg[REG_R1].type != REG_DOUBLE) { + ERR("Double operator should have at least one double register\n"); + ret = -EINVAL; + goto end; + } + reg[REG_R0].type = REG_DOUBLE; + next_pc += sizeof(struct binary_op); + break; + } + /* unary */ case FILTER_OP_UNARY_PLUS: case FILTER_OP_UNARY_MINUS: @@ -991,11 +1307,8 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) { struct logical_op *insn = (struct logical_op *) pc; - if (unlikely(reg[REG_R0].type == REG_TYPE_UNKNOWN - || reg[REG_R0].type == REG_TYPE_UNKNOWN - || reg[REG_R0].type == REG_STRING - || reg[REG_R1].type == REG_STRING)) { - ERR("Logical comparator can only be applied to numeric and floating point registers\n"); + if (reg[REG_R0].type != REG_S64) { + ERR("Logical comparator expects S64 register\n"); ret = -EINVAL; goto end; } @@ -1123,6 +1436,50 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) + sizeof(struct literal_double); break; } + + case FILTER_OP_CAST_TO_S64: + case FILTER_OP_CAST_DOUBLE_TO_S64: + { + struct cast_op *insn = (struct cast_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("Cast op can only be applied to numeric or floating point registers\n"); + ret = -EINVAL; + goto end; + case REG_S64: + break; + case REG_DOUBLE: + break; + } + if (insn->op == FILTER_OP_CAST_DOUBLE_TO_S64) { + if (reg[insn->reg].type != REG_DOUBLE) { + ERR("Cast expects double\n"); + ret = -EINVAL; + goto end; + } + } + reg[insn->reg].type = REG_S64; + next_pc += sizeof(struct cast_op); + break; + } + case FILTER_OP_CAST_NOP: + { + next_pc += sizeof(struct cast_op); + break; + } + } } end: @@ -1174,11 +1531,190 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) goto end; case FILTER_OP_EQ: + { + struct binary_op *insn = (struct binary_op *) pc; + + switch(reg[REG_R0].type) { + default: + ERR("unknown register type\n"); + ret = -EINVAL; + goto end; + + case REG_STRING: + insn->op = FILTER_OP_EQ_STRING; + break; + case REG_S64: + if (reg[REG_R1].type == REG_S64) + insn->op = FILTER_OP_EQ_S64; + else + insn->op = FILTER_OP_EQ_DOUBLE; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_EQ_DOUBLE; + break; + } + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case FILTER_OP_NE: + { + struct binary_op *insn = (struct binary_op *) pc; + + switch(reg[REG_R0].type) { + default: + ERR("unknown register type\n"); + ret = -EINVAL; + goto end; + + case REG_STRING: + insn->op = FILTER_OP_NE_STRING; + break; + case REG_S64: + if (reg[REG_R1].type == REG_S64) + insn->op = FILTER_OP_NE_S64; + else + insn->op = FILTER_OP_NE_DOUBLE; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_NE_DOUBLE; + break; + } + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case FILTER_OP_GT: + { + struct binary_op *insn = (struct binary_op *) pc; + + switch(reg[REG_R0].type) { + default: + ERR("unknown register type\n"); + ret = -EINVAL; + goto end; + + case REG_STRING: + insn->op = FILTER_OP_GT_STRING; + break; + case REG_S64: + if (reg[REG_R1].type == REG_S64) + insn->op = FILTER_OP_GT_S64; + else + insn->op = FILTER_OP_GT_DOUBLE; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_GT_DOUBLE; + break; + } + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case FILTER_OP_LT: + { + struct binary_op *insn = (struct binary_op *) pc; + + switch(reg[REG_R0].type) { + default: + ERR("unknown register type\n"); + ret = -EINVAL; + goto end; + + case REG_STRING: + insn->op = FILTER_OP_LT_STRING; + break; + case REG_S64: + if (reg[REG_R1].type == REG_S64) + insn->op = FILTER_OP_LT_S64; + else + insn->op = FILTER_OP_LT_DOUBLE; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_LT_DOUBLE; + break; + } + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case FILTER_OP_GE: + { + struct binary_op *insn = (struct binary_op *) pc; + + switch(reg[REG_R0].type) { + default: + ERR("unknown register type\n"); + ret = -EINVAL; + goto end; + + case REG_STRING: + insn->op = FILTER_OP_GE_STRING; + break; + case REG_S64: + if (reg[REG_R1].type == REG_S64) + insn->op = FILTER_OP_GE_S64; + else + insn->op = FILTER_OP_GE_DOUBLE; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_GE_DOUBLE; + break; + } + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } case FILTER_OP_LE: + { + struct binary_op *insn = (struct binary_op *) pc; + + switch(reg[REG_R0].type) { + default: + ERR("unknown register type\n"); + ret = -EINVAL; + goto end; + + case REG_STRING: + insn->op = FILTER_OP_LE_STRING; + break; + case REG_S64: + if (reg[REG_R1].type == REG_S64) + insn->op = FILTER_OP_LE_S64; + else + insn->op = FILTER_OP_LE_DOUBLE; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_LE_DOUBLE; + break; + } + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + + case FILTER_OP_EQ_STRING: + case FILTER_OP_NE_STRING: + case FILTER_OP_GT_STRING: + case FILTER_OP_LT_STRING: + case FILTER_OP_GE_STRING: + case FILTER_OP_LE_STRING: + case FILTER_OP_EQ_S64: + case FILTER_OP_NE_S64: + case FILTER_OP_GT_S64: + case FILTER_OP_LT_S64: + case FILTER_OP_GE_S64: + case FILTER_OP_LE_S64: + case FILTER_OP_EQ_DOUBLE: + case FILTER_OP_NE_DOUBLE: + case FILTER_OP_GT_DOUBLE: + case FILTER_OP_LT_DOUBLE: + case FILTER_OP_GE_DOUBLE: + case FILTER_OP_LE_DOUBLE: { reg[REG_R0].type = REG_S64; next_pc += sizeof(struct binary_op); @@ -1203,6 +1739,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_UNARY_PLUS_DOUBLE; break; } + next_pc += sizeof(struct unary_op); break; } @@ -1223,6 +1760,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_UNARY_MINUS_DOUBLE; break; } + next_pc += sizeof(struct unary_op); break; } @@ -1243,6 +1781,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_UNARY_NOT_DOUBLE; break; } + next_pc += sizeof(struct unary_op); break; } @@ -1332,14 +1871,54 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) + sizeof(struct literal_double); break; } + + /* cast */ + case FILTER_OP_CAST_TO_S64: + { + struct cast_op *insn = (struct cast_op *) pc; + + switch (reg[insn->reg].type) { + default: + ERR("unknown register type\n"); + ret = -EINVAL; + goto end; + + case REG_STRING: + ERR("Cast op can only be applied to numeric or floating point registers\n"); + ret = -EINVAL; + goto end; + case REG_S64: + insn->op = FILTER_OP_CAST_NOP; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_CAST_DOUBLE_TO_S64; + break; + } + reg[insn->reg].type = REG_S64; + next_pc += sizeof(struct cast_op); + break; + } + case FILTER_OP_CAST_DOUBLE_TO_S64: + { + struct cast_op *insn = (struct cast_op *) pc; + + reg[insn->reg].type = REG_S64; + next_pc += sizeof(struct cast_op); + break; + } + case FILTER_OP_CAST_NOP: + { + next_pc += sizeof(struct cast_op); + break; + } + + } } end: return ret; } - - static int apply_field_reloc(struct ltt_event *event, struct bytecode_runtime *runtime,