X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;ds=sidebyside;f=liblttng-ust%2Flttng-filter.c;h=64576e88633178bf9f48386c2d9af79526a7831f;hb=fb72494a0993e167b4736c3c655bc38a46c31d9d;hp=a695f1cd91878add2df239ec9612859656f2e650;hpb=2f0145d1ef14717353a29e8d79d674bf0bdc2c4e;p=lttng-ust.git diff --git a/liblttng-ust/lttng-filter.c b/liblttng-ust/lttng-filter.c index a695f1cd..64576e88 100644 --- a/liblttng-ust/lttng-filter.c +++ b/liblttng-ust/lttng-filter.c @@ -68,6 +68,7 @@ enum reg_type { REG_S64, REG_DOUBLE, REG_STRING, + REG_TYPE_UNKNOWN, }; /* Validation registers */ @@ -103,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", @@ -110,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", @@ -239,16 +273,6 @@ int lttng_filter_interpret_bytecode(void *filter_data, 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; @@ -287,277 +311,164 @@ int lttng_filter_interpret_bytecode(void *filter_data, goto end; case FILTER_OP_EQ: - { - switch (reg[REG_R0].type) { - default: - ERR("unknown register type\n"); - ret = -EINVAL; - goto end; + case FILTER_OP_NE: + case FILTER_OP_GT: + case FILTER_OP_LT: + case FILTER_OP_GE: + case FILTER_OP_LE: + ERR("unsupported non-specialized bytecode op %u\n", + (unsigned int) *(filter_opcode_t *) pc); + 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; - } + case 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; } - case FILTER_OP_NE: + case 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; } - case FILTER_OP_GT: + case 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; } - case FILTER_OP_LT: + case 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; } - case FILTER_OP_GE: + case FILTER_OP_GE_STRING: { - switch (reg[REG_R0].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); + break; + } + case FILTER_OP_LE_STRING: + { + reg[REG_R0].v = (reg_strcmp(reg, "<=") <= 0); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } - 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; - } + case 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); break; } - case FILTER_OP_LE: + case FILTER_OP_NE_S64: { - switch (reg[REG_R0].type) { - default: - ERR("unknown register type\n"); - ret = -EINVAL; - goto end; + reg[REG_R0].v = (reg[REG_R0].v != reg[REG_R1].v); + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case 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); + break; + } + case 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); + break; + } + case 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); + break; + } + case 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); + break; + } - 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; - } + case 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; + } + case 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); + break; + } + case 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); + break; + } + case 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); + break; + } + case 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); + break; + } + case 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); break; @@ -741,6 +652,7 @@ 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; @@ -754,6 +666,7 @@ 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; @@ -820,7 +733,7 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) int i; for (i = 0; i < NR_REG; i++) { - reg[i].type = REG_S64; + reg[i].type = REG_TYPE_UNKNOWN; reg[i].literal = 0; } @@ -918,6 +831,60 @@ 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; + } + reg[REG_R0].type = REG_DOUBLE; + next_pc += sizeof(struct binary_op); + break; + } + /* unary */ case FILTER_OP_UNARY_PLUS: case FILTER_OP_UNARY_MINUS: @@ -949,14 +916,60 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) next_pc += sizeof(struct unary_op); break; } + + case FILTER_OP_UNARY_PLUS_S64: + case FILTER_OP_UNARY_MINUS_S64: + case FILTER_OP_UNARY_NOT_S64: + { + 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; + } + if (reg[insn->reg].type != REG_S64) { + ERR("Invalid register type\n"); + ret = -EINVAL; + goto end; + } + next_pc += sizeof(struct unary_op); + break; + } + + case FILTER_OP_UNARY_PLUS_DOUBLE: + case FILTER_OP_UNARY_MINUS_DOUBLE: + case FILTER_OP_UNARY_NOT_DOUBLE: + { + 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; + } + if (reg[insn->reg].type != REG_DOUBLE) { + ERR("Invalid register type\n"); + ret = -EINVAL; + goto end; + } + 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"); + if (unlikely(reg[REG_R0].type == REG_TYPE_UNKNOWN + || reg[REG_R1].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"); ret = -EINVAL; goto end; } @@ -1062,6 +1075,7 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) goto end; } reg[insn->reg].type = REG_S64; + reg[insn->reg].literal = 1; next_pc += sizeof(struct load_op) + sizeof(struct literal_numeric); break; @@ -1078,6 +1092,7 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) goto end; } reg[insn->reg].type = REG_DOUBLE; + reg[insn->reg].literal = 1; next_pc += sizeof(struct load_op) + sizeof(struct literal_double); break; @@ -1089,34 +1104,425 @@ end: } static -int apply_field_reloc(struct ltt_event *event, - struct bytecode_runtime *runtime, - uint32_t runtime_len, - uint32_t reloc_offset, - const char *field_name) +int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { - const struct lttng_event_desc *desc; - 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; + void *pc, *next_pc, *start_pc; + int ret = -EINVAL; + struct vreg reg[NR_REG]; + int i; - dbg_printf("Apply reloc: %u %s\n", reloc_offset, field_name); + for (i = 0; i < NR_REG; i++) { + reg[i].type = REG_TYPE_UNKNOWN; + reg[i].literal = 0; + } - /* Ensure that the reloc is within the code */ - if (runtime_len - reloc_offset < sizeof(uint16_t)) - return -EINVAL; + start_pc = &bytecode->data[0]; + for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; + pc = next_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; - /* Lookup event by name */ - desc = event->desc; - if (!desc) - return -EINVAL; - fields = desc->fields; - if (!fields) - return -EINVAL; - nr_fields = desc->nr_fields; - for (i = 0; i < nr_fields; i++) { + 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: + { + 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); + break; + } + + + /* unary */ + case FILTER_OP_UNARY_PLUS: + { + 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_S64: + insn->op = FILTER_OP_UNARY_PLUS_S64; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_UNARY_PLUS_DOUBLE; + break; + } + break; + } + + case FILTER_OP_UNARY_MINUS: + { + 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_S64: + insn->op = FILTER_OP_UNARY_MINUS_S64; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_UNARY_MINUS_DOUBLE; + break; + } + break; + } + + case FILTER_OP_UNARY_NOT: + { + 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_S64: + insn->op = FILTER_OP_UNARY_NOT_S64; + break; + case REG_DOUBLE: + insn->op = FILTER_OP_UNARY_NOT_DOUBLE; + break; + } + break; + } + + 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: + { + next_pc += sizeof(struct unary_op); + break; + } + + /* logical */ + case FILTER_OP_AND: + case FILTER_OP_OR: + { + next_pc += sizeof(struct logical_op); + break; + } + + /* load */ + case FILTER_OP_LOAD_FIELD_REF: + { + ERR("Unknown field ref type\n"); + ret = -EINVAL; + goto end; + } + case FILTER_OP_LOAD_FIELD_REF_STRING: + case FILTER_OP_LOAD_FIELD_REF_SEQUENCE: + { + struct load_op *insn = (struct load_op *) pc; + + reg[insn->reg].type = REG_STRING; + reg[insn->reg].literal = 0; + next_pc += sizeof(struct load_op) + sizeof(struct field_ref); + break; + } + case FILTER_OP_LOAD_FIELD_REF_S64: + { + struct load_op *insn = (struct load_op *) pc; + + reg[insn->reg].type = REG_S64; + reg[insn->reg].literal = 0; + next_pc += sizeof(struct load_op) + sizeof(struct field_ref); + break; + } + case FILTER_OP_LOAD_FIELD_REF_DOUBLE: + { + struct load_op *insn = (struct load_op *) pc; + + reg[insn->reg].type = REG_DOUBLE; + reg[insn->reg].literal = 0; + next_pc += sizeof(struct load_op) + sizeof(struct field_ref); + break; + } + + case FILTER_OP_LOAD_STRING: + { + struct load_op *insn = (struct load_op *) pc; + + 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; + + reg[insn->reg].type = REG_S64; + reg[insn->reg].literal = 1; + next_pc += sizeof(struct load_op) + + sizeof(struct literal_numeric); + break; + } + + case FILTER_OP_LOAD_DOUBLE: + { + struct load_op *insn = (struct load_op *) pc; + + reg[insn->reg].type = REG_DOUBLE; + reg[insn->reg].literal = 1; + 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, + uint32_t runtime_len, + uint32_t reloc_offset, + const char *field_name) +{ + const struct lttng_event_desc *desc; + 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); + + /* Ensure that the reloc is within the code */ + if (runtime_len - reloc_offset < sizeof(uint16_t)) + return -EINVAL; + + /* Lookup event by name */ + desc = event->desc; + if (!desc) + return -EINVAL; + fields = desc->fields; + if (!fields) + return -EINVAL; + nr_fields = desc->nr_fields; + for (i = 0; i < nr_fields; i++) { if (!strcmp(fields[i].name, field_name)) { field = &fields[i]; break; @@ -1231,6 +1637,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;