From 0305960f8200d1db7002b75d9a5c3ea37541e2c5 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 16 Jul 2012 17:56:31 -0400 Subject: [PATCH] Filter: Implement stack-based interpreter Signed-off-by: Mathieu Desnoyers --- liblttng-ust/filter-bytecode.h | 9 - liblttng-ust/lttng-filter-interpreter.c | 308 +++++++++++++++--------- liblttng-ust/lttng-filter-specialize.c | 149 +++++++----- liblttng-ust/lttng-filter-validator.c | 279 ++++++++++----------- liblttng-ust/lttng-filter.h | 122 ++++++++-- 5 files changed, 534 insertions(+), 333 deletions(-) diff --git a/liblttng-ust/filter-bytecode.h b/liblttng-ust/filter-bytecode.h index 38c5d51c..50a60c69 100644 --- a/liblttng-ust/filter-bytecode.h +++ b/liblttng-ust/filter-bytecode.h @@ -28,12 +28,6 @@ * offsets are absolute from start of bytecode. */ -enum filter_register { - REG_R0 = 0, - REG_R1 = 1, - REG_ERROR, -}; - struct field_ref { /* Initially, symbol offset. After link, field offset. */ uint16_t offset; @@ -138,7 +132,6 @@ typedef uint8_t filter_opcode_t; struct load_op { filter_opcode_t op; - uint8_t reg; /* enum filter_register */ char data[0]; /* data to load. Size known by enum filter_opcode and null-term char. */ } __attribute__((packed)); @@ -149,7 +142,6 @@ struct binary_op { struct unary_op { filter_opcode_t op; - uint8_t reg; /* enum filter_register */ } __attribute__((packed)); /* skip_offset is absolute from start of bytecode */ @@ -160,7 +152,6 @@ struct logical_op { struct cast_op { filter_opcode_t op; - uint8_t reg; /* enum filter_register */ } __attribute__((packed)); struct return_op { diff --git a/liblttng-ust/lttng-filter-interpreter.c b/liblttng-ust/lttng-filter-interpreter.c index ee3f4a34..2982e52c 100644 --- a/liblttng-ust/lttng-filter-interpreter.c +++ b/liblttng-ust/lttng-filter-interpreter.c @@ -49,30 +49,30 @@ int parse_char(const char **p) } static -int reg_strcmp(struct reg reg[NR_REG], const char *cmp_type) +int stack_strcmp(struct estack *stack, const char *cmp_type) { - const char *p = reg[REG_R0].str, *q = reg[REG_R1].str; + const char *p = estack_bx(stack)->u.s.str, *q = estack_ax(stack)->u.s.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') + if (unlikely(p - estack_bx(stack)->u.s.str > estack_bx(stack)->u.s.seq_len || *p == '\0')) { + if (q - estack_ax(stack)->u.s.str > estack_ax(stack)->u.s.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') + if (unlikely(q - estack_ax(stack)->u.s.str > estack_ax(stack)->u.s.seq_len || *q == '\0')) { + if (p - estack_bx(stack)->u.s.str > estack_bx(stack)->u.s.seq_len || *p == '\0') diff = 0; else diff = 1; break; } - if (reg[REG_R0].literal) { + if (estack_bx(stack)->u.s.literal) { ret = parse_char(&p); if (ret == -1) { return 0; @@ -81,7 +81,7 @@ int reg_strcmp(struct reg reg[NR_REG], const char *cmp_type) } /* else compare both char */ } - if (reg[REG_R1].literal) { + if (estack_ax(stack)->u.s.literal) { ret = parse_char(&q); if (ret == -1) { return 0; @@ -164,7 +164,8 @@ int lttng_filter_interpret_bytecode(void *filter_data, void *pc, *next_pc, *start_pc; int ret = -EINVAL; int retval = 0; - struct reg reg[NR_REG]; + struct estack _stack; + struct estack *stack = &_stack; #ifndef INTERPRETER_USE_SWITCH static void *dispatch[NR_FILTER_OPS] = { [ FILTER_OP_UNKNOWN ] = &&LABEL_FILTER_OP_UNKNOWN, @@ -248,6 +249,8 @@ int lttng_filter_interpret_bytecode(void *filter_data, }; #endif /* #ifndef INTERPRETER_USE_SWITCH */ + estack_init(stack); + START_OP OP(FILTER_OP_UNKNOWN): @@ -261,7 +264,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, goto end; OP(FILTER_OP_RETURN): - retval = !!reg[0].v; + retval = !!estack_ax(stack)->u.v; ret = 0; goto end; @@ -294,153 +297,225 @@ int lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_EQ_STRING): { - reg[REG_R0].v = (reg_strcmp(reg, "==") == 0); - reg[REG_R0].type = REG_S64; + int res; + + res = (stack_strcmp(stack, "==") == 0); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); PO; } OP(FILTER_OP_NE_STRING): { - reg[REG_R0].v = (reg_strcmp(reg, "!=") != 0); - reg[REG_R0].type = REG_S64; + int res; + + res = (stack_strcmp(stack, "!=") != 0); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); PO; } OP(FILTER_OP_GT_STRING): { - reg[REG_R0].v = (reg_strcmp(reg, ">") > 0); - reg[REG_R0].type = REG_S64; + int res; + + res = (stack_strcmp(stack, ">") > 0); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); PO; } OP(FILTER_OP_LT_STRING): { - reg[REG_R0].v = (reg_strcmp(reg, "<") < 0); - reg[REG_R0].type = REG_S64; + int res; + + res = (stack_strcmp(stack, "<") < 0); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); PO; } OP(FILTER_OP_GE_STRING): { - reg[REG_R0].v = (reg_strcmp(reg, ">=") >= 0); - reg[REG_R0].type = REG_S64; + int res; + + res = (stack_strcmp(stack, ">=") >= 0); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); PO; } OP(FILTER_OP_LE_STRING): { - reg[REG_R0].v = (reg_strcmp(reg, "<=") <= 0); - reg[REG_R0].type = REG_S64; + int res; + + res = (stack_strcmp(stack, "<=") <= 0); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); PO; } OP(FILTER_OP_EQ_S64): { - reg[REG_R0].v = (reg[REG_R0].v == reg[REG_R1].v); - reg[REG_R0].type = REG_S64; + int res; + + res = (estack_bx(stack)->u.v == estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->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; + int res; + + res = (estack_bx(stack)->u.v != estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->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; + int res; + + res = (estack_bx(stack)->u.v > estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->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; + int res; + + res = (estack_bx(stack)->u.v < estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->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; + int res; + + res = (estack_bx(stack)->u.v >= estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->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; + int res; + + res = (estack_bx(stack)->u.v <= estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); PO; } 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; + int res; + + if (unlikely(estack_ax(stack)->type == REG_S64)) + estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; + else if (unlikely(estack_bx(stack)->type == REG_S64)) + estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; + res = (estack_bx(stack)->u.v == estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); 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; + int res; + + if (unlikely(estack_ax(stack)->type == REG_S64)) + estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; + else if (unlikely(estack_bx(stack)->type == REG_S64)) + estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; + res = (estack_bx(stack)->u.v != estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->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; + int res; + + if (unlikely(estack_ax(stack)->type == REG_S64)) + estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; + else if (unlikely(estack_bx(stack)->type == REG_S64)) + estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; + res = (estack_bx(stack)->u.v > estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->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; + int res; + + if (unlikely(estack_ax(stack)->type == REG_S64)) + estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; + else if (unlikely(estack_bx(stack)->type == REG_S64)) + estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; + res = (estack_bx(stack)->u.v < estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->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; + int res; + + if (unlikely(estack_ax(stack)->type == REG_S64)) + estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; + else if (unlikely(estack_bx(stack)->type == REG_S64)) + estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; + res = (estack_bx(stack)->u.v >= estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->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; + int res; + + if (unlikely(estack_ax(stack)->type == REG_S64)) + estack_ax(stack)->u.d = (double) estack_ax(stack)->u.v; + else if (unlikely(estack_bx(stack)->type == REG_S64)) + estack_bx(stack)->u.d = (double) estack_bx(stack)->u.v; + res = (estack_bx(stack)->u.v <= estack_ax(stack)->u.v); + estack_pop(stack); + estack_ax(stack)->u.v = res; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -463,33 +538,25 @@ int lttng_filter_interpret_bytecode(void *filter_data, } OP(FILTER_OP_UNARY_MINUS_S64): { - struct unary_op *insn = (struct unary_op *) pc; - - reg[insn->reg].v = -reg[insn->reg].v; + estack_ax(stack)->u.v = -estack_ax(stack)->u.v; next_pc += sizeof(struct unary_op); PO; } OP(FILTER_OP_UNARY_MINUS_DOUBLE): { - struct unary_op *insn = (struct unary_op *) pc; - - reg[insn->reg].d = -reg[insn->reg].d; + estack_ax(stack)->u.d = -estack_ax(stack)->u.d; next_pc += sizeof(struct unary_op); PO; } OP(FILTER_OP_UNARY_NOT_S64): { - struct unary_op *insn = (struct unary_op *) pc; - - reg[insn->reg].v = !reg[insn->reg].v; + estack_ax(stack)->u.v = !estack_ax(stack)->u.v; next_pc += sizeof(struct unary_op); PO; } OP(FILTER_OP_UNARY_NOT_DOUBLE): { - struct unary_op *insn = (struct unary_op *) pc; - - reg[insn->reg].d = !reg[insn->reg].d; + estack_ax(stack)->u.d = !estack_ax(stack)->u.d; next_pc += sizeof(struct unary_op); PO; } @@ -499,8 +566,8 @@ int lttng_filter_interpret_bytecode(void *filter_data, { struct logical_op *insn = (struct logical_op *) pc; - /* If REG_R0 is 0, skip and evaluate to 0 */ - if (unlikely(reg[REG_R0].v == 0)) { + /* If AX is 0, skip and evaluate to 0 */ + if (unlikely(estack_ax(stack)->u.v == 0)) { dbg_printf("Jumping to bytecode offset %u\n", (unsigned int) insn->skip_offset); next_pc = start_pc + insn->skip_offset; @@ -513,10 +580,10 @@ int lttng_filter_interpret_bytecode(void *filter_data, { struct logical_op *insn = (struct logical_op *) pc; - /* If REG_R0 is nonzero, skip and evaluate to 1 */ + /* If AX is nonzero, skip and evaluate to 1 */ - if (unlikely(reg[REG_R0].v != 0)) { - reg[REG_R0].v = 1; + if (unlikely(estack_ax(stack)->u.v != 0)) { + estack_ax(stack)->u.v = 1; dbg_printf("Jumping to bytecode offset %u\n", (unsigned int) insn->skip_offset); next_pc = start_pc + insn->skip_offset; @@ -535,17 +602,18 @@ int lttng_filter_interpret_bytecode(void *filter_data, dbg_printf("load field ref offset %u type string\n", ref->offset); - reg[insn->reg].str = + estack_push(stack); + estack_ax(stack)->u.s.str = *(const char * const *) &filter_stack_data[ref->offset]; - if (unlikely(!reg[insn->reg].str)) { + if (unlikely(!estack_ax(stack)->u.s.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); + estack_ax(stack)->type = REG_STRING; + estack_ax(stack)->u.s.seq_len = UINT_MAX; + estack_ax(stack)->u.s.literal = 0; + dbg_printf("ref load string %s\n", estack_ax(stack)->u.s.str); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; } @@ -557,18 +625,19 @@ int lttng_filter_interpret_bytecode(void *filter_data, dbg_printf("load field ref offset %u type sequence\n", ref->offset); - reg[insn->reg].seq_len = + estack_push(stack); + estack_ax(stack)->u.s.seq_len = *(unsigned long *) &filter_stack_data[ref->offset]; - reg[insn->reg].str = + estack_ax(stack)->u.s.str = *(const char **) (&filter_stack_data[ref->offset + sizeof(unsigned long)]); - if (unlikely(!reg[insn->reg].str)) { + if (unlikely(!estack_ax(stack)->u.s.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; + estack_ax(stack)->type = REG_STRING; + estack_ax(stack)->u.s.literal = 0; next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; } @@ -580,10 +649,11 @@ int lttng_filter_interpret_bytecode(void *filter_data, dbg_printf("load field ref offset %u type s64\n", ref->offset); - memcpy(®[insn->reg].v, &filter_stack_data[ref->offset], + estack_push(stack); + memcpy(&estack_ax(stack)->u.v, &filter_stack_data[ref->offset], sizeof(struct literal_numeric)); - reg[insn->reg].type = REG_S64; - dbg_printf("ref load s64 %" PRIi64 "\n", reg[insn->reg].v); + estack_ax(stack)->type = REG_S64; + dbg_printf("ref load s64 %" PRIi64 "\n", estack_ax(stack)->u.v); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; } @@ -595,10 +665,11 @@ int lttng_filter_interpret_bytecode(void *filter_data, dbg_printf("load field ref offset %u type double\n", ref->offset); - memcpy(®[insn->reg].d, &filter_stack_data[ref->offset], + estack_push(stack); + memcpy(&estack_ax(stack)->u.d, &filter_stack_data[ref->offset], sizeof(struct literal_double)); - reg[insn->reg].type = REG_DOUBLE; - dbg_printf("ref load double %g\n", reg[insn->reg].d); + estack_ax(stack)->type = REG_DOUBLE; + dbg_printf("ref load double %g\n", estack_ax(stack)->u.d); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; } @@ -608,10 +679,11 @@ int lttng_filter_interpret_bytecode(void *filter_data, struct load_op *insn = (struct load_op *) pc; 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; + estack_push(stack); + estack_ax(stack)->type = REG_STRING; + estack_ax(stack)->u.s.str = insn->data; + estack_ax(stack)->u.s.seq_len = UINT_MAX; + estack_ax(stack)->u.s.literal = 1; next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; PO; } @@ -620,10 +692,11 @@ int lttng_filter_interpret_bytecode(void *filter_data, { struct load_op *insn = (struct load_op *) pc; - memcpy(®[insn->reg].v, insn->data, + estack_push(stack); + memcpy(&estack_ax(stack)->u.v, insn->data, sizeof(struct literal_numeric)); - dbg_printf("load s64 %" PRIi64 "\n", reg[insn->reg].v); - reg[insn->reg].type = REG_S64; + dbg_printf("load s64 %" PRIi64 "\n", estack_ax(stack)->u.v); + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct load_op) + sizeof(struct literal_numeric); PO; @@ -633,10 +706,11 @@ int lttng_filter_interpret_bytecode(void *filter_data, { struct load_op *insn = (struct load_op *) pc; - memcpy(®[insn->reg].d, insn->data, + estack_push(stack); + memcpy(&estack_ax(stack)->u.d, insn->data, sizeof(struct literal_double)); - dbg_printf("load s64 %g\n", reg[insn->reg].d); - reg[insn->reg].type = REG_DOUBLE; + dbg_printf("load s64 %g\n", estack_ax(stack)->u.d); + estack_ax(stack)->type = REG_DOUBLE; next_pc += sizeof(struct load_op) + sizeof(struct literal_double); PO; @@ -651,10 +725,8 @@ int lttng_filter_interpret_bytecode(void *filter_data, 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; + estack_ax(stack)->u.v = (int64_t) estack_ax(stack)->u.d; + estack_ax(stack)->type = REG_S64; next_pc += sizeof(struct cast_op); PO; } diff --git a/liblttng-ust/lttng-filter-specialize.c b/liblttng-ust/lttng-filter-specialize.c index fc350fd6..ef0d811b 100644 --- a/liblttng-ust/lttng-filter-specialize.c +++ b/liblttng-ust/lttng-filter-specialize.c @@ -26,13 +26,10 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { void *pc, *next_pc, *start_pc; int ret = -EINVAL; - struct vreg reg[NR_REG]; - int i; + struct vstack _stack; + struct vstack *stack = &_stack; - for (i = 0; i < NR_REG; i++) { - reg[i].type = REG_TYPE_UNKNOWN; - reg[i].literal = 0; - } + vstack_init(stack); start_pc = &bytecode->data[0]; for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; @@ -69,7 +66,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct binary_op *insn = (struct binary_op *) pc; - switch(reg[REG_R0].type) { + switch(vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -79,7 +76,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_EQ_STRING; break; case REG_S64: - if (reg[REG_R1].type == REG_S64) + if (vstack_bx(stack)->type == REG_S64) insn->op = FILTER_OP_EQ_S64; else insn->op = FILTER_OP_EQ_DOUBLE; @@ -88,7 +85,12 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_EQ_DOUBLE; break; } - reg[REG_R0].type = REG_S64; + /* Pop 2, push 1 */ + if (vstack_pop(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); break; } @@ -97,7 +99,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct binary_op *insn = (struct binary_op *) pc; - switch(reg[REG_R0].type) { + switch(vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -107,7 +109,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_NE_STRING; break; case REG_S64: - if (reg[REG_R1].type == REG_S64) + if (vstack_bx(stack)->type == REG_S64) insn->op = FILTER_OP_NE_S64; else insn->op = FILTER_OP_NE_DOUBLE; @@ -116,7 +118,12 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_NE_DOUBLE; break; } - reg[REG_R0].type = REG_S64; + /* Pop 2, push 1 */ + if (vstack_pop(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); break; } @@ -125,7 +132,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct binary_op *insn = (struct binary_op *) pc; - switch(reg[REG_R0].type) { + switch(vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -135,7 +142,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_GT_STRING; break; case REG_S64: - if (reg[REG_R1].type == REG_S64) + if (vstack_bx(stack)->type == REG_S64) insn->op = FILTER_OP_GT_S64; else insn->op = FILTER_OP_GT_DOUBLE; @@ -144,7 +151,12 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_GT_DOUBLE; break; } - reg[REG_R0].type = REG_S64; + /* Pop 2, push 1 */ + if (vstack_pop(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); break; } @@ -153,7 +165,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct binary_op *insn = (struct binary_op *) pc; - switch(reg[REG_R0].type) { + switch(vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -163,7 +175,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_LT_STRING; break; case REG_S64: - if (reg[REG_R1].type == REG_S64) + if (vstack_bx(stack)->type == REG_S64) insn->op = FILTER_OP_LT_S64; else insn->op = FILTER_OP_LT_DOUBLE; @@ -172,7 +184,12 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_LT_DOUBLE; break; } - reg[REG_R0].type = REG_S64; + /* Pop 2, push 1 */ + if (vstack_pop(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); break; } @@ -181,7 +198,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct binary_op *insn = (struct binary_op *) pc; - switch(reg[REG_R0].type) { + switch(vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -191,7 +208,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_GE_STRING; break; case REG_S64: - if (reg[REG_R1].type == REG_S64) + if (vstack_bx(stack)->type == REG_S64) insn->op = FILTER_OP_GE_S64; else insn->op = FILTER_OP_GE_DOUBLE; @@ -200,7 +217,12 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_GE_DOUBLE; break; } - reg[REG_R0].type = REG_S64; + /* Pop 2, push 1 */ + if (vstack_pop(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); break; } @@ -208,7 +230,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct binary_op *insn = (struct binary_op *) pc; - switch(reg[REG_R0].type) { + switch(vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -218,7 +240,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_LE_STRING; break; case REG_S64: - if (reg[REG_R1].type == REG_S64) + if (vstack_bx(stack)->type == REG_S64) insn->op = FILTER_OP_LE_S64; else insn->op = FILTER_OP_LE_DOUBLE; @@ -227,7 +249,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_LE_DOUBLE; break; } - reg[REG_R0].type = REG_S64; + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); break; } @@ -251,7 +273,12 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) case FILTER_OP_GE_DOUBLE: case FILTER_OP_LE_DOUBLE: { - reg[REG_R0].type = REG_S64; + /* Pop 2, push 1 */ + if (vstack_pop(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); break; } @@ -261,7 +288,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct unary_op *insn = (struct unary_op *) pc; - switch(reg[insn->reg].type) { + switch(vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -274,6 +301,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_UNARY_PLUS_DOUBLE; break; } + /* Pop 1, push 1 */ next_pc += sizeof(struct unary_op); break; } @@ -282,7 +310,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct unary_op *insn = (struct unary_op *) pc; - switch(reg[insn->reg].type) { + switch(vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -295,6 +323,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_UNARY_MINUS_DOUBLE; break; } + /* Pop 1, push 1 */ next_pc += sizeof(struct unary_op); break; } @@ -303,7 +332,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct unary_op *insn = (struct unary_op *) pc; - switch(reg[insn->reg].type) { + switch(vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -316,6 +345,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_UNARY_NOT_DOUBLE; break; } + /* Pop 1, push 1 */ next_pc += sizeof(struct unary_op); break; } @@ -327,6 +357,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) case FILTER_OP_UNARY_MINUS_DOUBLE: case FILTER_OP_UNARY_NOT_DOUBLE: { + /* Pop 1, push 1 */ next_pc += sizeof(struct unary_op); break; } @@ -349,28 +380,31 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) 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; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_STRING; 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; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; 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; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_DOUBLE; next_pc += sizeof(struct load_op) + sizeof(struct field_ref); break; } @@ -379,18 +413,22 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct load_op *insn = (struct load_op *) pc; - reg[insn->reg].type = REG_STRING; - reg[insn->reg].literal = 1; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_STRING; 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; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct load_op) + sizeof(struct literal_numeric); break; @@ -398,10 +436,11 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) case FILTER_OP_LOAD_DOUBLE: { - struct load_op *insn = (struct load_op *) pc; - - reg[insn->reg].type = REG_DOUBLE; - reg[insn->reg].literal = 1; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_DOUBLE; next_pc += sizeof(struct load_op) + sizeof(struct literal_double); break; @@ -412,7 +451,7 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) { struct cast_op *insn = (struct cast_op *) pc; - switch (reg[insn->reg].type) { + switch (vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -429,15 +468,15 @@ int lttng_filter_specialize_bytecode(struct bytecode_runtime *bytecode) insn->op = FILTER_OP_CAST_DOUBLE_TO_S64; break; } - reg[insn->reg].type = REG_S64; + /* Pop 1, push 1 */ + vstack_ax(stack)->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; + /* Pop 1, push 1 */ + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct cast_op); break; } diff --git a/liblttng-ust/lttng-filter-validator.c b/liblttng-ust/lttng-filter-validator.c index 0f7d8bf8..239bda2f 100644 --- a/liblttng-ust/lttng-filter-validator.c +++ b/liblttng-ust/lttng-filter-validator.c @@ -28,12 +28,22 @@ #include #include "lttng-hash-helper.h" +/* + * Number of merge points for hash table size. Hash table initialized to + * that size, and we do not resize, because we do not want to trigger + * RCU worker thread execution: fall-back on linear traversal if number + * of merge points exceeds this value. + */ +#define DEFAULT_NR_MERGE_POINTS 128 +#define MIN_NR_BUCKETS 128 +#define MAX_NR_BUCKETS 128 + /* merge point table node */ struct lfht_mp_node { struct cds_lfht_node node; /* Context at merge point */ - struct vreg reg[NR_REG]; + struct vstack stack; unsigned long target_pc; }; @@ -55,7 +65,7 @@ int lttng_hash_match(struct cds_lfht_node *node, const void *key) static int merge_point_add(struct cds_lfht *ht, unsigned long target_pc, - const struct vreg reg[NR_REG]) + const struct vstack *stack) { struct lfht_mp_node *node; unsigned long hash = lttng_hash_mix((const void *) target_pc, @@ -68,30 +78,26 @@ int merge_point_add(struct cds_lfht *ht, unsigned long target_pc, if (!node) return -ENOMEM; node->target_pc = target_pc; - memcpy(node->reg, reg, sizeof(node->reg)); + memcpy(&node->stack, stack, sizeof(node->stack)); cds_lfht_add(ht, hash, &node->node); return 0; } /* - * Number of merge points for hash table size. Hash table initialized to - * that size, and we do not resize, because we do not want to trigger - * RCU worker thread execution: fall-back on linear traversal if number - * of merge points exceeds this value. + * Binary comparators use top of stack and top of stack -1. */ -#define DEFAULT_NR_MERGE_POINTS 128 -#define MIN_NR_BUCKETS 128 -#define MAX_NR_BUCKETS 128 - static -int bin_op_compare_check(const struct vreg reg[NR_REG], const char *str) +int bin_op_compare_check(struct vstack *stack, const char *str) { - switch (reg[REG_R0].type) { + if (unlikely(!vstack_ax(stack) || !vstack_bx(stack))) + goto error_unknown; + + switch (vstack_ax(stack)->type) { default: goto error_unknown; case REG_STRING: - switch (reg[REG_R1].type) { + switch (vstack_bx(stack)->type) { default: goto error_unknown; @@ -104,7 +110,7 @@ int bin_op_compare_check(const struct vreg reg[NR_REG], const char *str) break; case REG_S64: case REG_DOUBLE: - switch (reg[REG_R1].type) { + switch (vstack_bx(stack)->type) { default: goto error_unknown; @@ -120,8 +126,8 @@ int bin_op_compare_check(const struct vreg reg[NR_REG], const char *str) return 0; error_unknown: - return -EINVAL; + error_mismatch: ERR("type mismatch for '%s' binary operator\n", str); return -EINVAL; @@ -333,7 +339,7 @@ unsigned long delete_all_nodes(struct cds_lfht *ht) */ static int validate_instruction_context(struct bytecode_runtime *bytecode, - const struct vreg reg[NR_REG], + struct vstack *stack, void *start_pc, void *pc) { @@ -374,42 +380,42 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, case FILTER_OP_EQ: { - ret = bin_op_compare_check(reg, "=="); + ret = bin_op_compare_check(stack, "=="); if (ret) goto end; break; } case FILTER_OP_NE: { - ret = bin_op_compare_check(reg, "!="); + ret = bin_op_compare_check(stack, "!="); if (ret) goto end; break; } case FILTER_OP_GT: { - ret = bin_op_compare_check(reg, ">"); + ret = bin_op_compare_check(stack, ">"); if (ret) goto end; break; } case FILTER_OP_LT: { - ret = bin_op_compare_check(reg, "<"); + ret = bin_op_compare_check(stack, "<"); if (ret) goto end; break; } case FILTER_OP_GE: { - ret = bin_op_compare_check(reg, ">="); + ret = bin_op_compare_check(stack, ">="); if (ret) goto end; break; } case FILTER_OP_LE: { - ret = bin_op_compare_check(reg, "<="); + ret = bin_op_compare_check(stack, "<="); if (ret) goto end; break; @@ -422,8 +428,13 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, case FILTER_OP_GE_STRING: case FILTER_OP_LE_STRING: { - if (reg[REG_R0].type != REG_STRING - || reg[REG_R1].type != REG_STRING) { + if (!vstack_ax(stack) || !vstack_bx(stack)) { + ERR("Empty stack\n"); + ret = -EINVAL; + goto end; + } + if (vstack_ax(stack)->type != REG_STRING + || vstack_bx(stack)->type != REG_STRING) { ERR("Unexpected register type for string comparator\n"); ret = -EINVAL; goto end; @@ -438,8 +449,13 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, case FILTER_OP_GE_S64: case FILTER_OP_LE_S64: { - if (reg[REG_R0].type != REG_S64 - || reg[REG_R1].type != REG_S64) { + if (!vstack_ax(stack) || !vstack_bx(stack)) { + ERR("Empty stack\n"); + ret = -EINVAL; + goto end; + } + if (vstack_ax(stack)->type != REG_S64 + || vstack_bx(stack)->type != REG_S64) { ERR("Unexpected register type for s64 comparator\n"); ret = -EINVAL; goto end; @@ -454,13 +470,18 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, 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)) { + if (!vstack_ax(stack) || !vstack_bx(stack)) { + ERR("Empty stack\n"); + ret = -EINVAL; + goto end; + } + if ((vstack_ax(stack)->type != REG_DOUBLE && vstack_ax(stack)->type != REG_S64) + || (vstack_bx(stack)-> type != REG_DOUBLE && vstack_bx(stack)->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) { + if (vstack_ax(stack)->type != REG_DOUBLE && vstack_bx(stack)->type != REG_DOUBLE) { ERR("Double operator should have at least one double register\n"); ret = -EINVAL; goto end; @@ -473,15 +494,12 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, 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); + if (!vstack_ax(stack)) { + ERR("Empty stack\n"); ret = -EINVAL; goto end; } - switch (reg[insn->reg].type) { + switch (vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -503,15 +521,12 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, 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); + if (!vstack_ax(stack)) { + ERR("Empty stack\n"); ret = -EINVAL; goto end; } - if (reg[insn->reg].type != REG_S64) { + if (vstack_ax(stack)->type != REG_S64) { ERR("Invalid register type\n"); ret = -EINVAL; goto end; @@ -523,15 +538,12 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, 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); + if (!vstack_ax(stack)) { + ERR("Empty stack\n"); ret = -EINVAL; goto end; } - if (reg[insn->reg].type != REG_DOUBLE) { + if (vstack_ax(stack)->type != REG_DOUBLE) { ERR("Invalid register type\n"); ret = -EINVAL; goto end; @@ -545,7 +557,12 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, { struct logical_op *insn = (struct logical_op *) pc; - if (reg[REG_R0].type != REG_S64) { + if (!vstack_ax(stack)) { + ERR("Empty stack\n"); + ret = -EINVAL; + goto end; + } + if (vstack_ax(stack)->type != REG_S64) { ERR("Logical comparator expects S64 register\n"); ret = -EINVAL; goto end; @@ -574,12 +591,6 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, 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 string\n", ref->offset); break; @@ -589,12 +600,6 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, 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 s64\n", ref->offset); break; @@ -604,12 +609,6 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, 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 double\n", ref->offset); break; @@ -617,40 +616,16 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, 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; - } 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; - } 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; - } break; } @@ -659,13 +634,12 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, { struct cast_op *insn = (struct cast_op *) pc; - if (unlikely(insn->reg >= REG_ERROR)) { - ERR("invalid register %u\n", - (unsigned int) insn->reg); + if (!vstack_ax(stack)) { + ERR("Empty stack\n"); ret = -EINVAL; goto end; } - switch (reg[insn->reg].type) { + switch (vstack_ax(stack)->type) { default: ERR("unknown register type\n"); ret = -EINVAL; @@ -681,7 +655,7 @@ int validate_instruction_context(struct bytecode_runtime *bytecode, break; } if (insn->op == FILTER_OP_CAST_DOUBLE_TO_S64) { - if (reg[insn->reg].type != REG_DOUBLE) { + if (vstack_ax(stack)->type != REG_DOUBLE) { ERR("Cast expects double\n"); ret = -EINVAL; goto end; @@ -707,7 +681,7 @@ end: static int validate_instruction_all_contexts(struct bytecode_runtime *bytecode, struct cds_lfht *merge_points, - const struct vreg reg[NR_REG], + struct vstack *stack, void *start_pc, void *pc) { @@ -718,7 +692,7 @@ int validate_instruction_all_contexts(struct bytecode_runtime *bytecode, unsigned long hash; /* Validate the context resulting from the previous instruction */ - ret = validate_instruction_context(bytecode, reg, start_pc, pc); + ret = validate_instruction_context(bytecode, stack, start_pc, pc); if (ret) return ret; @@ -732,7 +706,7 @@ int validate_instruction_all_contexts(struct bytecode_runtime *bytecode, dbg_printf("Filter: validate merge point at offset %lu\n", target_pc); - ret = validate_instruction_context(bytecode, mp_node->reg, + ret = validate_instruction_context(bytecode, &mp_node->stack, start_pc, pc); if (ret) return ret; @@ -754,7 +728,7 @@ int validate_instruction_all_contexts(struct bytecode_runtime *bytecode, static int exec_insn(struct bytecode_runtime *bytecode, struct cds_lfht *merge_points, - struct vreg reg[NR_REG], + struct vstack *stack, void **_next_pc, void *pc) { @@ -820,7 +794,17 @@ int exec_insn(struct bytecode_runtime *bytecode, case FILTER_OP_GE_DOUBLE: case FILTER_OP_LE_DOUBLE: { - reg[REG_R0].type = REG_S64; + /* Pop 2, push 1 */ + if (vstack_pop(stack)) { + ret = -EINVAL; + goto end; + } + if (!vstack_ax(stack)) { + ERR("Empty stack\n"); + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct binary_op); break; } @@ -833,7 +817,13 @@ int exec_insn(struct bytecode_runtime *bytecode, case FILTER_OP_UNARY_MINUS_S64: case FILTER_OP_UNARY_NOT_S64: { - reg[REG_R0].type = REG_S64; + /* Pop 1, push 1 */ + if (!vstack_ax(stack)) { + ERR("Empty stack\n"); + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct unary_op); break; } @@ -842,7 +832,13 @@ int exec_insn(struct bytecode_runtime *bytecode, case FILTER_OP_UNARY_MINUS_DOUBLE: case FILTER_OP_UNARY_NOT_DOUBLE: { - reg[REG_R0].type = REG_DOUBLE; + /* Pop 1, push 1 */ + if (!vstack_ax(stack)) { + ERR("Empty stack\n"); + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_DOUBLE; next_pc += sizeof(struct unary_op); break; } @@ -855,7 +851,8 @@ int exec_insn(struct bytecode_runtime *bytecode, int merge_ret; /* Add merge point to table */ - merge_ret = merge_point_add(merge_points, insn->skip_offset, reg); + merge_ret = merge_point_add(merge_points, insn->skip_offset, + stack); if (merge_ret) { ret = merge_ret; goto end; @@ -875,28 +872,31 @@ int exec_insn(struct bytecode_runtime *bytecode, 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; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_STRING; 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; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; 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; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_DOUBLE; next_pc += sizeof(struct load_op) + sizeof(struct field_ref); break; } @@ -905,18 +905,22 @@ int exec_insn(struct bytecode_runtime *bytecode, { struct load_op *insn = (struct load_op *) pc; - reg[insn->reg].type = REG_STRING; - reg[insn->reg].literal = 1; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_STRING; 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; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct load_op) + sizeof(struct literal_numeric); break; @@ -924,10 +928,11 @@ int exec_insn(struct bytecode_runtime *bytecode, case FILTER_OP_LOAD_DOUBLE: { - struct load_op *insn = (struct load_op *) pc; - - reg[insn->reg].type = REG_DOUBLE; - reg[insn->reg].literal = 1; + if (vstack_push(stack)) { + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_DOUBLE; next_pc += sizeof(struct load_op) + sizeof(struct literal_double); break; @@ -936,9 +941,13 @@ int exec_insn(struct bytecode_runtime *bytecode, case FILTER_OP_CAST_TO_S64: case FILTER_OP_CAST_DOUBLE_TO_S64: { - struct cast_op *insn = (struct cast_op *) pc; - - reg[insn->reg].type = REG_S64; + /* Pop 1, push 1 */ + if (!vstack_ax(stack)) { + ERR("Empty stack\n"); + ret = -EINVAL; + goto end; + } + vstack_ax(stack)->type = REG_S64; next_pc += sizeof(struct cast_op); break; } @@ -962,13 +971,9 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) struct cds_lfht *merge_points; void *pc, *next_pc, *start_pc; int ret = -EINVAL; - struct vreg reg[NR_REG]; - int i; + struct vstack stack; - for (i = 0; i < NR_REG; i++) { - reg[i].type = REG_TYPE_UNKNOWN; - reg[i].literal = 0; - } + vstack_init(&stack); if (!lttng_hash_seed_ready) { lttng_hash_seed = time(NULL); @@ -1005,10 +1010,10 @@ int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) * all merge points targeting this instruction. */ ret = validate_instruction_all_contexts(bytecode, merge_points, - reg, start_pc, pc); + &stack, start_pc, pc); if (ret) goto end; - ret = exec_insn(bytecode, merge_points, reg, &next_pc, pc); + ret = exec_insn(bytecode, merge_points, &stack, &next_pc, pc); if (ret <= 0) goto end; } diff --git a/liblttng-ust/lttng-filter.h b/liblttng-ust/lttng-filter.h index 4ef1c757..5d22cca1 100644 --- a/liblttng-ust/lttng-filter.h +++ b/liblttng-ust/lttng-filter.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,8 @@ #include #include "filter-bytecode.h" -#define NR_REG 2 +/* Filter stack length, in number of entries */ +#define FILTER_STACK_LEN 8 #ifndef min_t #define min_t(type, a, b) \ @@ -67,30 +69,122 @@ struct bytecode_runtime { char data[0]; }; -enum reg_type { +enum entry_type { REG_S64, REG_DOUBLE, REG_STRING, REG_TYPE_UNKNOWN, }; -/* Validation registers */ -struct vreg { - enum reg_type type; - int literal; /* is string literal ? */ +/* Validation stack */ +struct vstack_entry { + enum entry_type type; }; -/* Execution registers */ -struct reg { - enum reg_type type; - int64_t v; - double d; +struct vstack { + int top; /* top of stack */ + struct vstack_entry e[FILTER_STACK_LEN]; +}; + +static inline +void vstack_init(struct vstack *stack) +{ + stack->top = -1; +} + +static inline +struct vstack_entry *vstack_ax(struct vstack *stack) +{ + if (unlikely(stack->top < 0)) + return NULL; + return &stack->e[stack->top]; +} + +static inline +struct vstack_entry *vstack_bx(struct vstack *stack) +{ + if (unlikely(stack->top < 1)) + return NULL; + return &stack->e[stack->top - 1]; +} + +static inline +int vstack_push(struct vstack *stack) +{ + if (stack->top >= FILTER_STACK_LEN - 1) { + ERR("Stack full\n"); + return -EINVAL; + } + ++stack->top; + return 0; +} + +static inline +int vstack_pop(struct vstack *stack) +{ + if (unlikely(stack->top < 0)) { + ERR("Stack empty\n"); + return -EINVAL; + } + stack->top--; + return 0; +} + +/* Execution stack */ +struct estack_entry { + enum entry_type type; + + union { + int64_t v; + double d; + + struct { + const char *str; + size_t seq_len; + int literal; /* is string literal ? */ + } s; + } u; +}; - const char *str; - size_t seq_len; - int literal; /* is string literal ? */ +struct estack { + int top; /* top of stack */ + struct estack_entry e[FILTER_STACK_LEN]; }; +static inline +void estack_init(struct estack *stack) +{ + stack->top = -1; +} + +static inline +struct estack_entry *estack_ax(struct estack *stack) +{ + assert(stack->top >= 0); + return &stack->e[stack->top]; +} + +static inline +struct estack_entry *estack_bx(struct estack *stack) +{ + assert(stack->top >= 1); + return &stack->e[stack->top - 1]; +} + +static inline +void estack_push(struct estack *stack) +{ + assert(stack->top < FILTER_STACK_LEN - 1); + ++stack->top; +} + +static inline +void estack_pop(struct estack *stack) +{ + assert(stack->top >= 0); + stack->top--; +} + const char *print_op(enum filter_op op); int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode); -- 2.34.1