X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=src%2Flttng-bytecode-interpreter.c;h=a2a932c65f2d488d1f119741801cdbf0ef3c2456;hb=HEAD;hp=fcbfe0b133a4d44410b33e957dc347347c8236e8;hpb=28cbcb59855c099a89b02054b15b45ee3ad6a52a;p=lttng-modules.git diff --git a/src/lttng-bytecode-interpreter.c b/src/lttng-bytecode-interpreter.c index fcbfe0b1..4bb3a79a 100644 --- a/src/lttng-bytecode-interpreter.c +++ b/src/lttng-bytecode-interpreter.c @@ -7,6 +7,7 @@ * Copyright (C) 2010-2016 Mathieu Desnoyers */ +#include #include #include #include @@ -14,6 +15,8 @@ #include #include +#include +#include /* * get_char should be called with page fault handler disabled if it is expected @@ -207,19 +210,13 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) return diff; } -uint64_t lttng_bytecode_filter_interpret_false(void *filter_data, - struct lttng_probe_ctx *lttng_probe_ctx, - const char *filter_stack_data) +int lttng_bytecode_interpret_error( + struct lttng_kernel_bytecode_runtime *bytecode_runtime __attribute__((unused)), + const char *stack_data __attribute__((unused)), + struct lttng_kernel_probe_ctx *probe_ctx __attribute__((unused)), + void *ctx __attribute__((unused))) { - return LTTNG_INTERPRETER_DISCARD; -} - -uint64_t lttng_bytecode_capture_interpret_false(void *filter_data, - struct lttng_probe_ctx *lttng_probe_ctx, - const char *capture_stack_data, - struct lttng_interpreter_output *output) -{ - return LTTNG_INTERPRETER_DISCARD; + return LTTNG_KERNEL_BYTECODE_INTERPRETER_ERROR; } #ifdef INTERPRETER_USE_SWITCH @@ -271,96 +268,123 @@ LABEL_##name #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, +static int context_get_index(struct lttng_kernel_probe_ctx *lttng_probe_ctx, struct load_ptr *ptr, uint32_t idx) { - struct lttng_ctx_field *ctx_field; - struct lttng_event_field *field; - union lttng_ctx_value v; + struct lttng_kernel_ctx_field *ctx_field; + const struct lttng_kernel_event_field *field; + struct lttng_ctx_value v; ctx_field = <tng_static_ctx->fields[idx]; - field = &ctx_field->event_field; + field = ctx_field->event_field; ptr->type = LOAD_OBJECT; /* field is only used for types nested within variants. */ ptr->field = NULL; - switch (field->type.type) { + switch (field->type->type) { case lttng_kernel_type_integer: - ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); - if (field->type.u.integer.signedness) { + { + const struct lttng_kernel_type_integer *integer_type = lttng_kernel_get_type_integer(field->type); + + ctx_field->get_value(ctx_field->priv, lttng_probe_ctx, &v); + if (lttng_kernel_get_type_integer(field->type)->signedness) { ptr->object_type = OBJECT_TYPE_S64; - ptr->u.s64 = v.s64; + ptr->u.s64 = v.u.s64; ptr->ptr = &ptr->u.s64; } else { ptr->object_type = OBJECT_TYPE_U64; - ptr->u.u64 = v.s64; /* Cast. */ + ptr->u.u64 = v.u.s64; /* Cast. */ ptr->ptr = &ptr->u.u64; } + ptr->rev_bo = integer_type->reverse_byte_order; + ptr->user = integer_type->user; break; - case lttng_kernel_type_enum_nestable: + } + case lttng_kernel_type_enum: { - const struct lttng_integer_type *itype = - &field->type.u.enum_nestable.container_type->u.integer; + const struct lttng_kernel_type_enum *enum_type = lttng_kernel_get_type_enum(field->type); + const struct lttng_kernel_type_integer *integer_type = lttng_kernel_get_type_integer(enum_type->container_type); - ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); - if (itype->signedness) { + ctx_field->get_value(ctx_field->priv, lttng_probe_ctx, &v); + if (integer_type->signedness) { ptr->object_type = OBJECT_TYPE_SIGNED_ENUM; - ptr->u.s64 = v.s64; + ptr->u.s64 = v.u.s64; ptr->ptr = &ptr->u.s64; } else { ptr->object_type = OBJECT_TYPE_UNSIGNED_ENUM; - ptr->u.u64 = v.s64; /* Cast. */ + ptr->u.u64 = v.u.s64; /* Cast. */ ptr->ptr = &ptr->u.u64; } + ptr->rev_bo = integer_type->reverse_byte_order; + ptr->user = integer_type->user; break; } - case lttng_kernel_type_array_nestable: - if (!lttng_is_bytewise_integer(field->type.u.array_nestable.elem_type)) { + case lttng_kernel_type_array: + { + const struct lttng_kernel_type_array *array_type = lttng_kernel_get_type_array(field->type); + const struct lttng_kernel_type_integer *integer_type; + + if (!lttng_kernel_type_is_bytewise_integer(array_type->elem_type)) { printk(KERN_WARNING "LTTng: bytecode: Array nesting only supports integer types.\n"); return -EINVAL; } - if (field->type.u.array_nestable.elem_type->u.integer.encoding == lttng_kernel_string_encoding_none) { + if (array_type->encoding == lttng_kernel_string_encoding_none) { printk(KERN_WARNING "LTTng: bytecode: Only string arrays are supported for contexts.\n"); return -EINVAL; } + integer_type = lttng_kernel_get_type_integer(array_type->elem_type); ptr->object_type = OBJECT_TYPE_STRING; - ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); - ptr->ptr = v.str; + ptr->user = integer_type->user; + ctx_field->get_value(ctx_field->priv, lttng_probe_ctx, &v); + ptr->ptr = v.u.str; break; - case lttng_kernel_type_sequence_nestable: - if (!lttng_is_bytewise_integer(field->type.u.sequence_nestable.elem_type)) { + } + case lttng_kernel_type_sequence: + { + const struct lttng_kernel_type_sequence *sequence_type = lttng_kernel_get_type_sequence(field->type); + const struct lttng_kernel_type_integer *integer_type; + + if (!lttng_kernel_type_is_bytewise_integer(sequence_type->elem_type)) { printk(KERN_WARNING "LTTng: bytecode: Sequence nesting only supports integer types.\n"); return -EINVAL; } - if (field->type.u.sequence_nestable.elem_type->u.integer.encoding == lttng_kernel_string_encoding_none) { + if (sequence_type->encoding == lttng_kernel_string_encoding_none) { printk(KERN_WARNING "LTTng: bytecode: Only string sequences are supported for contexts.\n"); return -EINVAL; } + integer_type = lttng_kernel_get_type_integer(sequence_type->elem_type); ptr->object_type = OBJECT_TYPE_STRING; - ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); - ptr->ptr = v.str; + ptr->user = integer_type->user; + ctx_field->get_value(ctx_field->priv, lttng_probe_ctx, &v); + ptr->ptr = v.u.str; break; + } case lttng_kernel_type_string: + { + const struct lttng_kernel_type_string *string_type = lttng_kernel_get_type_string(field->type); + ptr->object_type = OBJECT_TYPE_STRING; - ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); - ptr->ptr = v.str; + ptr->user = string_type->user; + ctx_field->get_value(ctx_field->priv, lttng_probe_ctx, &v); + ptr->ptr = v.u.str; break; - case lttng_kernel_type_struct_nestable: + } + case lttng_kernel_type_struct: printk(KERN_WARNING "LTTng: bytecode: Structure type cannot be loaded.\n"); return -EINVAL; - case lttng_kernel_type_variant_nestable: + case lttng_kernel_type_variant: printk(KERN_WARNING "LTTng: bytecode: Variant type cannot be loaded.\n"); return -EINVAL; default: - printk(KERN_WARNING "LTTng: bytecode: Unknown type: %d", (int) field->type.type); + printk(KERN_WARNING "LTTng: bytecode: Unknown type: %d", (int) field->type->type); return -EINVAL; } return 0; } -static int dynamic_get_index(struct lttng_probe_ctx *lttng_probe_ctx, +static int dynamic_get_index(struct lttng_kernel_probe_ctx *lttng_probe_ctx, struct bytecode_runtime *runtime, uint64_t index, struct estack_entry *stack_top) { @@ -382,7 +406,8 @@ 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; - BUG_ON(stack_top->u.ptr.field->type.type != lttng_kernel_type_array_nestable); + stack_top->u.ptr.user = gid->elem.user; + BUG_ON(stack_top->u.ptr.field->type->type != lttng_kernel_type_array); stack_top->u.ptr.field = NULL; break; } @@ -401,7 +426,8 @@ 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; - BUG_ON(stack_top->u.ptr.field->type.type != lttng_kernel_type_sequence_nestable); + stack_top->u.ptr.user = gid->elem.user; + BUG_ON(stack_top->u.ptr.field->type->type != lttng_kernel_type_sequence); stack_top->u.ptr.field = NULL; break; } @@ -418,7 +444,8 @@ static int dynamic_get_index(struct lttng_probe_ctx *lttng_probe_ctx, } break; case LOAD_ROOT_CONTEXT: - case LOAD_ROOT_APP_CONTEXT: /* Fall-through */ + lttng_fallthrough; + case LOAD_ROOT_APP_CONTEXT: { ret = context_get_index(lttng_probe_ctx, &stack_top->u.ptr, @@ -436,6 +463,7 @@ static int dynamic_get_index(struct lttng_probe_ctx *lttng_probe_ctx, stack_top->u.ptr.type = LOAD_OBJECT; stack_top->u.ptr.field = gid->field; stack_top->u.ptr.rev_bo = gid->elem.rev_bo; + stack_top->u.ptr.user = gid->elem.user; break; } @@ -465,7 +493,12 @@ static int dynamic_load_field(struct estack_entry *stack_top) switch (stack_top->u.ptr.object_type) { case OBJECT_TYPE_S8: dbg_printk("op load field s8\n"); - stack_top->u.v = *(int8_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.user) { + if (lttng_copy_from_user_check_nofault(&stack_top->u.v, (int8_t __user *) stack_top->u.ptr.ptr, sizeof(int8_t))) + stack_top->u.v = 0; + } else { + stack_top->u.v = *(int8_t *) stack_top->u.ptr.ptr; + } stack_top->type = REG_S64; break; case OBJECT_TYPE_S16: @@ -473,7 +506,12 @@ static int dynamic_load_field(struct estack_entry *stack_top) int16_t tmp; dbg_printk("op load field s16\n"); - tmp = *(int16_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.user) { + if (lttng_copy_from_user_check_nofault(&tmp, (int16_t __user *) stack_top->u.ptr.ptr, sizeof(int16_t))) + tmp = 0; + } else { + tmp = *(int16_t *) stack_top->u.ptr.ptr; + } if (stack_top->u.ptr.rev_bo) __swab16s(&tmp); stack_top->u.v = tmp; @@ -485,7 +523,12 @@ static int dynamic_load_field(struct estack_entry *stack_top) int32_t tmp; dbg_printk("op load field s32\n"); - tmp = *(int32_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.user) { + if (lttng_copy_from_user_check_nofault(&tmp, (int32_t __user *) stack_top->u.ptr.ptr, sizeof(int32_t))) + tmp = 0; + } else { + tmp = *(int32_t *) stack_top->u.ptr.ptr; + } if (stack_top->u.ptr.rev_bo) __swab32s(&tmp); stack_top->u.v = tmp; @@ -497,7 +540,12 @@ static int dynamic_load_field(struct estack_entry *stack_top) int64_t tmp; dbg_printk("op load field s64\n"); - tmp = *(int64_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.user) { + if (lttng_copy_from_user_check_nofault(&tmp, (int64_t __user *) stack_top->u.ptr.ptr, sizeof(int64_t))) + tmp = 0; + } else { + tmp = *(int64_t *) stack_top->u.ptr.ptr; + } if (stack_top->u.ptr.rev_bo) __swab64s(&tmp); stack_top->u.v = tmp; @@ -509,6 +557,11 @@ static int dynamic_load_field(struct estack_entry *stack_top) int64_t tmp; dbg_printk("op load field signed enumeration\n"); + if (stack_top->u.ptr.user) { + dbg_printk("Bytecode warning: user enum unsupported.\n"); + ret = -EINVAL; + goto end; + } tmp = *(int64_t *) stack_top->u.ptr.ptr; if (stack_top->u.ptr.rev_bo) __swab64s(&tmp); @@ -518,7 +571,12 @@ static int dynamic_load_field(struct estack_entry *stack_top) } case OBJECT_TYPE_U8: dbg_printk("op load field u8\n"); - stack_top->u.v = *(uint8_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.user) { + if (lttng_copy_from_user_check_nofault(&stack_top->u.v, (uint8_t __user *) stack_top->u.ptr.ptr, sizeof(uint8_t))) + stack_top->u.v = 0; + } else { + stack_top->u.v = *(uint8_t *) stack_top->u.ptr.ptr; + } stack_top->type = REG_U64; break; case OBJECT_TYPE_U16: @@ -526,7 +584,12 @@ static int dynamic_load_field(struct estack_entry *stack_top) uint16_t tmp; dbg_printk("op load field u16\n"); - tmp = *(uint16_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.user) { + if (lttng_copy_from_user_check_nofault(&tmp, (uint16_t __user *) stack_top->u.ptr.ptr, sizeof(uint16_t))) + tmp = 0; + } else { + tmp = *(uint16_t *) stack_top->u.ptr.ptr; + } if (stack_top->u.ptr.rev_bo) __swab16s(&tmp); stack_top->u.v = tmp; @@ -538,7 +601,12 @@ static int dynamic_load_field(struct estack_entry *stack_top) uint32_t tmp; dbg_printk("op load field u32\n"); - tmp = *(uint32_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.user) { + if (lttng_copy_from_user_check_nofault(&tmp, (uint32_t __user *) stack_top->u.ptr.ptr, sizeof(uint32_t))) + tmp = 0; + } else { + tmp = *(uint32_t *) stack_top->u.ptr.ptr; + } if (stack_top->u.ptr.rev_bo) __swab32s(&tmp); stack_top->u.v = tmp; @@ -550,7 +618,12 @@ static int dynamic_load_field(struct estack_entry *stack_top) uint64_t tmp; dbg_printk("op load field u64\n"); - tmp = *(uint64_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.user) { + if (lttng_copy_from_user_check_nofault(&tmp, (uint64_t __user *) stack_top->u.ptr.ptr, sizeof(uint64_t))) + tmp = 0; + } else { + tmp = *(uint64_t *) stack_top->u.ptr.ptr; + } if (stack_top->u.ptr.rev_bo) __swab64s(&tmp); stack_top->u.v = tmp; @@ -562,6 +635,11 @@ static int dynamic_load_field(struct estack_entry *stack_top) uint64_t tmp; dbg_printk("op load field unsigned enumeration\n"); + if (stack_top->u.ptr.user) { + dbg_printk("Bytecode warning: user enum unsupported.\n"); + ret = -EINVAL; + goto end; + } tmp = *(uint64_t *) stack_top->u.ptr.ptr; if (stack_top->u.ptr.rev_bo) __swab64s(&tmp); @@ -571,19 +649,30 @@ static int dynamic_load_field(struct estack_entry *stack_top) } case OBJECT_TYPE_STRING: { - const char *str; + dbg_printk("op load field string: user=%d\n", stack_top->u.ptr.user); + if (stack_top->u.ptr.user) { + const char __user *user_str = (const char __user *) stack_top->u.ptr.ptr; - dbg_printk("op load field string\n"); - str = (const char *) stack_top->u.ptr.ptr; - stack_top->u.s.str = str; - if (unlikely(!stack_top->u.s.str)) { - dbg_printk("Bytecode warning: loading a NULL string.\n"); - ret = -EINVAL; - goto end; + stack_top->u.s.user_str = user_str; + if (unlikely(!stack_top->u.s.user_str)) { + dbg_printk("Bytecode warning: loading a NULL user string.\n"); + ret = -EINVAL; + goto end; + } + stack_top->u.s.user = 1; + } else { + const char *str = (const char *) stack_top->u.ptr.ptr; + + stack_top->u.s.str = str; + if (unlikely(!stack_top->u.s.str)) { + dbg_printk("Bytecode warning: loading a NULL string.\n"); + ret = -EINVAL; + goto end; + } + stack_top->u.s.user = 0; } stack_top->u.s.seq_len = LTTNG_SIZE_MAX; - stack_top->u.s.literal_type = - ESTACK_STRING_LITERAL_TYPE_NONE; + stack_top->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; stack_top->type = REG_STRING; break; } @@ -591,17 +680,27 @@ static int dynamic_load_field(struct estack_entry *stack_top) { const char *ptr; - dbg_printk("op load field string sequence\n"); + dbg_printk("op load field string sequence: user=%d\n", stack_top->u.ptr.user); ptr = stack_top->u.ptr.ptr; stack_top->u.s.seq_len = *(unsigned long *) ptr; - stack_top->u.s.str = *(const char **) (ptr + sizeof(unsigned long)); - if (unlikely(!stack_top->u.s.str)) { - dbg_printk("Bytecode warning: loading a NULL sequence.\n"); - ret = -EINVAL; - goto end; + if (stack_top->u.ptr.user) { + stack_top->u.s.user_str = *(const char __user **) (ptr + sizeof(unsigned long)); + if (unlikely(!stack_top->u.s.user_str)) { + dbg_printk("Bytecode warning: loading a NULL user sequence.\n"); + ret = -EINVAL; + goto end; + } + stack_top->u.s.user = 1; + } else { + stack_top->u.s.str = *(const char **) (ptr + sizeof(unsigned long)); + if (unlikely(!stack_top->u.s.str)) { + dbg_printk("Bytecode warning: loading a NULL sequence.\n"); + ret = -EINVAL; + goto end; + } + stack_top->u.s.user = 0; } - stack_top->u.s.literal_type = - ESTACK_STRING_LITERAL_TYPE_NONE; + stack_top->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; stack_top->type = REG_STRING; break; } @@ -647,8 +746,13 @@ again: 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; + output->u.str.user = ax->u.s.user; + if (ax->u.s.user) { + output->u.str.user_str = ax->u.s.user_str; + } else { + output->u.str.str = ax->u.s.str; + } break; case REG_PTR: switch (ax->u.ptr.object_type) { @@ -672,14 +776,14 @@ again: 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; + output->u.sequence.nested_type = lttng_kernel_get_type_sequence(ax->u.ptr.field->type)->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; + output->u.sequence.nr_elem = lttng_kernel_get_type_array(ax->u.ptr.field->type)->length; + output->u.sequence.nested_type = lttng_kernel_get_type_array(ax->u.ptr.field->type)->elem_type; break; case OBJECT_TYPE_SIGNED_ENUM: ret = dynamic_load_field(ax); @@ -708,7 +812,7 @@ again: return -EINVAL; } - return LTTNG_INTERPRETER_RECORD_FLAG; + return 0; } #ifdef DEBUG @@ -745,17 +849,20 @@ void dbg_load_ref_user_str_printk(const struct estack_entry *user_str_reg) #endif /* - * Return 0 (discard), or raise the 0x1 flag (log event). - * Currently, other flags are kept for future extensions and have no - * effect. + * Return LTTNG_KERNEL_BYTECODE_INTERPRETER_OK on success. + * Return LTTNG_KERNEL_BYTECODE_INTERPRETER_ERROR on error. + * + * For FILTER bytecode: expect a struct lttng_kernel_bytecode_filter_ctx * + * as @ctx argument. + * For CAPTURE bytecode: expect a struct lttng_interpreter_output * + * as @ctx argument. */ -static -uint64_t bytecode_interpret(void *interpreter_data, - struct lttng_probe_ctx *lttng_probe_ctx, +int lttng_bytecode_interpret(struct lttng_kernel_bytecode_runtime *kernel_bytecode, const char *interpreter_stack_data, - struct lttng_interpreter_output *output) + struct lttng_kernel_probe_ctx *lttng_probe_ctx, + void *caller_ctx) { - struct bytecode_runtime *bytecode = interpreter_data; + struct bytecode_runtime *bytecode = container_of(kernel_bytecode, struct bytecode_runtime, p); void *pc, *next_pc, *start_pc; int ret = -EINVAL; uint64_t retval = 0; @@ -919,8 +1026,7 @@ uint64_t bytecode_interpret(void *interpreter_data, goto end; OP(BYTECODE_OP_RETURN): - OP(BYTECODE_OP_RETURN_S64): - /* LTTNG_INTERPRETER_DISCARD or LTTNG_INTERPRETER_RECORD_FLAG */ + /* LTTNG_KERNEL_BYTECODE_INTERPRETER_ERROR or LTTNG_KERNEL_BYTECODE_INTERPRETER_OK */ switch (estack_ax_t) { case REG_S64: case REG_U64: @@ -929,7 +1035,7 @@ uint64_t bytecode_interpret(void *interpreter_data, case REG_DOUBLE: case REG_STRING: case REG_PTR: - if (!output) { + if (kernel_bytecode->type != LTTNG_KERNEL_BYTECODE_TYPE_CAPTURE) { ret = -EINVAL; goto end; } @@ -943,6 +1049,12 @@ uint64_t bytecode_interpret(void *interpreter_data, ret = 0; goto end; + OP(BYTECODE_OP_RETURN_S64): + /* LTTNG_KERNEL_BYTECODE_INTERPRETER_ERROR or LTTNG_KERNEL_BYTECODE_INTERPRETER_OK */ + retval = !!estack_ax_v; + ret = 0; + goto end; + /* binary */ OP(BYTECODE_OP_MUL): OP(BYTECODE_OP_DIV): @@ -1476,15 +1588,15 @@ uint64_t bytecode_interpret(void *interpreter_data, { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; - struct lttng_ctx_field *ctx_field; - union lttng_ctx_value v; + struct lttng_kernel_ctx_field *ctx_field; + struct lttng_ctx_value v; dbg_printk("get context ref offset %u type string\n", ref->offset); ctx_field = <tng_static_ctx->fields[ref->offset]; - ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); + ctx_field->get_value(ctx_field->priv, lttng_probe_ctx, &v); estack_push(stack, top, ax, bx, ax_t, bx_t); - estack_ax(stack, top)->u.s.str = v.str; + estack_ax(stack, top)->u.s.str = v.u.str; if (unlikely(!estack_ax(stack, top)->u.s.str)) { dbg_printk("Bytecode warning: loading a NULL string.\n"); ret = -EINVAL; @@ -1504,15 +1616,15 @@ uint64_t bytecode_interpret(void *interpreter_data, { struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; - struct lttng_ctx_field *ctx_field; - union lttng_ctx_value v; + struct lttng_kernel_ctx_field *ctx_field; + struct lttng_ctx_value v; dbg_printk("get context ref offset %u type s64\n", ref->offset); ctx_field = <tng_static_ctx->fields[ref->offset]; - ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); + ctx_field->get_value(ctx_field->priv, lttng_probe_ctx, &v); estack_push(stack, top, ax, bx, ax_t, bx_t); - estack_ax_v = v.s64; + estack_ax_v = v.u.s64; estack_ax_t = REG_S64; dbg_printk("ref get context s64 %lld\n", (long long) estack_ax_v); @@ -1776,6 +1888,7 @@ uint64_t bytecode_interpret(void *interpreter_data, estack_ax(stack, top)->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->type = REG_STRING; + estack_ax(stack, top)->u.s.user = 0; next_pc += sizeof(struct load_op); PO; } @@ -1796,40 +1909,70 @@ uint64_t bytecode_interpret(void *interpreter_data, estack_ax(stack, top)->u.s.literal_type = ESTACK_STRING_LITERAL_TYPE_NONE; estack_ax(stack, top)->type = REG_STRING; + estack_ax(stack, top)->u.s.user = 0; next_pc += sizeof(struct load_op); PO; } END_OP end: - /* Return _DISCARD on error. */ + /* No need to prepare output if an error occurred. */ if (ret) - return LTTNG_INTERPRETER_DISCARD; + return LTTNG_KERNEL_BYTECODE_INTERPRETER_ERROR; - if (output) { - return lttng_bytecode_interpret_format_output( - estack_ax(stack, top), output); + /* Prepare output. */ + switch (kernel_bytecode->type) { + case LTTNG_KERNEL_BYTECODE_TYPE_FILTER: + { + struct lttng_kernel_bytecode_filter_ctx *filter_ctx = + (struct lttng_kernel_bytecode_filter_ctx *) caller_ctx; + if (retval) + filter_ctx->result = LTTNG_KERNEL_BYTECODE_FILTER_ACCEPT; + else + filter_ctx->result = LTTNG_KERNEL_BYTECODE_FILTER_REJECT; + break; } - - return retval; -} -LTTNG_STACK_FRAME_NON_STANDARD(bytecode_interpret); - -uint64_t lttng_bytecode_filter_interpret(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); + case LTTNG_KERNEL_BYTECODE_TYPE_CAPTURE: + ret = lttng_bytecode_interpret_format_output(estack_ax(stack, top), + (struct lttng_interpreter_output *) caller_ctx); + break; + default: + ret = -EINVAL; + break; + } + if (ret) + return LTTNG_KERNEL_BYTECODE_INTERPRETER_ERROR; + else + return LTTNG_KERNEL_BYTECODE_INTERPRETER_OK; } +LTTNG_STACK_FRAME_NON_STANDARD(lttng_bytecode_interpret); -uint64_t lttng_bytecode_capture_interpret(void *capture_data, - struct lttng_probe_ctx *lttng_probe_ctx, - const char *capture_stack_data, - struct lttng_interpreter_output *output) +/* + * Return LTTNG_KERNEL_EVENT_FILTER_ACCEPT or LTTNG_KERNEL_EVENT_FILTER_REJECT. + */ +int lttng_kernel_interpret_event_filter(const struct lttng_kernel_event_common *event, + const char *interpreter_stack_data, + struct lttng_kernel_probe_ctx *probe_ctx, + void *event_filter_ctx __attribute__((unused))) { - return bytecode_interpret(capture_data, lttng_probe_ctx, - capture_stack_data, output); + struct lttng_kernel_bytecode_runtime *filter_bc_runtime; + struct list_head *filter_bytecode_runtime_head = &event->priv->filter_bytecode_runtime_head; + struct lttng_kernel_bytecode_filter_ctx bytecode_filter_ctx; + bool filter_record = false; + + list_for_each_entry_rcu(filter_bc_runtime, filter_bytecode_runtime_head, node) { + if (likely(filter_bc_runtime->interpreter_func(filter_bc_runtime, + interpreter_stack_data, probe_ctx, &bytecode_filter_ctx) == LTTNG_KERNEL_BYTECODE_INTERPRETER_OK)) { + if (unlikely(bytecode_filter_ctx.result == LTTNG_KERNEL_BYTECODE_FILTER_ACCEPT)) { + filter_record = true; + break; + } + } + } + if (filter_record) + return LTTNG_KERNEL_EVENT_FILTER_ACCEPT; + else + return LTTNG_KERNEL_EVENT_FILTER_REJECT; } #undef START_OP