X-Git-Url: http://git.liburcu.org/?p=lttng-modules.git;a=blobdiff_plain;f=lttng-filter-interpreter.c;h=bf69549707657ed89fd524f35b74ecb0fc7dcea7;hp=e13146241ae36e4631d27319513b8f055b5194ca;hb=cef5d79ec834edb32f33cdf45ad10b3b32e59726;hpb=cbc190407df71e058ef656d4eaf30cee31b4bb58 diff --git a/lttng-filter-interpreter.c b/lttng-filter-interpreter.c index e1314624..bf695497 100644 --- a/lttng-filter-interpreter.c +++ b/lttng-filter-interpreter.c @@ -1,32 +1,16 @@ -/* +/* SPDX-License-Identifier: MIT + * * lttng-filter-interpreter.c * * LTTng modules filter interpreter. * * Copyright (C) 2010-2016 Mathieu Desnoyers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include #include #include +#include #include #include @@ -269,7 +253,7 @@ uint64_t lttng_filter_false(void *filter_data, */ #define START_OP \ - start_pc = &bytecode->data[0]; \ + start_pc = &bytecode->code[0]; \ pc = next_pc = start_pc; \ if (unlikely(pc - start_pc >= bytecode->len)) \ goto end; \ @@ -286,6 +270,337 @@ LABEL_##name #endif +static int context_get_index(struct lttng_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; + + ctx_field = <tng_static_ctx->fields[idx]; + field = &ctx_field->event_field; + ptr->type = LOAD_OBJECT; + /* field is only used for types nested within variants. */ + ptr->field = NULL; + + switch (field->type.atype) { + case atype_integer: + ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); + if (field->type.u.basic.integer.signedness) { + ptr->object_type = OBJECT_TYPE_S64; + ptr->u.s64 = v.s64; + ptr->ptr = &ptr->u.s64; + } else { + ptr->object_type = OBJECT_TYPE_U64; + ptr->u.u64 = v.s64; /* Cast. */ + ptr->ptr = &ptr->u.u64; + } + break; + case atype_enum: + { + const struct lttng_integer_type *itype = + &field->type.u.basic.enumeration.container_type; + + ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); + if (itype->signedness) { + ptr->object_type = OBJECT_TYPE_S64; + ptr->u.s64 = v.s64; + ptr->ptr = &ptr->u.s64; + } else { + ptr->object_type = OBJECT_TYPE_U64; + ptr->u.u64 = v.s64; /* Cast. */ + ptr->ptr = &ptr->u.u64; + } + break; + } + case atype_array: + if (field->type.u.array.elem_type.atype != atype_integer) { + printk(KERN_WARNING "Array nesting only supports integer types.\n"); + return -EINVAL; + } + if (field->type.u.array.elem_type.u.basic.integer.encoding == lttng_encode_none) { + printk(KERN_WARNING "Only string arrays are supported for contexts.\n"); + return -EINVAL; + } + ptr->object_type = OBJECT_TYPE_STRING; + ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); + ptr->ptr = v.str; + break; + case atype_sequence: + if (field->type.u.sequence.elem_type.atype != atype_integer) { + printk(KERN_WARNING "Sequence nesting only supports integer types.\n"); + return -EINVAL; + } + if (field->type.u.sequence.elem_type.u.basic.integer.encoding == lttng_encode_none) { + printk(KERN_WARNING "Only string sequences are supported for contexts.\n"); + return -EINVAL; + } + ptr->object_type = OBJECT_TYPE_STRING; + ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); + ptr->ptr = v.str; + break; + case atype_array_bitfield: + printk(KERN_WARNING "Bitfield array type is not supported.\n"); + return -EINVAL; + case atype_sequence_bitfield: + printk(KERN_WARNING "Bitfield sequence type is not supported.\n"); + return -EINVAL; + case atype_string: + ptr->object_type = OBJECT_TYPE_STRING; + ctx_field->get_value(ctx_field, lttng_probe_ctx, &v); + ptr->ptr = v.str; + break; + case atype_struct: + printk(KERN_WARNING "Structure type cannot be loaded.\n"); + return -EINVAL; + default: + printk(KERN_WARNING "Unknown type: %d", (int) field->type.atype); + return -EINVAL; + } + return 0; +} + +static int dynamic_get_index(struct lttng_probe_ctx *lttng_probe_ctx, + struct bytecode_runtime *runtime, + uint64_t index, struct estack_entry *stack_top) +{ + 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: + switch (stack_top->u.ptr.object_type) { + case OBJECT_TYPE_ARRAY: + { + const char *ptr; + + WARN_ON_ONCE(gid->offset >= gid->array_len); + /* Skip count (unsigned long) */ + ptr = *(const char **) (stack_top->u.ptr.ptr + sizeof(unsigned long)); + ptr = ptr + gid->offset; + 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. */ + stack_top->u.ptr.field = NULL; + break; + } + case OBJECT_TYPE_SEQUENCE: + { + const char *ptr; + size_t ptr_seq_len; + + ptr = *(const char **) (stack_top->u.ptr.ptr + sizeof(unsigned long)); + ptr_seq_len = *(unsigned long *) stack_top->u.ptr.ptr; + if (gid->offset >= gid->elem.len * ptr_seq_len) { + ret = -EINVAL; + goto end; + } + ptr = ptr + gid->offset; + 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. */ + stack_top->u.ptr.field = NULL; + break; + } + case OBJECT_TYPE_STRUCT: + printk(KERN_WARNING "Nested structures are not supported yet.\n"); + ret = -EINVAL; + goto end; + case OBJECT_TYPE_VARIANT: + default: + printk(KERN_WARNING "Unexpected get index type %d", + (int) stack_top->u.ptr.object_type); + ret = -EINVAL; + goto end; + } + break; + case LOAD_ROOT_CONTEXT: + case LOAD_ROOT_APP_CONTEXT: /* Fall-through */ + { + ret = context_get_index(lttng_probe_ctx, + &stack_top->u.ptr, + gid->ctx_index); + if (ret) { + goto end; + } + break; + } + case LOAD_ROOT_PAYLOAD: + stack_top->u.ptr.ptr += gid->offset; + if (gid->elem.type == OBJECT_TYPE_STRING) + 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; + break; + } + return 0; + +end: + return ret; +} + +static int dynamic_load_field(struct estack_entry *stack_top) +{ + int ret; + + switch (stack_top->u.ptr.type) { + case LOAD_OBJECT: + break; + case LOAD_ROOT_CONTEXT: + case LOAD_ROOT_APP_CONTEXT: + case LOAD_ROOT_PAYLOAD: + default: + dbg_printk("Filter warning: cannot load root, missing field name.\n"); + ret = -EINVAL; + goto end; + } + 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; + break; + case OBJECT_TYPE_S16: + { + int16_t tmp; + + dbg_printk("op load field s16\n"); + tmp = *(int16_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.rev_bo) + __swab16s(&tmp); + stack_top->u.v = tmp; + break; + } + case OBJECT_TYPE_S32: + { + int32_t tmp; + + dbg_printk("op load field s32\n"); + tmp = *(int32_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.rev_bo) + __swab32s(&tmp); + stack_top->u.v = tmp; + break; + } + case OBJECT_TYPE_S64: + { + int64_t tmp; + + dbg_printk("op load field s64\n"); + tmp = *(int64_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.rev_bo) + __swab64s(&tmp); + stack_top->u.v = tmp; + break; + } + case OBJECT_TYPE_U8: + dbg_printk("op load field u8\n"); + stack_top->u.v = *(uint8_t *) stack_top->u.ptr.ptr; + break; + case OBJECT_TYPE_U16: + { + uint16_t tmp; + + dbg_printk("op load field s16\n"); + tmp = *(uint16_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.rev_bo) + __swab16s(&tmp); + stack_top->u.v = tmp; + break; + } + case OBJECT_TYPE_U32: + { + uint32_t tmp; + + dbg_printk("op load field u32\n"); + tmp = *(uint32_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.rev_bo) + __swab32s(&tmp); + stack_top->u.v = tmp; + break; + } + case OBJECT_TYPE_U64: + { + uint64_t tmp; + + dbg_printk("op load field u64\n"); + tmp = *(uint64_t *) stack_top->u.ptr.ptr; + if (stack_top->u.ptr.rev_bo) + __swab64s(&tmp); + stack_top->u.v = tmp; + break; + } + case OBJECT_TYPE_STRING: + { + const char *str; + + 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("Filter warning: loading a NULL string.\n"); + ret = -EINVAL; + goto end; + } + stack_top->u.s.seq_len = LTTNG_SIZE_MAX; + stack_top->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; + break; + } + case OBJECT_TYPE_STRING_SEQUENCE: + { + const char *ptr; + + dbg_printk("op load field string sequence\n"); + 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("Filter warning: loading a NULL sequence.\n"); + ret = -EINVAL; + goto end; + } + stack_top->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; + break; + } + case OBJECT_TYPE_DYNAMIC: + /* + * Dynamic types in context are looked up + * by context get index. + */ + ret = -EINVAL; + goto end; + case OBJECT_TYPE_DOUBLE: + ret = -EINVAL; + goto end; + case OBJECT_TYPE_SEQUENCE: + 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"); + ret = -EINVAL; + goto end; + } + return 0; + +end: + return ret; +} + /* * Return 0 (discard), or raise the 0x1 flag (log event). * Currently, other flags are kept for future extensions and have no @@ -315,11 +630,11 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, [ FILTER_OP_MOD ] = &&LABEL_FILTER_OP_MOD, [ FILTER_OP_PLUS ] = &&LABEL_FILTER_OP_PLUS, [ FILTER_OP_MINUS ] = &&LABEL_FILTER_OP_MINUS, - [ FILTER_OP_RSHIFT ] = &&LABEL_FILTER_OP_RSHIFT, - [ FILTER_OP_LSHIFT ] = &&LABEL_FILTER_OP_LSHIFT, - [ FILTER_OP_BIN_AND ] = &&LABEL_FILTER_OP_BIN_AND, - [ FILTER_OP_BIN_OR ] = &&LABEL_FILTER_OP_BIN_OR, - [ FILTER_OP_BIN_XOR ] = &&LABEL_FILTER_OP_BIN_XOR, + [ FILTER_OP_BIT_RSHIFT ] = &&LABEL_FILTER_OP_BIT_RSHIFT, + [ FILTER_OP_BIT_LSHIFT ] = &&LABEL_FILTER_OP_BIT_LSHIFT, + [ FILTER_OP_BIT_AND ] = &&LABEL_FILTER_OP_BIT_AND, + [ FILTER_OP_BIT_OR ] = &&LABEL_FILTER_OP_BIT_OR, + [ FILTER_OP_BIT_XOR ] = &&LABEL_FILTER_OP_BIT_XOR, /* binary comparators */ [ FILTER_OP_EQ ] = &&LABEL_FILTER_OP_EQ, @@ -414,6 +729,33 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, /* load userspace field ref */ [ FILTER_OP_LOAD_FIELD_REF_USER_STRING ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_USER_STRING, [ FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE ] = &&LABEL_FILTER_OP_LOAD_FIELD_REF_USER_SEQUENCE, + + /* Instructions for recursive traversal through composed types. */ + [ FILTER_OP_GET_CONTEXT_ROOT ] = &&LABEL_FILTER_OP_GET_CONTEXT_ROOT, + [ FILTER_OP_GET_APP_CONTEXT_ROOT ] = &&LABEL_FILTER_OP_GET_APP_CONTEXT_ROOT, + [ FILTER_OP_GET_PAYLOAD_ROOT ] = &&LABEL_FILTER_OP_GET_PAYLOAD_ROOT, + + [ FILTER_OP_GET_SYMBOL ] = &&LABEL_FILTER_OP_GET_SYMBOL, + [ FILTER_OP_GET_SYMBOL_FIELD ] = &&LABEL_FILTER_OP_GET_SYMBOL_FIELD, + [ FILTER_OP_GET_INDEX_U16 ] = &&LABEL_FILTER_OP_GET_INDEX_U16, + [ FILTER_OP_GET_INDEX_U64 ] = &&LABEL_FILTER_OP_GET_INDEX_U64, + + [ FILTER_OP_LOAD_FIELD ] = &&LABEL_FILTER_OP_LOAD_FIELD, + [ FILTER_OP_LOAD_FIELD_S8 ] = &&LABEL_FILTER_OP_LOAD_FIELD_S8, + [ FILTER_OP_LOAD_FIELD_S16 ] = &&LABEL_FILTER_OP_LOAD_FIELD_S16, + [ FILTER_OP_LOAD_FIELD_S32 ] = &&LABEL_FILTER_OP_LOAD_FIELD_S32, + [ FILTER_OP_LOAD_FIELD_S64 ] = &&LABEL_FILTER_OP_LOAD_FIELD_S64, + [ FILTER_OP_LOAD_FIELD_U8 ] = &&LABEL_FILTER_OP_LOAD_FIELD_U8, + [ FILTER_OP_LOAD_FIELD_U16 ] = &&LABEL_FILTER_OP_LOAD_FIELD_U16, + [ FILTER_OP_LOAD_FIELD_U32 ] = &&LABEL_FILTER_OP_LOAD_FIELD_U32, + [ FILTER_OP_LOAD_FIELD_U64 ] = &&LABEL_FILTER_OP_LOAD_FIELD_U64, + [ FILTER_OP_LOAD_FIELD_STRING ] = &&LABEL_FILTER_OP_LOAD_FIELD_STRING, + [ FILTER_OP_LOAD_FIELD_SEQUENCE ] = &&LABEL_FILTER_OP_LOAD_FIELD_SEQUENCE, + [ FILTER_OP_LOAD_FIELD_DOUBLE ] = &&LABEL_FILTER_OP_LOAD_FIELD_DOUBLE, + + [ FILTER_OP_UNARY_BIT_NOT ] = &&LABEL_FILTER_OP_UNARY_BIT_NOT, + + [ FILTER_OP_RETURN_S64 ] = &&LABEL_FILTER_OP_RETURN_S64, }; #endif /* #ifndef INTERPRETER_USE_SWITCH */ @@ -431,6 +773,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; OP(FILTER_OP_RETURN): + OP(FILTER_OP_RETURN_S64): /* LTTNG_FILTER_DISCARD or LTTNG_FILTER_RECORD_FLAG */ retval = !!estack_ax_v; ret = 0; @@ -442,11 +785,6 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, OP(FILTER_OP_MOD): OP(FILTER_OP_PLUS): OP(FILTER_OP_MINUS): - OP(FILTER_OP_RSHIFT): - OP(FILTER_OP_LSHIFT): - OP(FILTER_OP_BIN_AND): - OP(FILTER_OP_BIN_OR): - OP(FILTER_OP_BIN_XOR): printk(KERN_WARNING "unsupported bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; @@ -634,6 +972,66 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, BUG_ON(1); PO; } + OP(FILTER_OP_BIT_RSHIFT): + { + int64_t res; + + /* 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_ax_v = res; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_BIT_LSHIFT): + { + int64_t res; + + /* 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_ax_v = res; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_BIT_AND): + { + int64_t res; + + res = ((uint64_t) estack_bx_v & (uint64_t) estack_ax_v); + estack_pop(stack, top, ax, bx); + estack_ax_v = res; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_BIT_OR): + { + int64_t res; + + res = ((uint64_t) estack_bx_v | (uint64_t) estack_ax_v); + estack_pop(stack, top, ax, bx); + estack_ax_v = res; + next_pc += sizeof(struct binary_op); + PO; + } + OP(FILTER_OP_BIT_XOR): + { + int64_t res; + + res = ((uint64_t) estack_bx_v ^ (uint64_t) estack_ax_v); + estack_pop(stack, top, ax, bx); + estack_ax_v = res; + next_pc += sizeof(struct binary_op); + PO; + } /* unary */ OP(FILTER_OP_UNARY_PLUS): @@ -645,6 +1043,13 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, goto end; + OP(FILTER_OP_UNARY_BIT_NOT): + { + estack_ax_v = ~(uint64_t) estack_ax_v; + next_pc += sizeof(struct unary_op); + PO; + } + OP(FILTER_OP_UNARY_PLUS_S64): { next_pc += sizeof(struct unary_op); @@ -955,6 +1360,214 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, PO; } + OP(FILTER_OP_GET_CONTEXT_ROOT): + { + dbg_printk("op get context root\n"); + estack_push(stack, top, ax, bx); + estack_ax(stack, top)->u.ptr.type = LOAD_ROOT_CONTEXT; + /* "field" only needed for variants. */ + estack_ax(stack, top)->u.ptr.field = NULL; + next_pc += sizeof(struct load_op); + PO; + } + + OP(FILTER_OP_GET_APP_CONTEXT_ROOT): + { + BUG_ON(1); + PO; + } + + OP(FILTER_OP_GET_PAYLOAD_ROOT): + { + dbg_printk("op get app payload root\n"); + estack_push(stack, top, ax, bx); + estack_ax(stack, top)->u.ptr.type = LOAD_ROOT_PAYLOAD; + estack_ax(stack, top)->u.ptr.ptr = filter_stack_data; + /* "field" only needed for variants. */ + estack_ax(stack, top)->u.ptr.field = NULL; + next_pc += sizeof(struct load_op); + PO; + } + + OP(FILTER_OP_GET_SYMBOL): + { + 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"); + ret = -EINVAL; + goto end; + case LOAD_ROOT_CONTEXT: + case LOAD_ROOT_APP_CONTEXT: + case LOAD_ROOT_PAYLOAD: + /* + * symbol lookup is performed by + * specialization. + */ + ret = -EINVAL; + goto end; + } + next_pc += sizeof(struct load_op) + sizeof(struct get_symbol); + PO; + } + + OP(FILTER_OP_GET_SYMBOL_FIELD): + { + /* + * Used for first variant encountered in a + * traversal. Variants are not implemented yet. + */ + ret = -EINVAL; + goto end; + } + + OP(FILTER_OP_GET_INDEX_U16): + { + struct load_op *insn = (struct load_op *) pc; + struct get_index_u16 *index = (struct get_index_u16 *) insn->data; + + dbg_printk("op get index u16\n"); + ret = dynamic_get_index(lttng_probe_ctx, bytecode, index->index, estack_ax(stack, top)); + if (ret) + goto end; + estack_ax_v = estack_ax(stack, top)->u.v; + next_pc += sizeof(struct load_op) + sizeof(struct get_index_u16); + PO; + } + + OP(FILTER_OP_GET_INDEX_U64): + { + struct load_op *insn = (struct load_op *) pc; + struct get_index_u64 *index = (struct get_index_u64 *) insn->data; + + dbg_printk("op get index u64\n"); + ret = dynamic_get_index(lttng_probe_ctx, bytecode, index->index, estack_ax(stack, top)); + if (ret) + goto end; + estack_ax_v = estack_ax(stack, top)->u.v; + next_pc += sizeof(struct load_op) + sizeof(struct get_index_u64); + PO; + } + + OP(FILTER_OP_LOAD_FIELD): + { + dbg_printk("op load field\n"); + ret = dynamic_load_field(estack_ax(stack, top)); + if (ret) + goto end; + estack_ax_v = estack_ax(stack, top)->u.v; + next_pc += sizeof(struct load_op); + PO; + } + + OP(FILTER_OP_LOAD_FIELD_S8): + { + dbg_printk("op load field s8\n"); + + estack_ax_v = *(int8_t *) estack_ax(stack, top)->u.ptr.ptr; + next_pc += sizeof(struct load_op); + PO; + } + OP(FILTER_OP_LOAD_FIELD_S16): + { + dbg_printk("op load field s16\n"); + + estack_ax_v = *(int16_t *) estack_ax(stack, top)->u.ptr.ptr; + next_pc += sizeof(struct load_op); + PO; + } + OP(FILTER_OP_LOAD_FIELD_S32): + { + dbg_printk("op load field s32\n"); + + estack_ax_v = *(int32_t *) estack_ax(stack, top)->u.ptr.ptr; + next_pc += sizeof(struct load_op); + PO; + } + OP(FILTER_OP_LOAD_FIELD_S64): + { + dbg_printk("op load field s64\n"); + + estack_ax_v = *(int64_t *) estack_ax(stack, top)->u.ptr.ptr; + next_pc += sizeof(struct load_op); + PO; + } + OP(FILTER_OP_LOAD_FIELD_U8): + { + dbg_printk("op load field u8\n"); + + estack_ax_v = *(uint8_t *) estack_ax(stack, top)->u.ptr.ptr; + next_pc += sizeof(struct load_op); + PO; + } + OP(FILTER_OP_LOAD_FIELD_U16): + { + dbg_printk("op load field u16\n"); + + estack_ax_v = *(uint16_t *) estack_ax(stack, top)->u.ptr.ptr; + next_pc += sizeof(struct load_op); + PO; + } + OP(FILTER_OP_LOAD_FIELD_U32): + { + dbg_printk("op load field u32\n"); + + estack_ax_v = *(uint32_t *) estack_ax(stack, top)->u.ptr.ptr; + next_pc += sizeof(struct load_op); + PO; + } + OP(FILTER_OP_LOAD_FIELD_U64): + { + dbg_printk("op load field u64\n"); + + estack_ax_v = *(uint64_t *) estack_ax(stack, top)->u.ptr.ptr; + next_pc += sizeof(struct load_op); + PO; + } + OP(FILTER_OP_LOAD_FIELD_DOUBLE): + { + ret = -EINVAL; + goto end; + } + + OP(FILTER_OP_LOAD_FIELD_STRING): + { + const char *str; + + dbg_printk("op load field string\n"); + str = (const char *) estack_ax(stack, top)->u.ptr.ptr; + estack_ax(stack, top)->u.s.str = str; + if (unlikely(!estack_ax(stack, top)->u.s.str)) { + dbg_printk("Filter warning: loading a NULL string.\n"); + ret = -EINVAL; + goto end; + } + estack_ax(stack, top)->u.s.seq_len = LTTNG_SIZE_MAX; + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; + next_pc += sizeof(struct load_op); + PO; + } + + OP(FILTER_OP_LOAD_FIELD_SEQUENCE): + { + const char *ptr; + + dbg_printk("op load field string sequence\n"); + ptr = estack_ax(stack, top)->u.ptr.ptr; + estack_ax(stack, top)->u.s.seq_len = *(unsigned long *) ptr; + estack_ax(stack, top)->u.s.str = *(const char **) (ptr + sizeof(unsigned long)); + if (unlikely(!estack_ax(stack, top)->u.s.str)) { + dbg_printk("Filter warning: loading a NULL sequence.\n"); + ret = -EINVAL; + goto end; + } + estack_ax(stack, top)->u.s.literal_type = + ESTACK_STRING_LITERAL_TYPE_NONE; + next_pc += sizeof(struct load_op); + PO; + } + END_OP end: /* return 0 (discard) on error */