X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=src%2Flttng-filter-interpreter.c;h=69db94940d961604f51cae2091a37441cc883ab7;hb=196e531f00db3dcc3faadb497ba677f4a52c4e87;hp=9599f9a672a300830eedb0bbefe2b591d9ce0602;hpb=5fae98f7a1c3fa7976c535237ea12709ae7acccf;p=lttng-modules.git diff --git a/src/lttng-filter-interpreter.c b/src/lttng-filter-interpreter.c index 9599f9a6..69db9494 100644 --- a/src/lttng-filter-interpreter.c +++ b/src/lttng-filter-interpreter.c @@ -8,15 +8,13 @@ */ #include -#include +#include #include #include #include #include -LTTNG_STACK_FRAME_NON_STANDARD(lttng_filter_interpret_bytecode); - /* * get_char should be called with page fault handler disabled if it is expected * to handle user-space read. @@ -81,16 +79,14 @@ static int stack_star_glob_match(struct estack *stack, int top, const char *cmp_type) { bool has_user = false; - mm_segment_t old_fs; int result; struct estack_entry *pattern_reg; struct estack_entry *candidate_reg; + /* Disable the page fault handler when reading from userspace. */ if (estack_bx(stack, top)->u.s.user || estack_ax(stack, top)->u.s.user) { has_user = true; - old_fs = get_fs(); - set_fs(KERNEL_DS); pagefault_disable(); } @@ -106,10 +102,8 @@ int stack_star_glob_match(struct estack *stack, int top, const char *cmp_type) /* Perform the match operation. */ result = !strutils_star_glob_match_char_cb(get_char_at_cb, pattern_reg, get_char_at_cb, candidate_reg); - if (has_user) { + if (has_user) pagefault_enable(); - set_fs(old_fs); - } return result; } @@ -119,13 +113,10 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) { size_t offset_bx = 0, offset_ax = 0; int diff, has_user = 0; - mm_segment_t old_fs; if (estack_bx(stack, top)->u.s.user || estack_ax(stack, top)->u.s.user) { has_user = 1; - old_fs = get_fs(); - set_fs(KERNEL_DS); pagefault_disable(); } @@ -210,18 +201,17 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) offset_bx++; offset_ax++; } - if (has_user) { + if (has_user) pagefault_enable(); - set_fs(old_fs); - } + return diff; } -uint64_t lttng_filter_false(void *filter_data, +uint64_t lttng_filter_interpret_bytecode_false(void *filter_data, struct lttng_probe_ctx *lttng_probe_ctx, const char *filter_stack_data) { - return 0; + return LTTNG_FILTER_DISCARD; } #ifdef INTERPRETER_USE_SWITCH @@ -234,7 +224,7 @@ uint64_t lttng_filter_false(void *filter_data, start_pc = &bytecode->data[0]; \ for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; \ pc = next_pc) { \ - dbg_printk("Executing op %s (%u)\n", \ + dbg_printk("LTTng: Executing op %s (%u)\n", \ lttng_filter_print_op((unsigned int) *(filter_opcode_t *) pc), \ (unsigned int) *(filter_opcode_t *) pc); \ switch (*(filter_opcode_t *) pc) { @@ -270,6 +260,9 @@ LABEL_##name #endif +#define IS_INTEGER_REGISTER(reg_type) \ + (reg_type == REG_S64 || reg_type == REG_U64) + static int context_get_index(struct lttng_probe_ctx *lttng_probe_ctx, struct load_ptr *ptr, uint32_t idx) @@ -317,11 +310,11 @@ static int context_get_index(struct lttng_probe_ctx *lttng_probe_ctx, } case atype_array_nestable: if (!lttng_is_bytewise_integer(field->type.u.array_nestable.elem_type)) { - printk(KERN_WARNING "Array nesting only supports integer types.\n"); + printk(KERN_WARNING "LTTng: filter: Array nesting only supports integer types.\n"); return -EINVAL; } if (field->type.u.array_nestable.elem_type->u.integer.encoding == lttng_encode_none) { - printk(KERN_WARNING "Only string arrays are supported for contexts.\n"); + printk(KERN_WARNING "LTTng: filter: Only string arrays are supported for contexts.\n"); return -EINVAL; } ptr->object_type = OBJECT_TYPE_STRING; @@ -330,11 +323,11 @@ static int context_get_index(struct lttng_probe_ctx *lttng_probe_ctx, break; case atype_sequence_nestable: if (!lttng_is_bytewise_integer(field->type.u.sequence_nestable.elem_type)) { - printk(KERN_WARNING "Sequence nesting only supports integer types.\n"); + printk(KERN_WARNING "LTTng: filter: Sequence nesting only supports integer types.\n"); return -EINVAL; } if (field->type.u.sequence_nestable.elem_type->u.integer.encoding == lttng_encode_none) { - printk(KERN_WARNING "Only string sequences are supported for contexts.\n"); + printk(KERN_WARNING "LTTng: filter: Only string sequences are supported for contexts.\n"); return -EINVAL; } ptr->object_type = OBJECT_TYPE_STRING; @@ -347,13 +340,13 @@ static int context_get_index(struct lttng_probe_ctx *lttng_probe_ctx, ptr->ptr = v.str; break; case atype_struct_nestable: - printk(KERN_WARNING "Structure type cannot be loaded.\n"); + printk(KERN_WARNING "LTTng: filter: Structure type cannot be loaded.\n"); return -EINVAL; case atype_variant_nestable: - printk(KERN_WARNING "Variant type cannot be loaded.\n"); + printk(KERN_WARNING "LTTng: filter: Variant type cannot be loaded.\n"); return -EINVAL; default: - printk(KERN_WARNING "Unknown type: %d", (int) field->type.atype); + printk(KERN_WARNING "LTTng: filter: Unknown type: %d", (int) field->type.atype); return -EINVAL; } return 0; @@ -366,13 +359,6 @@ static int dynamic_get_index(struct lttng_probe_ctx *lttng_probe_ctx, int ret; const struct filter_get_index_data *gid; - /* - * Types nested within variants need to perform dynamic lookup - * based on the field descriptions. LTTng-UST does not implement - * variants for now. - */ - if (stack_top->u.ptr.field) - return -EINVAL; gid = (const struct filter_get_index_data *) &runtime->data[index]; switch (stack_top->u.ptr.type) { case LOAD_OBJECT: @@ -388,7 +374,7 @@ static int dynamic_get_index(struct lttng_probe_ctx *lttng_probe_ctx, stack_top->u.ptr.ptr = ptr; stack_top->u.ptr.object_type = gid->elem.type; stack_top->u.ptr.rev_bo = gid->elem.rev_bo; - /* field is only used for types nested within variants. */ + BUG_ON(stack_top->u.ptr.field->type.atype != atype_array_nestable); stack_top->u.ptr.field = NULL; break; } @@ -407,17 +393,17 @@ static int dynamic_get_index(struct lttng_probe_ctx *lttng_probe_ctx, stack_top->u.ptr.ptr = ptr; stack_top->u.ptr.object_type = gid->elem.type; stack_top->u.ptr.rev_bo = gid->elem.rev_bo; - /* field is only used for types nested within variants. */ + BUG_ON(stack_top->u.ptr.field->type.atype != atype_sequence_nestable); stack_top->u.ptr.field = NULL; break; } case OBJECT_TYPE_STRUCT: - printk(KERN_WARNING "Nested structures are not supported yet.\n"); + printk(KERN_WARNING "LTTng: filter: Nested structures are not supported yet.\n"); ret = -EINVAL; goto end; case OBJECT_TYPE_VARIANT: default: - printk(KERN_WARNING "Unexpected get index type %d", + printk(KERN_WARNING "LTTng: filter: Unexpected get index type %d", (int) stack_top->u.ptr.object_type); ret = -EINVAL; goto end; @@ -440,10 +426,12 @@ static int dynamic_get_index(struct lttng_probe_ctx *lttng_probe_ctx, stack_top->u.ptr.ptr = *(const char * const *) stack_top->u.ptr.ptr; stack_top->u.ptr.object_type = gid->elem.type; stack_top->u.ptr.type = LOAD_OBJECT; - /* field is only used for types nested within variants. */ - stack_top->u.ptr.field = NULL; + stack_top->u.ptr.field = gid->field; break; } + + stack_top->type = REG_PTR; + return 0; end: @@ -469,6 +457,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) case OBJECT_TYPE_S8: dbg_printk("op load field s8\n"); stack_top->u.v = *(int8_t *) stack_top->u.ptr.ptr; + stack_top->type = REG_S64; break; case OBJECT_TYPE_S16: { @@ -479,6 +468,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) if (stack_top->u.ptr.rev_bo) __swab16s(&tmp); stack_top->u.v = tmp; + stack_top->type = REG_S64; break; } case OBJECT_TYPE_S32: @@ -490,6 +480,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) if (stack_top->u.ptr.rev_bo) __swab32s(&tmp); stack_top->u.v = tmp; + stack_top->type = REG_S64; break; } case OBJECT_TYPE_S64: @@ -501,11 +492,13 @@ static int dynamic_load_field(struct estack_entry *stack_top) if (stack_top->u.ptr.rev_bo) __swab64s(&tmp); stack_top->u.v = tmp; + stack_top->type = REG_S64; break; } case OBJECT_TYPE_U8: dbg_printk("op load field u8\n"); stack_top->u.v = *(uint8_t *) stack_top->u.ptr.ptr; + stack_top->type = REG_U64; break; case OBJECT_TYPE_U16: { @@ -516,6 +509,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) if (stack_top->u.ptr.rev_bo) __swab16s(&tmp); stack_top->u.v = tmp; + stack_top->type = REG_U64; break; } case OBJECT_TYPE_U32: @@ -527,6 +521,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) if (stack_top->u.ptr.rev_bo) __swab32s(&tmp); stack_top->u.v = tmp; + stack_top->type = REG_U64; break; } case OBJECT_TYPE_U64: @@ -538,6 +533,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) if (stack_top->u.ptr.rev_bo) __swab64s(&tmp); stack_top->u.v = tmp; + stack_top->type = REG_U64; break; } case OBJECT_TYPE_STRING: @@ -555,6 +551,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) stack_top->u.s.seq_len = LTTNG_SIZE_MAX; stack_top->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; + stack_top->type = REG_STRING; break; } case OBJECT_TYPE_STRING_SEQUENCE: @@ -572,6 +569,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) } stack_top->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; + stack_top->type = REG_STRING; break; } case OBJECT_TYPE_DYNAMIC: @@ -588,7 +586,7 @@ static int dynamic_load_field(struct estack_entry *stack_top) case OBJECT_TYPE_ARRAY: case OBJECT_TYPE_STRUCT: case OBJECT_TYPE_VARIANT: - printk(KERN_WARNING "Sequences, arrays, struct and variant cannot be loaded (nested types).\n"); + printk(KERN_WARNING "LTTng: filter: Sequences, arrays, struct and variant cannot be loaded (nested types).\n"); ret = -EINVAL; goto end; } @@ -598,22 +596,93 @@ end: return ret; } +static +int lttng_bytecode_interpret_format_output(struct estack_entry *ax, + struct lttng_interpreter_output *output) +{ + int ret; + +again: + switch (ax->type) { + case REG_S64: + output->type = LTTNG_INTERPRETER_TYPE_S64; + output->u.s = ax->u.v; + break; + case REG_U64: + output->type = LTTNG_INTERPRETER_TYPE_U64; + output->u.u = (uint64_t) ax->u.v; + break; + case REG_STRING: + output->type = LTTNG_INTERPRETER_TYPE_STRING; + output->u.str.str = ax->u.s.str; + output->u.str.len = ax->u.s.seq_len; + break; + case REG_PTR: + switch (ax->u.ptr.object_type) { + case OBJECT_TYPE_S8: + case OBJECT_TYPE_S16: + case OBJECT_TYPE_S32: + case OBJECT_TYPE_S64: + case OBJECT_TYPE_U8: + case OBJECT_TYPE_U16: + case OBJECT_TYPE_U32: + case OBJECT_TYPE_U64: + case OBJECT_TYPE_DOUBLE: + case OBJECT_TYPE_STRING: + case OBJECT_TYPE_STRING_SEQUENCE: + ret = dynamic_load_field(ax); + if (ret) + return ret; + /* Retry after loading ptr into stack top. */ + goto again; + case OBJECT_TYPE_SEQUENCE: + output->type = LTTNG_INTERPRETER_TYPE_SEQUENCE; + output->u.sequence.ptr = *(const char **) (ax->u.ptr.ptr + sizeof(unsigned long)); + output->u.sequence.nr_elem = *(unsigned long *) ax->u.ptr.ptr; + output->u.sequence.nested_type = ax->u.ptr.field->type.u.sequence_nestable.elem_type; + break; + case OBJECT_TYPE_ARRAY: + /* Skip count (unsigned long) */ + output->type = LTTNG_INTERPRETER_TYPE_SEQUENCE; + output->u.sequence.ptr = *(const char **) (ax->u.ptr.ptr + sizeof(unsigned long)); + output->u.sequence.nr_elem = ax->u.ptr.field->type.u.array_nestable.length; + output->u.sequence.nested_type = ax->u.ptr.field->type.u.array_nestable.elem_type; + break; + case OBJECT_TYPE_STRUCT: + case OBJECT_TYPE_VARIANT: + default: + return -EINVAL; + } + + break; + case REG_STAR_GLOB_STRING: + case REG_TYPE_UNKNOWN: + default: + return -EINVAL; + } + + return LTTNG_FILTER_RECORD_FLAG; +} + /* * Return 0 (discard), or raise the 0x1 flag (log event). * Currently, other flags are kept for future extensions and have no * effect. */ -uint64_t lttng_filter_interpret_bytecode(void *filter_data, +static +uint64_t bytecode_interpret(void *interpreter_data, struct lttng_probe_ctx *lttng_probe_ctx, - const char *filter_stack_data) + const char *interpreter_stack_data, + struct lttng_interpreter_output *output) { - struct bytecode_runtime *bytecode = filter_data; + struct bytecode_runtime *bytecode = interpreter_data; void *pc, *next_pc, *start_pc; int ret = -EINVAL; uint64_t retval = 0; struct estack _stack; struct estack *stack = &_stack; register int64_t ax = 0, bx = 0; + register enum entry_type ax_t = REG_TYPE_UNKNOWN, bx_t = REG_TYPE_UNKNOWN; register int top = FILTER_STACK_EMPTY; #ifndef INTERPRETER_USE_SWITCH static void *dispatch[NR_FILTER_OPS] = { @@ -764,15 +833,33 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, #ifdef INTERPRETER_USE_SWITCH default: #endif /* INTERPRETER_USE_SWITCH */ - printk(KERN_WARNING "unknown bytecode op %u\n", + printk(KERN_WARNING "LTTng: filter: unknown bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; goto end; OP(FILTER_OP_RETURN): OP(FILTER_OP_RETURN_S64): - /* LTTNG_FILTER_DISCARD or LTTNG_FILTER_RECORD_FLAG */ - retval = !!estack_ax_v; + /* LTTNG_FILTER_DISCARD or LTTNG_FILTER_RECORD_FLAG */ + switch (estack_ax_t) { + case REG_S64: + case REG_U64: + retval = !!estack_ax_v; + break; + case REG_DOUBLE: + case REG_STRING: + case REG_PTR: + if (!output) { + ret = -EINVAL; + goto end; + } + retval = 0; + break; + case REG_STAR_GLOB_STRING: + case REG_TYPE_UNKNOWN: + ret = -EINVAL; + goto end; + } ret = 0; goto end; @@ -782,7 +869,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_MOD): OP(FILTER_OP_PLUS): OP(FILTER_OP_MINUS): - printk(KERN_WARNING "unsupported bytecode op %u\n", + printk(KERN_WARNING "LTTng: filter: unsupported bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; goto end; @@ -793,7 +880,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_LT): OP(FILTER_OP_GE): OP(FILTER_OP_LE): - printk(KERN_WARNING "unsupported non-specialized bytecode op %u\n", + printk(KERN_WARNING "LTTng: filter: unsupported non-specialized bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; goto end; @@ -803,8 +890,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (stack_strcmp(stack, top, "==") == 0); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -813,8 +901,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (stack_strcmp(stack, top, "!=") != 0); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -823,8 +912,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (stack_strcmp(stack, top, ">") > 0); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -833,8 +923,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (stack_strcmp(stack, top, "<") < 0); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -843,8 +934,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (stack_strcmp(stack, top, ">=") >= 0); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -853,8 +945,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (stack_strcmp(stack, top, "<=") <= 0); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -864,8 +957,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (stack_star_glob_match(stack, top, "==") == 0); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -874,8 +968,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (stack_star_glob_match(stack, top, "!=") != 0); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -885,8 +980,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (estack_bx_v == estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -895,8 +991,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (estack_bx_v != estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -905,8 +1002,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (estack_bx_v > estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -915,8 +1013,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (estack_bx_v < estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -925,8 +1024,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (estack_bx_v >= estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -935,8 +1035,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, int res; res = (estack_bx_v <= estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_S64; next_pc += sizeof(struct binary_op); PO; } @@ -973,14 +1074,20 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; + if (!IS_INTEGER_REGISTER(estack_ax_t) || !IS_INTEGER_REGISTER(estack_bx_t)) { + ret = -EINVAL; + goto end; + } + /* Catch undefined behavior. */ if (unlikely(estack_ax_v < 0 || estack_ax_v >= 64)) { ret = -EINVAL; goto end; } res = ((uint64_t) estack_bx_v >> (uint32_t) estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_U64; next_pc += sizeof(struct binary_op); PO; } @@ -988,14 +1095,20 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; + if (!IS_INTEGER_REGISTER(estack_ax_t) || !IS_INTEGER_REGISTER(estack_bx_t)) { + ret = -EINVAL; + goto end; + } + /* Catch undefined behavior. */ if (unlikely(estack_ax_v < 0 || estack_ax_v >= 64)) { ret = -EINVAL; goto end; } res = ((uint64_t) estack_bx_v << (uint32_t) estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_U64; next_pc += sizeof(struct binary_op); PO; } @@ -1003,9 +1116,15 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; + if (!IS_INTEGER_REGISTER(estack_ax_t) || !IS_INTEGER_REGISTER(estack_bx_t)) { + ret = -EINVAL; + goto end; + } + res = ((uint64_t) estack_bx_v & (uint64_t) estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_U64; next_pc += sizeof(struct binary_op); PO; } @@ -1013,9 +1132,15 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; + if (!IS_INTEGER_REGISTER(estack_ax_t) || !IS_INTEGER_REGISTER(estack_bx_t)) { + ret = -EINVAL; + goto end; + } + res = ((uint64_t) estack_bx_v | (uint64_t) estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_U64; next_pc += sizeof(struct binary_op); PO; } @@ -1023,9 +1148,15 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { int64_t res; + if (!IS_INTEGER_REGISTER(estack_ax_t) || !IS_INTEGER_REGISTER(estack_bx_t)) { + ret = -EINVAL; + goto end; + } + res = ((uint64_t) estack_bx_v ^ (uint64_t) estack_ax_v); - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = res; + estack_ax_t = REG_U64; next_pc += sizeof(struct binary_op); PO; } @@ -1034,7 +1165,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_UNARY_PLUS): OP(FILTER_OP_UNARY_MINUS): OP(FILTER_OP_UNARY_NOT): - printk(KERN_WARNING "unsupported non-specialized bytecode op %u\n", + printk(KERN_WARNING "LTTng: filter: unsupported non-specialized bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; goto end; @@ -1043,6 +1174,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_UNARY_BIT_NOT): { estack_ax_v = ~(uint64_t) estack_ax_v; + estack_ax_t = REG_S64; next_pc += sizeof(struct unary_op); PO; } @@ -1055,6 +1187,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_UNARY_MINUS_S64): { estack_ax_v = -estack_ax_v; + estack_ax_t = REG_S64; next_pc += sizeof(struct unary_op); PO; } @@ -1067,6 +1200,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_UNARY_NOT_S64): { estack_ax_v = !estack_ax_v; + estack_ax_t = REG_S64; next_pc += sizeof(struct unary_op); PO; } @@ -1088,7 +1222,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, next_pc = start_pc + insn->skip_offset; } else { /* Pop 1 when jump not taken */ - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); next_pc += sizeof(struct logical_op); } PO; @@ -1106,7 +1240,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, next_pc = start_pc + insn->skip_offset; } else { /* Pop 1 when jump not taken */ - estack_pop(stack, top, ax, bx); + estack_pop(stack, top, ax, bx, ax_t, bx_t); next_pc += sizeof(struct logical_op); } PO; @@ -1121,9 +1255,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("load field ref offset %u type string\n", ref->offset); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.s.str = - *(const char * const *) &filter_stack_data[ref->offset]; + *(const char * const *) &interpreter_stack_data[ref->offset]; if (unlikely(!estack_ax(stack, top)->u.s.str)) { dbg_printk("Filter warning: loading a NULL string.\n"); ret = -EINVAL; @@ -1133,6 +1267,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, estack_ax(stack, top)->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->u.s.user = 0; + estack_ax(stack, top)->type = REG_STRING; dbg_printk("ref load string %s\n", estack_ax(stack, top)->u.s.str); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; @@ -1145,11 +1280,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("load field ref offset %u type sequence\n", ref->offset); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.s.seq_len = - *(unsigned long *) &filter_stack_data[ref->offset]; + *(unsigned long *) &interpreter_stack_data[ref->offset]; estack_ax(stack, top)->u.s.str = - *(const char **) (&filter_stack_data[ref->offset + *(const char **) (&interpreter_stack_data[ref->offset + sizeof(unsigned long)]); if (unlikely(!estack_ax(stack, top)->u.s.str)) { dbg_printk("Filter warning: loading a NULL sequence.\n"); @@ -1170,9 +1305,10 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("load field ref offset %u type s64\n", ref->offset); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = - ((struct literal_numeric *) &filter_stack_data[ref->offset])->v; + ((struct literal_numeric *) &interpreter_stack_data[ref->offset])->v; + estack_ax_t = REG_S64; dbg_printk("ref load s64 %lld\n", (long long) estack_ax_v); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); @@ -1191,7 +1327,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, struct load_op *insn = (struct load_op *) pc; dbg_printk("load string %s\n", insn->data); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.s.str = insn->data; estack_ax(stack, top)->u.s.seq_len = LTTNG_SIZE_MAX; estack_ax(stack, top)->u.s.literal_type = @@ -1206,7 +1342,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, struct load_op *insn = (struct load_op *) pc; dbg_printk("load globbing pattern %s\n", insn->data); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.s.str = insn->data; estack_ax(stack, top)->u.s.seq_len = LTTNG_SIZE_MAX; estack_ax(stack, top)->u.s.literal_type = @@ -1220,8 +1356,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, { struct load_op *insn = (struct load_op *) pc; - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = ((struct literal_numeric *) insn->data)->v; + estack_ax_t = REG_S64; dbg_printk("load s64 %lld\n", (long long) estack_ax_v); next_pc += sizeof(struct load_op) @@ -1237,7 +1374,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, /* cast */ OP(FILTER_OP_CAST_TO_S64): - printk(KERN_WARNING "unsupported non-specialized bytecode op %u\n", + printk(KERN_WARNING "LTTng: filter: unsupported non-specialized bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; goto end; @@ -1266,7 +1403,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, ref->offset); ctx_field = <tng_static_ctx->fields[ref->offset]; ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.s.str = v.str; if (unlikely(!estack_ax(stack, top)->u.s.str)) { dbg_printk("Filter warning: loading a NULL string.\n"); @@ -1277,6 +1414,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, estack_ax(stack, top)->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->u.s.user = 0; + estack_ax(stack, top)->type = REG_STRING; dbg_printk("ref get context string %s\n", estack_ax(stack, top)->u.s.str); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; @@ -1293,8 +1431,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, ref->offset); ctx_field = <tng_static_ctx->fields[ref->offset]; ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax_v = v.s64; + estack_ax_t = REG_S64; dbg_printk("ref get context s64 %lld\n", (long long) estack_ax_v); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); @@ -1315,9 +1454,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("load field ref offset %u type user string\n", ref->offset); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.s.user_str = - *(const char * const *) &filter_stack_data[ref->offset]; + *(const char * const *) &interpreter_stack_data[ref->offset]; if (unlikely(!estack_ax(stack, top)->u.s.str)) { dbg_printk("Filter warning: loading a NULL string.\n"); ret = -EINVAL; @@ -1327,6 +1466,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, estack_ax(stack, top)->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->u.s.user = 1; + estack_ax(stack, top)->type = REG_STRING; dbg_printk("ref load string %s\n", estack_ax(stack, top)->u.s.str); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); PO; @@ -1339,11 +1479,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("load field ref offset %u type user sequence\n", ref->offset); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.s.seq_len = - *(unsigned long *) &filter_stack_data[ref->offset]; + *(unsigned long *) &interpreter_stack_data[ref->offset]; estack_ax(stack, top)->u.s.user_str = - *(const char **) (&filter_stack_data[ref->offset + *(const char **) (&interpreter_stack_data[ref->offset + sizeof(unsigned long)]); if (unlikely(!estack_ax(stack, top)->u.s.str)) { dbg_printk("Filter warning: loading a NULL sequence.\n"); @@ -1360,10 +1500,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_GET_CONTEXT_ROOT): { dbg_printk("op get context root\n"); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.ptr.type = LOAD_ROOT_CONTEXT; /* "field" only needed for variants. */ estack_ax(stack, top)->u.ptr.field = NULL; + estack_ax(stack, top)->type = REG_PTR; next_pc += sizeof(struct load_op); PO; } @@ -1377,11 +1518,12 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_GET_PAYLOAD_ROOT): { dbg_printk("op get app payload root\n"); - estack_push(stack, top, ax, bx); + estack_push(stack, top, ax, bx, ax_t, bx_t); estack_ax(stack, top)->u.ptr.type = LOAD_ROOT_PAYLOAD; - estack_ax(stack, top)->u.ptr.ptr = filter_stack_data; + estack_ax(stack, top)->u.ptr.ptr = interpreter_stack_data; /* "field" only needed for variants. */ estack_ax(stack, top)->u.ptr.field = NULL; + estack_ax(stack, top)->type = REG_PTR; next_pc += sizeof(struct load_op); PO; } @@ -1391,7 +1533,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("op get symbol\n"); switch (estack_ax(stack, top)->u.ptr.type) { case LOAD_OBJECT: - printk(KERN_WARNING "Nested fields not implemented yet.\n"); + printk(KERN_WARNING "LTTng: filter: Nested fields not implemented yet.\n"); ret = -EINVAL; goto end; case LOAD_ROOT_CONTEXT: @@ -1428,6 +1570,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, if (ret) goto end; estack_ax_v = estack_ax(stack, top)->u.v; + estack_ax_t = estack_ax(stack, top)->type; next_pc += sizeof(struct load_op) + sizeof(struct get_index_u16); PO; } @@ -1442,6 +1585,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, if (ret) goto end; estack_ax_v = estack_ax(stack, top)->u.v; + estack_ax_t = estack_ax(stack, top)->type; next_pc += sizeof(struct load_op) + sizeof(struct get_index_u64); PO; } @@ -1453,6 +1597,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, if (ret) goto end; estack_ax_v = estack_ax(stack, top)->u.v; + estack_ax_t = estack_ax(stack, top)->type; next_pc += sizeof(struct load_op); PO; } @@ -1462,6 +1607,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("op load field s8\n"); estack_ax_v = *(int8_t *) estack_ax(stack, top)->u.ptr.ptr; + estack_ax_t = REG_S64; next_pc += sizeof(struct load_op); PO; } @@ -1470,6 +1616,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("op load field s16\n"); estack_ax_v = *(int16_t *) estack_ax(stack, top)->u.ptr.ptr; + estack_ax_t = REG_S64; next_pc += sizeof(struct load_op); PO; } @@ -1478,6 +1625,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("op load field s32\n"); estack_ax_v = *(int32_t *) estack_ax(stack, top)->u.ptr.ptr; + estack_ax_t = REG_S64; next_pc += sizeof(struct load_op); PO; } @@ -1486,6 +1634,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("op load field s64\n"); estack_ax_v = *(int64_t *) estack_ax(stack, top)->u.ptr.ptr; + estack_ax_t = REG_S64; next_pc += sizeof(struct load_op); PO; } @@ -1494,6 +1643,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("op load field u8\n"); estack_ax_v = *(uint8_t *) estack_ax(stack, top)->u.ptr.ptr; + estack_ax_t = REG_S64; next_pc += sizeof(struct load_op); PO; } @@ -1502,6 +1652,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("op load field u16\n"); estack_ax_v = *(uint16_t *) estack_ax(stack, top)->u.ptr.ptr; + estack_ax_t = REG_S64; next_pc += sizeof(struct load_op); PO; } @@ -1510,6 +1661,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("op load field u32\n"); estack_ax_v = *(uint32_t *) estack_ax(stack, top)->u.ptr.ptr; + estack_ax_t = REG_S64; next_pc += sizeof(struct load_op); PO; } @@ -1518,6 +1670,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("op load field u64\n"); estack_ax_v = *(uint64_t *) estack_ax(stack, top)->u.ptr.ptr; + estack_ax_t = REG_S64; next_pc += sizeof(struct load_op); PO; } @@ -1542,6 +1695,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, estack_ax(stack, top)->u.s.seq_len = LTTNG_SIZE_MAX; estack_ax(stack, top)->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; + estack_ax(stack, top)->type = REG_STRING; next_pc += sizeof(struct load_op); PO; } @@ -1561,17 +1715,33 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, } estack_ax(stack, top)->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; + estack_ax(stack, top)->type = REG_STRING; next_pc += sizeof(struct load_op); PO; } END_OP end: - /* return 0 (discard) on error */ + /* Return _DISCARD on error. */ if (ret) - return 0; + return LTTNG_FILTER_DISCARD; + + if (output) { + return lttng_bytecode_interpret_format_output( + estack_ax(stack, top), output); + } + return retval; } +LTTNG_STACK_FRAME_NON_STANDARD(bytecode_interpret); + +uint64_t lttng_filter_interpret_bytecode(void *filter_data, + struct lttng_probe_ctx *lttng_probe_ctx, + const char *filter_stack_data) +{ + return bytecode_interpret(filter_data, lttng_probe_ctx, + filter_stack_data, NULL); +} #undef START_OP #undef OP