From: Francis Deslauriers Date: Mon, 11 May 2020 19:57:20 +0000 (-0400) Subject: Add `lttng_bytecode_interpret_format_output()` for top of stack extraction X-Git-Tag: v2.13.0-rc1~102 X-Git-Url: http://git.lttng.org/?p=lttng-modules.git;a=commitdiff_plain;h=03cb0cdd5c45e758520e1ba9d9300d448314d527 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. 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: I1cfd3ab6e84b7e308c48ed7a8a9555a3e338eea7 --- diff --git a/include/lttng/filter.h b/include/lttng/filter.h index 26538b5e..12833992 100644 --- a/include/lttng/filter.h +++ b/include/lttng/filter.h @@ -88,6 +88,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; @@ -168,6 +175,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 { @@ -175,10 +183,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; }; @@ -241,13 +245,48 @@ 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; + + 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 *lttng_filter_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, struct lttng_probe_ctx *lttng_probe_ctx, const char *filter_stack_data); uint64_t lttng_filter_interpret_bytecode(void *filter_data, diff --git a/src/lttng-filter-interpreter.c b/src/lttng-filter-interpreter.c index 7c05c24f..3273d4a0 100644 --- a/src/lttng-filter-interpreter.c +++ b/src/lttng-filter-interpreter.c @@ -15,8 +15,6 @@ #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. @@ -209,7 +207,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, struct lttng_probe_ctx *lttng_probe_ctx, const char *filter_stack_data) { @@ -361,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: @@ -383,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; } @@ -402,7 +393,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_sequence_nestable); stack_top->u.ptr.field = NULL; break; } @@ -435,8 +426,7 @@ 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; } return 0; @@ -603,16 +593,86 @@ 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; @@ -786,6 +846,12 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, 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; @@ -1188,7 +1254,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_printk("Filter warning: loading a NULL string.\n"); ret = -EINVAL; @@ -1213,9 +1279,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)]); if (unlikely(!estack_ax(stack, top)->u.s.str)) { dbg_printk("Filter warning: loading a NULL sequence.\n"); @@ -1238,7 +1304,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_printk("ref load s64 %lld\n", (long long) estack_ax_v); @@ -1387,7 +1453,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.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; @@ -1412,9 +1478,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.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"); @@ -1451,7 +1517,7 @@ uint64_t lttng_filter_interpret_bytecode(void *filter_data, dbg_printk("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(stack, top)->type = REG_PTR; @@ -1656,8 +1722,23 @@ 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; } +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 diff --git a/src/lttng-filter-specialize.c b/src/lttng-filter-specialize.c index 82b5cb64..86f7c536 100644 --- a/src/lttng-filter-specialize.c +++ b/src/lttng-filter-specialize.c @@ -407,6 +407,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) { @@ -476,6 +477,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/src/lttng-filter.c b/src/lttng-filter.c index 05eecd86..e2420240 100644 --- a/src/lttng-filter.c +++ b/src/lttng-filter.c @@ -459,7 +459,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; list_add_rcu(&runtime->p.node, insert_loc); alloc_error: @@ -472,7 +472,7 @@ void lttng_filter_sync_state(struct lttng_bytecode_runtime *runtime) struct lttng_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; }