From: Francis Deslauriers Date: Wed, 18 Mar 2020 21:24:53 +0000 (-0400) Subject: Add `lttng_bytecode_interpret_format_output()` for top of stack extraction X-Git-Tag: v2.13.0-rc1~450 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=f3503ba91a8406767eec49927e847c681f4e994c;p=lttng-ust.git Add `lttng_bytecode_interpret_format_output()` for top of stack extraction This new static function will be used to extract the register on the top of stack after the execution of the bytecode. This is currently not used by the filter bytecode but will be used by capture bytecode in the future. The returned value is saved in a tagged union struct named `struct lttng_interpreter_output` and can be used by the caller of the interpreter function. Typically, this struct will be allocated on the stack to avoid dynamic allocation inside the tracepoint probes. Signed-off-by: Francis Deslauriers Signed-off-by: Mathieu Desnoyers Change-Id: Id8a64d55f2bfb1af1657634a36d34dba5325777f --- diff --git a/liblttng-ust/lttng-filter-interpreter.c b/liblttng-ust/lttng-filter-interpreter.c index 6c77cfe9..32610e6c 100644 --- a/liblttng-ust/lttng-filter-interpreter.c +++ b/liblttng-ust/lttng-filter-interpreter.c @@ -28,10 +28,15 @@ #include #include #include +#include + #include +#include + #include "lttng-filter.h" #include "string-utils.h" + /* * -1: wildcard found. * -2: unknown escape char. @@ -161,7 +166,7 @@ int stack_strcmp(struct estack *stack, int top, const char *cmp_type) return diff; } -uint64_t lttng_filter_false(void *filter_data, +uint64_t lttng_filter_interpret_bytecode_false(void *filter_data, const char *filter_stack_data) { return LTTNG_FILTER_DISCARD; @@ -235,8 +240,7 @@ static int context_get_index(struct lttng_ctx *ctx, ctx_field = &ctx->fields[idx]; field = &ctx_field->event_field; ptr->type = LOAD_OBJECT; - /* field is only used for types nested within variants. */ - ptr->field = NULL; + ptr->field = field; switch (field->type.atype) { case atype_integer: @@ -380,13 +384,6 @@ static int dynamic_get_index(struct lttng_ctx *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: @@ -402,7 +399,8 @@ static int dynamic_get_index(struct lttng_ctx *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. */ + assert(stack_top->u.ptr.field->type.atype == atype_array || + stack_top->u.ptr.field->type.atype == atype_array_nestable); stack_top->u.ptr.field = NULL; break; } @@ -421,7 +419,8 @@ static int dynamic_get_index(struct lttng_ctx *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. */ + assert(stack_top->u.ptr.field->type.atype == atype_sequence || + stack_top->u.ptr.field->type.atype == atype_sequence_nestable); stack_top->u.ptr.field = NULL; break; } @@ -454,8 +453,7 @@ static int dynamic_get_index(struct lttng_ctx *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; } return 0; @@ -625,15 +623,89 @@ 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_DOUBLE: + output->type = LTTNG_INTERPRETER_TYPE_DOUBLE; + output->u.d = ax->u.d; + 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_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, - const char *filter_stack_data) +static +uint64_t bytecode_interpret(void *interpreter_data, + const char *interpreter_stack_data, + struct lttng_interpreter_output *output) { - struct bytecode_runtime *bytecode = filter_data; + struct bytecode_runtime *bytecode = interpreter_data; struct lttng_ctx *ctx = rcu_dereference(*bytecode->p.pctx); void *pc, *next_pc, *start_pc; int ret = -EINVAL; @@ -802,7 +874,15 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, 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_UNKNOWN: default: ret = -EINVAL; goto end; @@ -1872,7 +1952,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, ref->offset); 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_printf("Filter warning: loading a NULL string.\n"); ret = -EINVAL; @@ -1896,9 +1976,9 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, ref->offset); 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)]); estack_ax_t = REG_STRING; if (unlikely(!estack_ax(stack, top)->u.s.str)) { @@ -1921,7 +2001,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, ref->offset); 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_printf("ref load s64 %" PRIi64 "\n", estack_ax_v); next_pc += sizeof(struct load_op) + sizeof(struct field_ref); @@ -1936,7 +2016,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printf("load field ref offset %u type double\n", ref->offset); estack_push(stack, top, ax, bx, ax_t, bx_t); - memcpy(&estack_ax(stack, top)->u.d, &filter_stack_data[ref->offset], + memcpy(&estack_ax(stack, top)->u.d, &interpreter_stack_data[ref->offset], sizeof(struct literal_double)); estack_ax_t = REG_DOUBLE; dbg_printf("ref load double %g\n", estack_ax(stack, top)->u.d); @@ -2183,7 +2263,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printf("op get app payload root\n"); 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_t = REG_PTR; @@ -2394,9 +2474,21 @@ end: /* Return _DISCARD on error. */ if (ret) return LTTNG_FILTER_DISCARD; + + if (output) { + return lttng_bytecode_interpret_format_output(estack_ax(stack, top), + output); + } + return retval; } +uint64_t lttng_filter_interpret_bytecode(void *filter_data, + const char *filter_stack_data) +{ + return bytecode_interpret(filter_data, filter_stack_data, NULL); +} + #undef START_OP #undef OP #undef PO diff --git a/liblttng-ust/lttng-filter-specialize.c b/liblttng-ust/lttng-filter-specialize.c index 171895b7..f480f5c4 100644 --- a/liblttng-ust/lttng-filter-specialize.c +++ b/liblttng-ust/lttng-filter-specialize.c @@ -531,6 +531,7 @@ static int specialize_context_lookup(struct lttng_ctx *ctx, memset(&gid, 0, sizeof(gid)); gid.ctx_index = idx; gid.elem.type = load->object_type; + gid.field = field; data_offset = bytecode_push_data(runtime, &gid, __alignof__(gid), sizeof(gid)); if (data_offset < 0) { @@ -584,6 +585,7 @@ static int specialize_app_context_lookup(struct lttng_ctx **pctx, memset(&gid, 0, sizeof(gid)); gid.ctx_index = idx; gid.elem.type = load->object_type; + gid.field = field; data_offset = bytecode_push_data(runtime, &gid, __alignof__(gid), sizeof(gid)); if (data_offset < 0) { @@ -663,6 +665,7 @@ static int specialize_payload_lookup(const struct lttng_event_desc *event_desc, memset(&gid, 0, sizeof(gid)); gid.offset = field_offset; gid.elem.type = load->object_type; + gid.field = field; data_offset = bytecode_push_data(runtime, &gid, __alignof__(gid), sizeof(gid)); if (data_offset < 0) { diff --git a/liblttng-ust/lttng-filter.c b/liblttng-ust/lttng-filter.c index 70e489fc..c25df62a 100644 --- a/liblttng-ust/lttng-filter.c +++ b/liblttng-ust/lttng-filter.c @@ -485,7 +485,7 @@ int _lttng_filter_link_bytecode(const struct lttng_event_desc *event_desc, return 0; link_error: - runtime->p.filter = lttng_filter_false; + runtime->p.filter = lttng_filter_interpret_bytecode_false; runtime->p.link_failed = 1; cds_list_add_rcu(&runtime->p.node, insert_loc); alloc_error: @@ -498,7 +498,7 @@ void lttng_filter_sync_state(struct lttng_bytecode_runtime *runtime) struct lttng_ust_filter_bytecode_node *bc = runtime->bc; if (!bc->enabler->enabled || runtime->link_failed) - runtime->filter = lttng_filter_false; + runtime->filter = lttng_filter_interpret_bytecode_false; else runtime->filter = lttng_filter_interpret_bytecode; } diff --git a/liblttng-ust/lttng-filter.h b/liblttng-ust/lttng-filter.h index bf553cea..61bc213b 100644 --- a/liblttng-ust/lttng-filter.h +++ b/liblttng-ust/lttng-filter.h @@ -128,6 +128,13 @@ struct filter_get_index_data { uint64_t offset; /* in bytes */ size_t ctx_index; size_t array_len; + /* + * Field is only populated for LOAD_ROOT_CONTEXT, LOAD_ROOT_APP_CONTEXT + * and LOAD_ROOT_PAYLOAD. Left NULL for LOAD_OBJECT, considering that the + * interpreter needs to find it from the event fields and types to + * support variants. + */ + const struct lttng_event_field *field; struct { size_t len; enum object_type type; @@ -208,6 +215,7 @@ struct load_ptr { enum load_type type; enum object_type object_type; const void *ptr; + size_t nr_elem; bool rev_bo; /* Temporary place-holders for contexts. */ union { @@ -215,10 +223,6 @@ struct load_ptr { uint64_t u64; double d; } u; - /* - * "field" is only needed when nested under a variant, in which - * case we cannot specialize the nested operations. - */ const struct lttng_event_field *field; }; @@ -289,13 +293,49 @@ struct estack { (top)--; \ } while (0) +enum lttng_interpreter_type { + LTTNG_INTERPRETER_TYPE_S64, + LTTNG_INTERPRETER_TYPE_U64, + LTTNG_INTERPRETER_TYPE_SIGNED_ENUM, + LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM, + LTTNG_INTERPRETER_TYPE_DOUBLE, + LTTNG_INTERPRETER_TYPE_STRING, + LTTNG_INTERPRETER_TYPE_SEQUENCE, +}; + +/* + * Represents the output parameter of the lttng interpreter. + * Currently capturable field classes are integer, double, string and sequence + * of integer. + */ +struct lttng_interpreter_output { + enum lttng_interpreter_type type; + union { + int64_t s; + uint64_t u; + double d; + + struct { + const char *str; + size_t len; + } str; + struct { + const void *ptr; + size_t nr_elem; + + /* Inner type. */ + const struct lttng_type *nested_type; + } sequence; + } u; +}; + const char *print_op(enum filter_op op); int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode); int lttng_filter_specialize_bytecode(const struct lttng_event_desc *event_desc, struct bytecode_runtime *bytecode); -uint64_t lttng_filter_false(void *filter_data, +uint64_t lttng_filter_interpret_bytecode_false(void *filter_data, const char *filter_stack_data); uint64_t lttng_filter_interpret_bytecode(void *filter_data, const char *filter_stack_data);