Add `lttng_bytecode_interpret_format_output()` for top of stack extraction
authorFrancis Deslauriers <francis.deslauriers@efficios.com>
Mon, 11 May 2020 19:57:20 +0000 (15:57 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 25 Nov 2020 18:08:01 +0000 (13:08 -0500)
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 <francis.deslauriers@efficios.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: I1cfd3ab6e84b7e308c48ed7a8a9555a3e338eea7

include/lttng/filter.h
src/lttng-filter-interpreter.c
src/lttng-filter-specialize.c
src/lttng-filter.c

index 26538b5e932957382e3344349ec6f7ade0bddddf..128339923aead6232f6faffdf90becf5d9e6a5f2 100644 (file)
@@ -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,
index 7c05c24f97786127fbdd8fffc94ae83fcbcd8c80..3273d4a0f284892b6d0188126cf8aea02f3b4234 100644 (file)
@@ -15,8 +15,6 @@
 #include <lttng/filter.h>
 #include <lttng/string-utils.h>
 
-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
index 82b5cb6400a785c7d8637e0674a8bba36d974c34..86f7c536a7bf29a75a4ccb746cac87436d1b2b60 100644 (file)
@@ -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) {
index 05eecd868b67c116010723affa28812bd559d72f..e24202408715a8e16f08a0e249af68fc1f0f44ba 100644 (file)
@@ -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;
 }
This page took 0.032126 seconds and 4 git commands to generate.